├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .nvmrc ├── .yo-rc.json ├── Gruntfile.coffee ├── README.md ├── bower.json ├── css ├── source │ └── theme.scss └── theme.css ├── js └── loadhtmlslides.js ├── package-lock.json ├── package.json ├── resources ├── .gitkeep ├── koolaid.jpg ├── testing-pyramid.svg ├── wapuu-struggle.png └── wordpress.svg ├── slides ├── aaa.md ├── assert-wperror.md ├── assertcontains.md ├── assertequals.md ├── assertions.md ├── asserttrue.md ├── authentication.md ├── automated-testing.md ├── bootstrap.md ├── data-providers.md ├── example-output.md ├── factories.md ├── fixtures.md ├── go_to.md ├── groups.md ├── index.md ├── list.json ├── messy-wordpress.md ├── messy-wordpress2.md ├── mockery.md ├── negative-assertions.md ├── phpunit-markup-assertions.md ├── phpunit.md ├── registering-post-type.md ├── regression-tests.md ├── regression-tests2.md ├── regression-tests3.md ├── scaffold-files.md ├── scaffold-files2.md ├── scaffold-with-wpcli.md ├── system-under-test.md ├── tdd.md ├── tdd2.md ├── test-class.md ├── test-doubles.md ├── test-method.md ├── test-structure.md ├── testing-assets.md ├── testing-fundamentals.md ├── testing-hooks.md ├── testing-hooks2.md ├── testing-http-requests.md ├── testing-output.md ├── testing-permissions.md ├── testing-pyramid.md ├── testing-toolbox.md ├── thank-you.md ├── the-search-for-truth.md ├── types-of-tests.md ├── wordpress-test-class.md ├── wordpress-testing.md └── writing-our-first-test.md └── templates ├── _index.html └── _section.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | dist 4 | *.log 5 | .sass-cache 6 | /index.html 7 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esnext": true, 3 | "bitwise": true, 4 | "camelcase": true, 5 | "curly": true, 6 | "eqeqeq": true, 7 | "immed": true, 8 | "indent": 4, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "quotmark": "single", 13 | "undef": true, 14 | "unused": true, 15 | "strict": true, 16 | "trailing": true, 17 | "smarttabs": true, 18 | "white": true 19 | } 20 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-reveal": { 3 | "presentationTitle": "Confidently Testing WordPress", 4 | "packageVersion": "0.0.0", 5 | "useSass": true, 6 | "deployToGithubPages": true, 7 | "githubUsername": "stevegrunwell", 8 | "githubRepository": "confidently-testing-wordpress" 9 | } 10 | } -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | # Generated on 2019-01-13 using generator-reveal 1.0.0 2 | module.exports = (grunt) -> 3 | 4 | grunt.initConfig 5 | pkg: grunt.file.readJSON 'package.json' 6 | 7 | watch: 8 | 9 | livereload: 10 | options: 11 | livereload: true 12 | files: [ 13 | 'index.html' 14 | 'slides/{,*/}*.{md,html}' 15 | 'js/*.js' 16 | 'css/*.css' 17 | 'resources/**' 18 | ] 19 | 20 | index: 21 | files: [ 22 | 'templates/_index.html' 23 | 'templates/_section.html' 24 | 'slides/list.json' 25 | ] 26 | tasks: ['buildIndex'] 27 | 28 | coffeelint: 29 | files: ['Gruntfile.coffee'] 30 | tasks: ['coffeelint'] 31 | 32 | jshint: 33 | files: ['js/*.js'] 34 | tasks: ['jshint'] 35 | 36 | sass: 37 | files: ['css/source/theme.scss'] 38 | tasks: ['sass'] 39 | 40 | sass: 41 | 42 | theme: 43 | files: 44 | 'css/theme.css': 'css/source/theme.scss' 45 | 46 | connect: 47 | 48 | livereload: 49 | options: 50 | port: 9005 51 | base: '.' 52 | open: true 53 | livereload: true 54 | 55 | coffeelint: 56 | 57 | options: 58 | indentation: 59 | value: 4 60 | max_line_length: 61 | level: 'ignore' 62 | 63 | all: ['Gruntfile.coffee'] 64 | 65 | jshint: 66 | 67 | options: 68 | jshintrc: '.jshintrc' 69 | 70 | all: ['js/*.js'] 71 | 72 | copy: 73 | 74 | dist: 75 | files: [{ 76 | expand: true 77 | src: [ 78 | 'slides/**' 79 | 'bower_components/**' 80 | 'js/**' 81 | 'css/*.css' 82 | 'resources/**' 83 | ] 84 | dest: 'dist/' 85 | },{ 86 | expand: true 87 | src: ['index.html'] 88 | dest: 'dist/' 89 | filter: 'isFile' 90 | }] 91 | 92 | 93 | buildcontrol: 94 | 95 | options: 96 | dir: 'dist' 97 | commit: true 98 | push: true 99 | message: 'Built from %sourceCommit% on branch %sourceBranch%' 100 | pages: 101 | options: 102 | remote: '<%= pkg.repository.url %>' 103 | branch: 'gh-pages' 104 | 105 | 106 | 107 | # Load all grunt tasks. 108 | require('load-grunt-tasks')(grunt) 109 | 110 | grunt.registerTask 'buildIndex', 111 | 'Build index.html from templates/_index.html and slides/list.json.', 112 | -> 113 | indexTemplate = grunt.file.read 'templates/_index.html' 114 | sectionTemplate = grunt.file.read 'templates/_section.html' 115 | slides = grunt.file.readJSON 'slides/list.json' 116 | 117 | html = grunt.template.process indexTemplate, data: 118 | slides: 119 | slides 120 | section: (slide) -> 121 | grunt.template.process sectionTemplate, data: 122 | slide: 123 | slide 124 | grunt.file.write 'index.html', html 125 | 126 | grunt.registerTask 'test', 127 | '*Lint* javascript and coffee files.', [ 128 | 'coffeelint' 129 | 'jshint' 130 | ] 131 | 132 | grunt.registerTask 'serve', 133 | 'Run presentation locally and start watch process (living document).', [ 134 | 'buildIndex' 135 | 'sass' 136 | 'connect:livereload' 137 | 'watch' 138 | ] 139 | 140 | grunt.registerTask 'dist', 141 | 'Save presentation files to *dist* directory.', [ 142 | 'test' 143 | 'sass' 144 | 'buildIndex' 145 | 'copy' 146 | ] 147 | 148 | 149 | grunt.registerTask 'deploy', 150 | 'Deploy to Github Pages', [ 151 | 'dist' 152 | 'buildcontrol' 153 | ] 154 | 155 | 156 | # Define default task. 157 | grunt.registerTask 'default', [ 158 | 'test' 159 | 'serve' 160 | ] 161 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Confidently Testing WordPress 2 | 3 | WordPress is a tightly-coupled system, representing over a decade and a half of ideas, decisions, technological shifts, and ideological struggles. There's a lot of history to be parsed and often the simplest task can have unintended consequences. 4 | 5 | Meanwhile, automated testing is one of the best ways to ensure software can be released regularly with high confidence and low risk of regressions. Sadly, the leap from "building WordPress plugins" to "building WordPress plugins with tests" is often viewed as a challenging hurdle. Luckily, there are tools to set up a test harness within an existing codebase with ease. 6 | 7 | This talk introduces the fundamentals of automated testing, especially within the context of WordPress. After developing an understanding why automated testing is so critical, attendees will learn how to begin testing their plugins and themes, using features found both in PHPUnit and the WordPress core testing framework, to build and release quality software. 8 | 9 | :sparkles: **[View slides](http://stevegrunwell.github.io/confidently-testing-wordpress)** :sparkles: 10 | 11 | ## Resources 12 | 13 | * [PHPUnit](https://phpunit.de/) 14 | * [WordPress automated testing docs](https://make.wordpress.org/core/handbook/testing/automated-testing/phpunit/) 15 | * [The Five Types of Test Doubles and How to Create them in PHPUnit](https://jmauerhan.wordpress.com/2018/10/04/the-5-types-of-test-doubles-and-how-to-create-them-in-phpunit/) 16 | * [Mockery](http://docs.mockery.io/en/latest/) 17 | * [PHPUnit Markup Assertions](https://github.com/stevegrunwell/phpunit-markup-assertions) 18 | * [Trac ticket #46149: PHPUnit 8.x support](https://core.trac.wordpress.org/ticket/46149) 19 | 20 | ## Presentation History 21 | 22 | * [WordCamp US 2019](https://2019.us.wordcamp.org) — November 2, 2019 ([PDF](https://github.com/stevegrunwell/confidently-testing-wordpress/releases/download/wordcamp-us-2019/slides.pdf)) 23 | * [Cascadia PHP 2019](https://2019.cascadiaphp.com) — September 20, 2019 ([PDF](https://github.com/stevegrunwell/confidently-testing-wordpress/releases/download/cascadia-php-2019/slides.pdf), [Joind.in](https://joind.in/talk/e126f)) 24 | * [WordCamp Grand Rapids 2019](https://2019.grandrapids.wordcamp.org) — July 13, 2019 ([PDF](https://github.com/stevegrunwell/confidently-testing-wordpress/releases/download/wordcamp-grand-rapids-2019/slides.pdf)) 25 | * [WordCamp Kent 2019](https://2019.kent.wordcamp.org) — June 15, 2019 ([PDF](https://github.com/stevegrunwell/confidently-testing-wordpress/releases/download/wordcamp-kent-2019/slides.pdf)) 26 | * [WordCamp Dayton 2019](https://2019.dayton.wordcamp.org) — March 2, 2019 ([PDF](https://github.com/stevegrunwell/confidently-testing-wordpress/releases/download/wordcamp-dayton-2019/slides.pdf)) 27 | 28 | ## Credits 29 | 30 | * Struggle Wapuu by [Michelle Schulp](https://mynameismichelle.com/) 31 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confidently-testing-wordpress", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "reveal.js": "~3.3.0", 6 | "highlightjs": "~9.0.0" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /css/source/theme.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * White theme for reveal.js. This is the opposite of the 'black' theme. 3 | * 4 | * By Hakim El Hattab, http://hakim.se 5 | */ 6 | 7 | // Default mixins and settings ----------------- 8 | @import "../../bower_components/reveal.js/css/theme/template/mixins"; 9 | @import "../../bower_components/reveal.js/css/theme/template/settings"; 10 | // --------------------------------------------- 11 | 12 | // Include theme-specific fonts 13 | @import url('https://fonts.googleapis.com/css?family=Paytone+One|Open+Sans'); 14 | 15 | // Override theme settings (see ../../bower_components/reveal.js/css/theme/template/settings.scss) 16 | $backgroundColor: #fff; 17 | 18 | $mainColor: #434850; 19 | $headingColor: #333; 20 | 21 | $mainFontSize: 38px; 22 | $mainFont: 'Open Sans', sans-serif; 23 | $headingFont: 'Paytone One', 'Open Sans', sans-serif; 24 | $headingTextShadow: none; 25 | $headingLetterSpacing: normal; 26 | $headingTextTransform: uppercase; 27 | $headingFontWeight: 400; 28 | $linkColor: #5992bf; 29 | $linkColorHover: #396b93; 30 | $selectionBackgroundColor: lighten($linkColor, 25%); 31 | 32 | $heading1Size: 2em; 33 | $heading2Size: 1.6em; 34 | $heading3Size: 1.3em; 35 | $heading4Size: 1.0em; 36 | 37 | $red: #D8000C; 38 | $green: #4F8A10; 39 | 40 | section.has-dark-background { 41 | &, h1, h2, h3, h4, h5, h6 { 42 | color: #fff; 43 | } 44 | } 45 | 46 | // Theme template ------------------------------ 47 | @import "../../bower_components/reveal.js/css/theme/template/theme"; 48 | // --------------------------------------------- 49 | 50 | .reveal { 51 | .slide-background { 52 | video { 53 | height: auto; 54 | } 55 | } 56 | 57 | footer { 58 | position: fixed; 59 | top: auto; 60 | bottom: 1em; 61 | left: 1em; 62 | padding: .5em; 63 | z-index: 100; 64 | font-size: 0.5em; 65 | background: rgba(255, 255, 255, 0.7); 66 | 67 | a { 68 | color: darken($linkColor, 15%); 69 | } 70 | } 71 | 72 | output { 73 | @extend code; 74 | 75 | .text-notice { 76 | color: teal; 77 | } 78 | 79 | .text-fail { 80 | color: $red; 81 | } 82 | 83 | .highlight-warning, .highlight-fail { 84 | display: inline-block; 85 | padding: 0 2px; 86 | } 87 | 88 | .highlight-warning { 89 | color: #222; 90 | background: yellow; 91 | } 92 | 93 | .highlight-fail { 94 | color: #fff; 95 | background: $red; 96 | } 97 | } 98 | } 99 | 100 | .slides { 101 | 102 | h1, h2, h3, h4, h5, h6 { 103 | line-height: 1.35; 104 | 105 | img { 106 | border: none; 107 | box-shadow: none; 108 | max-width: 50%; 109 | max-height: 1.5em; 110 | } 111 | 112 | code { 113 | text-transform: none; 114 | } 115 | 116 | &.wordpress-icon { 117 | &:before { 118 | content: ''; 119 | display: inline-block; 120 | width: .7em; 121 | height: .7em; 122 | margin-right: .2em; 123 | vertical-align: middle; 124 | background: url('../resources/wordpress.svg') center center no-repeat; 125 | background-size: contain; 126 | } 127 | } 128 | } 129 | 130 | h1 { 131 | line-height: 1.5; 132 | small { 133 | display: block; 134 | margin-top: .5em; 135 | } 136 | } 137 | 138 | a { 139 | &:hover { 140 | img { 141 | box-shadow: none; 142 | } 143 | } 144 | } 145 | 146 | cite { 147 | display: block; 148 | margin-top: 1em; 149 | font-size: .8em; 150 | } 151 | 152 | .slides-link { 153 | display: block; 154 | margin-top: 1em; 155 | font-size: .86em; 156 | white-space: nowrap; 157 | + .slides-link { 158 | margin-top: 0; 159 | } 160 | } 161 | 162 | dl { 163 | width: 100%; 164 | margin: 0; 165 | 166 | dt { 167 | clear: both; 168 | float: left; 169 | width: 35%; 170 | font-family: $headingFont; 171 | text-align: right; 172 | } 173 | 174 | dd { 175 | clear: right; 176 | float: right; 177 | width: calc(65% - 40px); 178 | 179 | + dt, + dd { 180 | margin-top: .5em; 181 | } 182 | 183 | pre { 184 | width: 100%; 185 | } 186 | } 187 | 188 | dd + dt, 189 | dd + dt + dd { 190 | margin-top: .5em; 191 | } 192 | } 193 | 194 | blockquote { 195 | background: rgba(255, 255, 255, 0.8); 196 | } 197 | 198 | table { 199 | &.equivalence-table { 200 | td { 201 | border: none; 202 | } 203 | } 204 | } 205 | 206 | .fragment-replacement { 207 | .fragment.fade-out.visible, 208 | .fragment.fade-in:not(.visible) { 209 | display: none; 210 | } 211 | } 212 | 213 | .fragment.visible { 214 | &.highlight-red { 215 | color: $red !important; 216 | } 217 | &.highlight-green { 218 | color: $green !important; 219 | } 220 | } 221 | 222 | .pass { 223 | color: $green; 224 | } 225 | 226 | .fail { 227 | color: $red; 228 | } 229 | 230 | .status-icon { 231 | display: inline-block; 232 | width: 1em; 233 | font-size: .8em; 234 | vertical-align: center; 235 | } 236 | 237 | .seamless { 238 | &, img { 239 | border: 0; 240 | box-shadow: none; 241 | background: transparent; 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /css/theme.css: -------------------------------------------------------------------------------- 1 | /** 2 | * White theme for reveal.js. This is the opposite of the 'black' theme. 3 | * 4 | * By Hakim El Hattab, http://hakim.se 5 | */ 6 | @import url("https://fonts.googleapis.com/css?family=Paytone+One|Open+Sans"); 7 | section.has-dark-background, section.has-dark-background h1, section.has-dark-background h2, section.has-dark-background h3, section.has-dark-background h4, section.has-dark-background h5, section.has-dark-background h6 { 8 | color: #fff; } 9 | 10 | /********************************************* 11 | * GLOBAL STYLES 12 | *********************************************/ 13 | body { 14 | background: #fff; 15 | background-color: #fff; } 16 | 17 | .reveal { 18 | font-family: "Open Sans", sans-serif; 19 | font-size: 38px; 20 | font-weight: normal; 21 | color: #434850; } 22 | 23 | ::selection { 24 | color: #fff; 25 | background: #b5cee2; 26 | text-shadow: none; } 27 | 28 | .reveal .slides > section, 29 | .reveal .slides > section > section { 30 | line-height: 1.3; 31 | font-weight: inherit; } 32 | 33 | /********************************************* 34 | * HEADERS 35 | *********************************************/ 36 | .reveal h1, 37 | .reveal h2, 38 | .reveal h3, 39 | .reveal h4, 40 | .reveal h5, 41 | .reveal h6 { 42 | margin: 0 0 20px 0; 43 | color: #333; 44 | font-family: "Paytone One", "Open Sans", sans-serif; 45 | font-weight: 400; 46 | line-height: 1.2; 47 | letter-spacing: normal; 48 | text-transform: uppercase; 49 | text-shadow: none; 50 | word-wrap: break-word; } 51 | 52 | .reveal h1 { 53 | font-size: 2em; } 54 | 55 | .reveal h2 { 56 | font-size: 1.6em; } 57 | 58 | .reveal h3 { 59 | font-size: 1.3em; } 60 | 61 | .reveal h4 { 62 | font-size: 1em; } 63 | 64 | .reveal h1 { 65 | text-shadow: none; } 66 | 67 | /********************************************* 68 | * OTHER 69 | *********************************************/ 70 | .reveal p { 71 | margin: 20px 0; 72 | line-height: 1.3; } 73 | 74 | /* Ensure certain elements are never larger than the slide itself */ 75 | .reveal img, 76 | .reveal video, 77 | .reveal iframe { 78 | max-width: 95%; 79 | max-height: 95%; } 80 | 81 | .reveal strong, 82 | .reveal b { 83 | font-weight: bold; } 84 | 85 | .reveal em { 86 | font-style: italic; } 87 | 88 | .reveal ol, 89 | .reveal dl, 90 | .reveal ul { 91 | display: inline-block; 92 | text-align: left; 93 | margin: 0 0 0 1em; } 94 | 95 | .reveal ol { 96 | list-style-type: decimal; } 97 | 98 | .reveal ul { 99 | list-style-type: disc; } 100 | 101 | .reveal ul ul { 102 | list-style-type: square; } 103 | 104 | .reveal ul ul ul { 105 | list-style-type: circle; } 106 | 107 | .reveal ul ul, 108 | .reveal ul ol, 109 | .reveal ol ol, 110 | .reveal ol ul { 111 | display: block; 112 | margin-left: 40px; } 113 | 114 | .reveal dt { 115 | font-weight: bold; } 116 | 117 | .reveal dd { 118 | margin-left: 40px; } 119 | 120 | .reveal q, 121 | .reveal blockquote { 122 | quotes: none; } 123 | 124 | .reveal blockquote { 125 | display: block; 126 | position: relative; 127 | width: 70%; 128 | margin: 20px auto; 129 | padding: 5px; 130 | font-style: italic; 131 | background: rgba(255, 255, 255, 0.05); 132 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.2); } 133 | 134 | .reveal blockquote p:first-child, 135 | .reveal blockquote p:last-child { 136 | display: inline-block; } 137 | 138 | .reveal q { 139 | font-style: italic; } 140 | 141 | .reveal pre { 142 | display: block; 143 | position: relative; 144 | width: 90%; 145 | margin: 20px auto; 146 | text-align: left; 147 | font-size: 0.55em; 148 | font-family: monospace; 149 | line-height: 1.2em; 150 | word-wrap: break-word; 151 | box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.3); } 152 | 153 | .reveal code, .reveal output { 154 | font-family: monospace; } 155 | 156 | .reveal pre code, .reveal pre output { 157 | display: block; 158 | padding: 5px; 159 | overflow: auto; 160 | max-height: 400px; 161 | word-wrap: normal; } 162 | 163 | .reveal table { 164 | margin: auto; 165 | border-collapse: collapse; 166 | border-spacing: 0; } 167 | 168 | .reveal table th { 169 | font-weight: bold; } 170 | 171 | .reveal table th, 172 | .reveal table td { 173 | text-align: left; 174 | padding: 0.2em 0.5em 0.2em 0.5em; 175 | border-bottom: 1px solid; } 176 | 177 | .reveal table th[align="center"], 178 | .reveal table td[align="center"] { 179 | text-align: center; } 180 | 181 | .reveal table th[align="right"], 182 | .reveal table td[align="right"] { 183 | text-align: right; } 184 | 185 | .reveal table tbody tr:last-child th, 186 | .reveal table tbody tr:last-child td { 187 | border-bottom: none; } 188 | 189 | .reveal sup { 190 | vertical-align: super; } 191 | 192 | .reveal sub { 193 | vertical-align: sub; } 194 | 195 | .reveal small { 196 | display: inline-block; 197 | font-size: 0.6em; 198 | line-height: 1.2em; 199 | vertical-align: top; } 200 | 201 | .reveal small * { 202 | vertical-align: top; } 203 | 204 | /********************************************* 205 | * LINKS 206 | *********************************************/ 207 | .reveal a { 208 | color: #5992bf; 209 | text-decoration: none; 210 | -webkit-transition: color .15s ease; 211 | -moz-transition: color .15s ease; 212 | transition: color .15s ease; } 213 | 214 | .reveal a:hover { 215 | color: #396b93; 216 | text-shadow: none; 217 | border: none; } 218 | 219 | .reveal .roll span:after { 220 | color: #fff; 221 | background: #396b93; } 222 | 223 | /********************************************* 224 | * IMAGES 225 | *********************************************/ 226 | .reveal section img { 227 | margin: 15px 0px; 228 | background: rgba(255, 255, 255, 0.12); 229 | border: 4px solid #434850; 230 | box-shadow: 0 0 10px rgba(0, 0, 0, 0.15); } 231 | 232 | .reveal section img.plain { 233 | border: 0; 234 | box-shadow: none; } 235 | 236 | .reveal a img { 237 | -webkit-transition: all .15s linear; 238 | -moz-transition: all .15s linear; 239 | transition: all .15s linear; } 240 | 241 | .reveal a:hover img { 242 | background: rgba(255, 255, 255, 0.2); 243 | border-color: #5992bf; 244 | box-shadow: 0 0 20px rgba(0, 0, 0, 0.55); } 245 | 246 | /********************************************* 247 | * NAVIGATION CONTROLS 248 | *********************************************/ 249 | .reveal .controls .navigate-left, 250 | .reveal .controls .navigate-left.enabled { 251 | border-right-color: #5992bf; } 252 | 253 | .reveal .controls .navigate-right, 254 | .reveal .controls .navigate-right.enabled { 255 | border-left-color: #5992bf; } 256 | 257 | .reveal .controls .navigate-up, 258 | .reveal .controls .navigate-up.enabled { 259 | border-bottom-color: #5992bf; } 260 | 261 | .reveal .controls .navigate-down, 262 | .reveal .controls .navigate-down.enabled { 263 | border-top-color: #5992bf; } 264 | 265 | .reveal .controls .navigate-left.enabled:hover { 266 | border-right-color: #396b93; } 267 | 268 | .reveal .controls .navigate-right.enabled:hover { 269 | border-left-color: #396b93; } 270 | 271 | .reveal .controls .navigate-up.enabled:hover { 272 | border-bottom-color: #396b93; } 273 | 274 | .reveal .controls .navigate-down.enabled:hover { 275 | border-top-color: #396b93; } 276 | 277 | /********************************************* 278 | * PROGRESS BAR 279 | *********************************************/ 280 | .reveal .progress { 281 | background: rgba(0, 0, 0, 0.2); } 282 | 283 | .reveal .progress span { 284 | background: #5992bf; 285 | -webkit-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 286 | -moz-transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); 287 | transition: width 800ms cubic-bezier(0.26, 0.86, 0.44, 0.985); } 288 | 289 | .reveal .slide-background video { 290 | height: auto; } 291 | 292 | .reveal footer { 293 | position: fixed; 294 | top: auto; 295 | bottom: 1em; 296 | left: 1em; 297 | padding: .5em; 298 | z-index: 100; 299 | font-size: 0.5em; 300 | background: rgba(255, 255, 255, 0.7); } 301 | .reveal footer a { 302 | color: #396b93; } 303 | 304 | .reveal output .text-notice { 305 | color: teal; } 306 | 307 | .reveal output .text-fail { 308 | color: #D8000C; } 309 | 310 | .reveal output .highlight-warning, .reveal output .highlight-fail { 311 | display: inline-block; 312 | padding: 0 2px; } 313 | 314 | .reveal output .highlight-warning { 315 | color: #222; 316 | background: yellow; } 317 | 318 | .reveal output .highlight-fail { 319 | color: #fff; 320 | background: #D8000C; } 321 | 322 | .slides h1, .slides h2, .slides h3, .slides h4, .slides h5, .slides h6 { 323 | line-height: 1.35; } 324 | .slides h1 img, .slides h2 img, .slides h3 img, .slides h4 img, .slides h5 img, .slides h6 img { 325 | border: none; 326 | box-shadow: none; 327 | max-width: 50%; 328 | max-height: 1.5em; } 329 | .slides h1 code, .slides h1 .reveal output, .reveal .slides h1 output, .slides h2 code, .slides h2 .reveal output, .reveal .slides h2 output, .slides h3 code, .slides h3 .reveal output, .reveal .slides h3 output, .slides h4 code, .slides h4 .reveal output, .reveal .slides h4 output, .slides h5 code, .slides h5 .reveal output, .reveal .slides h5 output, .slides h6 code, .slides h6 .reveal output, .reveal .slides h6 output { 330 | text-transform: none; } 331 | .slides h1.wordpress-icon:before, .slides h2.wordpress-icon:before, .slides h3.wordpress-icon:before, .slides h4.wordpress-icon:before, .slides h5.wordpress-icon:before, .slides h6.wordpress-icon:before { 332 | content: ''; 333 | display: inline-block; 334 | width: .7em; 335 | height: .7em; 336 | margin-right: .2em; 337 | vertical-align: middle; 338 | background: url("../resources/wordpress.svg") center center no-repeat; 339 | background-size: contain; } 340 | 341 | .slides h1 { 342 | line-height: 1.5; } 343 | .slides h1 small { 344 | display: block; 345 | margin-top: .5em; } 346 | 347 | .slides a:hover img { 348 | box-shadow: none; } 349 | 350 | .slides cite { 351 | display: block; 352 | margin-top: 1em; 353 | font-size: .8em; } 354 | 355 | .slides .slides-link { 356 | display: block; 357 | margin-top: 1em; 358 | font-size: .86em; 359 | white-space: nowrap; } 360 | .slides .slides-link + .slides-link { 361 | margin-top: 0; } 362 | 363 | .slides dl { 364 | width: 100%; 365 | margin: 0; } 366 | .slides dl dt { 367 | clear: both; 368 | float: left; 369 | width: 35%; 370 | font-family: "Paytone One", "Open Sans", sans-serif; 371 | text-align: right; } 372 | .slides dl dd { 373 | clear: right; 374 | float: right; 375 | width: calc(65% - 40px); } 376 | .slides dl dd + dt, .slides dl dd + dd { 377 | margin-top: .5em; } 378 | .slides dl dd pre { 379 | width: 100%; } 380 | .slides dl dd + dt, 381 | .slides dl dd + dt + dd { 382 | margin-top: .5em; } 383 | 384 | .slides blockquote { 385 | background: rgba(255, 255, 255, 0.8); } 386 | 387 | .slides table.equivalence-table td { 388 | border: none; } 389 | 390 | .slides .fragment-replacement .fragment.fade-out.visible, 391 | .slides .fragment-replacement .fragment.fade-in:not(.visible) { 392 | display: none; } 393 | 394 | .slides .fragment.visible.highlight-red { 395 | color: #D8000C !important; } 396 | 397 | .slides .fragment.visible.highlight-green { 398 | color: #4F8A10 !important; } 399 | 400 | .slides .pass { 401 | color: #4F8A10; } 402 | 403 | .slides .fail { 404 | color: #D8000C; } 405 | 406 | .slides .status-icon { 407 | display: inline-block; 408 | width: 1em; 409 | font-size: .8em; 410 | vertical-align: center; } 411 | 412 | .slides .seamless, .slides .seamless img { 413 | border: 0; 414 | box-shadow: none; 415 | background: transparent; } 416 | -------------------------------------------------------------------------------- /js/loadhtmlslides.js: -------------------------------------------------------------------------------- 1 | // Modified from markdown.js from Hakim to handle external html files 2 | (function () { 3 | /*jslint loopfunc: true, browser: true*/ 4 | /*globals alert*/ 5 | 'use strict'; 6 | 7 | var querySlidingHtml = function () { 8 | var sections = document.querySelectorAll('[data-html]'), 9 | section, j, jlen; 10 | 11 | for (j = 0, jlen = sections.length; j < jlen; j++) { 12 | section = sections[j]; 13 | 14 | if (section.getAttribute('data-html').length) { 15 | 16 | var xhr = new XMLHttpRequest(), 17 | url = section.getAttribute('data-html'), 18 | cb = function () { 19 | if (xhr.readyState === 4) { 20 | if ( 21 | (xhr.status >= 200 && xhr.status < 300) || 22 | xhr.status === 0 // file protocol yields status code 0 (useful for local debug, mobile applications etc.) 23 | ) { 24 | section.innerHTML = xhr.responseText; 25 | } else { 26 | section.outerHTML = '
ERROR: The attempt to fetch ' + url + ' failed with the HTTP status ' + xhr.status + '. Check your browser\'s JavaScript console for more details.

