govuk_tech_docs 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +90 -0
  4. data/docs/configuration.md +15 -0
  5. data/docs/frontmatter.md +2 -14
  6. data/docs/page-expiry.md +69 -0
  7. data/example/Gemfile +1 -0
  8. data/example/config/tech-docs.yml +6 -0
  9. data/example/source/api-path.html.md +7 -0
  10. data/example/source/api-reference.html.md +5 -0
  11. data/example/source/pets.yml +106 -0
  12. data/govuk_tech_docs.gemspec +2 -0
  13. data/lib/assets/javascripts/_analytics.js +12 -0
  14. data/lib/assets/javascripts/_modules/collapsible-navigation.js +5 -3
  15. data/lib/assets/javascripts/_modules/search.js +175 -6
  16. data/lib/assets/stylesheets/modules/_collapsible.scss +12 -5
  17. data/lib/assets/stylesheets/modules/_technical-documentation.scss +16 -11
  18. data/lib/assets/stylesheets/modules/_toc.scss +1 -1
  19. data/lib/govuk_tech_docs.rb +13 -2
  20. data/lib/govuk_tech_docs/api_reference/api_reference_extension.rb +100 -0
  21. data/lib/govuk_tech_docs/api_reference/api_reference_renderer.rb +279 -0
  22. data/lib/govuk_tech_docs/api_reference/templates/api_reference_full.html.erb +9 -0
  23. data/lib/govuk_tech_docs/api_reference/templates/operation.html.erb +11 -0
  24. data/lib/govuk_tech_docs/api_reference/templates/parameters.html.erb +28 -0
  25. data/lib/govuk_tech_docs/api_reference/templates/path.html.erb +4 -0
  26. data/lib/govuk_tech_docs/api_reference/templates/responses.html.erb +33 -0
  27. data/lib/govuk_tech_docs/api_reference/templates/schema.html.erb +29 -0
  28. data/lib/govuk_tech_docs/page_review.rb +15 -3
  29. data/lib/govuk_tech_docs/pages.rb +3 -2
  30. data/lib/govuk_tech_docs/tech_docs_html_renderer.rb +10 -0
  31. data/lib/govuk_tech_docs/version.rb +1 -1
  32. data/lib/source/layouts/_header.erb +2 -4
  33. metadata +42 -4
  34. data/lib/source/images/arrow-down.svg +0 -9
  35. data/lib/source/images/arrow-up.svg +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0b627893fa39ba6cc6484a977b7b9c00639ad28
4
- data.tar.gz: a45ebcff76937b949bb5c7388359bbd26cbe1d53
3
+ metadata.gz: 7e106d8464ee73119270e939801832a1e49118a7
4
+ data.tar.gz: 334c5c672945bd52df62772578ccb862356cafd1
5
5
  SHA512:
6
- metadata.gz: fe4b821226d40bff2fd3d2eff34887862e74eda39c00ef058f512b448f995d1d0181aff90e3448c5493108dbae2eb76d5ee34746a5c7077adb4fede3107c3553
7
- data.tar.gz: b9e34c88cfc72c46f4cab5e73bd3946e4475e6a1a3a42f2140ef8fb024f48f57ef6f8e57a8f1dc5b47aef41a9ccf7f07bb7ce080d6cb7f81a806da52d5ee8881
6
+ metadata.gz: b507269b3da54e98e28db73fb89a0d4f2f2e1032f0829f2c3a7acc2401eb4f24b37e6776c16b6fdd0bfe49693a3df270ca8a68fcc162a78bbc380f5ec68d68f1
7
+ data.tar.gz: d825189334f2ea5612ca72836d2259a7d983c0b20ea5a559f7c1c9e61d47647700964ab20dca97d2f66bd3e2cf187681725becab2cb089e2343a7dfa49b89cf0
@@ -6,3 +6,6 @@ Naming/HeredocDelimiterNaming:
6
6
 
7
7
  Lint/NestedMethodDefinition:
8
8
  Enabled: false
