├── .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 | 
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 | assertEquals()
6 | assertNotEquals()
7 |
8 |
9 | assertContains()
10 | assertNotContains()
11 |
12 |
13 | assertArrayHasKey()
14 | assertArrayNotHasKey()
15 |
16 |
17 | assertCount()
18 | assertNotCount()
19 |
20 |
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 |
--------------------------------------------------------------------------------