'; 27 | } 28 | } 29 | }; 30 | 31 | xhr.onreadystatechange = cb; 32 | 33 | xhr.open('GET', url, false); 34 | try { 35 | xhr.send(); 36 | } catch (e) { 37 | alert('Failed to get file' + url + '.' + e); 38 | } 39 | } 40 | } 41 | }; 42 | 43 | querySlidingHtml(); 44 | })(); 45 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confidently-testing-wordpress", 3 | "version": "0.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "abbrev": { 8 | "version": "1.1.1", 9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 10 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 11 | "dev": true 12 | }, 13 | "accepts": { 14 | "version": "1.3.5", 15 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 16 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 17 | "dev": true, 18 | "requires": { 19 | "mime-types": "2.1.20", 20 | "negotiator": "0.6.1" 21 | } 22 | }, 23 | "ajv": { 24 | "version": "5.5.2", 25 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", 26 | "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", 27 | "dev": true, 28 | "requires": { 29 | "co": "4.6.0", 30 | "fast-deep-equal": "1.1.0", 31 | "fast-json-stable-stringify": "2.0.0", 32 | "json-schema-traverse": "0.3.1" 33 | } 34 | }, 35 | "amdefine": { 36 | "version": "1.0.1", 37 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 38 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", 39 | "dev": true 40 | }, 41 | "ansi-regex": { 42 | "version": "2.1.1", 43 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 44 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 45 | "dev": true 46 | }, 47 | "ansi-styles": { 48 | "version": "3.2.1", 49 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 50 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 51 | "dev": true, 52 | "requires": { 53 | "color-convert": "1.9.3" 54 | } 55 | }, 56 | "aproba": { 57 | "version": "1.2.0", 58 | "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", 59 | "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", 60 | "dev": true 61 | }, 62 | "are-we-there-yet": { 63 | "version": "1.1.5", 64 | "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", 65 | "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", 66 | "dev": true, 67 | "requires": { 68 | "delegates": "1.0.0", 69 | "readable-stream": "2.3.6" 70 | }, 71 | "dependencies": { 72 | "isarray": { 73 | "version": "1.0.0", 74 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 75 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 76 | "dev": true 77 | }, 78 | "readable-stream": { 79 | "version": "2.3.6", 80 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 81 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 82 | "dev": true, 83 | "requires": { 84 | "core-util-is": "1.0.2", 85 | "inherits": "2.0.3", 86 | "isarray": "1.0.0", 87 | "process-nextick-args": "2.0.0", 88 | "safe-buffer": "5.1.2", 89 | "string_decoder": "1.1.1", 90 | "util-deprecate": "1.0.2" 91 | } 92 | }, 93 | "string_decoder": { 94 | "version": "1.1.1", 95 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 96 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 97 | "dev": true, 98 | "requires": { 99 | "safe-buffer": "5.1.2" 100 | } 101 | } 102 | } 103 | }, 104 | "argparse": { 105 | "version": "1.0.10", 106 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 107 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 108 | "dev": true, 109 | "requires": { 110 | "sprintf-js": "1.0.3" 111 | }, 112 | "dependencies": { 113 | "sprintf-js": { 114 | "version": "1.0.3", 115 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 116 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 117 | "dev": true 118 | } 119 | } 120 | }, 121 | "array-differ": { 122 | "version": "1.0.0", 123 | "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", 124 | "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", 125 | "dev": true 126 | }, 127 | "array-find-index": { 128 | "version": "1.0.2", 129 | "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", 130 | "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", 131 | "dev": true 132 | }, 133 | "array-union": { 134 | "version": "1.0.2", 135 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 136 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 137 | "dev": true, 138 | "requires": { 139 | "array-uniq": "1.0.3" 140 | } 141 | }, 142 | "array-uniq": { 143 | "version": "1.0.3", 144 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 145 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 146 | "dev": true 147 | }, 148 | "arrify": { 149 | "version": "1.0.1", 150 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", 151 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", 152 | "dev": true 153 | }, 154 | "asn1": { 155 | "version": "0.2.4", 156 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 157 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 158 | "dev": true, 159 | "requires": { 160 | "safer-buffer": "2.1.2" 161 | } 162 | }, 163 | "assert-plus": { 164 | "version": "1.0.0", 165 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 166 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 167 | "dev": true 168 | }, 169 | "async": { 170 | "version": "1.5.2", 171 | "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", 172 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", 173 | "dev": true 174 | }, 175 | "async-foreach": { 176 | "version": "0.1.3", 177 | "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", 178 | "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", 179 | "dev": true 180 | }, 181 | "asynckit": { 182 | "version": "0.4.0", 183 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 184 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 185 | "dev": true 186 | }, 187 | "aws-sign2": { 188 | "version": "0.7.0", 189 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 190 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", 191 | "dev": true 192 | }, 193 | "aws4": { 194 | "version": "1.8.0", 195 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 196 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", 197 | "dev": true 198 | }, 199 | "balanced-match": { 200 | "version": "1.0.0", 201 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 202 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 203 | "dev": true 204 | }, 205 | "basic-auth": { 206 | "version": "2.0.1", 207 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", 208 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", 209 | "dev": true, 210 | "requires": { 211 | "safe-buffer": "5.1.2" 212 | } 213 | }, 214 | "batch": { 215 | "version": "0.6.1", 216 | "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", 217 | "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", 218 | "dev": true 219 | }, 220 | "bcrypt-pbkdf": { 221 | "version": "1.0.2", 222 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 223 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 224 | "dev": true, 225 | "optional": true, 226 | "requires": { 227 | "tweetnacl": "0.14.5" 228 | } 229 | }, 230 | "block-stream": { 231 | "version": "0.0.9", 232 | "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", 233 | "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", 234 | "dev": true, 235 | "requires": { 236 | "inherits": "2.0.3" 237 | } 238 | }, 239 | "bluebird": { 240 | "version": "3.5.2", 241 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", 242 | "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==", 243 | "dev": true 244 | }, 245 | "body": { 246 | "version": "5.1.0", 247 | "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", 248 | "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", 249 | "dev": true, 250 | "requires": { 251 | "continuable-cache": "0.3.1", 252 | "error": "7.0.2", 253 | "raw-body": "1.1.7", 254 | "safe-json-parse": "1.0.1" 255 | } 256 | }, 257 | "brace-expansion": { 258 | "version": "1.1.11", 259 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 260 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 261 | "dev": true, 262 | "requires": { 263 | "balanced-match": "1.0.0", 264 | "concat-map": "0.0.1" 265 | } 266 | }, 267 | "builtin-modules": { 268 | "version": "1.1.1", 269 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", 270 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", 271 | "dev": true 272 | }, 273 | "bytes": { 274 | "version": "1.0.0", 275 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", 276 | "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", 277 | "dev": true 278 | }, 279 | "camelcase": { 280 | "version": "2.1.1", 281 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", 282 | "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", 283 | "dev": true 284 | }, 285 | "camelcase-keys": { 286 | "version": "2.1.0", 287 | "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", 288 | "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", 289 | "dev": true, 290 | "requires": { 291 | "camelcase": "2.1.1", 292 | "map-obj": "1.0.1" 293 | } 294 | }, 295 | "caseless": { 296 | "version": "0.12.0", 297 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 298 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", 299 | "dev": true 300 | }, 301 | "chalk": { 302 | "version": "2.4.1", 303 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 304 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 305 | "dev": true, 306 | "requires": { 307 | "ansi-styles": "3.2.1", 308 | "escape-string-regexp": "1.0.5", 309 | "supports-color": "5.5.0" 310 | } 311 | }, 312 | "cli": { 313 | "version": "1.0.1", 314 | "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", 315 | "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", 316 | "dev": true, 317 | "requires": { 318 | "exit": "0.1.2", 319 | "glob": "7.1.3" 320 | } 321 | }, 322 | "cliui": { 323 | "version": "3.2.0", 324 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", 325 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", 326 | "dev": true, 327 | "requires": { 328 | "string-width": "1.0.2", 329 | "strip-ansi": "3.0.1", 330 | "wrap-ansi": "2.1.0" 331 | } 332 | }, 333 | "co": { 334 | "version": "4.6.0", 335 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", 336 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", 337 | "dev": true 338 | }, 339 | "code-point-at": { 340 | "version": "1.1.0", 341 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 342 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", 343 | "dev": true 344 | }, 345 | "coffee-script": { 346 | "version": "1.11.1", 347 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.11.1.tgz", 348 | "integrity": "sha1-vxxHrWREOg2V0S3ysUfMCk2q1uk=", 349 | "dev": true 350 | }, 351 | "coffeelint": { 352 | "version": "1.16.2", 353 | "resolved": "https://registry.npmjs.org/coffeelint/-/coffeelint-1.16.2.tgz", 354 | "integrity": "sha512-6mzgOo4zb17WfdrSui/cSUEgQ0AQkW3gXDht+6lHkfkqGUtSYKwGdGcXsDfAyuScVzTlTtKdfwkAlJWfqul7zg==", 355 | "dev": true, 356 | "requires": { 357 | "coffee-script": "1.11.1", 358 | "glob": "7.1.3", 359 | "ignore": "3.3.10", 360 | "optimist": "0.6.1", 361 | "resolve": "0.6.3", 362 | "strip-json-comments": "1.0.4" 363 | } 364 | }, 365 | "coffeelint-stylish": { 366 | "version": "0.1.2", 367 | "resolved": "https://registry.npmjs.org/coffeelint-stylish/-/coffeelint-stylish-0.1.2.tgz", 368 | "integrity": "sha1-q1AaZENeIxcG2hOidSeraVcAq8k=", 369 | "dev": true, 370 | "requires": { 371 | "chalk": "1.1.3", 372 | "text-table": "0.2.0" 373 | }, 374 | "dependencies": { 375 | "ansi-styles": { 376 | "version": "2.2.1", 377 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 378 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 379 | "dev": true 380 | }, 381 | "chalk": { 382 | "version": "1.1.3", 383 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 384 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 385 | "dev": true, 386 | "requires": { 387 | "ansi-styles": "2.2.1", 388 | "escape-string-regexp": "1.0.5", 389 | "has-ansi": "2.0.0", 390 | "strip-ansi": "3.0.1", 391 | "supports-color": "2.0.0" 392 | } 393 | }, 394 | "supports-color": { 395 | "version": "2.0.0", 396 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 397 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 398 | "dev": true 399 | } 400 | } 401 | }, 402 | "color-convert": { 403 | "version": "1.9.3", 404 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 405 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 406 | "dev": true, 407 | "requires": { 408 | "color-name": "1.1.3" 409 | } 410 | }, 411 | "color-name": { 412 | "version": "1.1.3", 413 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 414 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", 415 | "dev": true 416 | }, 417 | "colors": { 418 | "version": "1.1.2", 419 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", 420 | "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", 421 | "dev": true 422 | }, 423 | "combined-stream": { 424 | "version": "1.0.7", 425 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 426 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 427 | "dev": true, 428 | "requires": { 429 | "delayed-stream": "1.0.0" 430 | } 431 | }, 432 | "concat-map": { 433 | "version": "0.0.1", 434 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 435 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 436 | "dev": true 437 | }, 438 | "connect": { 439 | "version": "3.6.6", 440 | "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", 441 | "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", 442 | "dev": true, 443 | "requires": { 444 | "debug": "2.6.9", 445 | "finalhandler": "1.1.0", 446 | "parseurl": "1.3.2", 447 | "utils-merge": "1.0.1" 448 | } 449 | }, 450 | "connect-livereload": { 451 | "version": "0.5.4", 452 | "resolved": "https://registry.npmjs.org/connect-livereload/-/connect-livereload-0.5.4.tgz", 453 | "integrity": "sha1-gBV9E3HJ83zBQDmrGJWXDRGdw7w=", 454 | "dev": true 455 | }, 456 | "console-browserify": { 457 | "version": "1.1.0", 458 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", 459 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", 460 | "dev": true, 461 | "requires": { 462 | "date-now": "0.1.4" 463 | } 464 | }, 465 | "console-control-strings": { 466 | "version": "1.1.0", 467 | "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", 468 | "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", 469 | "dev": true 470 | }, 471 | "continuable-cache": { 472 | "version": "0.3.1", 473 | "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", 474 | "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", 475 | "dev": true 476 | }, 477 | "core-util-is": { 478 | "version": "1.0.2", 479 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 480 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 481 | "dev": true 482 | }, 483 | "cross-spawn": { 484 | "version": "3.0.1", 485 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", 486 | "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", 487 | "dev": true, 488 | "requires": { 489 | "lru-cache": "4.1.3", 490 | "which": "1.3.1" 491 | } 492 | }, 493 | "currently-unhandled": { 494 | "version": "0.4.1", 495 | "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", 496 | "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", 497 | "dev": true, 498 | "requires": { 499 | "array-find-index": "1.0.2" 500 | } 501 | }, 502 | "dashdash": { 503 | "version": "1.14.1", 504 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 505 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 506 | "dev": true, 507 | "requires": { 508 | "assert-plus": "1.0.0" 509 | } 510 | }, 511 | "date-now": { 512 | "version": "0.1.4", 513 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", 514 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", 515 | "dev": true 516 | }, 517 | "dateformat": { 518 | "version": "1.0.12", 519 | "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", 520 | "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", 521 | "dev": true, 522 | "requires": { 523 | "get-stdin": "4.0.1", 524 | "meow": "3.7.0" 525 | } 526 | }, 527 | "debug": { 528 | "version": "2.6.9", 529 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 530 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 531 | "dev": true, 532 | "requires": { 533 | "ms": "2.0.0" 534 | } 535 | }, 536 | "decamelize": { 537 | "version": "1.2.0", 538 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 539 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 540 | "dev": true 541 | }, 542 | "delayed-stream": { 543 | "version": "1.0.0", 544 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 545 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 546 | "dev": true 547 | }, 548 | "delegates": { 549 | "version": "1.0.0", 550 | "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", 551 | "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", 552 | "dev": true 553 | }, 554 | "depd": { 555 | "version": "1.1.2", 556 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 557 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", 558 | "dev": true 559 | }, 560 | "destroy": { 561 | "version": "1.0.4", 562 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 563 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", 564 | "dev": true 565 | }, 566 | "dom-serializer": { 567 | "version": "0.1.0", 568 | "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", 569 | "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", 570 | "dev": true, 571 | "requires": { 572 | "domelementtype": "1.1.3", 573 | "entities": "1.1.1" 574 | }, 575 | "dependencies": { 576 | "domelementtype": { 577 | "version": "1.1.3", 578 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", 579 | "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=", 580 | "dev": true 581 | }, 582 | "entities": { 583 | "version": "1.1.1", 584 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", 585 | "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", 586 | "dev": true 587 | } 588 | } 589 | }, 590 | "domelementtype": { 591 | "version": "1.3.0", 592 | "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", 593 | "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=", 594 | "dev": true 595 | }, 596 | "domhandler": { 597 | "version": "2.3.0", 598 | "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", 599 | "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", 600 | "dev": true, 601 | "requires": { 602 | "domelementtype": "1.3.0" 603 | } 604 | }, 605 | "domutils": { 606 | "version": "1.5.1", 607 | "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", 608 | "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", 609 | "dev": true, 610 | "requires": { 611 | "dom-serializer": "0.1.0", 612 | "domelementtype": "1.3.0" 613 | } 614 | }, 615 | "each-async": { 616 | "version": "1.1.1", 617 | "resolved": "https://registry.npmjs.org/each-async/-/each-async-1.1.1.tgz", 618 | "integrity": "sha1-3uUim98KtrogEqOV4bhpq/iBNHM=", 619 | "dev": true, 620 | "requires": { 621 | "onetime": "1.1.0", 622 | "set-immediate-shim": "1.0.1" 623 | } 624 | }, 625 | "ecc-jsbn": { 626 | "version": "0.1.2", 627 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 628 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 629 | "dev": true, 630 | "optional": true, 631 | "requires": { 632 | "jsbn": "0.1.1", 633 | "safer-buffer": "2.1.2" 634 | } 635 | }, 636 | "ee-first": { 637 | "version": "1.1.1", 638 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 639 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", 640 | "dev": true 641 | }, 642 | "encodeurl": { 643 | "version": "1.0.2", 644 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 645 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", 646 | "dev": true 647 | }, 648 | "entities": { 649 | "version": "1.0.0", 650 | "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", 651 | "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", 652 | "dev": true 653 | }, 654 | "error": { 655 | "version": "7.0.2", 656 | "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", 657 | "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", 658 | "dev": true, 659 | "requires": { 660 | "string-template": "0.2.1", 661 | "xtend": "4.0.1" 662 | } 663 | }, 664 | "error-ex": { 665 | "version": "1.3.2", 666 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", 667 | "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", 668 | "dev": true, 669 | "requires": { 670 | "is-arrayish": "0.2.1" 671 | } 672 | }, 673 | "escape-html": { 674 | "version": "1.0.3", 675 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 676 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", 677 | "dev": true 678 | }, 679 | "escape-string-regexp": { 680 | "version": "1.0.5", 681 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 682 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 683 | "dev": true 684 | }, 685 | "esprima": { 686 | "version": "2.7.3", 687 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 688 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 689 | "dev": true 690 | }, 691 | "etag": { 692 | "version": "1.8.1", 693 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 694 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", 695 | "dev": true 696 | }, 697 | "eventemitter2": { 698 | "version": "0.4.14", 699 | "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", 700 | "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", 701 | "dev": true 702 | }, 703 | "exit": { 704 | "version": "0.1.2", 705 | "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", 706 | "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", 707 | "dev": true 708 | }, 709 | "extend": { 710 | "version": "3.0.2", 711 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 712 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", 713 | "dev": true 714 | }, 715 | "extsprintf": { 716 | "version": "1.3.0", 717 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 718 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", 719 | "dev": true 720 | }, 721 | "fast-deep-equal": { 722 | "version": "1.1.0", 723 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", 724 | "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", 725 | "dev": true 726 | }, 727 | "fast-json-stable-stringify": { 728 | "version": "2.0.0", 729 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 730 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", 731 | "dev": true 732 | }, 733 | "faye-websocket": { 734 | "version": "0.10.0", 735 | "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", 736 | "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", 737 | "dev": true, 738 | "requires": { 739 | "websocket-driver": "0.7.0" 740 | } 741 | }, 742 | "file-sync-cmp": { 743 | "version": "0.1.1", 744 | "resolved": "https://registry.npmjs.org/file-sync-cmp/-/file-sync-cmp-0.1.1.tgz", 745 | "integrity": "sha1-peeo/7+kk7Q7kju9TKiaU7Y7YSs=", 746 | "dev": true 747 | }, 748 | "finalhandler": { 749 | "version": "1.1.0", 750 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", 751 | "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", 752 | "dev": true, 753 | "requires": { 754 | "debug": "2.6.9", 755 | "encodeurl": "1.0.2", 756 | "escape-html": "1.0.3", 757 | "on-finished": "2.3.0", 758 | "parseurl": "1.3.2", 759 | "statuses": "1.3.1", 760 | "unpipe": "1.0.0" 761 | } 762 | }, 763 | "find-up": { 764 | "version": "1.1.2", 765 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", 766 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", 767 | "dev": true, 768 | "requires": { 769 | "path-exists": "2.1.0", 770 | "pinkie-promise": "2.0.1" 771 | } 772 | }, 773 | "findup-sync": { 774 | "version": "0.3.0", 775 | "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", 776 | "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", 777 | "dev": true, 778 | "requires": { 779 | "glob": "5.0.15" 780 | }, 781 | "dependencies": { 782 | "glob": { 783 | "version": "5.0.15", 784 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", 785 | "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", 786 | "dev": true, 787 | "requires": { 788 | "inflight": "1.0.6", 789 | "inherits": "2.0.3", 790 | "minimatch": "3.0.4", 791 | "once": "1.4.0", 792 | "path-is-absolute": "1.0.1" 793 | } 794 | } 795 | } 796 | }, 797 | "forever-agent": { 798 | "version": "0.6.1", 799 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 800 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", 801 | "dev": true 802 | }, 803 | "form-data": { 804 | "version": "2.3.2", 805 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", 806 | "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", 807 | "dev": true, 808 | "requires": { 809 | "asynckit": "0.4.0", 810 | "combined-stream": "1.0.6", 811 | "mime-types": "2.1.20" 812 | }, 813 | "dependencies": { 814 | "combined-stream": { 815 | "version": "1.0.6", 816 | "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", 817 | "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", 818 | "dev": true, 819 | "requires": { 820 | "delayed-stream": "1.0.0" 821 | } 822 | } 823 | } 824 | }, 825 | "fresh": { 826 | "version": "0.5.2", 827 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 828 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", 829 | "dev": true 830 | }, 831 | "fs.realpath": { 832 | "version": "1.0.0", 833 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 834 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 835 | "dev": true 836 | }, 837 | "fstream": { 838 | "version": "1.0.11", 839 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", 840 | "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", 841 | "dev": true, 842 | "requires": { 843 | "graceful-fs": "4.1.11", 844 | "inherits": "2.0.3", 845 | "mkdirp": "0.5.1", 846 | "rimraf": "2.6.2" 847 | } 848 | }, 849 | "gauge": { 850 | "version": "2.7.4", 851 | "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", 852 | "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", 853 | "dev": true, 854 | "requires": { 855 | "aproba": "1.2.0", 856 | "console-control-strings": "1.1.0", 857 | "has-unicode": "2.0.1", 858 | "object-assign": "4.1.1", 859 | "signal-exit": "3.0.2", 860 | "string-width": "1.0.2", 861 | "strip-ansi": "3.0.1", 862 | "wide-align": "1.1.3" 863 | } 864 | }, 865 | "gaze": { 866 | "version": "1.1.3", 867 | "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", 868 | "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", 869 | "dev": true, 870 | "requires": { 871 | "globule": "1.2.1" 872 | } 873 | }, 874 | "get-caller-file": { 875 | "version": "1.0.3", 876 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 877 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", 878 | "dev": true 879 | }, 880 | "get-stdin": { 881 | "version": "4.0.1", 882 | "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", 883 | "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", 884 | "dev": true 885 | }, 886 | "getobject": { 887 | "version": "0.1.0", 888 | "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", 889 | "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", 890 | "dev": true 891 | }, 892 | "getpass": { 893 | "version": "0.1.7", 894 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 895 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 896 | "dev": true, 897 | "requires": { 898 | "assert-plus": "1.0.0" 899 | } 900 | }, 901 | "glob": { 902 | "version": "7.1.3", 903 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 904 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 905 | "dev": true, 906 | "requires": { 907 | "fs.realpath": "1.0.0", 908 | "inflight": "1.0.6", 909 | "inherits": "2.0.3", 910 | "minimatch": "3.0.4", 911 | "once": "1.4.0", 912 | "path-is-absolute": "1.0.1" 913 | } 914 | }, 915 | "globule": { 916 | "version": "1.2.1", 917 | "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", 918 | "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", 919 | "dev": true, 920 | "requires": { 921 | "glob": "7.1.3", 922 | "lodash": "4.17.11", 923 | "minimatch": "3.0.4" 924 | } 925 | }, 926 | "graceful-fs": { 927 | "version": "4.1.11", 928 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 929 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 930 | "dev": true 931 | }, 932 | "grunt": { 933 | "version": "1.0.3", 934 | "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.3.tgz", 935 | "integrity": "sha512-/JzmZNPfKorlCrrmxWqQO4JVodO+DVd5XX4DkocL/1WlLlKVLE9+SdEIempOAxDhWPysLle6afvn/hg7Ck2k9g==", 936 | "dev": true, 937 | "requires": { 938 | "coffeescript": "1.10.0", 939 | "dateformat": "1.0.12", 940 | "eventemitter2": "0.4.14", 941 | "exit": "0.1.2", 942 | "findup-sync": "0.3.0", 943 | "glob": "7.0.6", 944 | "grunt-cli": "1.2.0", 945 | "grunt-known-options": "1.1.1", 946 | "grunt-legacy-log": "2.0.0", 947 | "grunt-legacy-util": "1.1.1", 948 | "iconv-lite": "0.4.24", 949 | "js-yaml": "3.5.5", 950 | "minimatch": "3.0.4", 951 | "mkdirp": "0.5.1", 952 | "nopt": "3.0.6", 953 | "path-is-absolute": "1.0.1", 954 | "rimraf": "2.6.2" 955 | }, 956 | "dependencies": { 957 | "coffeescript": { 958 | "version": "1.10.0", 959 | "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz", 960 | "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=", 961 | "dev": true 962 | }, 963 | "glob": { 964 | "version": "7.0.6", 965 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", 966 | "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", 967 | "dev": true, 968 | "requires": { 969 | "fs.realpath": "1.0.0", 970 | "inflight": "1.0.6", 971 | "inherits": "2.0.3", 972 | "minimatch": "3.0.4", 973 | "once": "1.4.0", 974 | "path-is-absolute": "1.0.1" 975 | } 976 | }, 977 | "grunt-cli": { 978 | "version": "1.2.0", 979 | "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", 980 | "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", 981 | "dev": true, 982 | "requires": { 983 | "findup-sync": "0.3.0", 984 | "grunt-known-options": "1.1.1", 985 | "nopt": "3.0.6", 986 | "resolve": "1.1.7" 987 | } 988 | }, 989 | "resolve": { 990 | "version": "1.1.7", 991 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", 992 | "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", 993 | "dev": true 994 | } 995 | } 996 | }, 997 | "grunt-build-control": { 998 | "version": "0.7.1", 999 | "resolved": "https://registry.npmjs.org/grunt-build-control/-/grunt-build-control-0.7.1.tgz", 1000 | "integrity": "sha1-lCnTRRZ+eg+8DM3FnLHtvZye4Ng=", 1001 | "dev": true, 1002 | "requires": { 1003 | "bluebird": "3.5.2", 1004 | "semver": "4.3.6", 1005 | "shelljs": "0.2.6" 1006 | }, 1007 | "dependencies": { 1008 | "semver": { 1009 | "version": "4.3.6", 1010 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", 1011 | "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", 1012 | "dev": true 1013 | } 1014 | } 1015 | }, 1016 | "grunt-coffeelint": { 1017 | "version": "0.0.16", 1018 | "resolved": "https://registry.npmjs.org/grunt-coffeelint/-/grunt-coffeelint-0.0.16.tgz", 1019 | "integrity": "sha1-0iPUIwWmuXdqtbehQuFFP4hmK5s=", 1020 | "dev": true, 1021 | "requires": { 1022 | "coffeelint": "1.16.2", 1023 | "coffeelint-stylish": "0.1.2" 1024 | } 1025 | }, 1026 | "grunt-contrib-connect": { 1027 | "version": "1.0.2", 1028 | "resolved": "https://registry.npmjs.org/grunt-contrib-connect/-/grunt-contrib-connect-1.0.2.tgz", 1029 | "integrity": "sha1-XPkzuRpnOGBEJzwLJERgPNmIebo=", 1030 | "dev": true, 1031 | "requires": { 1032 | "async": "1.5.2", 1033 | "connect": "3.6.6", 1034 | "connect-livereload": "0.5.4", 1035 | "http2": "3.3.7", 1036 | "morgan": "1.9.1", 1037 | "opn": "4.0.2", 1038 | "portscanner": "1.2.0", 1039 | "serve-index": "1.9.1", 1040 | "serve-static": "1.13.2" 1041 | } 1042 | }, 1043 | "grunt-contrib-copy": { 1044 | "version": "1.0.0", 1045 | "resolved": "https://registry.npmjs.org/grunt-contrib-copy/-/grunt-contrib-copy-1.0.0.tgz", 1046 | "integrity": "sha1-cGDGWB6QS4qw0A8HbgqPbj58NXM=", 1047 | "dev": true, 1048 | "requires": { 1049 | "chalk": "1.1.3", 1050 | "file-sync-cmp": "0.1.1" 1051 | }, 1052 | "dependencies": { 1053 | "ansi-styles": { 1054 | "version": "2.2.1", 1055 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 1056 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 1057 | "dev": true 1058 | }, 1059 | "chalk": { 1060 | "version": "1.1.3", 1061 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 1062 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 1063 | "dev": true, 1064 | "requires": { 1065 | "ansi-styles": "2.2.1", 1066 | "escape-string-regexp": "1.0.5", 1067 | "has-ansi": "2.0.0", 1068 | "strip-ansi": "3.0.1", 1069 | "supports-color": "2.0.0" 1070 | } 1071 | }, 1072 | "supports-color": { 1073 | "version": "2.0.0", 1074 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1075 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1076 | "dev": true 1077 | } 1078 | } 1079 | }, 1080 | "grunt-contrib-jshint": { 1081 | "version": "1.1.0", 1082 | "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-1.1.0.tgz", 1083 | "integrity": "sha1-Np2QmyWTxA6L55lAshNAhQx5Oaw=", 1084 | "dev": true, 1085 | "requires": { 1086 | "chalk": "1.1.3", 1087 | "hooker": "0.2.3", 1088 | "jshint": "2.9.7" 1089 | }, 1090 | "dependencies": { 1091 | "ansi-styles": { 1092 | "version": "2.2.1", 1093 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 1094 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 1095 | "dev": true 1096 | }, 1097 | "chalk": { 1098 | "version": "1.1.3", 1099 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 1100 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 1101 | "dev": true, 1102 | "requires": { 1103 | "ansi-styles": "2.2.1", 1104 | "escape-string-regexp": "1.0.5", 1105 | "has-ansi": "2.0.0", 1106 | "strip-ansi": "3.0.1", 1107 | "supports-color": "2.0.0" 1108 | } 1109 | }, 1110 | "supports-color": { 1111 | "version": "2.0.0", 1112 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1113 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1114 | "dev": true 1115 | } 1116 | } 1117 | }, 1118 | "grunt-contrib-watch": { 1119 | "version": "1.1.0", 1120 | "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", 1121 | "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", 1122 | "dev": true, 1123 | "requires": { 1124 | "async": "2.6.1", 1125 | "gaze": "1.1.3", 1126 | "lodash": "4.17.11", 1127 | "tiny-lr": "1.1.1" 1128 | }, 1129 | "dependencies": { 1130 | "async": { 1131 | "version": "2.6.1", 1132 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz", 1133 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==", 1134 | "dev": true, 1135 | "requires": { 1136 | "lodash": "4.17.11" 1137 | } 1138 | } 1139 | } 1140 | }, 1141 | "grunt-known-options": { 1142 | "version": "1.1.1", 1143 | "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", 1144 | "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", 1145 | "dev": true 1146 | }, 1147 | "grunt-legacy-log": { 1148 | "version": "2.0.0", 1149 | "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", 1150 | "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", 1151 | "dev": true, 1152 | "requires": { 1153 | "colors": "1.1.2", 1154 | "grunt-legacy-log-utils": "2.0.1", 1155 | "hooker": "0.2.3", 1156 | "lodash": "4.17.11" 1157 | } 1158 | }, 1159 | "grunt-legacy-log-utils": { 1160 | "version": "2.0.1", 1161 | "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", 1162 | "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", 1163 | "dev": true, 1164 | "requires": { 1165 | "chalk": "2.4.1", 1166 | "lodash": "4.17.11" 1167 | } 1168 | }, 1169 | "grunt-legacy-util": { 1170 | "version": "1.1.1", 1171 | "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", 1172 | "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", 1173 | "dev": true, 1174 | "requires": { 1175 | "async": "1.5.2", 1176 | "exit": "0.1.2", 1177 | "getobject": "0.1.0", 1178 | "hooker": "0.2.3", 1179 | "lodash": "4.17.11", 1180 | "underscore.string": "3.3.5", 1181 | "which": "1.3.1" 1182 | } 1183 | }, 1184 | "grunt-sass": { 1185 | "version": "2.1.0", 1186 | "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-2.1.0.tgz", 1187 | "integrity": "sha512-XkexnQt/9rhReNd+Y7T0n/2g5FqYOQKfi2iSlpwDqvgs7EgEaGTxNhnWzHnbW5oNRvzL9AHopBG3AgRxL0d+DA==", 1188 | "dev": true, 1189 | "requires": { 1190 | "each-async": "1.1.1", 1191 | "node-sass": "4.9.3", 1192 | "object-assign": "4.1.1" 1193 | } 1194 | }, 1195 | "har-schema": { 1196 | "version": "2.0.0", 1197 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 1198 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", 1199 | "dev": true 1200 | }, 1201 | "har-validator": { 1202 | "version": "5.0.3", 1203 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", 1204 | "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", 1205 | "dev": true, 1206 | "requires": { 1207 | "ajv": "5.5.2", 1208 | "har-schema": "2.0.0" 1209 | } 1210 | }, 1211 | "has-ansi": { 1212 | "version": "2.0.0", 1213 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 1214 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 1215 | "dev": true, 1216 | "requires": { 1217 | "ansi-regex": "2.1.1" 1218 | } 1219 | }, 1220 | "has-flag": { 1221 | "version": "3.0.0", 1222 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1223 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", 1224 | "dev": true 1225 | }, 1226 | "has-unicode": { 1227 | "version": "2.0.1", 1228 | "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", 1229 | "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", 1230 | "dev": true 1231 | }, 1232 | "hooker": { 1233 | "version": "0.2.3", 1234 | "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", 1235 | "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", 1236 | "dev": true 1237 | }, 1238 | "hosted-git-info": { 1239 | "version": "2.7.1", 1240 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", 1241 | "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", 1242 | "dev": true 1243 | }, 1244 | "htmlparser2": { 1245 | "version": "3.8.3", 1246 | "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", 1247 | "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", 1248 | "dev": true, 1249 | "requires": { 1250 | "domelementtype": "1.3.0", 1251 | "domhandler": "2.3.0", 1252 | "domutils": "1.5.1", 1253 | "entities": "1.0.0", 1254 | "readable-stream": "1.1.14" 1255 | } 1256 | }, 1257 | "http-errors": { 1258 | "version": "1.6.3", 1259 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 1260 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 1261 | "dev": true, 1262 | "requires": { 1263 | "depd": "1.1.2", 1264 | "inherits": "2.0.3", 1265 | "setprototypeof": "1.1.0", 1266 | "statuses": "1.5.0" 1267 | }, 1268 | "dependencies": { 1269 | "statuses": { 1270 | "version": "1.5.0", 1271 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 1272 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", 1273 | "dev": true 1274 | } 1275 | } 1276 | }, 1277 | "http-parser-js": { 1278 | "version": "0.4.13", 1279 | "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.13.tgz", 1280 | "integrity": "sha1-O9bW/ebjFyyTNMOzO2wZPYD+ETc=", 1281 | "dev": true 1282 | }, 1283 | "http-signature": { 1284 | "version": "1.2.0", 1285 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 1286 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 1287 | "dev": true, 1288 | "requires": { 1289 | "assert-plus": "1.0.0", 1290 | "jsprim": "1.4.1", 1291 | "sshpk": "1.14.2" 1292 | } 1293 | }, 1294 | "http2": { 1295 | "version": "3.3.7", 1296 | "resolved": "https://registry.npmjs.org/http2/-/http2-3.3.7.tgz", 1297 | "integrity": "sha512-puSi8M8WNlFJm9Pk4c/Mbz9Gwparuj3gO9/RRO5zv6piQ0FY+9Qywp0PdWshYgsMJSalixFY7eC6oPu0zRxLAQ==", 1298 | "dev": true 1299 | }, 1300 | "iconv-lite": { 1301 | "version": "0.4.24", 1302 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 1303 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 1304 | "dev": true, 1305 | "requires": { 1306 | "safer-buffer": "2.1.2" 1307 | } 1308 | }, 1309 | "ignore": { 1310 | "version": "3.3.10", 1311 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", 1312 | "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==", 1313 | "dev": true 1314 | }, 1315 | "in-publish": { 1316 | "version": "2.0.0", 1317 | "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", 1318 | "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", 1319 | "dev": true 1320 | }, 1321 | "indent-string": { 1322 | "version": "2.1.0", 1323 | "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", 1324 | "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", 1325 | "dev": true, 1326 | "requires": { 1327 | "repeating": "2.0.1" 1328 | } 1329 | }, 1330 | "inflight": { 1331 | "version": "1.0.6", 1332 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1333 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1334 | "dev": true, 1335 | "requires": { 1336 | "once": "1.4.0", 1337 | "wrappy": "1.0.2" 1338 | } 1339 | }, 1340 | "inherits": { 1341 | "version": "2.0.3", 1342 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1343 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 1344 | "dev": true 1345 | }, 1346 | "invert-kv": { 1347 | "version": "1.0.0", 1348 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", 1349 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", 1350 | "dev": true 1351 | }, 1352 | "is-arrayish": { 1353 | "version": "0.2.1", 1354 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", 1355 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", 1356 | "dev": true 1357 | }, 1358 | "is-builtin-module": { 1359 | "version": "1.0.0", 1360 | "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", 1361 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", 1362 | "dev": true, 1363 | "requires": { 1364 | "builtin-modules": "1.1.1" 1365 | } 1366 | }, 1367 | "is-finite": { 1368 | "version": "1.0.2", 1369 | "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", 1370 | "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", 1371 | "dev": true, 1372 | "requires": { 1373 | "number-is-nan": "1.0.1" 1374 | } 1375 | }, 1376 | "is-fullwidth-code-point": { 1377 | "version": "1.0.0", 1378 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 1379 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 1380 | "dev": true, 1381 | "requires": { 1382 | "number-is-nan": "1.0.1" 1383 | } 1384 | }, 1385 | "is-typedarray": { 1386 | "version": "1.0.0", 1387 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 1388 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 1389 | "dev": true 1390 | }, 1391 | "is-utf8": { 1392 | "version": "0.2.1", 1393 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 1394 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", 1395 | "dev": true 1396 | }, 1397 | "isarray": { 1398 | "version": "0.0.1", 1399 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 1400 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", 1401 | "dev": true 1402 | }, 1403 | "isexe": { 1404 | "version": "2.0.0", 1405 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1406 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 1407 | "dev": true 1408 | }, 1409 | "isstream": { 1410 | "version": "0.1.2", 1411 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 1412 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", 1413 | "dev": true 1414 | }, 1415 | "js-base64": { 1416 | "version": "2.4.9", 1417 | "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz", 1418 | "integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==", 1419 | "dev": true 1420 | }, 1421 | "js-yaml": { 1422 | "version": "3.5.5", 1423 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.5.tgz", 1424 | "integrity": "sha1-A3fDgBfKvHMisNH7zSWkkWQfL74=", 1425 | "dev": true, 1426 | "requires": { 1427 | "argparse": "1.0.10", 1428 | "esprima": "2.7.3" 1429 | } 1430 | }, 1431 | "jsbn": { 1432 | "version": "0.1.1", 1433 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 1434 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 1435 | "dev": true, 1436 | "optional": true 1437 | }, 1438 | "jshint": { 1439 | "version": "2.9.7", 1440 | "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.7.tgz", 1441 | "integrity": "sha512-Q8XN38hGsVQhdlM+4gd1Xl7OB1VieSuCJf+fEJjpo59JH99bVJhXRXAh26qQ15wfdd1VPMuDWNeSWoNl53T4YA==", 1442 | "dev": true, 1443 | "requires": { 1444 | "cli": "1.0.1", 1445 | "console-browserify": "1.1.0", 1446 | "exit": "0.1.2", 1447 | "htmlparser2": "3.8.3", 1448 | "lodash": "4.17.11", 1449 | "minimatch": "3.0.4", 1450 | "shelljs": "0.3.0", 1451 | "strip-json-comments": "1.0.4" 1452 | }, 1453 | "dependencies": { 1454 | "shelljs": { 1455 | "version": "0.3.0", 1456 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", 1457 | "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", 1458 | "dev": true 1459 | } 1460 | } 1461 | }, 1462 | "json-schema": { 1463 | "version": "0.2.3", 1464 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 1465 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", 1466 | "dev": true 1467 | }, 1468 | "json-schema-traverse": { 1469 | "version": "0.3.1", 1470 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", 1471 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", 1472 | "dev": true 1473 | }, 1474 | "json-stringify-safe": { 1475 | "version": "5.0.1", 1476 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 1477 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 1478 | "dev": true 1479 | }, 1480 | "jsprim": { 1481 | "version": "1.4.1", 1482 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 1483 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 1484 | "dev": true, 1485 | "requires": { 1486 | "assert-plus": "1.0.0", 1487 | "extsprintf": "1.3.0", 1488 | "json-schema": "0.2.3", 1489 | "verror": "1.10.0" 1490 | } 1491 | }, 1492 | "lcid": { 1493 | "version": "1.0.0", 1494 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", 1495 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", 1496 | "dev": true, 1497 | "requires": { 1498 | "invert-kv": "1.0.0" 1499 | } 1500 | }, 1501 | "livereload-js": { 1502 | "version": "2.4.0", 1503 | "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", 1504 | "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", 1505 | "dev": true 1506 | }, 1507 | "load-grunt-tasks": { 1508 | "version": "3.5.2", 1509 | "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.5.2.tgz", 1510 | "integrity": "sha1-ByhWEYD9IP+KaSdQWFL8WKrqDIg=", 1511 | "dev": true, 1512 | "requires": { 1513 | "arrify": "1.0.1", 1514 | "multimatch": "2.1.0", 1515 | "pkg-up": "1.0.0", 1516 | "resolve-pkg": "0.1.0" 1517 | } 1518 | }, 1519 | "load-json-file": { 1520 | "version": "1.1.0", 1521 | "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", 1522 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", 1523 | "dev": true, 1524 | "requires": { 1525 | "graceful-fs": "4.1.11", 1526 | "parse-json": "2.2.0", 1527 | "pify": "2.3.0", 1528 | "pinkie-promise": "2.0.1", 1529 | "strip-bom": "2.0.0" 1530 | } 1531 | }, 1532 | "lodash": { 1533 | "version": "4.17.11", 1534 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", 1535 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", 1536 | "dev": true 1537 | }, 1538 | "lodash.assign": { 1539 | "version": "4.2.0", 1540 | "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", 1541 | "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", 1542 | "dev": true 1543 | }, 1544 | "lodash.clonedeep": { 1545 | "version": "4.5.0", 1546 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", 1547 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", 1548 | "dev": true 1549 | }, 1550 | "lodash.mergewith": { 1551 | "version": "4.6.1", 1552 | "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", 1553 | "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", 1554 | "dev": true 1555 | }, 1556 | "loud-rejection": { 1557 | "version": "1.6.0", 1558 | "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", 1559 | "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", 1560 | "dev": true, 1561 | "requires": { 1562 | "currently-unhandled": "0.4.1", 1563 | "signal-exit": "3.0.2" 1564 | } 1565 | }, 1566 | "lru-cache": { 1567 | "version": "4.1.3", 1568 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", 1569 | "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", 1570 | "dev": true, 1571 | "requires": { 1572 | "pseudomap": "1.0.2", 1573 | "yallist": "2.1.2" 1574 | } 1575 | }, 1576 | "map-obj": { 1577 | "version": "1.0.1", 1578 | "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", 1579 | "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", 1580 | "dev": true 1581 | }, 1582 | "meow": { 1583 | "version": "3.7.0", 1584 | "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", 1585 | "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", 1586 | "dev": true, 1587 | "requires": { 1588 | "camelcase-keys": "2.1.0", 1589 | "decamelize": "1.2.0", 1590 | "loud-rejection": "1.6.0", 1591 | "map-obj": "1.0.1", 1592 | "minimist": "1.2.0", 1593 | "normalize-package-data": "2.4.0", 1594 | "object-assign": "4.1.1", 1595 | "read-pkg-up": "1.0.1", 1596 | "redent": "1.0.0", 1597 | "trim-newlines": "1.0.0" 1598 | }, 1599 | "dependencies": { 1600 | "minimist": { 1601 | "version": "1.2.0", 1602 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1603 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 1604 | "dev": true 1605 | } 1606 | } 1607 | }, 1608 | "mime": { 1609 | "version": "1.4.1", 1610 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 1611 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", 1612 | "dev": true 1613 | }, 1614 | "mime-db": { 1615 | "version": "1.36.0", 1616 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", 1617 | "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==", 1618 | "dev": true 1619 | }, 1620 | "mime-types": { 1621 | "version": "2.1.20", 1622 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", 1623 | "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", 1624 | "dev": true, 1625 | "requires": { 1626 | "mime-db": "1.36.0" 1627 | } 1628 | }, 1629 | "minimatch": { 1630 | "version": "3.0.4", 1631 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1632 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1633 | "dev": true, 1634 | "requires": { 1635 | "brace-expansion": "1.1.11" 1636 | } 1637 | }, 1638 | "minimist": { 1639 | "version": "0.0.10", 1640 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", 1641 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", 1642 | "dev": true 1643 | }, 1644 | "mkdirp": { 1645 | "version": "0.5.1", 1646 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 1647 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 1648 | "dev": true, 1649 | "requires": { 1650 | "minimist": "0.0.8" 1651 | }, 1652 | "dependencies": { 1653 | "minimist": { 1654 | "version": "0.0.8", 1655 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 1656 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 1657 | "dev": true 1658 | } 1659 | } 1660 | }, 1661 | "morgan": { 1662 | "version": "1.9.1", 1663 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz", 1664 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==", 1665 | "dev": true, 1666 | "requires": { 1667 | "basic-auth": "2.0.1", 1668 | "debug": "2.6.9", 1669 | "depd": "1.1.2", 1670 | "on-finished": "2.3.0", 1671 | "on-headers": "1.0.1" 1672 | } 1673 | }, 1674 | "ms": { 1675 | "version": "2.0.0", 1676 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 1677 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 1678 | "dev": true 1679 | }, 1680 | "multimatch": { 1681 | "version": "2.1.0", 1682 | "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", 1683 | "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", 1684 | "dev": true, 1685 | "requires": { 1686 | "array-differ": "1.0.0", 1687 | "array-union": "1.0.2", 1688 | "arrify": "1.0.1", 1689 | "minimatch": "3.0.4" 1690 | } 1691 | }, 1692 | "nan": { 1693 | "version": "2.11.1", 1694 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz", 1695 | "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA==", 1696 | "dev": true 1697 | }, 1698 | "negotiator": { 1699 | "version": "0.6.1", 1700 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 1701 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", 1702 | "dev": true 1703 | }, 1704 | "node-gyp": { 1705 | "version": "3.8.0", 1706 | "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", 1707 | "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", 1708 | "dev": true, 1709 | "requires": { 1710 | "fstream": "1.0.11", 1711 | "glob": "7.1.3", 1712 | "graceful-fs": "4.1.11", 1713 | "mkdirp": "0.5.1", 1714 | "nopt": "3.0.6", 1715 | "npmlog": "4.1.2", 1716 | "osenv": "0.1.5", 1717 | "request": "2.87.0", 1718 | "rimraf": "2.6.2", 1719 | "semver": "5.3.0", 1720 | "tar": "2.2.1", 1721 | "which": "1.3.1" 1722 | }, 1723 | "dependencies": { 1724 | "semver": { 1725 | "version": "5.3.0", 1726 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", 1727 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", 1728 | "dev": true 1729 | } 1730 | } 1731 | }, 1732 | "node-sass": { 1733 | "version": "4.9.3", 1734 | "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz", 1735 | "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==", 1736 | "dev": true, 1737 | "requires": { 1738 | "async-foreach": "0.1.3", 1739 | "chalk": "1.1.3", 1740 | "cross-spawn": "3.0.1", 1741 | "gaze": "1.1.3", 1742 | "get-stdin": "4.0.1", 1743 | "glob": "7.1.3", 1744 | "in-publish": "2.0.0", 1745 | "lodash.assign": "4.2.0", 1746 | "lodash.clonedeep": "4.5.0", 1747 | "lodash.mergewith": "4.6.1", 1748 | "meow": "3.7.0", 1749 | "mkdirp": "0.5.1", 1750 | "nan": "2.11.1", 1751 | "node-gyp": "3.8.0", 1752 | "npmlog": "4.1.2", 1753 | "request": "2.87.0", 1754 | "sass-graph": "2.2.4", 1755 | "stdout-stream": "1.4.1", 1756 | "true-case-path": "1.0.3" 1757 | }, 1758 | "dependencies": { 1759 | "ansi-styles": { 1760 | "version": "2.2.1", 1761 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 1762 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 1763 | "dev": true 1764 | }, 1765 | "chalk": { 1766 | "version": "1.1.3", 1767 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 1768 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 1769 | "dev": true, 1770 | "requires": { 1771 | "ansi-styles": "2.2.1", 1772 | "escape-string-regexp": "1.0.5", 1773 | "has-ansi": "2.0.0", 1774 | "strip-ansi": "3.0.1", 1775 | "supports-color": "2.0.0" 1776 | } 1777 | }, 1778 | "supports-color": { 1779 | "version": "2.0.0", 1780 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 1781 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 1782 | "dev": true 1783 | } 1784 | } 1785 | }, 1786 | "nopt": { 1787 | "version": "3.0.6", 1788 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", 1789 | "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", 1790 | "dev": true, 1791 | "requires": { 1792 | "abbrev": "1.1.1" 1793 | } 1794 | }, 1795 | "normalize-package-data": { 1796 | "version": "2.4.0", 1797 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", 1798 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", 1799 | "dev": true, 1800 | "requires": { 1801 | "hosted-git-info": "2.7.1", 1802 | "is-builtin-module": "1.0.0", 1803 | "semver": "5.5.1", 1804 | "validate-npm-package-license": "3.0.4" 1805 | } 1806 | }, 1807 | "npmlog": { 1808 | "version": "4.1.2", 1809 | "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", 1810 | "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", 1811 | "dev": true, 1812 | "requires": { 1813 | "are-we-there-yet": "1.1.5", 1814 | "console-control-strings": "1.1.0", 1815 | "gauge": "2.7.4", 1816 | "set-blocking": "2.0.0" 1817 | } 1818 | }, 1819 | "number-is-nan": { 1820 | "version": "1.0.1", 1821 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 1822 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 1823 | "dev": true 1824 | }, 1825 | "oauth-sign": { 1826 | "version": "0.8.2", 1827 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 1828 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", 1829 | "dev": true 1830 | }, 1831 | "object-assign": { 1832 | "version": "4.1.1", 1833 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1834 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1835 | "dev": true 1836 | }, 1837 | "on-finished": { 1838 | "version": "2.3.0", 1839 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 1840 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 1841 | "dev": true, 1842 | "requires": { 1843 | "ee-first": "1.1.1" 1844 | } 1845 | }, 1846 | "on-headers": { 1847 | "version": "1.0.1", 1848 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", 1849 | "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=", 1850 | "dev": true 1851 | }, 1852 | "once": { 1853 | "version": "1.4.0", 1854 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1855 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1856 | "dev": true, 1857 | "requires": { 1858 | "wrappy": "1.0.2" 1859 | } 1860 | }, 1861 | "onetime": { 1862 | "version": "1.1.0", 1863 | "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", 1864 | "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", 1865 | "dev": true 1866 | }, 1867 | "opn": { 1868 | "version": "4.0.2", 1869 | "resolved": "http://registry.npmjs.org/opn/-/opn-4.0.2.tgz", 1870 | "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", 1871 | "dev": true, 1872 | "requires": { 1873 | "object-assign": "4.1.1", 1874 | "pinkie-promise": "2.0.1" 1875 | } 1876 | }, 1877 | "optimist": { 1878 | "version": "0.6.1", 1879 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 1880 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 1881 | "dev": true, 1882 | "requires": { 1883 | "minimist": "0.0.10", 1884 | "wordwrap": "0.0.3" 1885 | } 1886 | }, 1887 | "os-homedir": { 1888 | "version": "1.0.2", 1889 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 1890 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 1891 | "dev": true 1892 | }, 1893 | "os-locale": { 1894 | "version": "1.4.0", 1895 | "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", 1896 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", 1897 | "dev": true, 1898 | "requires": { 1899 | "lcid": "1.0.0" 1900 | } 1901 | }, 1902 | "os-tmpdir": { 1903 | "version": "1.0.2", 1904 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 1905 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 1906 | "dev": true 1907 | }, 1908 | "osenv": { 1909 | "version": "0.1.5", 1910 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 1911 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 1912 | "dev": true, 1913 | "requires": { 1914 | "os-homedir": "1.0.2", 1915 | "os-tmpdir": "1.0.2" 1916 | } 1917 | }, 1918 | "parse-json": { 1919 | "version": "2.2.0", 1920 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", 1921 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", 1922 | "dev": true, 1923 | "requires": { 1924 | "error-ex": "1.3.2" 1925 | } 1926 | }, 1927 | "parseurl": { 1928 | "version": "1.3.2", 1929 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 1930 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", 1931 | "dev": true 1932 | }, 1933 | "path-exists": { 1934 | "version": "2.1.0", 1935 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", 1936 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", 1937 | "dev": true, 1938 | "requires": { 1939 | "pinkie-promise": "2.0.1" 1940 | } 1941 | }, 1942 | "path-is-absolute": { 1943 | "version": "1.0.1", 1944 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1945 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1946 | "dev": true 1947 | }, 1948 | "path-type": { 1949 | "version": "1.1.0", 1950 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", 1951 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", 1952 | "dev": true, 1953 | "requires": { 1954 | "graceful-fs": "4.1.11", 1955 | "pify": "2.3.0", 1956 | "pinkie-promise": "2.0.1" 1957 | } 1958 | }, 1959 | "performance-now": { 1960 | "version": "2.1.0", 1961 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 1962 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", 1963 | "dev": true 1964 | }, 1965 | "pify": { 1966 | "version": "2.3.0", 1967 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1968 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1969 | "dev": true 1970 | }, 1971 | "pinkie": { 1972 | "version": "2.0.4", 1973 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1974 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1975 | "dev": true 1976 | }, 1977 | "pinkie-promise": { 1978 | "version": "2.0.1", 1979 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1980 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1981 | "dev": true, 1982 | "requires": { 1983 | "pinkie": "2.0.4" 1984 | } 1985 | }, 1986 | "pkg-up": { 1987 | "version": "1.0.0", 1988 | "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", 1989 | "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", 1990 | "dev": true, 1991 | "requires": { 1992 | "find-up": "1.1.2" 1993 | } 1994 | }, 1995 | "portscanner": { 1996 | "version": "1.2.0", 1997 | "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-1.2.0.tgz", 1998 | "integrity": "sha1-sUu9olfRTDEPqcwJaCrwLUCWGAI=", 1999 | "dev": true, 2000 | "requires": { 2001 | "async": "1.5.2" 2002 | } 2003 | }, 2004 | "process-nextick-args": { 2005 | "version": "2.0.0", 2006 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 2007 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 2008 | "dev": true 2009 | }, 2010 | "pseudomap": { 2011 | "version": "1.0.2", 2012 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 2013 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 2014 | "dev": true 2015 | }, 2016 | "punycode": { 2017 | "version": "1.4.1", 2018 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 2019 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 2020 | "dev": true 2021 | }, 2022 | "qs": { 2023 | "version": "6.5.2", 2024 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 2025 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", 2026 | "dev": true 2027 | }, 2028 | "range-parser": { 2029 | "version": "1.2.0", 2030 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 2031 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", 2032 | "dev": true 2033 | }, 2034 | "raw-body": { 2035 | "version": "1.1.7", 2036 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", 2037 | "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", 2038 | "dev": true, 2039 | "requires": { 2040 | "bytes": "1.0.0", 2041 | "string_decoder": "0.10.31" 2042 | } 2043 | }, 2044 | "read-pkg": { 2045 | "version": "1.1.0", 2046 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", 2047 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", 2048 | "dev": true, 2049 | "requires": { 2050 | "load-json-file": "1.1.0", 2051 | "normalize-package-data": "2.4.0", 2052 | "path-type": "1.1.0" 2053 | } 2054 | }, 2055 | "read-pkg-up": { 2056 | "version": "1.0.1", 2057 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", 2058 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", 2059 | "dev": true, 2060 | "requires": { 2061 | "find-up": "1.1.2", 2062 | "read-pkg": "1.1.0" 2063 | } 2064 | }, 2065 | "readable-stream": { 2066 | "version": "1.1.14", 2067 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 2068 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 2069 | "dev": true, 2070 | "requires": { 2071 | "core-util-is": "1.0.2", 2072 | "inherits": "2.0.3", 2073 | "isarray": "0.0.1", 2074 | "string_decoder": "0.10.31" 2075 | } 2076 | }, 2077 | "redent": { 2078 | "version": "1.0.0", 2079 | "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", 2080 | "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", 2081 | "dev": true, 2082 | "requires": { 2083 | "indent-string": "2.1.0", 2084 | "strip-indent": "1.0.1" 2085 | } 2086 | }, 2087 | "repeating": { 2088 | "version": "2.0.1", 2089 | "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", 2090 | "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", 2091 | "dev": true, 2092 | "requires": { 2093 | "is-finite": "1.0.2" 2094 | } 2095 | }, 2096 | "request": { 2097 | "version": "2.87.0", 2098 | "resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz", 2099 | "integrity": "sha512-fcogkm7Az5bsS6Sl0sibkbhcKsnyon/jV1kF3ajGmF0c8HrttdKTPRT9hieOaQHA5HEq6r8OyWOo/o781C1tNw==", 2100 | "dev": true, 2101 | "requires": { 2102 | "aws-sign2": "0.7.0", 2103 | "aws4": "1.8.0", 2104 | "caseless": "0.12.0", 2105 | "combined-stream": "1.0.7", 2106 | "extend": "3.0.2", 2107 | "forever-agent": "0.6.1", 2108 | "form-data": "2.3.2", 2109 | "har-validator": "5.0.3", 2110 | "http-signature": "1.2.0", 2111 | "is-typedarray": "1.0.0", 2112 | "isstream": "0.1.2", 2113 | "json-stringify-safe": "5.0.1", 2114 | "mime-types": "2.1.20", 2115 | "oauth-sign": "0.8.2", 2116 | "performance-now": "2.1.0", 2117 | "qs": "6.5.2", 2118 | "safe-buffer": "5.1.2", 2119 | "tough-cookie": "2.3.4", 2120 | "tunnel-agent": "0.6.0", 2121 | "uuid": "3.3.2" 2122 | } 2123 | }, 2124 | "require-directory": { 2125 | "version": "2.1.1", 2126 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 2127 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", 2128 | "dev": true 2129 | }, 2130 | "require-main-filename": { 2131 | "version": "1.0.1", 2132 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 2133 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", 2134 | "dev": true 2135 | }, 2136 | "resolve": { 2137 | "version": "0.6.3", 2138 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-0.6.3.tgz", 2139 | "integrity": "sha1-3ZV5gufnNt699TtYpN2RdUV13UY=", 2140 | "dev": true 2141 | }, 2142 | "resolve-from": { 2143 | "version": "2.0.0", 2144 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", 2145 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", 2146 | "dev": true 2147 | }, 2148 | "resolve-pkg": { 2149 | "version": "0.1.0", 2150 | "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-0.1.0.tgz", 2151 | "integrity": "sha1-AsyZNBDik2livZcWahsHfalyVTE=", 2152 | "dev": true, 2153 | "requires": { 2154 | "resolve-from": "2.0.0" 2155 | } 2156 | }, 2157 | "rimraf": { 2158 | "version": "2.6.2", 2159 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 2160 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 2161 | "dev": true, 2162 | "requires": { 2163 | "glob": "7.1.3" 2164 | } 2165 | }, 2166 | "safe-buffer": { 2167 | "version": "5.1.2", 2168 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 2169 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 2170 | "dev": true 2171 | }, 2172 | "safe-json-parse": { 2173 | "version": "1.0.1", 2174 | "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", 2175 | "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", 2176 | "dev": true 2177 | }, 2178 | "safer-buffer": { 2179 | "version": "2.1.2", 2180 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 2181 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", 2182 | "dev": true 2183 | }, 2184 | "sass-graph": { 2185 | "version": "2.2.4", 2186 | "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", 2187 | "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", 2188 | "dev": true, 2189 | "requires": { 2190 | "glob": "7.1.3", 2191 | "lodash": "4.17.11", 2192 | "scss-tokenizer": "0.2.3", 2193 | "yargs": "7.1.0" 2194 | } 2195 | }, 2196 | "scss-tokenizer": { 2197 | "version": "0.2.3", 2198 | "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", 2199 | "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", 2200 | "dev": true, 2201 | "requires": { 2202 | "js-base64": "2.4.9", 2203 | "source-map": "0.4.4" 2204 | } 2205 | }, 2206 | "semver": { 2207 | "version": "5.5.1", 2208 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", 2209 | "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", 2210 | "dev": true 2211 | }, 2212 | "send": { 2213 | "version": "0.16.2", 2214 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 2215 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 2216 | "dev": true, 2217 | "requires": { 2218 | "debug": "2.6.9", 2219 | "depd": "1.1.2", 2220 | "destroy": "1.0.4", 2221 | "encodeurl": "1.0.2", 2222 | "escape-html": "1.0.3", 2223 | "etag": "1.8.1", 2224 | "fresh": "0.5.2", 2225 | "http-errors": "1.6.3", 2226 | "mime": "1.4.1", 2227 | "ms": "2.0.0", 2228 | "on-finished": "2.3.0", 2229 | "range-parser": "1.2.0", 2230 | "statuses": "1.4.0" 2231 | }, 2232 | "dependencies": { 2233 | "statuses": { 2234 | "version": "1.4.0", 2235 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 2236 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", 2237 | "dev": true 2238 | } 2239 | } 2240 | }, 2241 | "serve-index": { 2242 | "version": "1.9.1", 2243 | "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", 2244 | "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", 2245 | "dev": true, 2246 | "requires": { 2247 | "accepts": "1.3.5", 2248 | "batch": "0.6.1", 2249 | "debug": "2.6.9", 2250 | "escape-html": "1.0.3", 2251 | "http-errors": "1.6.3", 2252 | "mime-types": "2.1.20", 2253 | "parseurl": "1.3.2" 2254 | } 2255 | }, 2256 | "serve-static": { 2257 | "version": "1.13.2", 2258 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 2259 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 2260 | "dev": true, 2261 | "requires": { 2262 | "encodeurl": "1.0.2", 2263 | "escape-html": "1.0.3", 2264 | "parseurl": "1.3.2", 2265 | "send": "0.16.2" 2266 | } 2267 | }, 2268 | "set-blocking": { 2269 | "version": "2.0.0", 2270 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 2271 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 2272 | "dev": true 2273 | }, 2274 | "set-immediate-shim": { 2275 | "version": "1.0.1", 2276 | "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", 2277 | "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", 2278 | "dev": true 2279 | }, 2280 | "setprototypeof": { 2281 | "version": "1.1.0", 2282 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 2283 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", 2284 | "dev": true 2285 | }, 2286 | "shelljs": { 2287 | "version": "0.2.6", 2288 | "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz", 2289 | "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=", 2290 | "dev": true 2291 | }, 2292 | "signal-exit": { 2293 | "version": "3.0.2", 2294 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 2295 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 2296 | "dev": true 2297 | }, 2298 | "source-map": { 2299 | "version": "0.4.4", 2300 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 2301 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 2302 | "dev": true, 2303 | "requires": { 2304 | "amdefine": "1.0.1" 2305 | } 2306 | }, 2307 | "spdx-correct": { 2308 | "version": "3.0.1", 2309 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.1.tgz", 2310 | "integrity": "sha512-hxSPZbRZvSDuOvADntOElzJpenIR7wXJkuoUcUtS0erbgt2fgeaoPIYretfKpslMhfFDY4k0MZ2F5CUzhBsSvQ==", 2311 | "dev": true, 2312 | "requires": { 2313 | "spdx-expression-parse": "3.0.0", 2314 | "spdx-license-ids": "3.0.1" 2315 | } 2316 | }, 2317 | "spdx-exceptions": { 2318 | "version": "2.2.0", 2319 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", 2320 | "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", 2321 | "dev": true 2322 | }, 2323 | "spdx-expression-parse": { 2324 | "version": "3.0.0", 2325 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", 2326 | "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", 2327 | "dev": true, 2328 | "requires": { 2329 | "spdx-exceptions": "2.2.0", 2330 | "spdx-license-ids": "3.0.1" 2331 | } 2332 | }, 2333 | "spdx-license-ids": { 2334 | "version": "3.0.1", 2335 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.1.tgz", 2336 | "integrity": "sha512-TfOfPcYGBB5sDuPn3deByxPhmfegAhpDYKSOXZQN81Oyrrif8ZCodOLzK3AesELnCx03kikhyDwh0pfvvQvF8w==", 2337 | "dev": true 2338 | }, 2339 | "sprintf-js": { 2340 | "version": "1.1.1", 2341 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.1.tgz", 2342 | "integrity": "sha1-Nr54Mgr+WAH2zqPueLblqrlA6gw=", 2343 | "dev": true 2344 | }, 2345 | "sshpk": { 2346 | "version": "1.14.2", 2347 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", 2348 | "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", 2349 | "dev": true, 2350 | "requires": { 2351 | "asn1": "0.2.4", 2352 | "assert-plus": "1.0.0", 2353 | "bcrypt-pbkdf": "1.0.2", 2354 | "dashdash": "1.14.1", 2355 | "ecc-jsbn": "0.1.2", 2356 | "getpass": "0.1.7", 2357 | "jsbn": "0.1.1", 2358 | "safer-buffer": "2.1.2", 2359 | "tweetnacl": "0.14.5" 2360 | } 2361 | }, 2362 | "statuses": { 2363 | "version": "1.3.1", 2364 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", 2365 | "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", 2366 | "dev": true 2367 | }, 2368 | "stdout-stream": { 2369 | "version": "1.4.1", 2370 | "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", 2371 | "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", 2372 | "dev": true, 2373 | "requires": { 2374 | "readable-stream": "2.3.6" 2375 | }, 2376 | "dependencies": { 2377 | "isarray": { 2378 | "version": "1.0.0", 2379 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 2380 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 2381 | "dev": true 2382 | }, 2383 | "readable-stream": { 2384 | "version": "2.3.6", 2385 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 2386 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 2387 | "dev": true, 2388 | "requires": { 2389 | "core-util-is": "1.0.2", 2390 | "inherits": "2.0.3", 2391 | "isarray": "1.0.0", 2392 | "process-nextick-args": "2.0.0", 2393 | "safe-buffer": "5.1.2", 2394 | "string_decoder": "1.1.1", 2395 | "util-deprecate": "1.0.2" 2396 | } 2397 | }, 2398 | "string_decoder": { 2399 | "version": "1.1.1", 2400 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 2401 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 2402 | "dev": true, 2403 | "requires": { 2404 | "safe-buffer": "5.1.2" 2405 | } 2406 | } 2407 | } 2408 | }, 2409 | "string-template": { 2410 | "version": "0.2.1", 2411 | "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", 2412 | "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", 2413 | "dev": true 2414 | }, 2415 | "string-width": { 2416 | "version": "1.0.2", 2417 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 2418 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 2419 | "dev": true, 2420 | "requires": { 2421 | "code-point-at": "1.1.0", 2422 | "is-fullwidth-code-point": "1.0.0", 2423 | "strip-ansi": "3.0.1" 2424 | } 2425 | }, 2426 | "string_decoder": { 2427 | "version": "0.10.31", 2428 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 2429 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", 2430 | "dev": true 2431 | }, 2432 | "strip-ansi": { 2433 | "version": "3.0.1", 2434 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2435 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2436 | "dev": true, 2437 | "requires": { 2438 | "ansi-regex": "2.1.1" 2439 | } 2440 | }, 2441 | "strip-bom": { 2442 | "version": "2.0.0", 2443 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", 2444 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", 2445 | "dev": true, 2446 | "requires": { 2447 | "is-utf8": "0.2.1" 2448 | } 2449 | }, 2450 | "strip-indent": { 2451 | "version": "1.0.1", 2452 | "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", 2453 | "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", 2454 | "dev": true, 2455 | "requires": { 2456 | "get-stdin": "4.0.1" 2457 | } 2458 | }, 2459 | "strip-json-comments": { 2460 | "version": "1.0.4", 2461 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", 2462 | "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", 2463 | "dev": true 2464 | }, 2465 | "supports-color": { 2466 | "version": "5.5.0", 2467 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 2468 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 2469 | "dev": true, 2470 | "requires": { 2471 | "has-flag": "3.0.0" 2472 | } 2473 | }, 2474 | "tar": { 2475 | "version": "2.2.1", 2476 | "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", 2477 | "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", 2478 | "dev": true, 2479 | "requires": { 2480 | "block-stream": "0.0.9", 2481 | "fstream": "1.0.11", 2482 | "inherits": "2.0.3" 2483 | } 2484 | }, 2485 | "text-table": { 2486 | "version": "0.2.0", 2487 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 2488 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", 2489 | "dev": true 2490 | }, 2491 | "tiny-lr": { 2492 | "version": "1.1.1", 2493 | "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", 2494 | "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", 2495 | "dev": true, 2496 | "requires": { 2497 | "body": "5.1.0", 2498 | "debug": "3.2.5", 2499 | "faye-websocket": "0.10.0", 2500 | "livereload-js": "2.4.0", 2501 | "object-assign": "4.1.1", 2502 | "qs": "6.5.2" 2503 | }, 2504 | "dependencies": { 2505 | "debug": { 2506 | "version": "3.2.5", 2507 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", 2508 | "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", 2509 | "dev": true, 2510 | "requires": { 2511 | "ms": "2.1.1" 2512 | } 2513 | }, 2514 | "ms": { 2515 | "version": "2.1.1", 2516 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 2517 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", 2518 | "dev": true 2519 | } 2520 | } 2521 | }, 2522 | "tough-cookie": { 2523 | "version": "2.3.4", 2524 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", 2525 | "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", 2526 | "dev": true, 2527 | "requires": { 2528 | "punycode": "1.4.1" 2529 | } 2530 | }, 2531 | "trim-newlines": { 2532 | "version": "1.0.0", 2533 | "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", 2534 | "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", 2535 | "dev": true 2536 | }, 2537 | "true-case-path": { 2538 | "version": "1.0.3", 2539 | "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", 2540 | "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", 2541 | "dev": true, 2542 | "requires": { 2543 | "glob": "7.1.3" 2544 | } 2545 | }, 2546 | "tunnel-agent": { 2547 | "version": "0.6.0", 2548 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2549 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 2550 | "dev": true, 2551 | "requires": { 2552 | "safe-buffer": "5.1.2" 2553 | } 2554 | }, 2555 | "tweetnacl": { 2556 | "version": "0.14.5", 2557 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 2558 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 2559 | "dev": true, 2560 | "optional": true 2561 | }, 2562 | "underscore.string": { 2563 | "version": "3.3.5", 2564 | "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", 2565 | "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", 2566 | "dev": true, 2567 | "requires": { 2568 | "sprintf-js": "1.1.1", 2569 | "util-deprecate": "1.0.2" 2570 | } 2571 | }, 2572 | "unpipe": { 2573 | "version": "1.0.0", 2574 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 2575 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", 2576 | "dev": true 2577 | }, 2578 | "util-deprecate": { 2579 | "version": "1.0.2", 2580 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2581 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 2582 | "dev": true 2583 | }, 2584 | "utils-merge": { 2585 | "version": "1.0.1", 2586 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 2587 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", 2588 | "dev": true 2589 | }, 2590 | "uuid": { 2591 | "version": "3.3.2", 2592 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 2593 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", 2594 | "dev": true 2595 | }, 2596 | "validate-npm-package-license": { 2597 | "version": "3.0.4", 2598 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", 2599 | "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", 2600 | "dev": true, 2601 | "requires": { 2602 | "spdx-correct": "3.0.1", 2603 | "spdx-expression-parse": "3.0.0" 2604 | } 2605 | }, 2606 | "verror": { 2607 | "version": "1.10.0", 2608 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 2609 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 2610 | "dev": true, 2611 | "requires": { 2612 | "assert-plus": "1.0.0", 2613 | "core-util-is": "1.0.2", 2614 | "extsprintf": "1.3.0" 2615 | } 2616 | }, 2617 | "websocket-driver": { 2618 | "version": "0.7.0", 2619 | "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.0.tgz", 2620 | "integrity": "sha1-DK+dLXVdk67gSdS90NP+LMoqJOs=", 2621 | "dev": true, 2622 | "requires": { 2623 | "http-parser-js": "0.4.13", 2624 | "websocket-extensions": "0.1.3" 2625 | } 2626 | }, 2627 | "websocket-extensions": { 2628 | "version": "0.1.3", 2629 | "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", 2630 | "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", 2631 | "dev": true 2632 | }, 2633 | "which": { 2634 | "version": "1.3.1", 2635 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 2636 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 2637 | "dev": true, 2638 | "requires": { 2639 | "isexe": "2.0.0" 2640 | } 2641 | }, 2642 | "which-module": { 2643 | "version": "1.0.0", 2644 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", 2645 | "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", 2646 | "dev": true 2647 | }, 2648 | "wide-align": { 2649 | "version": "1.1.3", 2650 | "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", 2651 | "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", 2652 | "dev": true, 2653 | "requires": { 2654 | "string-width": "1.0.2" 2655 | } 2656 | }, 2657 | "wordwrap": { 2658 | "version": "0.0.3", 2659 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 2660 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", 2661 | "dev": true 2662 | }, 2663 | "wrap-ansi": { 2664 | "version": "2.1.0", 2665 | "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 2666 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 2667 | "dev": true, 2668 | "requires": { 2669 | "string-width": "1.0.2", 2670 | "strip-ansi": "3.0.1" 2671 | } 2672 | }, 2673 | "wrappy": { 2674 | "version": "1.0.2", 2675 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2676 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2677 | "dev": true 2678 | }, 2679 | "xtend": { 2680 | "version": "4.0.1", 2681 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 2682 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 2683 | "dev": true 2684 | }, 2685 | "y18n": { 2686 | "version": "3.2.1", 2687 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", 2688 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", 2689 | "dev": true 2690 | }, 2691 | "yallist": { 2692 | "version": "2.1.2", 2693 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 2694 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 2695 | "dev": true 2696 | }, 2697 | "yargs": { 2698 | "version": "7.1.0", 2699 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", 2700 | "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", 2701 | "dev": true, 2702 | "requires": { 2703 | "camelcase": "3.0.0", 2704 | "cliui": "3.2.0", 2705 | "decamelize": "1.2.0", 2706 | "get-caller-file": "1.0.3", 2707 | "os-locale": "1.4.0", 2708 | "read-pkg-up": "1.0.1", 2709 | "require-directory": "2.1.1", 2710 | "require-main-filename": "1.0.1", 2711 | "set-blocking": "2.0.0", 2712 | "string-width": "1.0.2", 2713 | "which-module": "1.0.0", 2714 | "y18n": "3.2.1", 2715 | "yargs-parser": "5.0.0" 2716 | }, 2717 | "dependencies": { 2718 | "camelcase": { 2719 | "version": "3.0.0", 2720 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 2721 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", 2722 | "dev": true 2723 | } 2724 | } 2725 | }, 2726 | "yargs-parser": { 2727 | "version": "5.0.0", 2728 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", 2729 | "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", 2730 | "dev": true, 2731 | "requires": { 2732 | "camelcase": "3.0.0" 2733 | }, 2734 | "dependencies": { 2735 | "camelcase": { 2736 | "version": "3.0.0", 2737 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", 2738 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", 2739 | "dev": true 2740 | } 2741 | } 2742 | } 2743 | } 2744 | } 2745 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confidently-testing-wordpress", 3 | "version": "0.0.0", 4 | "private": true, 5 | "devDependencies": { 6 | "grunt": "^1.0.0", 7 | "grunt-sass": "^2.0.0", 8 | "grunt-contrib-connect": "^1.0.2", 9 | "grunt-contrib-watch": "^1.0.0", 10 | "grunt-contrib-copy": "^1.0.0", 11 | "grunt-contrib-jshint": "^1.1.0", 12 | "load-grunt-tasks": "^3.5.2", 13 | "grunt-build-control": "^0.7.1", 14 | "grunt-coffeelint": "0.0.16", 15 | "coffeelint": "^1.16.0" 16 | }, 17 | "engines": { 18 | "node": ">=4" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git@github.com:stevegrunwell/confidently-testing-wordpress.git" 23 | }, 24 | "scripts": { 25 | "test": "grunt test" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/.gitkeep: -------------------------------------------------------------------------------- 1 | Used to store static assets -------------------------------------------------------------------------------- /resources/koolaid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stevegrunwell/confidently-testing-wordpress/932a39d78d97af5100ee406f0a8b35001b6cfa2a/resources/koolaid.jpg -------------------------------------------------------------------------------- /resources/testing-pyramid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/wapuu-struggle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stevegrunwell/confidently-testing-wordpress/932a39d78d97af5100ee406f0a8b35001b6cfa2a/resources/wapuu-struggle.png -------------------------------------------------------------------------------- /resources/wordpress.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /slides/aaa.md: -------------------------------------------------------------------------------- 1 | ### Arrange - Act - Assert 2 | 3 |
4 |
Arrange
5 |
Set up the scenario
6 |
Act
7 |
Execute the code
8 |
Assert
9 |
Verify things happened as you expected
10 |
11 | 12 | Note: 13 | 14 | Pattern is commonly called "Arrange - Act - Assert" 15 | -------------------------------------------------------------------------------- /slides/assert-wperror.md: -------------------------------------------------------------------------------- 1 | ### Checking for WP_Errors 2 | 3 | Was the response an instance of `WP_Error`? 4 | 5 | ```php 6 | public function test_function_can_return_wp_error() { 7 | $response = myplugin_function(); 8 | 9 | $this->assertWPError($response); 10 | } 11 | ``` 12 | 13 | Note: 14 | 15 | Since WordPress doesn't really use Exceptions, instead favoring the WP_Error class, the assertWPError() assertion included in the core test suite can be useful if you need to check for WP_Error instances. 16 | -------------------------------------------------------------------------------- /slides/assertcontains.md: -------------------------------------------------------------------------------- 1 | ### Verifying contents 2 | 3 |
4 |
assertContains()
5 |
Does $value contain $expected?
6 |
$this->assertContains('b', ['a', 'b', 'c']);
7 |
assertRegexp()
8 |
Does $value match the given $regex?
9 |
$this->assertRegexp('/^Fo+/', 'Foo Bar');
10 |
11 | 12 | Note: 13 | 14 | * Older versions of PHPUnit will use assertContains() for checking both strings and iterables, but the latest uses assertStringContainsString() for substring checking 15 | -------------------------------------------------------------------------------- /slides/assertequals.md: -------------------------------------------------------------------------------- 1 | ### Equality 2 | 3 |
4 |
assertEquals()
5 |
$expected == $actual?
6 |
$this->assertEquals($expected, $actual);
7 |
assertSame()
8 |
$expected === $actual?
9 |
$this->assertSame($expected, $actual);
10 |
11 | 12 | Note: 13 | 14 | * Subtle difference, but assertSame() does strict comparisons 15 | - If comparing two objects, assertSame wants them to reference the same object 16 | -------------------------------------------------------------------------------- /slides/assertions.md: -------------------------------------------------------------------------------- 1 | ### Assertions 2 | 3 | Do things work the way we expect? 4 | 5 | Note: 6 | 7 | * Each test method will contain at least one assertion 8 | * PHPUnit comes with a ton of default assertions 9 | - Easily extended by frameworks or applications 10 | * A look at some of the most common assertions... 11 | -------------------------------------------------------------------------------- /slides/asserttrue.md: -------------------------------------------------------------------------------- 1 | ### True or False? 2 | 3 |
4 |
assertTrue()
5 |
$value === true?
6 |
$this->assertTrue(true);
7 |
assertFalse()
8 |
$value === false?
9 |
$this->assertFalse(false);
10 |
11 | 12 | Note: 13 | 14 | As you'll see, everything boils down to a simple assertion of true or false 15 | -------------------------------------------------------------------------------- /slides/authentication.md: -------------------------------------------------------------------------------- 1 | ### Impersonating users 2 | 3 | Act as users with different roles & capabilities: 4 | 5 | ```php 6 | public function test_authors_cant_blow_stuff_up() { 7 | $user_id = $this->factory->user->create( [ 8 | 'role' => 'author', 9 | ] ); 10 | 11 | wp_set_current_user( $user_id ); 12 | 13 | $this->assertFalse( current_user_can( 'blow_stuff_up' ) ); 14 | } 15 | ``` 16 | 17 | Note: 18 | 19 | If you need to do any sort of permission checks, you'll likely find yourself doing this: create a new user, then use wp_set_current_user() to tell WordPress you're acting as the given user ID. 20 | -------------------------------------------------------------------------------- /slides/automated-testing.md: -------------------------------------------------------------------------------- 1 | ### Automated testing 2 | 3 | * Reduces time + chance of human error 4 | * Easily reproducible 5 | * Gateway to CI/CD 6 | 7 | Note: 8 | 9 | * Necessary to understand the role of automated testing in software development 10 | * Able to codify exact testing procedure 11 | - Reduces the chance someone forgets a step 12 | - Everyone's running the same tests, easily reproducible 13 | * Vital in utilizing CI/CD 14 | - Build and deploy with confidence! 15 | -------------------------------------------------------------------------------- /slides/bootstrap.md: -------------------------------------------------------------------------------- 1 | ### Bootstrap File 2 | 3 |
// 1. Locate the WordPress installation
 4 | $_tests_dir = getenv( 'WP_TESTS_DIR' );
 5 | if ( ! $_tests_dir ) {
 6 |     $_tests_dir = '/tmp/wordpress-tests-lib';
 7 | }
 8 | // 2. Gain access to the tests_add_filter() function.
 9 | require_once $_tests_dir . '/includes/functions.php';