9
+
10
+ Performance/HashEachMethods:
11
+ Enabled: false
@@ -1,5 +1,95 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 1.6.0
6
+
7
+ Version 1.6.0 adds API reference generation, and improves the search function.
8
+
9
+ ### New feature: API reference
10
+
11
+ Specify an OpenAPI spec file using `api_path`, for example: `api_path: source/pets.yml`.
12
+
13
+ To output the generated content in the page of your choice, write `api>` in any markdown parsed file (.md, .html.md, .html.md.erb). You can also specify to just print a specific path: `api> /pets`
14
+
15
+ This generates request and response schemas and examples for each API operation.
16
+
17
+ More info:
18
+
19
+ - https://github.com/alphagov/tech-docs-gem/pull/40
20
+ - https://github.com/alphagov/tech-docs-gem/pull/48
21
+
22
+ ### Search result improvements
23
+
24
+ The search indexing pipeline has been tweaked to provide expected results. The display of the search results has also been
25
+
26
+ If you're using search then you'll need to add this line to your project `Gemfile`:
27
+
28
+ ```
29
+ gem 'middleman-search', git: 'git://github.com/alphagov/middleman-search.git'
30
+ ```
31
+
32
+ More info:
33
+ - https://github.com/alphagov/tech-docs-gem/pull/37
34
+ - https://github.com/alphagov/tech-docs-gem/pull/38
35
+ - https://github.com/alphagov/tech-docs-gem/pull/41
36
+ - https://github.com/alphagov/tech-docs-gem/pull/42
37
+ - https://github.com/alphagov/tech-docs-gem/pull/43
38
+
39
+ ### Correct fork of middleman in example project
40
+
41
+ The example gem project now uses alphagov/middleman-search. This prevents `bundle exec middleman serve` from crashing.
42
+
43
+ More info:
44
+ - https://github.com/alphagov/tech-docs-gem/pull/35
45
+
46
+ ### Accessibility improvements
47
+
48
+ Accessibility improvements to search, collapsible navigation, and the logo.
49
+
50
+ More info:
51
+ - https://github.com/alphagov/tech-docs-gem/pull/36
52
+ - https://github.com/alphagov/tech-docs-gem/pull/33
53
+
54
+ ### Additional configuration options for review system
55
+
56
+ `default_owner_slack` and `owner_slack_workspace` are now configurable for use within the review system.
57
+
58
+ More info:
59
+ - https://github.com/alphagov/tech-docs-gem/pull/47
60
+
61
+ ### Correct fork of middleman in example project
62
+
63
+ The example gem project now uses alphagov/middleman-search. This prevents `bundle exec middleman serve` from crashing.
64
+
65
+ More info:
66
+ - https://github.com/alphagov/tech-docs-gem/pull/35
67
+
68
+ ### Accessibility improvements
69
+
70
+ Accessibility improvements to search, collapsible navigation, and the logo.
71
+
72
+ More info:
73
+ - https://github.com/alphagov/tech-docs-gem/pull/36
74
+ - https://github.com/alphagov/tech-docs-gem/pull/33
75
+
76
+ ### Search result improvements
77
+
78
+ The search indexing pipeline has been tweaked to provide expected results. The display of the search results has also been improved.
79
+
80
+ If you're using search then you'll need to add this line to your project `Gemfile`:
81
+
82
+ ```
83
+ gem 'middleman-search', git: 'git://github.com/alphagov/middleman-search.git'
84
+ ```
85
+
86
+ More info:
87
+ - https://github.com/alphagov/tech-docs-gem/pull/37
88
+ - https://github.com/alphagov/tech-docs-gem/pull/38
89
+ - https://github.com/alphagov/tech-docs-gem/pull/41
90
+ - https://github.com/alphagov/tech-docs-gem/pull/42
91
+ - https://github.com/alphagov/tech-docs-gem/pull/43
92
+
3
93
  ## 1.5.0
4
94
 
5
95
  ### New feature: Search
@@ -148,3 +148,18 @@ default: `true`
148
148
  ```yaml
149
149
  show_govuk_logo: true
150
150
  ```
151
+
152
+ ## `api_path`
153
+
154
+ Define a path to an Open API V3 spec file. This can be a relative file path or a URI to a raw file.
155
+
156
+ ```yaml
157
+ api_path: ./source/pets.yml
158
+ ```
159
+
160
+ ## `owner_slack_workspace` and `default_owner_slack`
161
+
162
+ These attributes are used to specify the owner of a page. See the separate
163
+ [documentation for page expiry][expiry] for more details.
164
+
165
+ [expiry]: https://alphagov.github.io/tech-docs-manual/#page-expiry-and-review-notices
@@ -5,24 +5,12 @@
5
5
  ## `last_reviewed_on` and `review_in`
6
6
 