10 | // 3. Load the main plugin file.
11 | tests_add_filter( 'muplugins_loaded', function () {
12 |     require dirname( dirname( __FILE__ ) ) . '/my-plugin.php';
13 | } );
14 | // 4. Bootstrap WordPress core.
15 | require $_tests_dir . '/includes/bootstrap.php';
16 | 17 | Note: 18 | 19 | Basic outline of the bootstrap file, adjust for your needs: 20 | 21 | 1. Locate the test directory, which would be installed by the install-wp-tests shell script 22 | 2. Load in a file from the test environment so we have access to the tests_add_filter() function 23 | 3. Register a callback that explicitly loads your main plugin file 24 | 4. Load the core test suite's bootstrap file 25 | -------------------------------------------------------------------------------- /slides/data-providers.md: -------------------------------------------------------------------------------- 1 | ### Data providers 2 | 3 |
/**
 4 |  * @dataProvider my_data_provider()
 5 |  */
 6 | public function test_my_function( $expected, $value ) {
 7 |     $this->assertEquals( $expected, my_function( $value ) );
 8 | }
 9 | 
10 | public function my_data_provider() {
11 |     return [
12 |         'Description of case 1' => ['foo', 'bar'],
13 |         'Description of case 2' => ['bar', 'baz'],
14 |     ];
15 | }/**
16 |  * @testWith ["foo", "bar"]
17 |  *           ["bar", "baz"]
18 |  */
19 | public function test_my_function( $expected, $value ) {
20 |     $this->assertEquals( $expected, my_function( $value ) );
21 | }
22 | 23 | Note: 24 | 25 | * Lets you pass multiple variants to the same test method 26 | * @dataProvider tag lets you reference another method, which should return an array of scenarios 27 | * Can also use @testWith and pass them directly in the DocBlock 28 | - Cannot call functions or use constants 29 | -------------------------------------------------------------------------------- /slides/example-output.md: -------------------------------------------------------------------------------- 1 |
PHPUnit 7.5.1 by Sebastian Bergmann and contributors.
 2 | 
 3 | ...............................................  47 / 511 (  9%)
 4 | ...............................................  94 / 511 ( 18%)
 5 | ...................................SSSS........ 141 / 511 ( 27%)
 6 | ............................................... 188 / 511 ( 36%)
 7 | ............................................... 235 / 511 ( 45%)
 8 | ............................................... 282 / 511 ( 55%)
 9 | ............................................... 329 / 511 ( 64%)
10 | ............................................... 376 / 511 ( 73%)
11 | ............................................... 423 / 511 ( 82%)
12 | ............................................... 470 / 511 ( 91%)
13 | .........................................       511 / 511 (100%)
14 | 
15 | Time: 1.13 minutes, Memory: 42.00MB
16 | 
17 | OK, but incomplete, skipped, or risky tests!
18 | Tests: 511, Assertions: 1085, Skipped: 4.PHPUnit 7.5.1 by Sebastian Bergmann and contributors.
19 | 
20 | .......F........                                 16/16 (100%)
21 | 
22 | Time: 7.15 seconds, Memory: 14.00MB
23 | 
24 | There was 1 failure:
25 | 
26 | 1) Tests\CoffeeTest::test_get_good_coffee
27 | Failed asserting that two strings are identical.
28 | --- Expected
29 | +++ Actual
30 | @@ @@
31 | -'great, well-balanced coffee'
32 | +'Starbucks'
33 | 
34 | /my-plugin/tests/test-coffee.php:14
35 | 
36 | FAILURES!
37 | Tests: 16, Assertions: 19, Failures: 1.
38 | 39 | Note: 40 | 41 | * When we chain all of our tests together, we get something that looks like this 42 | * Example output from actual app 43 | - Four skipped tests, but everything passes 44 | * Failures will show up in red, telling us what assertion(s) failed 45 | -------------------------------------------------------------------------------- /slides/factories.md: -------------------------------------------------------------------------------- 1 | ### Factories 2 | 3 | Generate users, posts, and more for testing. 4 | 5 |
// Create the post and retrieve its ID.
 6 | $post_id = $this->factory->post->create();
 7 | 
 8 | // Create and retrieve the new post.
 9 | $post = $this->factory->post->create_and_get();