7
7
  These attributes determine the date when the page needs to be reviewed next.
8
+ See the separate [documentation for page expiry][expiry] for more details.
8
9
 
9
- If the page doesn't need to be reviewed, we show a blue box with the last-reviewed date, when it needs review again, and the owner.
10
-
11
- ![](not-expired-page.png)
12
-
13
- If the page needs to be reviewed, we show a red box saying the page might not be accurate.
14
-
15
- ![](expired-page.png)
10
+ [expiry]: https://alphagov.github.io/tech-docs-manual/#page-expiry-and-review-notices
16
11
 
17
12
  Example:
18
13
 
19
- ```yaml
20
- ---
21
- last_reviewed_on: 2018-01-18
22
- review_in: 6 weeks
23
- ---
24
- ```
25
-
26
14
  You can use this in combination with [owner_slack](#owner-slack) to set an owner for the page.
27
15
 
28
16
  ## `layout`
@@ -0,0 +1,69 @@
1
+ # Page Expiry and Review Notices
2
+
3
+ It's possible to include frontmatter configuration for a page to set an
4
+ expiration date for a piece of content.
5
+
6
+ If the page doesn't need to be reviewed, we show a blue box with the
7
+ last-reviewed date, when it needs review again, and the owner.
8
+
9
+ ![](not-expired-page.png)
10
+
11
+ If the page needs to be reviewed, we show a red box saying the page might not
12
+ be accurate.
13
+
14
+ ![](expired-page.png)
15
+
16
+ This feature relies on JavaScript being enabled on the user's browser to
17
+ display the relevant notices.
18
+
19
+
20
+ ## Frontmatter configuration
21
+
22
+ ### `last_reviewed_on` and `review_in`
23
+
24
+ These attributes determine the date when the page needs to be reviewed next.
25
+
26
+ ```yaml
27
+ ---
28
+ last_reviewed_on: 2018-01-18
29
+ review_in: 6 weeks
30
+ ---
31
+ ```
32
+
33
+ You can use this in combination with `owner_slack` or `default_owner_slack` to
34
+ set an owner for the page.
35
+
36
+ ### `owner_slack`
37
+
38
+ The Slack username or channel of the page owner. This can be used to appoint an
39
+ individual or team as responsible for keeping the page up to date.
40
+
41
+
42
+ ## Global configuration
43
+
44
+ ### `owner_slack_workspace`
45
+
46
+ The Slack workspace name used when linking to the Slack owner of a piece of
47
+ content. If not provided, the owner of a piece of content (channel or user)
48
+ won't be linked.
49
+
50
+ ```yaml
51
+ owner_slack_workspace: gds
52
+ ```
53
+
54
+ ### `default_owner_slack`
55
+
56
+ The default Slack user or channel name to show as the owner of a piece of
57
+ content. Can be overridden using the `owner_slack` frontmatter config option.
58
+
59
+ ```yaml
60
+ default_owner_slack: '#owner'
61
+ ```
62
+
63
+
64
+ ## Page API
65
+
66
+ The expiry date for each page is also shown in the `/api/pages.json`
67
+ representation of all pages. This is used by the
68
+ [tech-docs-notifier](https://github.com/alphagov/tech-docs-notifier) to post
69
+ messages to Slack when pages have expired.
@@ -1,3 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'govuk_tech_docs', path: '..'
4
+ gem 'middleman-search', git: 'git://github.com/alphagov/middleman-search.git'
@@ -41,3 +41,9 @@ github_repo: alphagov/example-repo
41
41
 
42
42
  redirects:
43
43
  /something/old.html: /index.html
44
+
45
+ api_path: source/pets.yml
46
+
47
+ # Optional global settings for the page review process
48
+ owner_slack_workspace: gds
49
+ default_owner_slack: '#2nd-line'
@@ -0,0 +1,7 @@
1
+ ---
2
+ title: API /Pets
3
+ ---
4
+
5
+ # API /Pets
6
+
7
+ api> /pets
@@ -0,0 +1,5 @@
1
+ ---
2
+ title: Example API Petstore
3
+ ---
4
+
5
+ api>
@@ -0,0 +1,106 @@
1
+ openapi: "3.0.0"
2
+ info:
3
+ version: 1.0.0
4
+ title: Swagger Petstore
5
+ description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification
6
+ license:
7
+ name: MIT
8
+ servers:
9
+ - url: http://petstore.swagger.io/v1
10
+ paths:
11
+ /pets:
12
+ get:
13
+ summary: List all pets
14
+ operationId: listPets
15
+ tags:
16
+ - pets
17
+ parameters:
18
+ - name: limit
19
+ in: query
20
+ description: How many items to return at one time (max 100)
21
+ required: false
22
+ schema:
23
+ type: integer
24
+ format: int32
25
+ responses:
26
+ '200':
27
+ description: A paged array of pets
28
+ headers:
29
+ content:
30
+ application/json:
31
+ schema:
32
+ $ref: "#/components/schemas/Pets"
33
+ default:
34
+ description: unexpected error
35
+ content:
36
+ application/json:
37
+ schema:
38
+ $ref: "#/components/schemas/Error"
39
+ post:
40
+ summary: Create a pet
41
+ operationId: createPets
42
+ tags:
43
+ - pets
44
+ responses:
45
+ '201':
46
+ description: Null response
47
+ default:
48
+ description: unexpected error
49
+ content:
50
+ application/json:
51
+ schema:
52
+ $ref: "#/components/schemas/Error"
53
+ /pets/{petId}:
54
+ get:
55
+ summary: Info for a specific pet
56
+ operationId: showPetById
57
+ tags:
58
+ - pets
59
+ parameters:
60
+ - name: petId
61
+ in: path
62
+ required: true
63
+ description: The id of the pet to retrieve
64
+ schema:
65
+ type: string
66
+ responses:
67
+ '200':
68
+ description: Expected response to a valid request
69
+ content:
70
+ application/json:
71
+ schema:
72
+ $ref: "#/components/schemas/Pets"
73
+ default:
74
+ description: unexpected error
75
+ content:
76
+ application/json:
77
+ schema:
78
+ $ref: "#/components/schemas/Error"
79
+ components:
80
+ schemas:
81
+ Pet:
82
+ required:
83
+ - id
84
+ - name
85
+ properties:
86
+ id:
87
+ type: integer
88
+ format: int64
89
+ name:
90
+ type: string
91
+ tag:
92
+ type: string
93
+ Pets:
94
+ type: array
95
+ items:
96
+ $ref: "#/components/schemas/Pet"
97
+ Error:
98
+ required:
99
+ - code
100
+ - message
101
+ properties:
102
+ code:
103
+ type: integer
104
+ format: int32
105
+ message:
106
+ type: string
@@ -32,6 +32,8 @@ Gem::Specification.new do |spec|
32
32
  spec.add_dependency "middleman-search"
33
33
  spec.add_dependency "nokogiri"
34
34
  spec.add_dependency "redcarpet", "~> 3.3.2"
35
+ spec.add_dependency "openapi3_parser"
36
+ spec.add_dependency "pry"
35
37
 
36
38
 
37
39
  spec.add_development_dependency "bundler", "~> 1.15"
@@ -42,5 +42,17 @@
42
42
  $('.header a').on('click', linkTrackingEventHandler('topNavigationClick'));
43
43
  $('.toc a').on('click', linkTrackingEventHandler('tableOfContentsNavigationClick'));
44
44
  catchBrokenFragmentLinks();
45
+
46
+ // Borrowed from:
47
+ // https://github.com/alphagov/govuk_frontend_toolkit/blob/master/javascripts/govuk/analytics/analytics.js
48
+ window.stripPIIFromString = function (string) {
49
+ var EMAIL_PATTERN = /[^\s=/?&]+(?:@|%40)[^\s=/?&]+/g
50
+ var POSTCODE_PATTERN = /[A-PR-UWYZ][A-HJ-Z]?[0-9][0-9A-HJKMNPR-Y]?(?:[\s+]|%20)*[0-9][ABD-HJLNPQ-Z]{2}/gi
51
+ var DATE_PATTERN = /\d{4}(-?)\d{2}(-?)\d{2}/g
52
+ var stripped = string.replace(EMAIL_PATTERN, '[email]')
53
+ .replace(DATE_PATTERN, '[date]')
54
+ .replace(POSTCODE_PATTERN, '[postcode]');
55
+ return stripped
56
+ }
45
57
  });