10 | // Override default parameters.
11 | $post = $this->factory->post->create_and_get( [
12 |     'post_title'  => 'My Test Post',
13 |     'post_author' => $author_id,
14 | ] );
15 | // Create multiple instances.
16 | $posts = $this->factory->post->create_many( 5, [
17 |     'post_author' => $author_id,
18 | ] );
19 | 20 | Note: 21 | 22 | Factories, which are included in the core test suite, let us easily generate test data (posts, users, comments, terms, attachments, and more). 23 | 24 | The create method will return the object_id, while create_and_get() will return the generated object. 25 | 26 | We can also override default arguments by passing an array. 27 | 28 | Need to create an author with five posts? It's two lines. 29 | -------------------------------------------------------------------------------- /slides/fixtures.md: -------------------------------------------------------------------------------- 1 | ### Fixtures 2 | 3 |
public function setUp() {
 4 |     parent::setUp();
 5 | 
 6 |     // Set 'em up...
 7 | }
 8 | 
 9 | public function tearDown() {
10 |     parent::tearDown();
11 | 
12 |     // ...and knock 'em down.
13 | }public static function setUpBeforeClass() {
14 |     parent::setUpBeforeClass();
15 | 
16 |     // Set 'em up (once)...
17 | }
18 | 
19 | public static function tearDownAfterClass() {
20 |     parent::tearDownAfterClass();
21 | 
22 |     // ...and knock 'em down (once).
23 | }
24 | 25 | Note: 26 | 27 | * Enables common setup and tear-down actions to be run automatically before and after each test method 28 | - Really useful for integration tests 29 | - Can also use setUpBeforeClass() for things that only should be run once per test case 30 | * Likewise, can be used for tearing things down 31 | - Also can use tearDownAfterClass() 32 | -------------------------------------------------------------------------------- /slides/go_to.md: -------------------------------------------------------------------------------- 1 | ### go_to() 2 | 3 | Change the current page context: 4 | 5 | ```php 6 | public function test_go_to_usage() { 7 | $this->assertFalse( is_home() ); 8 | 9 | $this->go_to( '/blog' ); 10 | 11 | $this->assertTrue( is_home() ); 12 | } 13 | ``` 14 | 15 | Note: 16 | 17 | Lets you change the current page context, but does not actually load a page. Works by resetting the current page query. 18 | 19 | Sets super globals, globals, query variables, main query as if the given page was requested. 20 | -------------------------------------------------------------------------------- /slides/groups.md: -------------------------------------------------------------------------------- 1 | ### @group 2 | 3 | Used to run tests of a similar nature, across suites & classes: 4 | 5 | ```php 6 | /** 7 | * @group Posts 8 | * @group PostMeta 9 | */ 10 | public function test_includes_private_posts() 11 | { 12 | // ... 13 | } 14 | ``` 15 | 16 | ```sh 17 | $ phpunit --group=Posts 18 | ``` 19 | 20 | 21 | Note: 22 | 23 | * The @group tag lets us group tests — no matter where they live — together 24 | - Really useful when different areas of the app need tested together 25 | - Completely user-defined, and test methods can belong to multiple groups 26 | -------------------------------------------------------------------------------- /slides/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Confidently Testing WordPress 3 | 4 | Steve Grunwell
5 | [@stevegrunwell](https://twitter.com/stevegrunwell) 6 | 7 | [stevegrunwell.com/slides/testing-wordpress](https://stevegrunwell.com/testing-wordpress) 8 | -------------------------------------------------------------------------------- /slides/list.json: -------------------------------------------------------------------------------- 1 | [ 2 | "index.md", 3 | [ 4 | "testing-fundamentals.md", 5 | "automated-testing.md", 6 | "types-of-tests.md", 7 | "testing-pyramid.md", 8 | "system-under-test.md", 9 | "messy-wordpress.md", 10 | "messy-wordpress2.md" 11 | ], 12 | [ 13 | "testing-toolbox.md", 14 | "phpunit.md", 15 | "test-structure.md", 16 | "assertions.md", 17 | "asserttrue.md", 18 | "assertequals.md", 19 | "assertcontains.md", 20 | "negative-assertions.md", 21 | "the-search-for-truth.md", 22 | "example-output.md", 23 | "test-doubles.md", 24 | "mockery.md", 25 | "phpunit-markup-assertions.md" 26 | ], 27 | [ 28 | "wordpress-testing.md", 29 | "scaffold-with-wpcli.md", 30 | "scaffold-files.md", 31 | "scaffold-files2.md", 32 | "bootstrap.md", 33 | "wordpress-test-class.md", 34 | "fixtures.md", 35 | "groups.md", 36 | "data-providers.md", 37 | "factories.md", 38 | "authentication.md", 39 | "go_to.md", 40 | "assert-wperror.md" 41 | ], 42 | [ 43 | "writing-our-first-test.md", 44 | "aaa.md", 45 | "testing-permissions.md", 46 | "registering-post-type.md", 47 | "testing-hooks.md", 48 | "testing-hooks2.md", 49 | "testing-output.md", 50 | "testing-http-requests.md" 51 | ], 52 | [ 53 | "tdd.md", 54 | "tdd2.md", 55 | "regression-tests.md", 56 | "regression-tests2.md", 57 | "regression-tests3.md" 58 | ], 59 | "thank-you.md" 60 | ] 61 | -------------------------------------------------------------------------------- /slides/messy-wordpress.md: -------------------------------------------------------------------------------- 1 | ### Not so fast! 2 | 3 | ![A Wapuu struggling to move WordPress](resources/wapuu-struggle.png) 4 | 5 | Note: 6 | 7 | Well, along comes WordPress to make things more difficult. 8 | -------------------------------------------------------------------------------- /slides/messy-wordpress2.md: -------------------------------------------------------------------------------- 1 | ### It's…complicated 2 | 3 | * Tightly-coupled system 4 | * Difficult to test anything in true isolation 5 | 6 | Note: 7 | 8 | * WordPress is a very tightly-coupled system 9 | * parts strongly rely on one another 10 | * global variables holding state 11 | * Built like a teenaged application because it *is* one 12 | * Still workable, but requires a bit of creative thinking 13 | -------------------------------------------------------------------------------- /slides/mockery.md: -------------------------------------------------------------------------------- 1 | ### [Mockery](http://docs.mockery.io/) 2 | 3 | Popular library for creating test doubles: 4 | 5 | ```php 6 | public function test_handles_empty_order_list() { 7 | $api = Mockery::mock( Api::class )->makePartial(); 8 | $api->shouldReceive( 'get_all_orders' ) 9 | ->once() 10 | ->andReturn( [] ); 11 | 12 | $this->assertEmpty( $api->get_recent_orders() ); 13 | } 14 | ``` 15 | 16 | 17 | Note: 18 | 19 | * While PHPUnit allows for some test doubles, Mockery is a popular alternative 20 | - Expressive interface for defining test doubles, their expectations, and responses 21 | * API object should receive get_all_orders() exactly once and return an empty array 22 | - Will fail the test if get_all_orders() isn't called exactly once 23 | -------------------------------------------------------------------------------- /slides/negative-assertions.md: -------------------------------------------------------------------------------- 1 | ### Negative Assertions 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
assertEquals()assertNotEquals()
assertContains()assertNotContains()
assertArrayHasKey()assertArrayNotHasKey()
assertCount()assertNotCount()
21 | 22 | …etc. 23 | 24 | Note: 25 | 26 | * (Most) every assertion has an equal and opposite assertion 27 | - Typically in the form of assertThing(), assertNotThing() 28 | -------------------------------------------------------------------------------- /slides/phpunit-markup-assertions.md: -------------------------------------------------------------------------------- 1 | ### [PHPUnit Markup Assertions](https://github.com/stevegrunwell/phpunit-markup-assertions) 2 | 3 | Assertions powered by DOMDocument: 4 | 5 | ```php 6 | function test_button_contains_active_state() { 7 | $output = some_function(); 8 | 9 | $this->assertContainsSelector('.button.active', $output); 10 | } 11 | ``` 12 | 13 | Note: 14 | 15 | A bit of self-promotion, but sometimes you need to test that a certain ID is present or a specific element contains text. 16 | 17 | This PHPUnit Markup Assertions library has a set of assertions that wrap around PHP's DOMDocument. 18 | -------------------------------------------------------------------------------- /slides/phpunit.md: -------------------------------------------------------------------------------- 1 | ### PHPUnit 2 | 3 | [phpunit.de](https://phpunit.de/) 4 | 5 | Note: 6 | 7 | * Most popular framework/runner for testing PHP 8 | * Basis for WordPress core test suite 9 | -------------------------------------------------------------------------------- /slides/registering-post-type.md: -------------------------------------------------------------------------------- 1 | ### Registering a custom post type 2 | 3 | ```php 4 | public function test_book_cpt_is_registered() { 5 | myplugin_register_post_types(); 6 | 7 | $post_type = get_post_type_object( 'book' ); 8 | 9 | // Verify the post type is registered along with key properties. 10 | $this->assertNotNull( $post_type ); 11 | $this->assertTrue( $post_type->public ); 12 | $this->assertFalse( $post_type->hierarchical ); 13 | } 14 | ``` 15 | 16 | Note: 17 | 18 | A common test might be ensuring that a custom post type is being registered. 19 | 20 | Isn't much of an arrange step, but we're going to call our function (ACT), then inspect the registered post type. We don't need to check everything, but make sure the important properties are set as we expect. 21 | -------------------------------------------------------------------------------- /slides/regression-tests.md: -------------------------------------------------------------------------------- 1 | ### Regression tests 2 | 3 | ```php 4 | function recent_posts_heading( array $posts ) { 5 | if ( empty( $posts ) ) { 6 | _e( 'There have been no posts in the last 30 days.' ); 7 | } else { 8 | printf( 9 | __( '%d posts in the last 30 days.' ), 10 | count( $posts ) 11 | ); 12 | } 13 | } 14 | ``` 15 | 16 |
0:  There have been no posts in the last 30 days.
17 | 1: 𝗫 1 posts in the last 30 days.
18 | 2:  2 posts in the last 30 days.
19 | 20 | 21 | Note: 22 | 23 | * TDD lends itself really well to regression tests, which is a way of making sure bugs get fixed and don't come back. 24 | * Imagine we have this function, which renders a heading above a list of recent posts. 25 | - It looks like we might expect for 0 or 2 or more items 26 | - If $posts only has one post, we get the awkward and grammatically-incorrect "1 posts in the last 30 days." 27 | -------------------------------------------------------------------------------- /slides/regression-tests2.md: -------------------------------------------------------------------------------- 1 | ### Regression tests 2 | 3 | ```php 4 | /** 5 | * @test 6 | * @testWith [0, "There have been no posts in the last 30 days."] 7 | * [1, "One post in the last 30 days."] 8 | * [2, "2 posts in the last 30 days."] 9 | */ 10 | public function recent_posts_heading_plurals( $number, $expected ) { 11 | $posts = $this->factory->post->create_many( $number ); 12 | 13 | $this->expectOutput( $expected ); 14 | 15 | recent_posts_heading( $posts ); 16 | } 17 | ``` 18 | 19 | Note: 20 | 21 | * First thing, write a test to try to reproduce the issue 22 | * Could write the test thusly: 23 | - @testWith annotation to specify 0, 1, or greater-than 1 24 | - Generate the given number of posts through a helper or factory we might have 25 | - Set expected output, since our function is printing directly 26 | -------------------------------------------------------------------------------- /slides/regression-tests3.md: -------------------------------------------------------------------------------- 1 | ### Regression tests 2 | 3 |
function recent_posts_heading( array $posts ) {
 4 |     if ( empty( $posts ) ) {
 5 |         _e( 'There have been no posts in the last 30 days.' );
 6 |     } else {
 7 |         printf(
 8 |             __( '%d posts in the last 30 days.' ),
 9 |             count( $posts )
10 |         );
11 |     }
12 | }function recent_posts_heading( array $posts ) {
13 |     if ( empty( $posts ) ) {
14 |         _e( 'There have been no posts in the last 30 days.' );
15 |     } elseif ( 1 === count( $posts ) ) {
16 |         _e( 'One post in the last 30 days.' );
17 |     } else {
18 |         printf(
19 |             __( '%d posts in the last 30 days.' ),
20 |             count( $posts )
21 |         );
22 |     }
23 | }
24 | 25 |
0:  There have been no posts in the last 30 days.
26 | 1: 𝗫 One post in the last 30 days.
27 | 2:  2 posts in the last 30 days.0:  There have been no posts in the last 30 days.
28 | 1:  One post in the last 30 days.
29 | 2:  2 posts in the last 30 days.
30 | 31 | Note: 32 | 33 | * When we run our test, we start in a red state 34 | * Our tests help push us towards another conditional, which makes our new test pass (green) 35 | * If this function changes in the future, our test will break, alerting us to a regression 36 | -------------------------------------------------------------------------------- /slides/scaffold-files.md: -------------------------------------------------------------------------------- 1 | ### What do we get? 2 | 3 | * `phpunit.xml.dist` 4 | * `.phpcs.xml.dist` 5 | * `.travis.yml` 6 | * `bin/install-wp-tests.sh` 7 | * `tests/bootstrap.php` 8 | * `tests/test-sample.php` 9 | 10 | Note: 11 | 12 | * phpunit.xml.dist is our PHPUnit configuration 13 | * PHP_CodeSniffer configuration, ready for WordPress coding standards 14 | * .travis.yml is the Travis CI config. WP-CLI can also generate files for other popular CI providers 15 | * install-wp-tests.sh will create a local instance of WordPress to test with 16 | * Tools like VVV will already ship with a test environment 17 | * bootstrap.php loads the WordPress tests into the test runner (more in a sec) 18 | * test-sample.php is an example test 19 | -------------------------------------------------------------------------------- /slides/scaffold-files2.md: -------------------------------------------------------------------------------- 1 | ### What don't we get? 2 | 3 | ```sh 4 | $ composer init 5 | ``` 6 | 7 | ```json 8 | { 9 | "name": "stevegrunwell/test-plugin", 10 | "description": "An example WordPress plugin WITH TESTS!", 11 | "type": "wordpress-plugin", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Steve Grunwell", 16 | "homepage": "https://stevegrunwell.com" 17 | } 18 | ], 19 | "require-dev": { 20 | "phpunit/phpunit": "^7.0" 21 | } 22 | } 23 | ``` 24 | 25 | 26 | Note: 27 | 28 | * It's worth noting that WP-CLI will not generate a composer.json file for us 29 | * Some people like to rely on global PHPUnit installations, but this ensures that all developers and environments use the same version of PHPUnit 30 | * Also worth noting that the core test suite does not yet support PHPUnit 8. 31 | -------------------------------------------------------------------------------- /slides/scaffold-with-wpcli.md: -------------------------------------------------------------------------------- 1 | ### Scaffolding our Test Suite 2 | 3 | Generate test scaffolding via WP-CLI: 4 | 5 | ```sh 6 | $ wp scaffold plugin-tests my-plugin 7 | ``` 8 | 9 | Note: 10 | 11 | Easiest way to add tests is via WP-CLI's "scaffold" command 12 | 13 | Able to generate appropriate files for plugins and themes. Can also automatically include tests if scaffolding a new theme/plugin. 14 | -------------------------------------------------------------------------------- /slides/system-under-test.md: -------------------------------------------------------------------------------- 1 | ### System Under Test (SUT) 2 | 3 | * The system we're currently testing: 4 | - A single method 5 | - A class 6 | - A whole feature 7 | 8 | Note: 9 | 10 | An important term to understand is "System Under Test", which refers to the part of the application we're testing. 11 | 12 | Since we want to isolate the SUT from the rest of the app, knowing _what_ we're testing helps us know how best to test it. 13 | -------------------------------------------------------------------------------- /slides/tdd.md: -------------------------------------------------------------------------------- 1 | ## Basic Test-Driven Development 2 | 3 | Note: 4 | 5 | You may have heard the term "TDD" before, but if you're just learning how to test it might seem like a foreign concept: 6 | -------------------------------------------------------------------------------- /slides/tdd2.md: -------------------------------------------------------------------------------- 1 | ### Basic Workflow 2 | 3 | 1. Write a (failing) test to describe the functionality/behavior 𝗫 4 | 2. Write the code necessary to make the test pass 5 | 3. Refactor, rinse, & repeat 6 | 7 | Note: 8 | 9 | * First, write a test to describe what you're trying to do 10 | - This test should be failing, because you haven't yet written the code to make it work 11 | * Now, write the code necessary to make the test pass. 12 | * Once it's passing the tests, refactor to arrive at the best possible solution. 13 | * Often referred to as "red - green - refactor" 14 | -------------------------------------------------------------------------------- /slides/test-class.md: -------------------------------------------------------------------------------- 1 | ### Test Classes 2 | 3 |
class MyAppTest extends PHPUnit\Framework\TestCase
 4 | {
 5 |     // Include test methods.
 6 | }class MyTestClass extends PHPUnit\Framework\TestCase {
 7 |     // Common functionality.
 8 | }
 9 | 
10 | class MyAppTest extends MyTestClass
11 | {
12 |     // Include test methods.
13 | }
14 | 15 | Note: 16 | 17 | * A test class typically extends the PHPUnit\Framework\TestCase class 18 | * If you have functionality common between classes, consider creating your own base test class 19 | - Could also be moved into PHP traits 20 | -------------------------------------------------------------------------------- /slides/test-doubles.md: -------------------------------------------------------------------------------- 1 | ### Test Doubles 2 | 3 | Replacing actual systems with test versions. 4 | 5 | * Always return known values 6 | * Ensure systems behave a certain way 7 | * etc. 8 | 9 | Note: 10 | 11 | Another talk in itself, but test doubles let us focus on our system under test and replace anything else with something we can easily control. 12 | 13 | You might stub an API to make sure it always gives the type of response you're looking for, for instance. You're not testing the API, you're testing how your system handles different API responses. 14 | -------------------------------------------------------------------------------- /slides/test-method.md: -------------------------------------------------------------------------------- 1 | ### Test method 2 | 3 |
public function test_it_does_something()
 4 | {
 5 |     // Arrange, act, then assert.
 6 | }/**
 7 |  * @test
 8 |  */
 9 | public function it_should_do_something()
10 | {
11 |     // Arrange, act, then assert.
12 | }
13 | 14 | Note: 15 | 16 | * Test methods are public methods declared within the test class 17 | * By convention, methods begin with "test" 18 | - Some people prefer to write more descriptive test names 19 | - Can use @test DocBlock tag instead 20 | -------------------------------------------------------------------------------- /slides/test-structure.md: -------------------------------------------------------------------------------- 1 | ### Structure 2 | 3 |
4 |
Test Suite
5 |
Collection of test classes
6 |
Test Class (class)
7 |
Collection of test cases
8 |
Test Case (method)
9 |
A single scenario to be tested
10 |
11 | 12 | Note: 13 | 14 | * A test suite is a collection of test classes 15 | - e.g. Unit, integration, feature, etc. 16 | * Test class (class containing methods) 17 | - Usually centered around a feature or model 18 | * Test case (methods in the test class) 19 | - One or more assertions 20 | - Think of it as an individual scenario 21 | -------------------------------------------------------------------------------- /slides/testing-assets.md: -------------------------------------------------------------------------------- 1 | ### Testing assets 2 | 3 | ```php 4 | public function test_styles_get_enqueued() { 5 | $this->assertFalse( wp_style_is( 'my-plugin-styles', 'enqueued' ) ); 6 | 7 | do_action( 'enqueue_scripts' ); 8 | 9 | $this->assertTrue( wp_style_is( 'my-plugin-styles', 'enqueued' ) ); 10 | } 11 | ``` 12 | 13 | Note: 14 | 15 | The wp_script_is() and wp_style_is() functions are great for verifying the registration or enqueueing of scripts and styles, respectively. 16 | -------------------------------------------------------------------------------- /slides/testing-fundamentals.md: -------------------------------------------------------------------------------- 1 | ## Testing Fundamentals 2 | -------------------------------------------------------------------------------- /slides/testing-hooks.md: -------------------------------------------------------------------------------- 1 | ### Testing hooks 2 | 3 | ```php 4 | public function test_function_does_action() { 5 | myplugin_function(); 6 | 7 | $this->assertSame( 1, did_action( 'myplugin_action' ) ); 8 | } 9 | ``` 10 | 11 | Note: 12 | 13 | If we want to make sure that a custom action was called, we can use did_action() to see how many times it was called. 14 | 15 | In this case, did myplugin_function() call do_action() on the myplugin_action hook? 16 | -------------------------------------------------------------------------------- /slides/testing-hooks2.md: -------------------------------------------------------------------------------- 1 | ### Testing hooks 2 | 3 | ```php 4 | public function test_function_does_action() { 5 | $called = false; 6 | 7 | // Register a callback to validate arguments. 8 | add_action( 'myplugin_action', function () use (&$called) { 9 | 10 | // Only return true if validations passed. 11 | $called = true; 12 | } ); 13 | 14 | myplugin_function(); 15 | 16 | $this->assertTrue( $called ); 17 | } 18 | ``` 19 | 20 | Note: 21 | 22 | If you need to validate the arguments passed to the hook, you might register a callback on the hook being tested, letting you do anything you might need to do. 23 | 24 | Notice that the $called variable is being passed by reference! 25 | -------------------------------------------------------------------------------- /slides/testing-http-requests.md: -------------------------------------------------------------------------------- 1 | ### Stubbing HTTP Requests 2 | 3 | ```php 4 | add_filter( 'pre_http_request', function () { 5 | return [ 6 | 'headers' => [], 7 | 'body' => '', 8 | 'response' => [ 9 | 'code' => 200, 10 | 'message' => 'OK', 11 | ], 12 | 'cookies' => [], 13 | 'filename' => '', 14 | ]; 15 | } ); 16 | ``` 17 | 18 | Note: 19 | 20 | The pre_http_request filter will let us short-circuit responses from the WordPress HTTP API, we just need to return an array that matches the format of a WordPress HTTP response. 21 | 22 | By stubbing responses from external APIs, our tests won't have to rely on these external APIs. Remember the System Under Test: we're not testing the API, we're testing how we interact with it. 23 | -------------------------------------------------------------------------------- /slides/testing-output.md: -------------------------------------------------------------------------------- 1 | ### Testing Output 2 | 3 |
public function test_shortcode_output() {
 4 |     ob_start();
 5 |     do_shortcode( '[recent-posts title="Latest Posts"]' );
 6 |     $output = ob_get_clean();
 7 | 
 8 |     $this->assertContains( '<h2>Latest Posts</h2>', $output );
 9 | }public function test_shortcode_output() {
10 |     $this->expectOutput( '<h2>Latest Posts</h2>' );
11 | 
12 |     do_shortcode( '[recent-posts title="Latest Posts"]' );
13 | }
14 | 15 | Note: 16 | 17 | Since a lot of template tags will echo content directly to the screen, it's important to be able to test output. 18 | 19 | I prefer to use output buffering to capture the output in a string, then do checks on it. 20 | 21 | If you know exactly what the output will look like, you can also use $this->expectOutput(). 22 | -------------------------------------------------------------------------------- /slides/testing-permissions.md: -------------------------------------------------------------------------------- 1 | ### Testing permissions 2 | 3 | ```php 4 | public function test_non_admins_cannot_clear_cache() { 5 | // Arrange 6 | $user_id = $this->factory->user->create( [ 7 | 'role' => 'author', 8 | ] ); 9 | 10 | wp_set_current_user( $user_id ); 11 | 12 | // Act 13 | $response = myplugin_clear_cache(); 14 | 15 | // Assert 16 | $this->assertWPError($response); 17 | $this->assertSame(403, $response->get_error_code()); 18 | } 19 | ``` 20 | 21 | Note: 22 | 23 | Imagine we have a function that clears the site cache, but the function should check the user's capabilities before doing anything. If the user doesn't have permission, we should get back a WP_Error object. 24 | 25 | We'll start by arranging our test — creating a non-admin user and authenticating as them. Next, we'll call the myplugin_clear_cache() function (Act), then make assertions against the response. Is it a WP_Error, and are we getting the error code we expect? 26 | -------------------------------------------------------------------------------- /slides/testing-pyramid.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | Note: 4 | 5 | * Known as the Automation Pyramid 6 | * Base is unit tests — these are cheap to write, quick to run, and should make up the majority of the testing code 7 | * Middle is integration - more involved to write and slower to run, but still important 8 | * Top is E2E - typically much slower to run and not always necessary 9 | -------------------------------------------------------------------------------- /slides/testing-toolbox.md: -------------------------------------------------------------------------------- 1 | ## Our Testing Toolbox 2 | -------------------------------------------------------------------------------- /slides/thank-you.md: -------------------------------------------------------------------------------- 1 | ## Thank you! 2 | 3 | 4 | Steve Grunwell
5 | Senior Software Engineer, Liquid Web 6 | 7 | [stevegrunwell.com/slides/testing-wordpress](https://stevegrunwell.com/slides/testing-wordpress) 8 | -------------------------------------------------------------------------------- /slides/the-search-for-truth.md: -------------------------------------------------------------------------------- 1 | ### The search for truth 2 | 3 | ```php 4 | // $this->assertEquals($expected, $actual); 5 | $this->assertTrue($expected == $actual); 6 | ``` 7 | 8 | 9 | ```php 10 | // $this->assertNotContains($expected, $actual); 11 | $this->assertFalse(in_array($expected, $actual)); 12 | ``` 13 | 14 | 15 | ```php 16 | // $this->assertRegexp($regex, $actual); 17 | $this->assertTrue((bool) preg_match($expected, $actual)); 18 | ``` 19 | 20 | 21 | Note: 22 | 23 | When we look at how these assertions work, we see that everything comes down to TRUE or FALSE 24 | -------------------------------------------------------------------------------- /slides/types-of-tests.md: -------------------------------------------------------------------------------- 1 | ### Test types 2 | 3 |
4 |
Unit
5 |
Test the smallest possible unit of an app
6 |
Often a single function
7 |
Integration
8 |
How individual components interact
9 |
End-to-end (E2E)
10 |
An entire path through an application
11 |
12 | 13 | Note: 14 | 15 | * Unit tests are often limited to a single function 16 | - Should not have dependencies on any other functionality 17 | - Does this function do what we expect? 18 | * Integration testing, often called "feature" testing 19 | - Tests how the individual units come together 20 | * End-to-end (or "full-stack" testing) test the full application 21 | - Often includes front-end tests via headless browsers 22 | -------------------------------------------------------------------------------- /slides/wordpress-test-class.md: -------------------------------------------------------------------------------- 1 | ### Base Test Class 2 | 3 |
# Standard PHPUnit
 4 | class MyAppTest extends PHPUnit\Framework\TestCase {
 5 |     // Include test methods.
 6 | }# WP core test suite
 7 | class MyAppTest extends WP_UnitTestCase {
 8 |     // Include test methods for WordPress.
 9 | }
10 | 11 | Note: 12 | 13 | * If we were just using PHPUnit by itself, we'd extend PHPUnit\Framework\TestCase 14 | * For WordPress, extend the core test suite: WP_UnitTestCase 15 | - Handles bootstrapping of WordPress along with resets between tests 16 | -------------------------------------------------------------------------------- /slides/wordpress-testing.md: -------------------------------------------------------------------------------- 1 | ## WP Core Test Suite 2 | 3 | Note: 4 | 5 | Now let's talk about testing within the context of WordPress. 6 | 7 | The core test suite is what WordPress core itself uses, and is arguably the best way to test our themes and plugins as well. 8 | -------------------------------------------------------------------------------- /slides/writing-our-first-test.md: -------------------------------------------------------------------------------- 1 | ## Writing our First Tests 2 | 3 | Note: 4 | 5 | Now that we understand how everything comes together, let's write some common test cases. 6 | -------------------------------------------------------------------------------- /templates/_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Confidently Testing WordPress — Steve Grunwell 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 31 | 34 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 | <% _.forEach(slides, function(slide) { %> 43 | <% if (!_.isArray(slide)) { %> 44 | <%= section(slide) %> 45 | <% } %> 46 | <% if (_.isArray(slide)) { %> 47 |
48 | <% _.forEach(slide, function(verticalslide) { %> 49 | <%= section(verticalslide) %> 50 | <% }); %> 51 |
52 | <% } %> 53 | <% }); %> 54 |
55 | 56 | 59 | 60 |
61 | 62 | 63 | 64 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /templates/_section.html: -------------------------------------------------------------------------------- 1 | <% if (!_.isString(slide) && !_.isArray(slide) && _.isObject(slide)) { %> 2 |
<% if (_.isString(slide.filename)) { %>data-<% if (slide.filename.indexOf('.html') !== -1) { %>html<% } else { %>markdown<% }%>="slides/<%= slide.filename %>"<% } %>>
3 | <% } %><% if (_.isString(slide)) { %> 4 |
html<% } else { %>markdown<% }%>="slides/<%= slide %>">
5 | <% } %> 6 | --------------------------------------------------------------------------------