46
58
  })(jQuery);
@@ -31,15 +31,17 @@
31
31
  var $topLevelItem = $($topLevelItems[i]);
32
32
  var $heading = $topLevelItem.find('> a');
33
33
  var $listing = $topLevelItem.find('> ul');
34
+ var id = 'toc-' + $heading.text().toLowerCase().replace(' ', '-');
34
35
  // Only add collapsible functionality if there are children.
35
36
  if ($listing.length == 0) {
36
37
  continue;
37
38
  }
38
39
  $topLevelItem.addClass('collapsible');
39
40
  $listing.addClass('collapsible__body')
41
+ .attr('id', id)
40
42
  .attr('aria-expanded', 'false');
41
43
  $heading.addClass('collapsible__heading')
42
- .after('<button class="collapsible__toggle"><span class="collapsible__toggle-label">Expand ' + $heading.text() + '</span><span class="collapsible__toggle-icon" aria-hidden="true"></button>')
44
+ .after('<button class="collapsible__toggle" aria-controls="' + id +'"><span class="collapsible__toggle-label">Expand ' + $heading.text() + '</span><span class="collapsible__toggle-icon" aria-hidden="true"></button>')
43
45
  $topLevelItem.on('click', '.collapsible__toggle', function(e) {
44
46
  e.preventDefault();
45
47
  var $parent = $(this).parent();
@@ -51,11 +53,11 @@
51
53
  function toggleHeading($topLevelItem) {
52
54
  var isOpen = $topLevelItem.hasClass('is-open');
53
55
  var $heading = $topLevelItem.find('> a');
54
- var $body = $topLevelItem.find('collapsible__body');
56
+ var $body = $topLevelItem.find('.collapsible__body');
55
57
  var $toggleLabel = $topLevelItem.find('.collapsible__toggle-label');
56
58
 
57
59
  $topLevelItem.toggleClass('is-open', !isOpen);
58
- $body.attr('aria-expanded', isOpen ? 'true' : 'false');
60
+ $body.attr('aria-expanded', isOpen ? 'false' : 'true');
59
61
  $toggleLabel.text(isOpen ? 'Expand ' + $heading.text() : 'Collapse ' + $heading.text());
60
62
  }
61
63
 
@@ -16,7 +16,9 @@
16
16
  var $searchResultsWrapper;
17
17
  var $searchResultsClose;
18
18
  var results;
19
- var maxSearchEntries = 10;
19
+ var query;
20
+ var queryTimer;
21
+ var maxSearchEntries = 20;
20
22
 
21
23
  this.start = function start($element) {
22
24
  $searchForm = $element.find('form');
@@ -40,6 +42,7 @@
40
42
  success: function(data) {
41
43
  s.lunrData = data;
42
44
  s.lunrIndex = lunr.Index.load(s.lunrData.index);
45
+ replaceStopWordFilter();
43
46
  $(document).trigger('lunrIndexLoaded');
44
47
  }
45
48
  });
@@ -49,12 +52,16 @@
49
52
  // Search functionality on search text input
50
53
  $searchInput.on('input', function (e) {
51
54
  e.preventDefault();
52
- var query = $(this).val();
55
+ query = $(this).val();
53
56
  s.search(query, function(r) {
54
57
  results = r;
55
58
  renderResults(query);
56
59
  updateTitle();
57
60
  });
61
+ if(window.ga) {
62
+ window.clearTimeout(queryTimer);
63
+ queryTimer = window.setTimeout(sendQueryToAnalytics, 1000);
64
+ }
58
65
  });
59
66
 
60
67
  // Set focus on the first search result instead of submiting the search
@@ -71,6 +78,25 @@
71
78
  $searchInput.focus();
72
79
  hideResults();
73
80
  });
81
+
82
+ // Attach analytics events to search result clicks
83
+ if(window.ga) {
84
+ $searchResults.on('click', '.search-result__title a', function() {
85
+ var href = $(this).attr('href');
86
+ ga('send', {
87
+ hitType: 'event',
88
+ eventCategory: 'Search result',
89
+ eventAction: 'click',
90
+ eventLabel: href,
91
+ transport: 'beacon'
92
+ });
93
+ });
94
+ }
95
+
96
+ // When selecting navigation link, close the search results.
97
+ $('.toc').on('click','a', function(e) {
98
+ hideResults();
99
+ })
74
100
  }
75
101
 
76
102
  function changeSearchLabel() {
@@ -84,7 +110,6 @@
84
110
  results.push(s.lunrData.docs[item.ref]);
85
111
  }
86
112
  });
87
-
88
113
  return results;
89
114
  }
90
115
 
@@ -144,9 +169,10 @@
144
169
  break;
145
170
  }
146
171
 
147
- var containsMark = sentences[i].includes('mark>');
148
- if (containsMark) {
149
- selectedSentences.push(sentences[i].trim());
172
+ var sentence = sentences[i].trim();
173
+ var containsMark = sentence.includes('mark>');
174
+ if (containsMark && (selectedSentences.indexOf(sentence) == -1)) {
175
+ selectedSentences.push(sentence);
150
176
  }
151
177
  }
152
178
  if(selectedSentences.length > 0) {
@@ -175,6 +201,149 @@
175
201
  .attr('aria-hidden', 'true');
176
202
  $html.removeClass('has-search-results-open');
177
203
  }
204
+
205
+ function sendQueryToAnalytics() {
206
+ if(query === '') {
207
+ return;
208
+ }
209
+ var stripped = window.stripPIIFromString(query)
210
+ ga('send', {
211
+ hitType: 'event',
212
+ eventCategory: 'Search query',
213
+ eventAction: 'type',
214
+ eventLabel: stripped,
215
+ transport: 'beacon'
216
+ });
217
+ }
218
+
219
+ function replaceStopWordFilter() {
220
+ // Replace the default stopWordFilter as it excludes useful words like
221
+ // 'get'
222
+ // See: https://lunrjs.com/docs/stop_word_filter.js.html#line43
223
+ s.lunrIndex.pipeline.remove(lunr.stopWordFilter);
224
+ s.lunrIndex.pipeline.add(s.govukStopWorldFilter);
225
+ }
226
+
227
+ this.govukStopWorldFilter = lunr.generateStopWordFilter([
228
+ 'a',
229
+ 'able',
230
+ 'about',
231
+ 'across',
232
+ 'after',
233
+ 'all',
234
+ 'almost',
235
+ 'also',
236
+ 'am',
237
+ 'among',
238
+ 'an',
239
+ 'and',
240
+ 'any',
241
+ 'are',
242
+ 'as',
243
+ 'at',
244
+ 'be',
245
+ 'because',
246
+ 'been',
247
+ 'but',
248
+ 'by',
249
+ 'can',
250
+ 'cannot',
251
+ 'could',
252
+ 'dear',
253
+ 'did',
254
+ 'do',
255
+ 'does',
256
+ 'either',
257
+ 'else',
258
+ 'ever',
259
+ 'every',
260
+ 'for',
261
+ 'from',
262
+ 'got',
263
+ 'had',
264
+ 'has',
265
+ 'have',
266
+ 'he',
267
+ 'her',
268
+ 'hers',
269
+ 'him',
270
+ 'his',
271
+ 'how',
272
+ 'however',
273
+ 'i',
274
+ 'if',
275
+ 'in',
276
+ 'into',
277
+ 'is',
278
+ 'it',
279
+ 'its',
280
+ 'just',
281
+ 'least',
282
+ 'let',
283
+ 'like',
284
+ 'likely',
285
+ 'may',
286
+ 'me',
287
+ 'might',
288
+ 'most',
289
+ 'must',
290
+ 'my',
291
+ 'neither',
292
+ 'no',
293
+ 'nor',
294
+ 'not',
295
+ 'of',
296
+ 'off',
297
+ 'often',
298
+ 'on',
299
+ 'only',
300
+ 'or',
301
+ 'other',
302
+ 'our',
303
+ 'own',
304
+ 'rather',
305
+ 'said',
306
+ 'say',
307
+ 'says',
308
+ 'she',
309
+ 'should',
310
+ 'since',
311
+ 'so',
312
+ 'some',
313
+ 'than',
314
+ 'that',
315
+ 'the',
316
+ 'their',
317
+ 'them',
318
+ 'then',
319
+ 'there',
320
+ 'these',
321
+ 'they',
322
+ 'this',
323
+ 'tis',
324
+ 'to',
325
+ 'too',
326
+ 'twas',
327
+ 'us',
328
+ 'wants',
329
+ 'was',
330
+ 'we',
331
+ 'were',
332
+ 'what',
333
+ 'when',
334
+ 'where',
335
+ 'which',
336
+ 'while',
337
+ 'who',
338
+ 'whom',
339
+ 'why',
340
+ 'will',
341
+ 'with',
342
+ 'would',
343
+ 'yet',
344
+ 'you',
345
+ 'your'
346
+ ])
178
347
  };
179
348
 
180
349
  // Polyfill includes