[DRE-commits] [jekyll] 02/17: apply manually patch from 3.0.1 to 3.1.6

Cédric Boutillier boutil at moszumanska.debian.org
Sun Jun 5 20:33:03 UTC 2016


This is an automated email from the git hooks/post-receive script.

boutil pushed a commit to branch master
in repository jekyll.

commit 79b2641cb294f8abd6f6eddc458857329327ec71
Author: Cédric Boutillier <boutil at debian.org>
Date:   Sun Jun 5 09:25:16 2016 +0200

    apply manually patch from 3.0.1 to 3.1.6
---
 .codeclimate.yml                                   |  29 +
 .gitignore                                         |  26 +-
 .jrubyrc                                           |   3 -
 .rubocop.yml                                       |  80 +++
 .travis.yml                                        |  58 +-
 CONDUCT.markdown                                   |  49 ++
 CONDUCT.md                                         |  22 -
 Gemfile                                            | 105 ++--
 History.markdown                                   | 559 ++++++++++++-------
 ISSUE_TEMPLATE.md                                  |  20 +
 LICENSE                                            |   2 +-
 README.markdown                                    |  22 +-
 Rakefile                                           | 185 +------
 benchmark/end-with-vs-regexp                       |   2 +
 benchmark/file-dir-ensure-trailing-slash           |  54 ++
 bin/jekyll                                         |  25 +-
 features/collections.feature                       |  62 ++-
 features/create_sites.feature                      |  48 +-
 features/drafts.feature                            |  12 +-
 features/embed_filters.feature                     |  52 +-
 features/frontmatter_defaults.feature              |  38 +-
 features/hooks.feature                             |  33 +-
 features/include_tag.feature                       |  39 +-
 features/incremental_rebuild.feature               |  24 +-
 features/layout_data.feature                       |  70 +++
 features/markdown.feature                          |   6 +-
 features/permalinks.feature                        |  46 +-
 features/plugins.feature                           |   9 +-
 features/post_data.feature                         | 104 +++-
 features/post_excerpts.feature                     |   9 +-
 features/rendering.feature                         |  15 +-
 features/site_configuration.feature                |  42 +-
 features/site_data.feature                         |  33 +-
 features/step_definitions.rb                       | 245 +++++++++
 features/step_definitions/jekyll_steps.rb          | 234 --------
 features/support/env.rb                            | 116 ----
 features/support/{overview.rb => formatter.rb}     | 135 +++--
 features/support/helpers.rb                        | 161 ++++++
 jekyll.gemspec                                     |   2 +-
 lib/jekyll.rb                                      |  29 +-
 lib/jekyll/cleaner.rb                              |   4 +-
 lib/jekyll/collection.rb                           |  34 +-
 lib/jekyll/command.rb                              |   4 -
 lib/jekyll/commands/build.rb                       |  12 +-
 lib/jekyll/commands/clean.rb                       |   6 +-
 lib/jekyll/commands/doctor.rb                      |  44 +-
 lib/jekyll/commands/help.rb                        |   2 -
 lib/jekyll/commands/serve.rb                       | 260 +++++----
 lib/jekyll/commands/serve/servlet.rb               |  61 +++
 lib/jekyll/configuration.rb                        | 128 +++--
 lib/jekyll/converters/identity.rb                  |   2 +-
 lib/jekyll/converters/markdown.rb                  |  89 ++--
 lib/jekyll/converters/markdown/kramdown_parser.rb  | 117 +++-
 lib/jekyll/converters/markdown/rdiscount_parser.rb |   2 +-
 lib/jekyll/converters/markdown/redcarpet_parser.rb |  11 +-
 lib/jekyll/converters/smartypants.rb               |  34 ++
 lib/jekyll/convertible.rb                          |  55 +-
 lib/jekyll/deprecator.rb                           |   4 +-
 lib/jekyll/document.rb                             | 172 +++---
 lib/jekyll/drops/collection_drop.rb                |  22 +
 lib/jekyll/drops/document_drop.rb                  |  60 +++
 lib/jekyll/drops/drop.rb                           | 200 +++++++
 lib/jekyll/drops/excerpt_drop.rb                   |  15 +
 lib/jekyll/drops/jekyll_drop.rb                    |  33 ++
 lib/jekyll/drops/site_drop.rb                      |  38 ++
 lib/jekyll/drops/unified_payload_drop.rb           |  25 +
 lib/jekyll/drops/url_drop.rb                       |  83 +++
 lib/jekyll/entry_filter.rb                         |   2 +-
 lib/jekyll/errors.rb                               |   9 +-
 lib/jekyll/excerpt.rb                              |   9 +-
 lib/jekyll/external.rb                             |  10 +-
 lib/jekyll/filters.rb                              |  35 +-
 lib/jekyll/frontmatter_defaults.rb                 |  40 +-
 lib/jekyll/generator.rb                            |   3 +-
 lib/jekyll/hooks.rb                                |  52 +-
 lib/jekyll/liquid_renderer.rb                      |   2 +-
 lib/jekyll/liquid_renderer/file.rb                 |   2 +-
 lib/jekyll/liquid_renderer/table.rb                |   4 +-
 lib/jekyll/page.rb                                 |  54 +-
 lib/jekyll/plugin.rb                               |  43 +-
 lib/jekyll/plugin_manager.rb                       |  21 +-
 lib/jekyll/reader.rb                               |  14 +-
 lib/jekyll/readers/collection_reader.rb            |   3 +-
 lib/jekyll/readers/data_reader.rb                  |  14 +-
 lib/jekyll/readers/page_reader.rb                  |   6 +-
 lib/jekyll/readers/post_reader.rb                  |   4 +-
 lib/jekyll/readers/static_file_reader.rb           |   4 +-
 lib/jekyll/regenerator.rb                          |  35 +-
 lib/jekyll/related_posts.rb                        |   2 -
 lib/jekyll/renderer.rb                             |  69 ++-
 lib/jekyll/site.rb                                 |  66 +--
 lib/jekyll/static_file.rb                          |  30 +-
 lib/jekyll/stevenson.rb                            |   4 +-
 lib/jekyll/tags/highlight.rb                       |  27 +-
 lib/jekyll/tags/include.rb                         |  34 +-
 lib/jekyll/tags/post_url.rb                        |  17 +-
 lib/jekyll/url.rb                                  |  35 +-
 lib/jekyll/utils.rb                                | 132 ++++-
 lib/jekyll/utils/ansi.rb                           |  59 ++
 lib/jekyll/utils/platforms.rb                      |   4 +-
 lib/jekyll/version.rb                              |   2 +-
 lib/site_template/_includes/head.html              |   2 +-
 rake/docs.rake                                     |  23 +
 rake/release.rake                                  |  25 +
 Rakefile => rake/site.rake                         | 181 +------
 script/cibuild                                     |   2 +
 script/cucumber                                    |  11 +-
 script/proof                                       |   2 +-
 script/rebund                                      | 140 -----
 script/stackprof                                   |  10 +-
 script/travis                                      |  40 ++
 site/_config.yml                                   |   4 +
 site/_data/docs.yml                                |   4 +-
 site/_docs/assets.md                               |   7 +-
 site/_docs/conduct.md                              |  55 ++
 site/_docs/configuration.md                        |  84 ++-
 site/_docs/contributing.md                         |   2 +-
 site/_docs/datafiles.md                            |   6 +-
 site/_docs/deployment-methods.md                   |  77 ++-
 site/_docs/extras.md                               |   8 +-
 site/_docs/github-pages.md                         |  55 +-
 site/_docs/history.md                              | 591 ++++++++++++++-------
 site/_docs/index.md                                |   1 +
 site/_docs/installation.md                         |   8 +-
 site/_docs/pages.md                                |  24 +-
 site/_docs/pagination.md                           |  11 +-
 site/_docs/permalinks.md                           |   7 +-
 site/_docs/plugins.md                              |  28 +-
 site/_docs/posts.md                                |  16 +-
 site/_docs/quickstart.md                           |   3 +-
 site/_docs/resources.md                            |  40 +-
 site/_docs/sites.md                                |   8 +-
 site/_docs/structure.md                            |   6 +-
 site/_docs/templates.md                            |  52 +-
 site/_docs/upgrading.md                            | 136 +----
 site/_docs/{upgrading.md => upgrading.md~HEAD}     |   0
 site/_docs/upgrading.md~upstream                   |  10 +
 site/_docs/{upgrading.md => upgrading/0-to-2.md}   |   6 +-
 site/_docs/upgrading/2-to-3.md                     | 126 +++++
 site/_docs/variables.md                            |   2 +-
 site/_docs/windows.md                              |   8 +-
 site/_includes/docs_ul.html                        |   8 +-
 site/_includes/footer.html                         |   2 +-
 .../_posts/2015-10-26-jekyll-3-0-released.markdown |   2 +-
 .../2016-01-20-jekyll-3-0-2-released.markdown      |  19 +
 .../2016-01-24-jekyll-3-1-0-released.markdown      |  50 ++
 .../2016-01-28-jekyll-3-1-1-released.markdown      |  33 ++
 .../2016-02-08-jekyll-3-0-3-released.markdown      |  32 ++
 .../2016-02-19-jekyll-3-1-2-released.markdown      |  20 +
 site/_sass/_style.scss                             |   4 +
 site/help/index.md                                 |   5 +
 site/index.html                                    |   4 +-
 site/latest_version.txt                            |   2 +-
 site/redirects/github.html                         |   4 +
 site/redirects/issues.html                         |   4 +
 test/fixtures/empty_permalink.erb                  |   4 +
 test/helper.rb                                     |  92 +++-
 test/safe_glob_test[/find_me.txt                   |   0
 test/source/+/foo.md                               |   2 +-
 .../source/_posts/2015-12-27-extra-spaces.markdown |   3 +
 test/source/_slides/example-slide-7.md             |   6 +
 .../_thanksgiving/2015-11-26-thanksgiving.md       |   3 +
 test/source/_thanksgiving/black-friday.md          |   3 +
 .../source/_urls_differ_by_case_invalid/page1.html |   6 +
 .../source/_urls_differ_by_case_invalid/page2.html |   6 +
 test/source/_urls_differ_by_case_valid/page1.html  |   6 +
 test/source/_with.dots/mit.txt                     |   4 +
 test/source/_with.dots/permalink.with.slash.tho.md |   5 +
 test/source/contacts/humans.txt                    |   5 +
 test/source/deal.with.dots.html                    |   1 -
 test/source/dynamic_file.php                       |   4 +
 test/test_ansi.rb                                  |  23 +
 test/test_cleaner.rb                               |  18 +-
 test/test_coffeescript.rb                          |   2 +-
 test/test_collections.rb                           |   2 +-
 test/test_commands_serve.rb                        | 115 ++++
 test/test_configuration.rb                         | 174 +++++-
 test/test_convertible.rb                           |  14 +
 test/test_doctor_command.rb                        |  36 ++
 test/test_document.rb                              | 108 +++-
 test/test_excerpt.rb                               |   3 +-
 test/test_excerpt_drop.rb                          |  36 ++
 test/test_filters.rb                               |  86 ++-
 test/test_front_matter_defaults.rb                 |  69 ++-
 test/test_generated_site.rb                        |  30 +-
 test/test_kramdown.rb                              | 129 +++--
 test/test_layout_reader.rb                         |   2 +-
 test/test_new_command.rb                           |   8 +-
 test/test_page.rb                                  |  78 ++-
 test/test_path_sanitization.rb                     |   9 +
 test/test_regenerator.rb                           |   2 +-
 test/test_site.rb                                  |  56 +-
 test/test_static_file.rb                           |   5 +-
 test/test_tags.rb                                  |  14 +-
 test/test_url.rb                                   |  18 +
 test/test_utils.rb                                 | 106 ++++
 196 files changed, 5704 insertions(+), 2768 deletions(-)

diff --git a/.codeclimate.yml b/.codeclimate.yml
new file mode 100644
index 0000000..6e860b7
--- /dev/null
+++ b/.codeclimate.yml
@@ -0,0 +1,29 @@
+engines:
+  rubocop: { enabled: true  }
+  fixme:   { enabled: false }
+exclude_paths:
+- .rubocop.yml
+- .codeclimate.yml
+- .travis.yml
+- .gitignore
+- .rspec
+
+- Gemfile.lock
+- CHANGELOG.{md,markdown,txt,textile}
+- CONTRIBUTING.{md,markdown,txt,textile}
+- readme.{md,markdown,txt,textile}
+- README.{md,markdown,txt,textile}
+- Readme.{md,markdown,txt,textile}
+- ReadMe.{md,markdown,txt,textile}
+- COPYING
+- LICENSE
+
+- site/**/*
+- test/**/*
+- vendor/**/*
+- features/**/*
+- script/**/*
+- spec/**/*
+ratings:
+  paths:
+  - lib/**/*.rb
diff --git a/.gitignore b/.gitignore
index d75a498..1d62ecc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,20 +1,22 @@
-Gemfile.lock
-test/dest
 *.gem
-pkg/
 *.swp
 *~
-_site/
-.bundle/
 .DS_Store
+.analysis
+.bundle/
+.byebug_history
+.jekyll-metadata
+.ruby-gemset
+.ruby-version
+.sass-cache
+/test/source/file_name.txt
+/vendor
+Gemfile.lock
+_site/
 bbin/
+coverage
 gh-pages/
+pkg/
 site/_site/
-coverage
-.ruby-version
-.ruby-gemset
-.sass-cache
+test/dest
 tmp/*
-.jekyll-metadata
-/vendor
-/test/source/file_name.txt
diff --git a/.jrubyrc b/.jrubyrc
index c4f9370..39aa437 100644
--- a/.jrubyrc
+++ b/.jrubyrc
@@ -1,6 +1,3 @@
 backtrace.mask=true
-compile.invokedynamic=true
-objectspace.enabled=true
 backtrace.color=true
-compat.version=2.2
 backtrace.style=mri
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..1f0ffeb
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,80 @@
+Metrics/MethodLength: { Max:  24 }
+Metrics/ClassLength:  { Max: 240 }
+Metrics/ModuleLength: { Max: 240 }
+Metrics/LineLength:   { Max: 112 }
+Metrics/CyclomaticComplexity: { Max: 8 }
+Metrics/PerceivedComplexity: { Max: 8 }
+Metrics/ParameterLists: { Max: 4 }
+Metrics/MethodLength: { Max: 24 }
+Metrics/AbcSize: { Max: 20 }
+
+Style/IndentHash: { EnforcedStyle: consistent }
+Style/HashSyntax: { EnforcedStyle: hash_rockets }
+Style/SignalException: { EnforcedStyle: only_raise }
+Style/AlignParameters: { EnforcedStyle: with_fixed_indentation }
+Style/StringLiteralsInInterpolation: { EnforcedStyle: double_quotes }
+Style/MultilineMethodCallIndentation: { EnforcedStyle: indented }
+Style/MultilineOperationIndentation: { EnforcedStyle: indented }
+Style/FirstParameterIndentation: { EnforcedStyle: consistent }
+Style/StringLiterals: { EnforcedStyle: double_quotes }
+Style/RegexpLiteral: { EnforcedStyle: slashes }
+Style/IndentArray: { EnforcedStyle: consistent }
+Style/ExtraSpacing: { AllowForAlignment: true }
+
+Style/PercentLiteralDelimiters:
+  PreferredDelimiters:
+    '%q': '{}'
+    '%Q': '{}'
+    '%r': '!!'
+    '%s': '()'
+    '%w': '()'
+    '%W': '()'
+    '%x': '()'
+
+Style/AlignArray:                     { Enabled: false }
+Style/StringLiterals:                 { Enabled: false }
+Style/Documentation:                  { Enabled: false }
+Style/DoubleNegation:                 { Enabled: false }
+Style/UnneededCapitalW:               { Enabled: false }
+Style/EmptyLinesAroundModuleBody:     { Enabled: false }
+Style/EmptyLinesAroundAccessModifier: { Enabled: false }
+Style/BracesAroundHashParameters:     { Enabled: false }
+Style/SpaceInsideBrackets:            { Enabled: false }
+Style/IfUnlessModifier:               { Enabled: false }
+Style/ModuleFunction:                 { Enabled: false }
+Style/RescueModifier:                 { Enabled: false }
+Style/GuardClause:                    { Enabled: false }
+Style/FileName:                       { Enabled: false }
+Lint/UselessAccessModifier:           { Enabled: false }
+Style/SpaceAroundOperators:           { Enabled: false }
+Style/RedundantReturn:                { Enabled: false }
+Style/SingleLineMethods:              { Enabled: false }
+
+AllCops:
+  TargetRubyVersion: 2.0
+  Include:
+  - lib/**/*.rb
+
+  Exclude:
+  - .rubocop.yml
+  - .codeclimate.yml
+  - .travis.yml
+  - .gitignore
+  - .rspec
+
+  - Gemfile.lock
+  - CHANGELOG.{md,markdown,txt,textile}
+  - CONTRIBUTING.{md,markdown,txt,textile}
+  - readme.{md,markdown,txt,textile}
+  - README.{md,markdown,txt,textile}
+  - Readme.{md,markdown,txt,textile}
+  - ReadMe.{md,markdown,txt,textile}
+  - COPYING
+  - LICENSE
+
+  - site/**/*
+  - test/**/*
+  - vendor/**/*
+  - features/**/*
+  - script/**/*
+  - spec/**/*
diff --git a/.travis.yml b/.travis.yml
index 8026187..15bc3cc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,35 +1,49 @@
-language: ruby
+before_script: bundle update
+bundler_args: --without benchmark:site:development
+script: script/cibuild
 cache: bundler
+language: ruby
 sudo: false
+
 rvm:
-- 2.2
-- 2.1
-- 2.0
-- ruby-head
-- jruby-9.0.3.0
+  - &ruby1 2.3.0
+  - &ruby2 2.2.4
+  - &ruby3 2.1.8
+  - &ruby4 2.0.0-p648
+  - &jruby jruby-9.0.4.0
+  - &rhead ruby-head
+
 matrix:
+  fast_finish: true
   allow_failures:
-    - rvm: ruby-head
-    - rvm: jruby-9.0.3.0
-  exclude:
-    - rvm: jruby-9.0.3.0
-      env: TEST_SUITE=cucumber
+    - rvm: *jruby
+    - rvm: *rhead
 env:
   matrix:
     - TEST_SUITE=test
     - TEST_SUITE=cucumber
-before_script: bundle update
-script: script/cibuild
+
 notifications:
   irc:
-    on_success: change
-    on_failure: change
-    channels:
-      - irc.freenode.org#jekyll
-    template:
-      - "%{repository}#%{build_number} (%{branch}) %{message} %{build_url}"
+    template: "%{repository}#%{build_number} (%{branch}) %{message} %{build_url}"
+    channels: irc.freenode.org#jekyll
+
   email:
-    on_success: never
-    on_failure: never
+    recipients:
+      - jordon at envygeeks.io
+
   slack:
-    secure: dNdKk6nahNURIUbO3ULhA09/vTEQjK0fNbgjVjeYPEvROHgQBP1cIP3AJy8aWs8rl5Yyow4YGEilNRzKPz18AsFptVXofpwyqcBxaCfmHP809NX5PHBaadydveLm+TNVao2XeLXSWu+HUNAYO1AanCUbJSEyJTju347xCBGzESU=
+    secure: "\
+      dNdKk6nahNURIUbO3ULhA09/vTEQjK0fNbgjVjeYPEvROHgQBP1cIP3AJy8aWs8rl5Yyow4Y\
+      GEilNRzKPz18AsFptVXofpwyqcBxaCfmHP809NX5PHBaadydveLm+TNVao2XeLXSWu+HUNAY\
+      O1AanCUbJSEyJTju347xCBGzESU=\
+    "
+
+addons:
+  code_climate:
+    repo_token:
+      secure: "\
+        mAuvDu+nrzB8dOaLqsublDGt423mGRyZYM3vsrXh4Tf1sT+L1PxsRzU4gLmcV27HtX2Oq9\
+        DA4vsRURfABU0fIhwYkQuZqEcA3d8TL36BZcGEshG6MQ2AmnYsmFiTcxqV5bmlElHEqQuT\
+        5SUFXLafgZPBnL0qDwujQcHukID41sE=\
+      "
diff --git a/CONDUCT.markdown b/CONDUCT.markdown
new file mode 100644
index 0000000..a0f06de
--- /dev/null
+++ b/CONDUCT.markdown
@@ -0,0 +1,49 @@
+# Contributor Code of Conduct
+
+As contributors and maintainers of this project, and in the interest of
+fostering an open and welcoming community, we pledge to respect all people who
+contribute through reporting issues, posting feature requests, updating
+documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free
+experience for everyone, regardless of level of experience, gender, gender
+identity and expression, sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic
+  addresses, without explicit permission
+* Other unethical or unprofessional conduct
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+By adopting this Code of Conduct, project maintainers commit themselves to
+fairly and consistently applying these principles to every aspect of managing
+this project. Project maintainers who do not follow or enforce the Code of
+Conduct may be permanently removed from the project team.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by opening an issue or contacting a project maintainer. All complaints
+will be reviewed and investigated and will result in a response that is deemed
+necessary and appropriate to the circumstances. Maintainers are obligated to
+maintain confidentiality with regard to the reporter of an incident.
+
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.3.0, available at
+[http://contributor-covenant.org/version/1/3/0/][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/3/0/
diff --git a/CONDUCT.md b/CONDUCT.md
deleted file mode 100644
index 65c05c5..0000000
--- a/CONDUCT.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Contributor Code of Conduct
-
-As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
-
-We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality.
-
-Examples of unacceptable behavior by participants include:
-
-* The use of sexualized language or imagery
-* Personal attacks
-* Trolling or insulting/derogatory comments
-* Public or private harassment
-* Publishing other's private information, such as physical or electronic addresses, without explicit permission
-* Other unethical or unprofessional conduct.
-
-Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team.
-
-This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community.
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
-
-This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index 9b64809..157701b 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,55 +1,84 @@
-source 'https://rubygems.org'
-gemspec name: 'jekyll'
+source "https://rubygems.org"
+gemspec :name => "jekyll"
 
-gem 'rake', '~> 10.1'
+gem "rake", "~> 10.1"
 group :development do
-  gem 'rdoc', '~> 4.2'
-  gem 'launchy', '~> 2.3'
-  gem 'toml', '~> 0.1.0'
-  gem 'pry'
+  gem "launchy", "~> 2.3"
+  gem "rubocop", "~> 0.40"
+  gem "pry"
+
+  unless RUBY_ENGINE == "jruby"
+    gem "pry-byebug"
+  end
 end
 
+#
+
 group :test do
-  gem 'redgreen', '~> 1.2'
-  gem 'shoulda', '~> 3.5'
-  gem 'cucumber', '~> 2.0', '< 2.1'
-  gem 'simplecov', '~> 0.9'
-  gem 'jekyll_test_plugin'
-  gem 'jekyll_test_plugin_malicious'
-  gem 'minitest-reporters'
-  gem 'minitest-profile'
-  gem 'minitest'
-  gem 'rspec-mocks'
+  gem "cucumber", "~> 2.1"
+  gem "jekyll_test_plugin"
+  gem "jekyll_test_plugin_malicious"
+  gem "codeclimate-test-reporter"
+  gem "rspec-mocks"
+  gem "nokogiri"
+  gem "rspec"
+end
 
+#
+
+group :test_legacy do
   if RUBY_PLATFORM =~ /cygwin/ || RUBY_VERSION.start_with?("2.2")
     gem 'test-unit'
   end
 
-  if ENV['PROOF']
-    gem 'html-proofer', '~> 2.0'
-  end
+  gem "redgreen"
+  gem "simplecov"
+  gem "minitest-reporters"
+  gem "minitest-profile"
+  gem "minitest"
+  gem "shoulda"
 end
 
+#
+
 group :benchmark do
-  if ENV['BENCHMARK']
-    gem 'ruby-prof'
-    gem 'rbtrace'
-    gem 'stackprof'
-    gem 'benchmark-ips'
+  if ENV["BENCHMARK"]
+    gem "ruby-prof"
+    gem "benchmark-ips"
+    gem "stackprof"
+    gem "rbtrace"
   end
 end
 
-gem 'jekyll-paginate', '~> 1.0'
-gem 'jekyll-coffeescript', '~> 1.0'
-gem 'jekyll-feed'
-gem 'jekyll-gist', '~> 1.0'
-gem 'mime-types', '~> 2.6'
-gem 'kramdown', '~> 1.9'
-
-platform :ruby, :mswin, :mingw do
-  gem 'rdiscount', '~> 2.0'
-  gem 'pygments.rb', '~> 0.6.0'
-  gem 'redcarpet', '~> 3.2', '>= 3.2.3'
-  gem 'classifier-reborn', '~> 2.0'
-  gem 'liquid-c', '~> 3.0'
+#
+
+group :jekyll_optional_dependencies do
+  gem "toml", "~> 0.1.0"
+  gem "coderay", "~> 1.1.0"
+  gem "jekyll-docs", path: '../docs' if Dir.exist?('../docs') && ENV["JEKYLL_VERSION"]
+  gem "jekyll-gist", "~> 1.0"
+  gem "jekyll-feed", "~> 0.1.3"
+  gem "jekyll-coffeescript", "~> 1.0"
+  gem "jekyll-redirect-from", "~> 0.9.1"
+  gem "jekyll-paginate", "~> 1.0"
+  gem "mime-types", "~> 3.0"
+  gem "kramdown", "~> 1.9"
+  gem "rdoc", "~> 4.2"
+
+  platform :ruby, :mswin, :mingw do
+    gem "rdiscount", "~> 2.0"
+    gem "pygments.rb", "~> 0.6.0"
+    gem "redcarpet", "~> 3.2", ">= 3.2.3"
+    gem "classifier-reborn", "~> 2.0"
+    gem "liquid-c", "~> 3.0"
+  end
+end
+
+#
+
+group :site do
+  if ENV["PROOF"]
+    gem "html-proofer", "~> 2.0"
+  end
+  gem "jemoji"
 end
diff --git a/History.markdown b/History.markdown
index 26fa98d..93c3518 100644
--- a/History.markdown
+++ b/History.markdown
@@ -1,3 +1,189 @@
+## 3.1.6 / 2016-05-19
+
+### Bug Fixes
+
+  * Add ability to `jsonify` Drops such that, e.g. `site | jsonify`, works. (#4914)
+
+## 3.1.5 / 2016-05-18
+
+### Bug Fixes
+
+  * Sort the results of the `require_all` glob (affects Linux only). (#4912)
+
+## 3.1.4 / 2016-05-18
+
+### Bug Fixes
+
+  * Add `ExcerptDrop` and remove excerpt's ability to refer to itself in Liquid (#4907)
+  * Configuration permalink fix where `collections.posts.permalink` inherits properly from `permalink` only when it doesn't exist (#4910)
+  * Add `Configuration.from` to make it easier to build configs from just a hash
+  * Sorting `site.collections` in Liquid by label (#4910)
+  * Fix bug where `layout` in Liquid would inherit from previously-rendered layouts' metadatas (#4909)
+  * Fix bug where `layout` in Liquid would override in the wrong direction (more-specific layouts' data were overwritten by their parent layouts' data; this has now been reversed) (#4909)
+
+## 3.1.2 / 2016-02-19
+
+### Minor Enhancements
+
+  * Include `.rubocop.yml` in Gem (#4437)
+  * `LiquidRenderer#parse`: parse with line numbers. (#4452)
+  * Add consistency to the no-subcommand deprecation message (#4505)
+
+### Bug Fixes
+
+  * Fix syntax highlighting in kramdown by making `@config` accessible in the Markdown converter. (#4428)
+  * `Jekyll.sanitized_path`: sanitizing a questionable path should handle tildes (#4492)
+  * Fix `titleize` so already capitalized words are not dropped (#4525)
+  * Permalinks which end in a slash should always output HTML (#4546)
+
+### Development Fixes
+
+  * Require at least cucumber version 2.1.0 (#4514)
+
+### Site Enhancements
+
+  * Add jekyll-toc plugin (#4429)
+  * Docs: Quickstart - added documentation about the `--force` option (#4410)
+  * Fix broken links to the Code of Conduct (#4436)
+  * Upgrade notes: mention trailing slash in permalink; fixes #4440 (#4455)
+  * Add hooks to the plugin categories toc (#4463)
+  * [add note] Jekyll 3 requires newer version of Ruby. (#4461)
+  * Fix typo in upgrading docs (#4473)
+  * Add note about upgrading documentation on jekyllrb.com/help/ (#4484)
+  * Update Rake link (#4496)
+  * Update & prune the short list of example sites (#4374)
+  * Added amp-jekyll plugin to plugins docs (#4517)
+  * A few grammar fixes (#4512)
+  * Correct a couple mistakes in structure.md (#4522)
+
+## 3.1.1 / 2016-01-29
+
+### Meta
+
+  * Update the Code of Conduct to the latest version (#4402)
+
+### Bug Fixes
+
+  * `Page#dir`: ensure it ends in a slash (#4403)
+  * Add `Utils.merged_file_read_opts` to unify reading & strip the BOM (#4404)
+  * `Renderer#output_ext`: honor folders when looking for ext (#4401)
+
+### Development Fixes
+
+  * Suppress stdout in liquid profiling test (#4409)
+
+## 3.1.0 / 2016-01-23
+
+### Minor Enhancements
+
+  * Use `Liquid::Drop`s instead of `Hash`es in `#to_liquid` (#4277)
+  * Add 'sample' Liquid filter Equivalent to Array#sample functionality (#4223)
+  * Cache parsed include file to save liquid parsing time. (#4120)
+  * Slightly speed up url sanitization and handle multiples of ///. (#4168)
+  * Print debug message when a document is skipped from reading (#4180)
+  * Include tag should accept multiple variables in the include name (#4183)
+  * Add `-o` option to serve command which opens server URL (#4144)
+  * Add CodeClimate platform for better code quality. (#4220)
+  * General improvements for WEBrick via jekyll serve such as SSL & custom headers (#4224, #4228)
+  * Add a default charset to content-type on webrick. (#4231)
+  * Switch `PluginManager` to use `require_with_graceful_fail` for better UX (#4233)
+  * Allow quoted date in front matter defaults (#4184)
+  * Add a Jekyll doctor warning for URLs that only differ by case (#3171)
+  * drops: create one base Drop class which can be set as mutable or not (#4285)
+  * drops: provide `#to_h` to allow for hash introspection (#4281)
+  * Shim subcommands with indication of gem possibly required so users know how to use them (#4254)
+  * Add smartify Liquid filter for SmartyPants (#4323)
+  * Raise error on empty permalink (#4361)
+  * Refactor Page#permalink method (#4389)
+
+### Bug Fixes
+
+  * Pass build options into `clean` command (#4177)
+  * Allow users to use .htm and .xhtml (XHTML5.) (#4160)
+  * Prevent Shell Injection. (#4200)
+  * Convertible should make layout data accessible via `layout` instead of `page` (#4205)
+  * Avoid using `Dir.glob` with absolute path to allow special characters in the path (#4150)
+  * Handle empty config files (#4052)
+  * Rename `@options` so that it does not impact Liquid. (#4173)
+  * utils/drops: update Drop to support `Utils.deep_merge_hashes` (#4289)
+  * Make sure jekyll/drops/drop is loaded first. (#4292)
+  * Convertible/Page/Renderer: use payload hash accessor & setter syntax for backwards-compatibility (#4311)
+  * Drop: fix hash setter precendence (#4312)
+  * utils: `has_yaml_header?` should accept files with extraneous spaces (#4290)
+  * Escape html from site.title and page.title in site template (#4307)
+  * Allow custom file extensions if defined in `permalink` YAML front matter (#4314)
+  * Fix deep_merge_hashes! handling of drops and hashes (#4359)
+  * Page should respect output extension of its permalink (#4373)
+  * Disable auto-regeneration when running server detached (#4376)
+  * Drop#[]: only use public_send for keys in the content_methods array (#4388)
+  * Extract title from filename successfully when no date. (#4195)
+
+### Development Fixes
+
+  * `jekyll-docs` should be easily release-able (#4152)
+  * Allow use of Cucumber 2.1 or greater (#4181)
+  * Modernize Kramdown for Markdown converter. (#4109)
+  * Change TestDoctorCommand to JekyllUnitTest... (#4263)
+  * Create namespaced rake tasks in separate `.rake` files under `lib/tasks` (#4282)
+  * markdown: refactor for greater readability & efficiency (#3771)
+  * Fix many Rubocop style errors (#4301)
+  * Fix spelling of "GitHub" in docs and history (#4322)
+  * Reorganize and cleanup the Gemfile, shorten required depends. (#4318)
+  * Remove script/rebund. (#4341)
+  * Implement codeclimate platform (#4340)
+  * Remove ObectSpace dumping and start using inherited, it's faster. (#4342)
+  * Add script/travis so all people can play with Travis-CI images. (#4338)
+  * Move Cucumber to using RSpec-Expections and furthering JRuby support. (#4343)
+  * Rearrange Cucumber and add some flair. (#4347)
+  * Remove old FIXME (#4349)
+  * Clean up the Gemfile (and keep all the necessary dependencies) (#4350)
+
+### Site Enhancements
+
+  * Add three plugins to directory (#4163)
+  * Add upgrading docs from 2.x to 3.x (#4157)
+  * Add `protect_email` to the plugins index. (#4169)
+  * Add `jekyll-deploy` to list of third-party plugins (#4179)
+  * Clarify plugin docs (#4154)
+  * Add Kickster to deployment methods in documentation (#4190)
+  * Add DavidBurela's tutorial for Windows to Windows docs page (#4210)
+  * Change GitHub code block to highlight tag to avoid it overlaps parent div (#4121)
+  * Update FormKeep link to be something more specific to Jekyll (#4243)
+  * Remove example Roger Chapman site, as the domain doesn't exist (#4249)
+  * Added configuration options for `draft_posts` to configuration docs (#4251)
+  * Fix checklist in `_assets.md` (#4259)
+  * Add Markdown examples to Pages docs (#4275)
+  * Add jekyll-paginate-category to list of third-party plugins (#4273)
+  * Add `jekyll-responsive_image` to list of third-party plugins (#4286)
+  * Add `jekyll-commonmark` to list of third-party plugins (#4299)
+  * Add documentation for incremental regeneration (#4293)
+  * Add note about removal of relative permalink support in upgrading docs (#4303)
+  * Add Pro Tip to use front matter variable to create clean URLs (#4296)
+  * Fix grammar in the documentation for posts. (#4330)
+  * Add documentation for smartify Liquid filter (#4333)
+  * Fixed broken link to blog on using mathjax with jekyll (#4344)
+  * Documentation: correct reference in Precedence section of Configuration docs (#4355)
+  * Add @jmcglone's guide to github-pages doc page (#4364)
+  * Added the Wordpress2Jekyll Wordpress plugin (#4377)
+  * Add Contentful Extension to list of third-party plugins (#4390)
+  * Correct Minor spelling error (#4394)
+
+## 3.0.3 / 2016-02-08
+
+### Bug Fixes
+
+  * Fix extension weirdness with folders (#4493)
+  * EntryFilter: only include 'excluded' log on excluded files (#4479)
+  * `Jekyll.sanitized_path`: escape tildes before sanitizing a questionable path (#4468)
+  * `LiquidRenderer#parse`: parse with line numbers (#4453)
+  * `Document#<=>`: protect against nil comparison in dates. (#4446)
+
+## 3.0.2 / 2016-01-20
+
+### Bug Fixes
+
+  * Document: throw a useful error when an invalid date is given (#4378)
+
 ## 3.0.1 / 2015-11-17
 
 ### Bug Fixes
@@ -73,8 +259,7 @@
   * Perf: `Markdown#matches` should avoid regexp (#3321)
   * Perf: Use frozen regular expressions for `Utils#slugify` (#3321)
   * Split off Textile support into jekyll-textile-converter (#3319)
-  * Improve the navigation menu alignment in the site template on small
-    screens (#3331)
+  * Improve the navigation menu alignment in the site template on small screens (#3331)
   * Show the regeneration time after the initial generation (#3378)
   * Site template: Switch default font to Helvetica Neue (#3376)
   * Make the `include` tag a teensy bit faster. (#3391)
@@ -106,8 +291,7 @@
   * Set log level to debug when verbose flag is set (#3665)
   * Added a mention on the Gemfile to complete the instructions (#3671)
   * Perf: Cache `Document#to_liquid` and invalidate where necessary (#3693)
-  * Perf: `Jekyll::Cleaner#existing_files`: Call `keep_file_regex` and
-    `keep_dirs` only once, not once per iteration (#3696)
+  * Perf: `Jekyll::Cleaner#existing_files`: Call `keep_file_regex` and `keep_dirs` only once, not once per iteration (#3696)
   * Omit jekyll/jekyll-help from list of resources. (#3698)
   * Add basic `jekyll doctor` test to detect fsnotify (OSX) anomalies. (#3704)
   * Added talk.jekyllrb.com to "Have questions?" (#3694)
@@ -389,16 +573,14 @@
   * Strip newlines in site template `<meta>` description. (#2982)
   * Add link to atom feed in `head` of site template files (#2996)
   * Performance optimizations (#2994)
-  * Use `Hash#each_key` instead of `Hash#keys.each` to speed up iteration
-    over hash keys. (#3017)
+  * Use `Hash#each_key` instead of `Hash#keys.each` to speed up iteration over hash keys. (#3017)
   * Further minor performance enhancements. (#3022)
   * Add 'b' and 's' aliases for build and serve, respectively (#3065)
 
 ### Bug Fixes
 
   * Fix Rouge's RedCarpet plugin interface integration (#2951)
-  * Remove `--watch` from the site template blog post since it defaults
-    to watching in in 2.4.0 (#2922)
+  * Remove `--watch` from the site template blog post since it defaults to watching in in 2.4.0 (#2922)
   * Fix code for media query mixin in site template (#2946)
   * Allow post URL's to have `.htm` extensions (#2925)
   * `Utils.slugify`: Don't create new objects when gsubbing (#2997)
@@ -426,7 +608,7 @@
   * Add Big Footnotes for Kramdown plugin to list of third-party plugins (#2916)
   * Remove warning regarding GHP use of singular types for front matter defaults (#2919)
   * Fix quote character typo in site documentation for templates (#2917)
-  * Point Liquid links to Liquid’s Github wiki (#2887)
+  * Point Liquid links to Liquid’s GitHub wiki (#2887)
   * Add HTTP Basic Auth (.htaccess) plugin to list of third-party plugins (#2931)
   * (Minor) Grammar & `_config.yml` filename fixes (#2911)
   * Added `mathml.rb` to the list of third-party plugins. (#2937)
@@ -476,11 +658,9 @@
 
   * Document the `name` variable for collection permalinks (#2829)
   * Adds info about installing jekyll in current dir (#2839)
-  * Remove deprecated `jekyll-projectlist` plugin from list of third-party
-    plugins (#2742)
+  * Remove deprecated `jekyll-projectlist` plugin from list of third-party plugins (#2742)
   * Remove tag plugins that are built in to Jekyll (#2751)
-  * Add `markdown-writer` package for Atom Editor to list of third-party
-    plugins (#2763)
+  * Add `markdown-writer` package for Atom Editor to list of third-party plugins (#2763)
   * Fix typo in site documentation for collections (#2764)
   * Fix minor typo on plugins docs page (#2765)
   * Replace markdown with HTML in `sass_dir` note on assets page (#2791)
@@ -568,8 +748,7 @@
 ### Site Enhancements
 
   * Update Kramdown urls (#2588)
-  * Add `Jekyll::AutolinkEmail` and `Jekyll::GitMetadata` to the list of
-    third-party plugins (#2596)
+  * Add `Jekyll::AutolinkEmail` and `Jekyll::GitMetadata` to the list of third-party plugins (#2596)
   * Fix a bunch of broken links in the site (#2601)
   * Replace dead links with working links (#2611)
   * Add jekyll-hook to deployment methods (#2617)
@@ -606,12 +785,10 @@
   * Allow subdirectories in `_data` (#2395)
   * Extract Pagination Generator into gem: `jekyll-paginate` (#2455)
   * Utilize `date_to_rfc822` filter in site template (#2437)
-  * Add categories, last build datetime, and generator to site template
-    feed (#2438)
+  * Add categories, last build datetime, and generator to site template feed (#2438)
   * Configurable, replaceable Logger-compliant logger (#2444)
   * Extract `gist` tag into a separate gem (#2469)
-  * Add `collection` attribute to `Document#to_liquid` to access the
-    document's collection label. (#2436)
+  * Add `collection` attribute to `Document#to_liquid` to access the document's collection label. (#2436)
   * Upgrade listen to `2.7.6 <= x < 3.0.0` (#2492)
   * Allow configuration of different Twitter and GitHub usernames in site template (#2485)
   * Bump Pygments to v0.6.0 (#2504)
@@ -636,8 +813,7 @@
   * Allow front matter defaults to set post categories (#2373)
   * Fix command in subcommand deprecation warning (#2457)
   * Keep all parent directories of files/dirs in `keep_files` (#2458)
-  * When using RedCarpet and Rouge without Rouge installed, fixed erroneous
-    error which stated that redcarpet was missing, not rouge. (#2464)
+  * When using RedCarpet and Rouge without Rouge installed, fixed erroneous error which stated that redcarpet was missing, not rouge. (#2464)
   * Ignore *all* directories and files that merit it on auto-generation (#2459)
   * Before copying file, explicitly remove the old one (#2535)
   * Merge file system categories with categories from YAML. (#2531)
@@ -666,8 +842,7 @@
   * Prevent table from extending parent width in permalink style table (#2424)
   * Add collections to info about pagination support (#2389)
   * Add `jekyll_github_sample` plugin to list of third-party plugins (#2463)
-  * Clarify documentation around front matter defaults and add details
-    about defaults for collections. (#2439)
+  * Clarify documentation around front matter defaults and add details about defaults for collections. (#2439)
   * Add Jekyll Project Version Tag to list of third-party plugins (#2468)
   * Use `https` for GitHub links across whole site (#2470)
   * Add StickerMule + Jekyll post (#2476)
@@ -683,13 +858,11 @@
 
 ### Bug Fixes
 
-  * Properly prefix links in site template with URL or baseurl depending upon
-    need. (#2319)
+  * Properly prefix links in site template with URL or baseurl depending upon need. (#2319)
   * Update gist tag comments and error message to require username (#2326)
   * Fix `permalink` setting in site template (#2331)
   * Don't fail if any of the path objects are nil (#2325)
-  * Instantiate all descendants for converters and generators, not just
-    direct subclasses (#2334)
+  * Instantiate all descendants for converters and generators, not just direct subclasses (#2334)
   * Replace all instances of `site.name` with `site.title` in site template (#2324)
   * `Jekyll::Filters#time` now accepts UNIX timestamps in string or number form (#2339)
   * Use `item_property` for `where` filter so it doesn't break on collections (#2359)
@@ -725,17 +898,16 @@
 ## 2.0.0 / 2014-05-06
 
 ### Major Enhancements
+
   * Add "Collections" feature (#2199)
   * Add gem-based plugin whitelist to safe mode (#1657)
-  * Replace the commander command line parser with a more robust
-    solution for our needs called `mercenary` (#1706)
+  * Replace the commander command line parser with a more robust solution for our needs called `mercenary` (#1706)
   * Remove support for Ruby 1.8.x (#1780)
   * Move to jekyll/jekyll from mojombo/jekyll (#1817)
   * Allow custom markdown processors (#1872)
   * Provide support for the Rouge syntax highlighter (#1859)
   * Provide support for Sass (#1932)
-  * Provide a 300% improvement when generating sites that use
-    `Post#next` or `Post#previous` (#1983)
+  * Provide a 300% improvement when generating sites that use `Post#next` or `Post#previous` (#1983)
   * Provide support for CoffeeScript (#1991)
   * Replace Maruku with Kramdown as Default Markdown Processor (#1988)
   * Expose `site.static_files` to Liquid (#2075)
@@ -746,10 +918,9 @@
   * Exclude files based on prefix as well as `fnmatch?` (#2303)
 
 ### Minor Enhancements
-  * Move the EntryFilter class into the Jekyll module to avoid polluting the
-    global namespace (#1800)
-  * Add `group_by` Liquid filter create lists of items grouped by a common
-    property's value (#1788)
+
+  * Move the EntryFilter class into the Jekyll module to avoid polluting the global namespace (#1800)
+  * Add `group_by` Liquid filter create lists of items grouped by a common property's value (#1788)
   * Add support for Maruku's `fenced_code_blocks` option (#1799)
   * Update Redcarpet dependency to ~> 3.0 (#1815)
   * Automatically sort all pages by name (#1848)
@@ -760,12 +931,10 @@
   * Bump dependency `safe_yaml` to `~> 1.0` (#1886)
   * Allow sorting of content by custom properties (#1849)
   * Add `--quiet` flag to silence output during build and serve (#1898)
-  * Add a `where` filter to filter arrays based on a key/value pair
-    (#1875)
+  * Add a `where` filter to filter arrays based on a key/value pair (#1875)
   * Route 404 errors to a custom 404 page in development (#1899)
   * Excludes are now relative to the site source (#1916)
-  * Bring MIME Types file for `jekyll serve` to complete parity with GH Pages
-    servers (#1993)
+  * Bring MIME Types file for `jekyll serve` to complete parity with GH Pages servers (#1993)
   * Adding Breakpoint to make new site template more responsive (#2038)
   * Default to using the UTF-8 encoding when reading files. (#2031)
   * Update Redcarpet dependency to ~> 3.1 (#2044)
@@ -783,13 +952,11 @@
   * Add support for unpublished drafts (#2164)
   * Add `force_polling` option to the `serve` command (#2165)
   * Clean up the `<head>` in the site template (#2186)
-  * Permit YAML blocks to end with three dots to better conform with the
-    YAML spec (#2110)
+  * Permit YAML blocks to end with three dots to better conform with the YAML spec (#2110)
   * Use `File.exist?` instead of deprecated `File.exists?` (#2214)
   * Require newline after start of YAML Front Matter header (#2211)
   * Add the ability for pages to be marked as `published: false` (#1492)
-  * Add `Jekyll::LiquidExtensions` with `.lookup_variable` method for easy
-    looking up of variable values in a Liquid context. (#2253)
+  * Add `Jekyll::LiquidExtensions` with `.lookup_variable` method for easy looking up of variable values in a Liquid context. (#2253)
   * Remove literal lang name from class (#2292)
   * Return `utf-8` encoding in header for webrick error page response (#2289)
   * Make template site easier to customize (#2268)
@@ -798,13 +965,12 @@
   * Take into account missing values in the Liquid sort filter (#2299)
 
 ### Bug Fixes
+
   * Don't allow nil entries when loading posts (#1796)
-  * Remove the scrollbar that's always displayed in new sites generated
-    from the site template (#1805)
+  * Remove the scrollbar that's always displayed in new sites generated from the site template (#1805)
   * Add `#path` to required methods in `Jekyll::Convertible` (#1866)
   * Default Maruku fenced code blocks to ON for 2.0.0-dev (#1831)
-  * Change short opts for host and port for `jekyll docs` to be consistent with
-    other subcommands (#1877)
+  * Change short opts for host and port for `jekyll docs` to be consistent with other subcommands (#1877)
   * Fix typos (#1910)
   * Lock Maruku at 0.7.0 to prevent bugs caused by Maruku 0.7.1 (#1958)
   * Fixes full path leak to source directory when using include tag (#1951)
@@ -817,8 +983,7 @@
   * Sanitize paths uniformly, in a Windows-friendly way (#2065, #2109)
   * Update gem build steps to work correctly on Windows (#2118)
   * Remove obsolete `normalize_options` method call from `bin/jekyll` (#2121).
-  * Remove `+` characters from Pygments lexer names when adding as a CSS
-    class (#994)
+  * Remove `+` characters from Pygments lexer names when adding as a CSS class (#994)
   * Remove some code that caused Ruby interpreter warnings (#2178)
   * Only strip the drive name if it begins the string (#2175)
   * Remove default post with invalid date from site template (#2200)
@@ -833,14 +998,14 @@
   * Add `output` to `Document` liquid output hash (#2309)
 
 ### Development Fixes
+
   * Add a link to the site in the README.md file (#1795)
   * Add in History and site changes from `v1-stable` branch (#1836)
   * Testing additions on the Excerpt class (#1893)
   * Fix the `highlight` tag feature (#1859)
   * Test Jekyll under Ruby 2.1.0 (#1900)
   * Add script/cibuild for fun and profit (#1912)
-  * Use `Forwardable` for delegation between `Excerpt` and `Post`
-    (#1927)
+  * Use `Forwardable` for delegation between `Excerpt` and `Post` (#1927)
   * Rename `read_things` to `read_content` (#1928)
   * Add `script/branding` script for ASCII art lovin' (#1936)
   * Update the README to reflect the repo move (#1943)
@@ -868,11 +1033,11 @@
   * Workaround for Travis bug (#2290)
 
 ### Site Enhancements
+
   * Document Kramdown's GFM parser option (#1791)
   * Move CSS to includes & update normalize.css to v2.1.3 (#1787)
   * Minify CSS only in production (#1803)
-  * Fix broken link to installation of Ruby on Mountain Lion blog post on
-    Troubleshooting docs page (#1797)
+  * Fix broken link to installation of Ruby on Mountain Lion blog post on Troubleshooting docs page (#1797)
   * Fix issues with 1.4.1 release blog post (#1804)
   * Add note about deploying to OpenShift (#1812)
   * Collect all Windows-related docs onto one page (#1818)
@@ -887,8 +1052,7 @@
   * Add jekyll-compass to the plugin list (#1923)
   * Add note in Posts docs about stripping `<p>` tags from excerpt (#1933)
   * Add additional info about the new exclude behavior (#1938)
-  * Linkify 'awesome contributors' to point to the contributors graph on
-    GitHub (#1940)
+  * Linkify 'awesome contributors' to point to the contributors graph on GitHub (#1940)
   * Update `docs/sites.md` link to GitHub Training materials (#1949)
   * Update `master` with the release info from 1.4.3 (#1947)
   * Define docs nav in datafile (#1953)
@@ -905,8 +1069,7 @@
   * Update link to rack-jekyll on "Deployment Methods" page (#2047)
   * Fix typo in /docs/configuration (#2073)
   * Fix count in docs for `site.static_files` (#2077)
-  * Update configuration docs to indicate utf-8 is the default for 2.0.0
-    and ASCII for 1.9.3 (#2074)
+  * Update configuration docs to indicate utf-8 is the default for 2.0.0 and ASCII for 1.9.3 (#2074)
   * Add info about unreleased feature to the site (#2061)
   * Add whitespace to liquid example in GitHub Pages docs (#2084)
   * Clarify the way Sass and CoffeeScript files are read in and output (#2067)
@@ -923,8 +1086,7 @@
   * Some HTML tidying (#2130)
   * Remove modernizr and use html5shiv.js directly for IE less than v9 (#2131)
   * Remove unused images (#2187)
-  * Use `array_to_sentence_string` filter when outputting news item
-    categories (#2191)
+  * Use `array_to_sentence_string` filter when outputting news item categories (#2191)
   * Add link to Help repo in primary navigation bar (#2177)
   * Switch to using an ico file for the shortcut icon (#2193)
   * Use numbers to specify font weights and only bring in font weights used (#2185)
@@ -974,64 +1136,72 @@
 ## 1.4.3 / 2014-01-13
 
 ### Bug Fixes
+
   * Patch show-stopping security vulnerabilities (#1944)
 
 ## 1.4.2 / 2013-12-16
 
 ### Bug Fixes
+
   * Turn on Maruku fenced code blocks by default (#1830)
 
 ## 1.4.1 / 2013-12-09
 
 ### Bug Fixes
+
   * Don't allow nil entries when loading posts (#1796)
 
 ## 1.4.0 / 2013-12-07
 
 ### Major Enhancements
+
   * Add support for TOML config files (#1765)
 
 ### Minor Enhancements
+
   * Sort plugins as a way to establish a load order (#1682)
   * Update Maruku to 0.7.0 (#1775)
 
 ### Bug Fixes
+
   * Add a space between two words in a Pagination warning message (#1769)
   * Upgrade `toml` gem to `v0.1.0` to maintain compat with Ruby 1.8.7 (#1778)
 
 ### Development Fixes
+
   * Remove some whitespace in the code (#1755)
   * Remove some duplication in the reading of posts and drafts (#1779)
 
 ### Site Enhancements
+
   * Fixed case of a word in the Jekyll v1.3.0 release post (#1762)
   * Fixed the mime type for the favicon (#1772)
 
 ## 1.3.1 / 2013-11-26
 
 ### Minor Enhancements
+
   * Add a `--prefix` option to passthrough for the importers (#1669)
-  * Push the paginator plugin lower in the plugin priority order so
-    other plugins run before it (#1759)
+  * Push the paginator plugin lower in the plugin priority order so other plugins run before it (#1759)
 
 ### Bug Fixes
+
   * Fix the include tag when ran in a loop (#1726)
   * Fix errors when using `--watch` on 1.8.7 (#1730)
-  * Specify where the include is called from if an included file is
-    missing (#1746)
+  * Specify where the include is called from if an included file is missing (#1746)
 
 ### Development Fixes
+
   * Extract `Site#filter_entries` into its own object (#1697)
   * Enable Travis' bundle caching (#1734)
   * Remove trailing whitespace in some files (#1736)
   * Fix a duplicate test name (#1754)
 
 ### Site Enhancements
+
   * Update link to example Rakefile to point to specific commit (#1741)
-  * Fix drafts docs to indicate that draft time is based on file modification
-    time, not `Time.now` (#1695)
-  * Add `jekyll-monthly-archive-plugin` and `jekyll-category-archive-plugin` to
-    list of third-party plugins (#1693)
+  * Fix drafts docs to indicate that draft time is based on file modification time, not `Time.now` (#1695)
+  * Add `jekyll-monthly-archive-plugin` and `jekyll-category-archive-plugin` to list of third-party plugins (#1693)
   * Add `jekyll-asset-path-plugin` to list of third-party plugins (#1670)
   * Add `emoji-for-jekyll` to list of third-part plugins (#1708)
   * Fix previous section link on plugins page to point to pagination page (#1707)
@@ -1043,44 +1213,40 @@
 ## 1.3.0 / 2013-11-04
 
 ### Major Enhancements
-  * Add support for adding data as YAML files under a site's `_data`
-    directory (#1003)
+
+  * Add support for adding data as YAML files under a site's `_data` directory (#1003)
   * Allow variables to be used with `include` tags (#1495)
   * Allow using gems for plugin management (#1557)
 
 ### Minor Enhancements
+
   * Decrease the specificity in the site template CSS (#1574)
   * Add `encoding` configuration option (#1449)
-  * Provide better error handling for Jekyll's custom Liquid tags
-    (#1514)
-  * If an included file causes a Liquid error, add the path to the
-    include file that caused the error to the error message (#1596)
-  * If a layout causes a Liquid error, change the error message so that
-    we know it comes from the layout (#1601)
+  * Provide better error handling for Jekyll's custom Liquid tags (#1514)
+  * If an included file causes a Liquid error, add the path to the include file that caused the error to the error message (#1596)
+  * If a layout causes a Liquid error, change the error message so that we know it comes from the layout (#1601)
   * Update Kramdown dependency to `~> 1.2` (#1610)
   * Update `safe_yaml` dependency to `~> 0.9.7` (#1602)
   * Allow layouts to be in subfolders like includes (#1622)
   * Switch to listen for site watching while serving (#1589)
   * Add a `json` liquid filter to be used in sites (#1651)
-  * Point people to the migration docs when the `jekyll-import` gem is
-    missing (#1662)
+  * Point people to the migration docs when the `jekyll-import` gem is missing (#1662)
 
 ### Bug Fixes
-  * Fix up matching against source and destination when the two
-    locations are similar (#1556)
+
+  * Fix up matching against source and destination when the two locations are similar (#1556)
   * Fix the missing `pathname` require in certain cases (#1255)
   * Use `+` instead of `Array#concat` when building `Post` attribute list (#1571)
   * Print server address when launching a server (#1586)
   * Downgrade to Maruku `~> 0.6.0` in order to avoid changes in rendering (#1598)
   * Fix error with failing include tag when variable was file name (#1613)
   * Downcase lexers before passing them to pygments (#1615)
-  * Capitalize the short verbose switch because it conflicts with the
-    built-in Commander switch (#1660)
+  * Capitalize the short verbose switch because it conflicts with the built-in Commander switch (#1660)
   * Fix compatibility with 1.8.x (#1665)
-  * Fix an error with the new file watching code due to library version
-    incompatibilities (#1687)
+  * Fix an error with the new file watching code due to library version incompatibilities (#1687)
 
 ### Development Fixes
+
   * Add coverage reporting with Coveralls (#1539)
   * Refactor the Liquid `include` tag (#1490)
   * Update launchy dependency to `~> 2.3` (#1608)
@@ -1097,6 +1263,7 @@
   * Improve comparisons of timestamps by ignoring the seconds (#1582)
 
 ### Site Enhancements
+
   * Fix params for `JekyllImport::WordPress.process` arguments (#1554)
   * Add `jekyll-suggested-tweet` to list of third-party plugins (#1555)
   * Link to Liquid's docs for tags and filters (#1553)
@@ -1104,8 +1271,7 @@
   * Simplify/generalize pagination docs (#1577)
   * Add documentation for the new data sources feature (#1503)
   * Add more information on how to create generators (#1590, #1592)
-  * Improve the instructions for mimicking GitHub Flavored Markdown
-    (#1614)
+  * Improve the instructions for mimicking GitHub Flavored Markdown (#1614)
   * Add `jekyll-import` warning note of missing dependencies (#1626)
   * Fix grammar in the Usage section (#1635)
   * Add documentation for the use of gems as plugins (#1656)
@@ -1117,21 +1283,25 @@
 ## 1.2.1 / 2013-09-14
 
 ### Minor Enhancements
+
   * Print better messages for detached server. Mute output on detach. (#1518)
   * Disable reverse lookup when running `jekyll serve` (#1363)
   * Upgrade RedCarpet dependency to `~> 2.3.0` (#1515)
   * Upgrade to Liquid `>= 2.5.2, < 2.6` (#1536)
 
 ### Bug Fixes
+
   * Fix file discrepancy in gemspec (#1522)
   * Force rendering of Include tag (#1525)
 
 ### Development Fixes
+
   * Add a rake task to generate a new release post (#1404)
   * Mute LSI output in tests (#1531)
   * Update contributor documentation (#1537)
 
 ### Site Enhancements
+
   * Fix a couple of validation errors on the site (#1511)
   * Make navigation menus reusable (#1507)
   * Fix link to History page from Release v1.2.0 notes post.
@@ -1141,42 +1311,38 @@
 ## 1.2.0 / 2013-09-06
 
 ### Major Enhancements
+
   * Disable automatically-generated excerpts when `excerpt_separator` is `""`. (#1386)
   * Add checking for URL conflicts when running `jekyll doctor` (#1389)
 
 ### Minor Enhancements
+
   * Catch and fix invalid `paginate` values (#1390)
-  * Remove superfluous `div.container` from the default html template for
-    `jekyll new` (#1315)
+  * Remove superfluous `div.container` from the default html template for `jekyll new` (#1315)
   * Add `-D` short-form switch for the drafts option (#1394)
   * Update the links in the site template for Twitter and GitHub (#1400)
   * Update dummy email address to example.com domain (#1408)
-  * Update normalize.css to v2.1.2 and minify; add rake task to update
-    normalize.css with greater ease. (#1430)
-  * Add the ability to detach the server ran by `jekyll serve` from it's
-    controlling terminal (#1443)
+  * Update normalize.css to v2.1.2 and minify; add rake task to update normalize.css with greater ease. (#1430)
+  * Add the ability to detach the server ran by `jekyll serve` from it's controlling terminal (#1443)
   * Improve permalink generation for URLs with special characters (#944)
-  * Expose the current Jekyll version to posts and pages via a new
-    `jekyll.version` variable (#1481)
+  * Expose the current Jekyll version to posts and pages via a new `jekyll.version` variable (#1481)
 
 ### Bug Fixes
+
   * Markdown extension matching matches only exact matches (#1382)
   * Fixed NoMethodError when message passed to `Stevenson#message` is nil (#1388)
   * Use binary mode when writing file (#1364)
-  * Fix 'undefined method `encoding` for "mailto"' errors w/ Ruby 1.8 and
-    Kramdown > 0.14.0 (#1397)
+  * Fix 'undefined method `encoding` for "mailto"' errors w/ Ruby 1.8 and Kramdown > 0.14.0 (#1397)
   * Do not force the permalink to be a dir if it ends on .html (#963)
   * When a Liquid Exception is caught, show the full path rel. to site source (#1415)
-  * Properly read in the config options when serving the docs locally
-    (#1444)
+  * Properly read in the config options when serving the docs locally (#1444)
   * Fixed `--layouts` option for `build` and `serve` commands (#1458)
   * Remove kramdown as a runtime dependency since it's optional (#1498)
-  * Provide proper error handling for invalid file names in the include
-    tag (#1494)
+  * Provide proper error handling for invalid file names in the include tag (#1494)
 
 ### Development Fixes
-  * Remove redundant argument to
-    Jekyll::Commands::New#scaffold_post_content (#1356)
+
+  * Remove redundant argument to Jekyll::Commands::New#scaffold_post_content (#1356)
   * Add new dependencies to the README (#1360)
   * Fix link to contributing page in README (#1424)
   * Update TomDoc in Pager#initialize to match params (#1441)
@@ -1186,6 +1352,7 @@
   * Add Gem version and dependency badge to README (#1497)
 
 ### Site Enhancements
+
   * Add info about new releases (#1353)
   * Update plugin list with jekyll-rss plugin (#1354)
   * Update the site list page with Ruby's official site (#1358)
@@ -1210,59 +1377,59 @@
 ## 1.1.2 / 2013-07-25
 
 ### Bug Fixes
+
   * Require Liquid 2.5.1 (#1349)
 
 ## 1.1.1 / 2013-07-24
 
 ### Minor Enhancements
+
   * Remove superfluous `table` selector from main.css in `jekyll new` template (#1328)
   * Abort with non-zero exit codes (#1338)
 
 ### Bug Fixes
+
   * Fix up the rendering of excerpts (#1339)
 
 ### Site Enhancements
+
   * Add Jekyll Image Tag to the plugins list (#1306)
   * Remove erroneous statement that `site.pages` are sorted alphabetically.
-  * Add info about the `_drafts` directory to the directory structure
-    docs (#1320)
-  * Improve the layout of the plugin listing by organizing it into
-    categories (#1310)
+  * Add info about the `_drafts` directory to the directory structure docs (#1320)
+  * Improve the layout of the plugin listing by organizing it into categories (#1310)
   * Add generator-jekyllrb and grunt-jekyll to plugins page (#1330)
   * Mention Kramdown as option for markdown parser on Extras page (#1318)
   * Update Quick-Start page to include reminder that all requirements must be installed (#1327)
-  * Change filename in `include` example to an HTML file so as not to indicate that Jekyll
-    will automatically convert them. (#1303)
+  * Change filename in `include` example to an HTML file so as not to indicate that Jekyll will automatically convert them. (#1303)
   * Add an RSS feed for commits to Jekyll (#1343)
 
 ## 1.1.0 / 2013-07-14
 
 ### Major Enhancements
+
   * Add `docs` subcommand to read Jekyll's docs when offline. (#1046)
   * Support passing parameters to templates in `include` tag (#1204)
   * Add support for Liquid tags to post excerpts (#1302)
 
 ### Minor Enhancements
-  * Search the hierarchy of pagination path up to site root to determine template page for
-    pagination. (#1198)
+
+  * Search the hierarchy of pagination path up to site root to determine template page for pagination. (#1198)
   * Add the ability to generate a new Jekyll site without a template (#1171)
-  * Use redcarpet as the default markdown engine in newly generated
-    sites (#1245, #1247)
-  * Add `redcarpet` as a runtime dependency so `jekyll build` works out-of-the-box for new
-    sites. (#1247)
-  * In the generated site, remove files that will be replaced by a
-    directory (#1118)
+  * Use redcarpet as the default markdown engine in newly generated sites (#1245, #1247)
+  * Add `redcarpet` as a runtime dependency so `jekyll build` works out-of-the-box for new sites. (#1247)
+  * In the generated site, remove files that will be replaced by a directory (#1118)
   * Fail loudly if a user-specified configuration file doesn't exist (#1098)
   * Allow for all options for Kramdown HTML Converter (#1201)
 
 ### Bug Fixes
+
   * Fix pagination in subdirectories. (#1198)
-  * Fix an issue with directories and permalinks that have a plus sign
-    (+) in them (#1215)
+  * Fix an issue with directories and permalinks that have a plus sign (+) in them (#1215)
   * Provide better error reporting when generating sites (#1253)
   * Latest posts first in non-LSI `related_posts` (#1271)
 
 ### Development Fixes
+
   * Merge the theme and layout Cucumber steps into one step (#1151)
   * Restrict activesupport dependency to pre-4.0.0 to maintain compatibility with `<= 1.9.2`
   * Include/exclude deprecation handling simplification (#1284)
@@ -1270,22 +1437,20 @@
   * Refactor Jekyll::Site (#1144)
 
 ### Site Enhancements
+
   * Add "News" section for release notes, along with an RSS feed (#1093, #1285, #1286)
   * Add "History" page.
   * Restructured docs sections to include "Meta" section.
-  * Add message to "Templates" page that specifies that Python must be installed in order
-    to use Pygments. (#1182)
+  * Add message to "Templates" page that specifies that Python must be installed in order to use Pygments. (#1182)
   * Update link to the official Maruku repo (#1175)
   * Add documentation about `paginate_path` to "Templates" page in docs (#1129)
   * Give the quick-start guide its own page (#1191)
-  * Update ProTip on Installation page in docs to point to all the info about Pygments and
-    the 'highlight' tag. (#1196)
+  * Update ProTip on Installation page in docs to point to all the info about Pygments and the 'highlight' tag. (#1196)
   * Run `site/img` through ImageOptim (thanks @qrush!) (#1208)
   * Added Jade Converter to `site/docs/plugins` (#1210)
   * Fix location of docs pages in Contributing pages (#1214)
   * Add ReadInXMinutes plugin to the plugin list (#1222)
-  * Remove plugins from the plugin list that have equivalents in Jekyll
-    proper (#1223)
+  * Remove plugins from the plugin list that have equivalents in Jekyll proper (#1223)
   * Add jekyll-assets to the plugin list (#1225)
   * Add jekyll-pandoc-mulitple-formats to the plugin list (#1229)
   * Remove dead link to "Using Git to maintain your blog" (#1227)
@@ -1299,17 +1464,16 @@
   * Add `jekyll-timeago` to list of third-party plugins. (#1260)
   * Add `jekyll-swfobject` to list of third-party plugins. (#1263)
   * Add `jekyll-picture-tag` to list of third-party plugins. (#1280)
-  * Update the GitHub Pages documentation regarding relative URLs
-    (#1291)
+  * Update the GitHub Pages documentation regarding relative URLs (#1291)
   * Update the S3 deployment documentation (#1294)
   * Add suggestion for Xcode CLT install to troubleshooting page in docs (#1296)
   * Add 'Working with drafts' page to docs (#1289)
-  * Add information about time zones to the documentation for a page's
-    date (#1304)
+  * Add information about time zones to the documentation for a page's date (#1304)
 
 ## 1.0.3 / 2013-06-07
 
 ### Minor Enhancements
+
   * Add support to gist tag for private gists. (#1189)
   * Fail loudly when Maruku errors out (#1190)
   * Move the building of related posts into their own class (#1057)
@@ -1318,16 +1482,16 @@
   * Convert IDs in the site template to classes (#1170)
 
 ### Bug Fixes
+
   * Fix typo in Stevenson constant "ERROR". (#1166)
   * Rename Jekyll::Logger to Jekyll::Stevenson to fix inheritance issue (#1106)
   * Exit with a non-zero exit code when dealing with a Liquid error (#1121)
-  * Make the `exclude` and `include` options backwards compatible with
-    versions of Jekyll prior to 1.0 (#1114)
+  * Make the `exclude` and `include` options backwards compatible with versions of Jekyll prior to 1.0 (#1114)
   * Fix pagination on Windows (#1063)
-  * Fix the application of Pygments' Generic Output style to Go code
-    (#1156)
+  * Fix the application of Pygments' Generic Output style to Go code (#1156)
 
 ### Site Enhancements
+
   * Add a Pro Tip to docs about front matter variables being optional (#1147)
   * Add changelog to site as History page in /docs/ (#1065)
   * Add note to Upgrading page about new config options in 1.0.x (#1146)
@@ -1341,12 +1505,12 @@
   * Fix logic for `relative_permalinks` instructions on Upgrading page (#1101)
   * Add docs for post excerpt (#1072)
   * Add docs for gist tag (#1072)
-  * Add docs indicating that Pygments does not need to be installed
-    separately (#1099, #1119)
+  * Add docs indicating that Pygments does not need to be installed separately (#1099, #1119)
   * Update the migrator docs to be current (#1136)
   * Add the Jekyll Gallery Plugin to the plugin list (#1143)
 
 ### Development Fixes
+
   * Use Jekyll.logger instead of Jekyll::Stevenson to log things (#1149)
   * Fix pesky Cucumber infinite loop (#1139)
   * Do not write posts with timezones in Cucumber tests (#1124)
@@ -1355,20 +1519,24 @@
 ## 1.0.2 / 2013-05-12
 
 ### Major Enhancements
+
   * Add `jekyll doctor` command to check site for any known compatibility problems (#1081)
   * Backwards-compatibilize relative permalinks (#1081)
 
 ### Minor Enhancements
+
   * Add a `data-lang="<lang>"` attribute to Redcarpet code blocks (#1066)
   * Deprecate old config `server_port`, match to `port` if `port` isn't set (#1084)
   * Update pygments.rb version to 0.5.0 (#1061)
   * Update Kramdown version to 1.0.2 (#1067)
 
 ### Bug Fixes
+
   * Fix issue when categories are numbers (#1078)
   * Catching that Redcarpet gem isn't installed (#1059)
 
 ### Site Enhancements
+
   * Add documentation about `relative_permalinks` (#1081)
   * Remove pygments-installation instructions, as pygments.rb is bundled with it (#1079)
   * Move pages to be Pages for realz (#985)
@@ -1377,29 +1545,34 @@
 ## 1.0.1 / 2013-05-08
 
 ### Minor Enhancements
+
   * Do not force use of `toc_token` when using `generate_tok` in RDiscount (#1048)
   * Add newer `language-` class name prefix to code blocks (#1037)
   * Commander error message now preferred over process abort with incorrect args (#1040)
 
 ### Bug Fixes
+
   * Make Redcarpet respect the pygments configuration option (#1053)
   * Fix the index build with LSI (#1045)
   * Don't print deprecation warning when no arguments are specified. (#1041)
   * Add missing `</div>` to site template used by `new` subcommand, fixed typos in code (#1032)
 
 ### Site Enhancements
+
   * Changed https to http in the GitHub Pages link (#1051)
   * Remove CSS cruft, fix typos, fix HTML errors (#1028)
   * Removing manual install of Pip and Distribute (#1025)
   * Updated URL for Markdown references plugin (#1022)
 
 ### Development Fixes
+
   * Markdownify history file (#1027)
   * Update links on README to point to new jekyllrb.com (#1018)
 
 ## 1.0.0 / 2013-05-06
 
 ### Major Enhancements
+
   * Add `jekyll new` subcommand: generate a Jekyll scaffold (#764)
   * Refactored Jekyll commands into subcommands: build, serve, and migrate. (#690)
   * Removed importers/migrators from main project, migrated to jekyll-import sub-gem (#793)
@@ -1407,6 +1580,7 @@
   * Add ordinal date permalink style (/:categories/:year/:y_day/:title.html) (#928)
 
 ### Minor Enhancements
+
   * Site template HTML5-ified (#964)
   * Use post's directory path when matching for the `post_url` tag (#998)
   * Loosen dependency on Pygments so it's only required when it's needed (#1015)
@@ -1446,8 +1620,7 @@
   * Massively accelerate LSI performance (#664)
   * Truncate post slugs when importing from Tumblr (#496)
   * Add glob support to include, exclude option (#743)
-  * Layout of Page or Post defaults to 'page' or 'post', respectively (#580)
-    REPEALED by (#977)
+  * Layout of Page or Post defaults to 'page' or 'post', respectively (#580) REPEALED by (#977)
   * "Keep files" feature (#685)
   * Output full path & name for files that don't parse (#745)
   * Add source and destination directory protection (#535)
@@ -1473,14 +1646,14 @@
   * Fixed Page#dir and Page#url for edge cases (#536)
   * Fix broken `post_url` with posts with a time in their YAML front matter (#831)
   * Look for plugins under the source directory (#654)
-  * Tumblr Migrator: finds `_posts` dir correctly, fixes truncation of long
-      post names (#775)
+  * Tumblr Migrator: finds `_posts` dir correctly, fixes truncation of long post names (#775)
   * Force Categories to be Strings (#767)
   * Safe YAML plugin to prevent vulnerability (#777)
   * Add SVG support to Jekyll/WEBrick. (#407, #406)
   * Prevent custom destination from causing continuous regen on watch (#528, #820, #862)
 
 ### Site Enhancements
+
   * Responsify (#860)
   * Fix spelling, punctuation and phrasal errors (#989)
   * Update quickstart instructions with `new` command (#966)
@@ -1491,20 +1664,20 @@
   * Redesigned site (#583)
 
 ### Development Fixes
+
   * Exclude Cucumber 1.2.4, which causes tests to fail in 1.9.2 (#938)
-  * Added "features:html" rake task for debugging purposes, cleaned up
-      Cucumber profiles (#832)
+  * Added "features:html" rake task for debugging purposes, cleaned up Cucumber profiles (#832)
   * Explicitly require HTTPS rubygems source in Gemfile (#826)
   * Changed Ruby version for development to 1.9.3-p374 from p362 (#801)
   * Including a link to the GitHub Ruby style guide in CONTRIBUTING.md (#806)
   * Added script/bootstrap (#776)
-  * Running Simplecov under 2 conditions: ENV(COVERAGE)=true and with Ruby version
-      of greater than 1.9 (#771)
+  * Running Simplecov under 2 conditions: ENV(COVERAGE)=true and with Ruby version of greater than 1.9 (#771)
   * Switch to Simplecov for coverage report (#765)
 
 ## 0.12.1 / 2013-02-19
 
 ### Minor Enhancements
+
   * Update Kramdown version to 0.14.1 (#744)
   * Test Enhancements
   * Update Rake version to 10.0.3 (#744)
@@ -1514,6 +1687,7 @@
 ## 0.12.0 / 2012-12-22
 
 ### Minor Enhancements
+
   * Add ability to explicitly specify included files (#261)
   * Add `--default-mimetype` option (#279)
   * Allow setting of RedCloth options (#284)
@@ -1533,10 +1707,12 @@
   * Ensure front matter is at start of file (#562)
 
 ## 0.11.2 / 2011-12-27
+
   * Bug Fixes
   * Fix gemspec
 
 ## 0.11.1 / 2011-12-27
+
   * Bug Fixes
   * Fix extra blank line in highlight blocks (#409)
   * Update dependencies
@@ -1544,12 +1720,14 @@
 ## 0.11.0 / 2011-07-10
 
 ### Major Enhancements
+
   * Add command line importer functionality (#253)
   * Add Redcarpet Markdown support (#318)
   * Make markdown/textile extensions configurable (#312)
   * Add `markdownify` filter
 
 ### Minor Enhancements
+
   * Switch to Albino gem
   * Bundler support
   * Use English library to avoid hoops (#292)
@@ -1563,12 +1741,14 @@
   * Secure additional path exploits
 
 ## 0.10.0 / 2010-12-16
+
   * Bug Fixes
   * Add `--no-server` option.
 
 ## 0.9.0 / 2010-12-15
 
 ### Minor Enhancements
+
   * Use OptionParser's `[no-]` functionality for better boolean parsing.
   * Add Drupal migrator (#245)
   * Complain about YAML and Liquid errors (#249)
@@ -1578,6 +1758,7 @@
 ## 0.8.0 / 2010-11-22
 
 ### Minor Enhancements
+
   * Add wordpress.com importer (#207)
   * Add `--limit-posts` cli option (#212)
   * Add `uri_escape` filter (#234)
@@ -1592,12 +1773,14 @@
 ## 0.7.0 / 2010-08-24
 
 ### Minor Enhancements
+
   * Add support for rdiscount extensions (#173)
   * Bug Fixes
   * Highlight should not be able to render local files
   * The site configuration may not always provide a 'time' setting (#184)
 
 ## 0.6.2 / 2010-06-25
+
   * Bug Fixes
   * Fix Rakefile 'release' task (tag pushing was missing origin)
   * Ensure that RedCloth is loaded when textilize filter is used (#183)
@@ -1605,24 +1788,24 @@
   * Fix `page.url` to include full relative path (#181)
 
 ## 0.6.1 / 2010-06-24
+
   * Bug Fixes
   * Fix Markdown Pygments prefix and suffix (#178)
 
 ## 0.6.0 / 2010-06-23
 
 ### Major Enhancements
+
   * Proper plugin system (#19, #100)
   * Add safe mode so unsafe converters/generators can be added
-  * Maruku is now the only processor dependency installed by default.
-      Other processors will be lazy-loaded when necessary (and prompt the
-      user to install them when necessary) (#57)
+  * Maruku is now the only processor dependency installed by default. Other processors will be lazy-loaded when necessary (and prompt the user to install them when necessary) (#57)
 
 ### Minor Enhancements
+
   * Inclusion/exclusion of future dated posts (#59)
   * Generation for a specific time (#59)
   * Allocate `site.time` on render not per site_payload invocation (#59)
-  * Pages now present in the site payload and can be used through the
-      `site.pages` and `site.html_pages` variables
+  * Pages now present in the site payload and can be used through the `site.pages` and `site.html_pages` variables
   * Generate phase added to site#process and pagination is now a generator
   * Switch to RakeGem for build/test process
   * Only regenerate static files when they have changed (#142)
@@ -1639,87 +1822,80 @@
 ## 0.5.7 / 2010-01-12
 
 ### Minor Enhancements
+
   * Allow overriding of post date in the front matter (#62, #38)
   * Bug Fixes
   * Categories isn't always an array (#73)
   * Empty tags causes error in read_posts (#84)
   * Fix pagination to adhere to read/render/write paradigm
   * Test Enhancement
-  * Cucumber features no longer use site.posts.first where a better
-      alternative is available
+  * Cucumber features no longer use site.posts.first where a better alternative is available
 
 ## 0.5.6 / 2010-01-08
+
   * Bug Fixes
   * Require redcloth >= 4.2.1 in tests (#92)
   * Don't break on triple dashes in yaml front matter (#93)
 
 ### Minor Enhancements
+
   * Allow .mkd as markdown extension
   * Use $stdout/err instead of constants (#99)
   * Properly wrap code blocks (#91)
   * Add javascript mime type for webrick (#98)
 
 ## 0.5.5 / 2010-01-08
+
   * Bug Fixes
   * Fix pagination % 0 bug (#78)
-  * Ensure all posts are processed first (#71)
-
-## NOTE
-  * After this point I will no longer be giving credit in the history;
-    that is what the commit log is for.
+  * Ensure all posts are processed first (#71) ## NOTE
+  * After this point I will no longer be giving credit in the history; that is what the commit log is for.
 
 ## 0.5.4 / 2009-08-23
+
   * Bug Fixes
   * Do not allow symlinks (security vulnerability)
 
 ## 0.5.3 / 2009-07-14
+
   * Bug Fixes
-  * Solving the permalink bug where non-html files wouldn't work
-      (@jeffrydegrande)
+  * Solving the permalink bug where non-html files wouldn't work (@jeffrydegrande)
 
 ## 0.5.2 / 2009-06-24
+
   * Enhancements
-  * Added --paginate option to the executable along with a paginator object
-      for the payload (@calavera)
-  * Upgraded RedCloth to 4.2.1, which makes `<notextile>` tags work once
-      again.
-  * Configuration options set in config.yml are now available through the
-      site payload (@vilcans)
-  * Posts can now have an empty YAML front matter or none at all
-      (@ bahuvrihi)
+  * Added --paginate option to the executable along with a paginator object for the payload (@calavera)
+  * Upgraded RedCloth to 4.2.1, which makes `<notextile>` tags work once again.
+  * Configuration options set in config.yml are now available through the site payload (@vilcans)
+  * Posts can now have an empty YAML front matter or none at all (@ bahuvrihi)
   * Bug Fixes
-  * Fixing Ruby 1.9 issue that requires `#to_s` on the err object
-      (@Chrononaut)
+  * Fixing Ruby 1.9 issue that requires `#to_s` on the err object (@Chrononaut)
   * Fixes for pagination and ordering posts on the same day (@ujh)
-  * Made pages respect permalinks style and permalinks in yml front matter
-      (@eugenebolshakov)
-  * Index.html file should always have index.html permalink
-      (@eugenebolshakov)
-  * Added trailing slash to pretty permalink style so Apache is happy
-      (@eugenebolshakov)
-  * Bad markdown processor in config fails sooner and with better message
-      (@ gcnovus)
+  * Made pages respect permalinks style and permalinks in yml front matter (@eugenebolshakov)
+  * Index.html file should always have index.html permalink (@eugenebolshakov)
+  * Added trailing slash to pretty permalink style so Apache is happy (@eugenebolshakov)
+  * Bad markdown processor in config fails sooner and with better message (@ gcnovus)
   * Allow CRLFs in yaml front matter (@juretta)
   * Added Date#xmlschema for Ruby versions < 1.9
 
 ## 0.5.1 / 2009-05-06
 
 ### Major Enhancements
+
   * Next/previous posts in site payload (@pantulis, @tomo)
   * Permalink templating system
   * Moved most of the README out to the GitHub wiki
-  * Exclude option in configuration so specified files won't be brought over
-      with generated site (@duritong)
+  * Exclude option in configuration so specified files won't be brought over with generated site (@duritong)
   * Bug Fixes
   * Making sure config.yaml references are all gone, using only config.yml
   * Fixed syntax highlighting breaking for UTF-8 code (@henrik)
-  * Worked around RDiscount bug that prevents Markdown from getting parsed
-      after highlight (@henrik)
+  * Worked around RDiscount bug that prevents Markdown from getting parsed after highlight (@henrik)
   * CGI escaped post titles (@Chrononaut)
 
 ## 0.5.0 / 2009-04-07
 
 ### Minor Enhancements
+
   * Ability to set post categories via YAML (@qrush)
   * Ability to set prevent a post from publishing via YAML (@qrush)
   * Add textilize filter (@willcodeforfoo)
@@ -1739,6 +1915,7 @@
 ## 0.4.1
 
 ### Minor Enhancements
+
   * Changed date format on wordpress converter (zeropadding) (@dysinger)
   * Bug Fixes
   * Add Jekyll binary as executable to gemspec (@dysinger)
@@ -1746,9 +1923,11 @@
 ## 0.4.0 / 2009-02-03
 
 ### Major Enhancements
+
   * Switch to Jeweler for packaging tasks
 
 ### Minor Enhancements
+
   * Type importer (@codeslinger)
   * `site.topics` accessor (@baz)
   * Add `array_to_sentence_string` filter (@mchung)
@@ -1767,55 +1946,62 @@
 ## 0.3.0 / 2008-12-24
 
 ### Major Enhancements
-  * Added `--server` option to start a simple WEBrick server on destination
-      directory (@johnreilly and @mchung)
+
+  * Added `--server` option to start a simple WEBrick server on destination directory (@johnreilly and @mchung)
 
 ### Minor Enhancements
+
   * Added post categories based on directories containing `_posts` (@mreid)
   * Added post topics based on directories underneath `_posts`
   * Added new date filter that shows the full month name (@mreid)
   * Merge Post's YAML front matter into its to_liquid payload (@remi)
   * Restrict includes to regular files underneath `_includes`
   * Bug Fixes
-  * Change YAML delimiter matcher so as to not chew up 2nd level markdown
-      headers (@mreid)
-  * Fix bug that meant page data (such as the date) was not available in
-      templates (@mreid)
+  * Change YAML delimiter matcher so as to not chew up 2nd level markdown headers (@mreid)
+  * Fix bug that meant page data (such as the date) was not available in templates (@mreid)
   * Properly reject directories in `_layouts`
 
 ## 0.2.1 / 2008-12-15
+
   * Major Changes
   * Use Maruku (pure Ruby) for Markdown by default (@mreid)
   * Allow use of RDiscount with `--rdiscount` flag
 
 ### Minor Enhancements
+
   * Don't load directory_watcher unless it's needed (@pjhyett)
 
 ## 0.2.0 / 2008-12-14
+
   * Major Changes
   * related_posts is now found in `site.related_posts`
 
 ## 0.1.6 / 2008-12-13
+
   * Major Features
   * Include files in `_includes` with `{% include x.textile %}`
 
 ## 0.1.5 / 2008-12-12
 
 ### Major Enhancements
+
   * Code highlighting with Pygments if `--pygments` is specified
   * Disable true LSI by default, enable with `--lsi`
 
 ### Minor Enhancements
+
   * Output informative message if RDiscount is not available (@JackDanger)
   * Bug Fixes
   * Prevent Jekyll from picking up the output directory as a source (@JackDanger)
   * Skip `related_posts` when there is only one post (@JackDanger)
 
 ## 0.1.4 / 2008-12-08
+
   * Bug Fixes
   * DATA does not work properly with rubygems
 
 ## 0.1.3 / 2008-12-06
+
   * Major Features
   * Markdown support (@vanpelt)
   * Mephisto and CSV converters (@vanpelt)
@@ -1825,21 +2011,24 @@
   * Accept both `\r\n` and `\n` in YAML header (@vanpelt)
 
 ## 0.1.2 / 2008-11-22
+
   * Major Features
   * Add a real "related posts" implementation using Classifier
   * Command Line Changes
-  * Allow cli to be called with 0, 1, or 2 args intuiting dir paths
-      if they are omitted
+  * Allow cli to be called with 0, 1, or 2 args intuiting dir paths if they are omitted
 
 ## 0.1.1 / 2008-11-22
+
   * Minor Additions
   * Posts now support introspectional data e.g. `{{ page.url }}`
 
 ## 0.1.0 / 2008-11-05
+
   * First release
   * Converts posts written in Textile
   * Converts regular site pages
   * Simple copy of binary files
 
 ## 0.0.0 / 2008-10-19
+
   * Birthday!
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..614de1c
--- /dev/null
+++ b/ISSUE_TEMPLATE.md
@@ -0,0 +1,20 @@
+###### What version of Jekyll are you using (`jekyll -v`)?
+
+
+
+###### What operating system are you using?
+
+
+
+###### What did you do?
+(Please include the content causing the issue, any relevant configuration settings, and the command you ran)
+
+
+
+###### What did you expect to see?
+
+
+
+###### What did you see instead?
+
+
diff --git a/LICENSE b/LICENSE
index 527166b..94dbfc3 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2008-2015 Tom Preston-Werner
+Copyright (c) 2008-2016 Tom Preston-Werner
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.markdown b/README.markdown
index b1dfae4..0e37c53 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,12 +1,18 @@
 # [Jekyll](http://jekyllrb.com/)
 
-[![Gem Version](https://img.shields.io/gem/v/jekyll.svg)](https://rubygems.org/gems/jekyll)
-[![Build Status](https://img.shields.io/travis/jekyll/jekyll/master.svg)](https://travis-ci.org/jekyll/jekyll)
-[![Code Climate](https://img.shields.io/codeclimate/github/jekyll/jekyll.svg)](https://codeclimate.com/github/jekyll/jekyll)
-[![Dependency Status](https://img.shields.io/gemnasium/jekyll/jekyll.svg)](https://gemnasium.com/jekyll/jekyll)
-[![Security](https://hakiri.io/github/jekyll/jekyll/master.svg)](https://hakiri.io/github/jekyll/jekyll/master)
-
-By Tom Preston-Werner, Nick Quaranto, Parker Moore, and many [awesome contributors](https://github.com/jekyll/jekyll/graphs/contributors)!
+[![Gem Version](https://img.shields.io/gem/v/jekyll.svg)][ruby-gems]
+[![Build Status](https://travis-ci.org/jekyll/jekyll.svg?branch=master)][travis]
+[![Test Coverage](https://codeclimate.com/github/jekyll/jekyll/badges/coverage.svg)][coverage]
+[![Code Climate](https://codeclimate.com/github/jekyll/jekyll/badges/gpa.svg)][codeclimate]
+[![Dependency Status](https://gemnasium.com/jekyll/jekyll.svg)][gemnasium]
+[![Security](https://hakiri.io/github/jekyll/jekyll/master.svg)][hakiri]
+
+[ruby-gems]: https://rubygems.org/gems/jekyll
+[gemnasium]: https://gemnasium.com/jekyll/jekyll
+[codeclimate]: https://codeclimate.com/github/jekyll/jekyll
+[coverage]: https://codeclimate.com/github/jekyll/jekyll/coverage
+[hakiri]: https://hakiri.io/github/jekyll/jekyll/master
+[travis]: https://travis-ci.org/jekyll/jekyll
 
 Jekyll is a simple, blog-aware, static site generator perfect for personal, project, or organization sites. Think of it like a file-based CMS, without all the complexity. Jekyll takes your content, renders Markdown and Liquid templates, and spits out a complete, static website ready to be served by Apache, Nginx or another web server. Jekyll is the engine behind [GitHub Pages](http://pages.github.com), which you can use to host sites right from your GitHub repositories.
 
@@ -29,7 +35,7 @@ See: http://jekyllrb.com/docs/troubleshooting/#jekyll-amp-mac-os-x-1011
 ## Code of Conduct
 
 In order to have a more open and welcoming community, Jekyll adheres to a
-[code of conduct](CONDUCT.md) adapted from the Ruby on Rails code of
+[code of conduct](CONDUCT.markdown) adapted from the Ruby on Rails code of
 conduct.
 
 Please adhere to this code of conduct in any interactions you have in the
diff --git a/Rakefile b/Rakefile
index ff473e6..e3f99c4 100644
--- a/Rakefile
+++ b/Rakefile
@@ -7,6 +7,8 @@ require 'yaml'
 $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w[lib]))
 require 'jekyll/version'
 
+Dir.glob('rake/**.rake').each { |f| import f }
+
 #############################################################################
 #
 # Helper functions
@@ -14,13 +16,17 @@ require 'jekyll/version'
 #############################################################################
 
 def name
-  'jekyll'.freeze
+  "jekyll"
 end
 
 def version
   Jekyll::VERSION
 end
 
+def docs_name
+  "#{name}-docs"
+end
+
 def gemspec_file
   "#{name}.gemspec"
 end
@@ -124,180 +130,3 @@ desc "Open an irb session preloaded with this library"
 task :console do
   sh "irb -rubygems -r ./lib/#{name}.rb"
 end
-
-#############################################################################
-#
-# Site tasks - http://jekyllrb.com
-#
-#############################################################################
-
-namespace :site do
-  desc "Generate and view the site locally"
-  task :preview do
-    require "launchy"
-    require "jekyll"
-
-    # Yep, it's a hack! Wait a few seconds for the Jekyll site to generate and
-    # then open it in a browser. Someday we can do better than this, I hope.
-    Thread.new do
-      sleep 4
-      puts "Opening in browser..."
-      Launchy.open("http://localhost:4000")
-    end
-
-    # Generate the site in server mode.
-    puts "Running Jekyll..."
-    options = {
-      "source"      => File.expand_path("site"),
-      "destination" => File.expand_path("site/_site"),
-      "watch"       => true,
-      "serving"     => true
-    }
-    Jekyll::Commands::Build.process(options)
-    Jekyll::Commands::Serve.process(options)
-  end
-
-  desc "Generate the site"
-  task :generate => [:history, :version_file] do
-    require "jekyll"
-    Jekyll::Commands::Build.process({
-      "source"      => File.expand_path("site"),
-      "destination" => File.expand_path("site/_site")
-    })
-  end
-
-  desc "Update normalize.css library to the latest version and minify"
-  task :update_normalize_css do
-    Dir.chdir("site/_sass") do
-      sh 'curl "http://necolas.github.io/normalize.css/latest/normalize.css" -o "normalize.scss"'
-      sh 'sass "normalize.scss":"_normalize.scss" --style compressed'
-      rm ['normalize.scss', Dir.glob('*.map')].flatten
-    end
-  end
-
-  desc "Commit the local site to the gh-pages branch and publish to GitHub Pages"
-  task :publish => [:history, :version_file] do
-    # Ensure the gh-pages dir exists so we can generate into it.
-    puts "Checking for gh-pages dir..."
-    unless File.exist?("./gh-pages")
-      puts "Creating gh-pages dir..."
-      sh "git clone git at github.com:jekyll/jekyll gh-pages"
-    end
-
-    # Ensure latest gh-pages branch history.
-    Dir.chdir('gh-pages') do
-      sh "git checkout gh-pages"
-      sh "git pull origin gh-pages"
-    end
-
-    # Proceed to purge all files in case we removed a file in this release.
-    puts "Cleaning gh-pages directory..."
-    purge_exclude = %w[
-      gh-pages/.
-      gh-pages/..
-      gh-pages/.git
-      gh-pages/.gitignore
-    ]
-    FileList["gh-pages/{*,.*}"].exclude(*purge_exclude).each do |path|
-      sh "rm -rf #{path}"
-    end
-
-    # Copy site to gh-pages dir.
-    puts "Building site into gh-pages branch..."
-    ENV['JEKYLL_ENV'] = 'production'
-    require "jekyll"
-    Jekyll::Commands::Build.process({
-      "source"       => File.expand_path("site"),
-      "destination"  => File.expand_path("gh-pages"),
-      "sass"         => { "style" => "compressed" }
-    })
-
-    File.open('gh-pages/.nojekyll', 'wb') { |f| f.puts(":dog: food.") }
-
-    # Commit and push.
-    puts "Committing and pushing to GitHub Pages..."
-    sha = `git rev-parse HEAD`.strip
-    Dir.chdir('gh-pages') do
-      sh "git add ."
-      sh "git commit --allow-empty -m 'Updating to #{sha}.'"
-      sh "git push origin gh-pages"
-    end
-    puts 'Done.'
-  end
-
-  desc "Create a nicely formatted history page for the jekyll site based on the repo history."
-  task :history do
-    if File.exist?("History.markdown")
-      history_file = File.read("History.markdown")
-      front_matter = {
-        "layout" => "docs",
-        "title" => "History",
-        "permalink" => "/docs/history/"
-      }
-      Dir.chdir('site/_docs/') do
-        File.open("history.md", "w") do |file|
-          file.write("#{front_matter.to_yaml}---\n\n")
-          file.write(converted_history(history_file))
-        end
-      end
-    else
-      abort "You seem to have misplaced your History.markdown file. I can haz?"
-    end
-  end
-
-  desc "Write the site latest_version.txt file"
-  task :version_file do
-    File.open('site/latest_version.txt', 'wb') { |f| f.puts(version) } unless version =~ /(beta|rc|alpha)/i
-  end
-
-  namespace :releases do
-    desc "Create new release post"
-    task :new, :version do |t, args|
-      raise "Specify a version: rake site:releases:new['1.2.3']" unless args.version
-      today = Time.new.strftime('%Y-%m-%d')
-      release = args.version.to_s
-      filename = "site/_posts/#{today}-jekyll-#{release.split('.').join('-')}-released.markdown"
-
-      File.open(filename, "wb") do |post|
-        post.puts("---")
-        post.puts("layout: news_item")
-        post.puts("title: 'Jekyll #{release} Released'")
-        post.puts("date: #{Time.new.strftime('%Y-%m-%d %H:%M:%S %z')}")
-        post.puts("author: ")
-        post.puts("version: #{release}")
-        post.puts("categories: [release]")
-        post.puts("---")
-        post.puts
-        post.puts
-      end
-
-      puts "Created #{filename}"
-    end
-  end
-end
-
-#############################################################################
-#
-# Packaging tasks
-#
-#############################################################################
-
-desc "Release #{name} v#{version}"
-task :release => :build do
-  unless `git branch` =~ /^\* master$/
-    puts "You must be on the master branch to release!"
-    exit!
-  end
-  sh "git commit --allow-empty -m 'Release :gem: #{version}'"
-  sh "git tag v#{version}"
-  sh "git push origin master"
-  sh "git push origin v#{version}"
-  sh "gem push pkg/#{name}-#{version}.gem"
-end
-
-desc "Build #{name} v#{version} into pkg/"
-task :build do
-  mkdir_p "pkg"
-  sh "gem build #{gemspec_file}"
-  sh "mv #{gem_file} pkg"
-end
diff --git a/benchmark/end-with-vs-regexp b/benchmark/end-with-vs-regexp
index cb849f4..76f0312 100644
--- a/benchmark/end-with-vs-regexp
+++ b/benchmark/end-with-vs-regexp
@@ -4,10 +4,12 @@ Benchmark.ips do |x|
   path_without_ending_slash = '/some/very/very/long/path/to/a/file/i/like'
   x.report('no slash regexp')    { path_without_ending_slash =~ /\/$/ }
   x.report('no slash end_with?') { path_without_ending_slash.end_with?("/")  }
+  x.report('no slash [-1, 1]') { path_without_ending_slash[-1, 1] == "/"  }
 end
 
 Benchmark.ips do |x|
   path_with_ending_slash = '/some/very/very/long/path/to/a/file/i/like/'
   x.report('slash regexp')    { path_with_ending_slash =~ /\/$/ }
   x.report('slash end_with?') { path_with_ending_slash.end_with?("/")  }
+  x.report('slash [-1, 1]')   { path_with_ending_slash[-1, 1] == "/"  }
 end
diff --git a/benchmark/file-dir-ensure-trailing-slash b/benchmark/file-dir-ensure-trailing-slash
new file mode 100644
index 0000000..aecfc03
--- /dev/null
+++ b/benchmark/file-dir-ensure-trailing-slash
@@ -0,0 +1,54 @@
+#!/usr/bin/env ruby
+require 'benchmark/ips'
+
+# For this pull request, which changes Page#dir
+# https://github.com/jekyll/jekyll/pull/4403
+
+FORWARD_SLASH = '/'.freeze
+
+def pre_pr(url)
+  url[-1, 1] == FORWARD_SLASH ? url : File.dirname(url)
+end
+
+def pr(url)
+  if url.end_with?(FORWARD_SLASH)
+    url
+  else
+    url_dir = File.dirname(url)
+    url_dir.end_with?(FORWARD_SLASH) ? url_dir : "#{url_dir}/"
+  end
+end
+
+def envygeeks(url)
+  return url if url.end_with?(FORWARD_SLASH) || url == FORWARD_SLASH
+
+  url = File.dirname(url)
+  url == FORWARD_SLASH ? url : "#{url}/"
+end
+
+# Just a slash
+Benchmark.ips do |x|
+  path = '/'
+  x.report("pre_pr:#{path}")    { pre_pr(path) }
+  x.report("pr:#{path}")        { pr(path) }
+  x.report("envygeeks:#{path}") { pr(path) }
+  x.compare!
+end
+
+# No trailing slash
+Benchmark.ips do |x|
+  path = '/some/very/very/long/path/to/a/file/i/like'
+  x.report("pre_pr:#{path}")    { pre_pr(path) }
+  x.report("pr:#{path}")        { pr(path) }
+  x.report("envygeeks:#{path}") { pr(path) }
+  x.compare!
+end
+
+# No trailing slash
+Benchmark.ips do |x|
+  path = '/some/very/very/long/path/to/a/file/i/like/'
+  x.report("pre_pr:#{path}")    { pre_pr(path) }
+  x.report("pr:#{path}")        { pr(path) }
+  x.report("envygeeks:#{path}") { pr(path) }
+  x.compare!
+end
diff --git a/bin/jekyll b/bin/jekyll
index 67705b5..43364b9 100755
--- a/bin/jekyll
+++ b/bin/jekyll
@@ -1,15 +1,11 @@
 #!/usr/bin/env ruby
 STDOUT.sync = true
 
-$:.unshift File.join(File.dirname(__FILE__), *%w{ .. lib })
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w( .. lib ))
 
 require 'jekyll'
 require 'mercenary'
 
-Jekyll::External.require_if_present(
-  Jekyll::External.blessed_gems
-)
-
 Jekyll::PluginManager.require_from_bundler
 
 Jekyll::Deprecator.process(ARGV)
@@ -26,16 +22,29 @@ Mercenary.program(:jekyll) do |p|
   p.option 'layouts_dir', '--layouts DIR', String, 'Layouts directory (defaults to ./_layouts)'
   p.option 'profile', '--profile', 'Generate a Liquid rendering profile'
 
+  Jekyll::External.require_if_present(Jekyll::External.blessed_gems) do |g|
+    cmd = g.split('-').last
+    p.command(cmd.to_sym) do |c|
+      c.syntax cmd
+      c.action do
+        Jekyll.logger.abort_with "You must install the '#{g}' gem to use the 'jekyll #{cmd}' command."
+      end
+    end
+  end
+
   Jekyll::Command.subclasses.each { |c| c.init_with_program(p) }
 
-  p.action do |args, options|
+  p.action do |args, _|
     if args.empty?
       Jekyll.logger.error "A subcommand is required."
       puts p
       abort
     else
-      unless p.has_command?(args.first)
-        Jekyll.logger.abort_with "Invalid command. Use --help for more information"
+      subcommand = args.first
+      unless p.has_command? subcommand
+        Jekyll.logger.abort_with "fatal: 'jekyll #{args.first}' could not" \
+          " be found. You may need to install the jekyll-#{args.first} gem" \
+          " or a related gem to be able to use this subcommand."
       end
     end
   end
diff --git a/features/collections.feature b/features/collections.feature
index d97918b..ad17a89 100644
--- a/features/collections.feature
+++ b/features/collections.feature
@@ -8,12 +8,13 @@ Feature: Collections
     And I have fixture collections
     And I have a configuration file with "collections" set to "['methods']"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Collections: <p>Use <code class=\"highlighter-rouge\">Jekyll.configuration</code> to build a full configuration for use w/Jekyll.</p>\n\n<p>Whatever: foo.bar</p>\n<p>Signs are nice</p>\n<p><code class=\"highlighter-rouge\">Jekyll.sanitized_path</code> is used to make sure your path is in your source.</p>\n<p>Run your generators! default</p>\n<p>Page without title.</p>\n<p>Run your generators! default</p>" in "_site/index.html"
     And the "_site/methods/configuration.html" file should not exist
 
   Scenario: Rendered collection
-    Given I have an "index.html" page that contains "Collections: {{ site.collections }}"
+    Given I have an "index.html" page that contains "Collections: output => {{ site.collections[0].output }} label => {{ site.collections[0].label }}"
     And I have an "collection_metadata.html" page that contains "Methods metadata: {{ site.collections[0].foo }} {{ site.collections[0] }}"
     And I have fixture collections
     And I have a "_config.yml" file with content:
@@ -24,9 +25,10 @@ Feature: Collections
         foo:   bar
     """
     When I run jekyll build
-    Then the _site directory should exist
-    And I should see "Collections: {\"output\"=>true" in "_site/index.html"
-    And I should see "\"label\"=>\"methods\"," in "_site/index.html"
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "Collections: output => true" in "_site/index.html"
+    And I should see "label => methods" in "_site/index.html"
     And I should see "Methods metadata: bar" in "_site/collection_metadata.html"
     And I should see "<p>Whatever: foo.bar</p>" in "_site/methods/configuration.html"
 
@@ -41,11 +43,12 @@ Feature: Collections
         permalink: /:collection/:path/
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<p>Whatever: foo.bar</p>" in "_site/methods/configuration/index.html"
 
   Scenario: Rendered document in a layout
-    Given I have an "index.html" page that contains "Collections: {{ site.collections }}"
+    Given I have an "index.html" page that contains "Collections: output => {{ site.collections[0].output }} label => {{ site.collections[0].label }} foo => {{ site.collections[0].foo }}"
     And I have a default layout that contains "<div class='title'>Tom Preston-Werner</div> {{content}}"
     And I have fixture collections
     And I have a "_config.yml" file with content:
@@ -56,9 +59,11 @@ Feature: Collections
         foo:   bar
     """
     When I run jekyll build
-    Then the _site directory should exist
-    And I should see "Collections: {\"output\"=>true" in "_site/index.html"
-    And I should see "\"label\"=>\"methods\"," in "_site/index.html"
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "Collections: output => true" in "_site/index.html"
+    And I should see "label => methods" in "_site/index.html"
+    And I should see "foo => bar" in "_site/index.html"
     And I should see "<p>Run your generators! default</p>" in "_site/methods/site/generate.html"
     And I should see "<div class='title'>Tom Preston-Werner</div>" in "_site/methods/site/generate.html"
 
@@ -71,7 +76,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Collections: _methods/configuration.md _methods/escape-\+ #%20\[\].md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html"
 
   Scenario: Collections specified as an hash
@@ -83,7 +89,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Collections: _methods/configuration.md _methods/escape-\+ #%20\[\].md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html"
 
   Scenario: All the documents
@@ -95,7 +102,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "All documents: _methods/configuration.md _methods/escape-\+ #%20\[\].md _methods/sanitized_path.md _methods/site/generate.md _methods/site/initialize.md _methods/um_hi.md" in "_site/index.html"
 
   Scenario: Documents have an output attribute, which is the converted HTML
@@ -107,7 +115,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "First document's output: <p>Use <code class=\"highlighter-rouge\">Jekyll.configuration</code> to build a full configuration for use w/Jekyll.</p>\n\n<p>Whatever: foo.bar</p>" in "_site/index.html"
 
   Scenario: Filter documents by where
@@ -119,7 +128,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Item count: 2" in "_site/index.html"
 
   Scenario: Sort by title
@@ -131,7 +141,8 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "1. of 7: <p>Page without title.</p>" in "_site/index.html"
 
   Scenario: Sort by relative_path
@@ -143,5 +154,22 @@ Feature: Collections
     - methods
     """
     When I run jekyll build
+    Then I should get a zero exit status
     Then the _site directory should exist
-    And I should see "Collections: Jekyll.configuration, Jekyll.escape, Jekyll.sanitized_path, Site#generate, , Site#generate," in "_site/index.html"
+    And I should see "Collections: Jekyll.configuration, Jekyll.escape, Jekyll.sanitized_path, Site#generate, Initialize, Site#generate, YAML with Dots," in "_site/index.html"
+
+  Scenario: Rendered collection with date/dateless filename
+    Given I have an "index.html" page that contains "Collections: {% for method in site.thanksgiving %}{{ method.title }} {% endfor %}"
+    And I have fixture collections
+    And I have a "_config.yml" file with content:
+    """
+    collections:
+      thanksgiving:
+        output: true
+    """
+    When I run jekyll build
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "Thanksgiving Black Friday" in "_site/index.html"
+    And I should see "Happy Thanksgiving" in "_site/thanksgiving/2015-11-26-thanksgiving.html"
+    And I should see "Black Friday" in "_site/thanksgiving/black-friday.html"
diff --git a/features/create_sites.feature b/features/create_sites.feature
index 898115c..031fa43 100644
--- a/features/create_sites.feature
+++ b/features/create_sites.feature
@@ -13,7 +13,8 @@ Feature: Create sites
   Scenario: Basic site
     Given I have an "index.html" file that contains "Basic Site"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site" in "_site/index.html"
 
   Scenario: Basic site with a post
@@ -22,7 +23,8 @@ Feature: Create sites
       | title   | date       | content          |
       | Hackers | 2009-03-27 | My First Exploit |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "My First Exploit" in "_site/2009/03/27/hackers.html"
 
   Scenario: Basic site with layout and a page
@@ -30,7 +32,8 @@ Feature: Create sites
     And I have an "index.html" page with layout "default" that contains "Basic Site with Layout"
     And I have a default layout that contains "Page Layout: {{ content }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout: Basic Site with Layout" in "_site/index.html"
 
   Scenario: Basic site with layout and a post
@@ -41,7 +44,8 @@ Feature: Create sites
       | Wargames | 2009-03-27 | default | The only winning move is not to play. |
     And I have a default layout that contains "Post Layout: {{ content }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
 
   Scenario: Basic site with layout inside a subfolder and a post
@@ -52,7 +56,8 @@ Feature: Create sites
       | Wargames | 2009-03-27 | post/simple | The only winning move is not to play. |
     And I have a post/simple layout that contains "Post Layout: {{ content }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
 
   Scenario: Basic site with layouts, pages, posts and files
@@ -75,7 +80,8 @@ Feature: Create sites
       | entry3 | 2009-05-27 | post   | content for entry3. |
       | entry4 | 2009-06-27 | post   | content for entry4. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page : Site contains 2 pages and 4 posts" in "_site/index.html"
     And I should see "No replacement \{\{ site.posts.size \}\}" in "_site/about.html"
     And I should see "" in "_site/another_file"
@@ -90,7 +96,8 @@ Feature: Create sites
     And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
     And I have an "_includes/about.textile" file that contains "Generated by Jekyll"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"
 
   Scenario: Basic site with subdir include tag
@@ -99,7 +106,8 @@ Feature: Create sites
     And I have an info directory
     And I have an "info/index.html" page that contains "Basic Site with subdir include tag: {% include about.textile %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site with subdir include tag: Generated by Jekyll" in "_site/info/index.html"
 
   Scenario: Basic site with nested include tag
@@ -108,7 +116,8 @@ Feature: Create sites
     And I have an "_includes/jekyll.textile" file that contains "Jekyll"
     And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"
 
   Scenario: Basic site with internal post linking
@@ -120,19 +129,22 @@ Feature: Create sites
       | entry1 | 2007-12-31 | post   | content for entry1. |
       | entry2 | 2008-01-01 | post   | content for entry2. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "URL: /2008/01/01/entry2/" in "_site/index.html"
 
   Scenario: Basic site with whitelisted dotfile
     Given I have an ".htaccess" file that contains "SomeDirective"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "SomeDirective" in "_site/.htaccess"
 
   Scenario: File was replaced by a directory
     Given I have a "test" file that contains "some stuff"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     When I delete the file "test"
     Given I have a test directory
     And I have a "test/index.html" file that contains "some other stuff"
@@ -146,13 +158,15 @@ Feature: Create sites
     And I have a "secret.html" page with published "false" that contains "Unpublished page"
 
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/index.html" file should exist
     And the "_site/public.html" file should exist
     But the "_site/secret.html" file should not exist
 
     When I run jekyll build --unpublished
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/index.html" file should exist
     And the "_site/public.html" file should exist
     And the "_site/secret.html" file should exist
@@ -164,9 +178,11 @@ Feature: Create sites
       | entry1 | 2020-12-31 | post   | content for entry1. |
       | entry2 | 2007-12-31 | post   | content for entry2. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "content for entry2" in "_site/2007/12/31/entry2.html"
     And the "_site/2020/12/31/entry1.html" file should not exist
     When I run jekyll build --future
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/2020/12/31/entry1.html" file should exist
diff --git a/features/drafts.feature b/features/drafts.feature
index 5d7982e..5a7f49f 100644
--- a/features/drafts.feature
+++ b/features/drafts.feature
@@ -10,7 +10,8 @@ Feature: Draft Posts
       | title  | date       | layout  | content        |
       | Recipe | 2009-03-27 | default | Not baked yet. |
     When I run jekyll build --drafts
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Not baked yet." in "_site/recipe.html"
 
   Scenario: Don't preview a draft
@@ -21,7 +22,8 @@ Feature: Draft Posts
       | title  | date       | layout  | content        |
       | Recipe | 2009-03-27 | default | Not baked yet. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/recipe.html" file should not exist
 
   Scenario: Don't preview a draft that is not published
@@ -32,7 +34,8 @@ Feature: Draft Posts
       | title  | date       | layout  | published | content        |
       | Recipe | 2009-03-27 | default | false     | Not baked yet. |
     When I run jekyll build --drafts
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/recipe.html" file should not exist
 
   Scenario: Use page.path variable
@@ -42,5 +45,6 @@ Feature: Draft Posts
       | title  | date       | layout | content                    |
       | Recipe | 2009-03-27 | simple | Post path: {{ page.path }} |
     When I run jekyll build --drafts
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post path: _drafts/recipe.markdown" in "_site/recipe.html"
diff --git a/features/embed_filters.feature b/features/embed_filters.feature
index d6f99fc..e3802fe 100644
--- a/features/embed_filters.feature
+++ b/features/embed_filters.feature
@@ -11,7 +11,8 @@ Feature: Embed filters
       | Star Wars | 2009-03-27 | default | These aren't the droids you're looking for. |
     And I have a default layout that contains "{{ site.time | date_to_xmlschema }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see today's date in "_site/2009/03/27/star-wars.html"
 
   Scenario: Escape text for XML
@@ -22,7 +23,8 @@ Feature: Embed filters
       | Star & Wars | 2009-03-27 | default | These aren't the droids you're looking for. |
     And I have a default layout that contains "{{ page.title | xml_escape }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Star & Wars" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Calculate number of words
@@ -33,7 +35,8 @@ Feature: Embed filters
       | Star Wars | 2009-03-27 | default | These aren't the droids you're looking for. |
     And I have a default layout that contains "{{ content | number_of_words }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "7" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Convert an array into a sentence
@@ -44,7 +47,8 @@ Feature: Embed filters
       | Star Wars | 2009-03-27 | default | [scifi, movies, force] | These aren't the droids you're looking for. |
     And I have a default layout that contains "{{ page.tags | array_to_sentence_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "scifi, movies, and force" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Markdownify a given string
@@ -55,7 +59,8 @@ Feature: Embed filters
       | Star Wars | 2009-03-27 | default | These aren't the droids you're looking for. |
     And I have a default layout that contains "By {{ '_Obi-wan_' | markdownify }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "By <p><em>Obi-wan</em></p>" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Sort by an arbitrary variable
@@ -68,38 +73,37 @@ Feature: Embed filters
       | Page-2 | default | 6     | Something |
     And I have a default layout that contains "{{ site.pages | sort:'value' | map:'title' | join:', ' }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see exactly "Page-2, Page-1" in "_site/page-1.html"
     And I should see exactly "Page-2, Page-1" in "_site/page-2.html"
 
   Scenario: Sort pages by the title
     Given I have a _layouts directory
+    And I have the following pages:
+      | title | layout  | content |
+      | Dog   | default | Run     |
+      | Bird  | default | Fly     |
     And I have the following page:
-      | title | layout | content |
-      | Dog | default | Run |
-    And I have the following page:
-      | title | layout | content |
-      | Bird | default | Fly |
-    And I have the following page:
-      | layout | content |
-      | default | Jump |
+      | layout  | content |
+      | default | Jump    |
     And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title' %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see exactly "The rule of 3: Jump, Fly, Run," in "_site/bird.html"
 
   Scenario: Sort pages by the title ordering pages without title last
     Given I have a _layouts directory
+    And I have the following pages:
+      | title | layout  | content |
+      | Dog   | default | Run     |
+      | Bird  | default | Fly     |
     And I have the following page:
-      | title | layout | content |
-      | Dog | default | Run |
-    And I have the following page:
-      | title | layout | content |
-      | Bird | default | Fly |
-    And I have the following page:
-      | layout | content |
-      | default | Jump |
+      | layout  | content |
+      | default | Jump    |
     And I have a default layout that contains "{% assign sorted_pages = site.pages | sort: 'title', 'last' %}The rule of {{ sorted_pages.size }}: {% for p in sorted_pages %}{{ p.content | strip_html | strip_newlines }}, {% endfor %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see exactly "The rule of 3: Fly, Run, Jump," in "_site/bird.html"
diff --git a/features/frontmatter_defaults.feature b/features/frontmatter_defaults.feature
index a9a64ae..47d81ab 100644
--- a/features/frontmatter_defaults.feature
+++ b/features/frontmatter_defaults.feature
@@ -12,7 +12,8 @@ Feature: frontmatter defaults
     And I have a configuration file with "defaults" set to "[{scope: {path: ""}, values: {layout: "pretty"}}]"
 
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "THIS IS THE LAYOUT: <p>just some post</p>" in "_site/2013/09/11/default-layout.html"
     And I should see "THIS IS THE LAYOUT: just some page" in "_site/index.html"
 
@@ -24,7 +25,8 @@ Feature: frontmatter defaults
     And I have an "index.html" page that contains "just {{page.custom}} by {{page.author}}"
     And I have a configuration file with "defaults" set to "[{scope: {path: ""}, values: {custom: "some special data", author: "Ben"}}]"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<p>some special data</p>\n<div>Ben</div>" in "_site/2013/09/11/default-data.html"
     And I should see "just some special data by Ben" in "_site/index.html"
 
@@ -48,7 +50,8 @@ Feature: frontmatter defaults
     And I have a configuration file with "defaults" set to "[{scope: {path: "special"}, values: {layout: "subfolder", description: "the special section"}}, {scope: {path: ""}, values: {layout: "root", description: "the webpage"}}]"
 
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "root: <p>info on the webpage</p>" in "_site/2013/10/14/about.html"
     And I should see "subfolder: <p>info on the special section</p>" in "_site/special/2013/10/14/about.html"
     And I should see "root: Overview for the webpage" in "_site/index.html"
@@ -71,11 +74,32 @@ Feature: frontmatter defaults
     And I have a configuration file with "defaults" set to "[{scope: {path: "special"}, values: {layout: "main"}}, {scope: {path: "special/_posts"}, values: {layout: "main"}}, {scope: {path: "_posts"}, values: {layout: "main"}}]"
 
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "main: <p>content of site/2013/10/14/about.html</p>" in "_site/2013/10/14/about.html"
     And I should see "main: <p>content of site/special/2013/10/14/about1.html</p>" in "_site/special/2013/10/14/about1.html"
     And I should see "main: <p>content of site/special/2013/10/14/about2.html</p>" in "_site/special/2013/10/14/about2.html"
 
+  Scenario: Use frontmatter scopes for subdirectories
+    Given I have a _layouts directory
+    And I have a main layout that contains "main: {{ content }}"
+
+    And I have a _posts/en directory
+    And I have the following post under "en":
+      | title | date       | content                               |
+      | helloworld | 2014-09-01 | {{page.lang}} is the current language |
+    And I have a _posts/de directory
+    And I have the following post under "de":
+      | title  | date       | content                                        |
+      | hallowelt | 2014-09-01 | {{page.lang}} is the current language |
+
+    And I have a configuration file with "defaults" set to "[{scope: {path: "_posts/en"}, values: {layout: "main", lang: "en"}}, {scope: {path: "_posts/de"}, values: {layout: "main", lang: "de"}}]"
+
+    When I run jekyll build
+    Then the _site directory should exist
+    And I should see "main: <p>en is the current language</p>" in "_site/2014/09/01/helloworld.html"
+    And I should see "main: <p>de is the current language</p>" in "_site/2014/09/01/hallowelt.html"
+
   Scenario: Override frontmatter defaults by type
     Given I have a _posts directory
     And I have the following post:
@@ -132,7 +156,8 @@ Feature: frontmatter defaults
             myval: "Test"
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Value: Test" in "_site/slides/slide1.html"
 
   Scenario: Override frontmatter defaults inside a collection
@@ -159,7 +184,8 @@ Feature: frontmatter defaults
             myval: "Test"
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Value: Override" in "_site/slides/slide2.html"
 
   Scenario: Deep merge frontmatter defaults
diff --git a/features/hooks.feature b/features/hooks.feature
index 489f256..48b2884 100644
--- a/features/hooks.feature
+++ b/features/hooks.feature
@@ -24,7 +24,8 @@ Feature: Hooks
     end
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "mytinypage" in "_site/foo.html"
 
   Scenario: Modify the payload before rendering the site
@@ -37,7 +38,8 @@ Feature: Hooks
     end
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "myparam!" in "_site/index.html"
 
   Scenario: Modify the site contents after reading
@@ -51,7 +53,8 @@ Feature: Hooks
     end
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/page1.html" file should not exist
     And I should see "page2" in "_site/page2.html"
 
@@ -67,7 +70,8 @@ Feature: Hooks
     """
     And I have a "page1.html" page that contains "page1"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "page1" in "_site/firstpage.html"
 
   Scenario: Alter a page right after it is initialized
@@ -81,7 +85,8 @@ Feature: Hooks
     """
     And I have a "page1.html" page that contains "page1"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "page1" in "_site/renamed.html"
 
   Scenario: Alter the payload for one page but not another
@@ -89,11 +94,11 @@ Feature: Hooks
     And I have a "_plugins/ext.rb" file with content:
     """
     Jekyll::Hooks.register :pages, :pre_render do |page, payload|
-      payload['myparam'] = 'special' if page.name == 'page1.html'
+      payload['page']['myparam'] = 'special' if page.name == 'page1.html'
     end
     """
-    And I have a "page1.html" page that contains "{{ myparam }}"
-    And I have a "page2.html" page that contains "{{ myparam }}"
+    And I have a "page1.html" page that contains "{{ page.myparam }}"
+    And I have a "page2.html" page that contains "{{ page.myparam }}"
     When I run jekyll build
     Then I should see "special" in "_site/page1.html"
     And I should not see "special" in "_site/page2.html"
@@ -138,7 +143,8 @@ Feature: Hooks
       | title  | date       | layout | content               |
       | entry1 | 2015-03-14 | nil    | {{ page.harold }} |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "pbagrag sbe ragel1." in "_site/2015/03/14/entry1.html"
 
   Scenario: Alter the payload for certain posts
@@ -268,7 +274,8 @@ Feature: Hooks
     {{ site.memes.first.text }}
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "all your base are belong to us" in "_site/index.html"
 
   Scenario: Update a document after rendering it, but before writing it to disk
@@ -294,7 +301,8 @@ Feature: Hooks
     {{ page.text }}
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<p class=\"meme\">all your base are belong to us" in "_site/memes/doc1.html"
 
   Scenario: Perform an action after every document is written
@@ -322,5 +330,6 @@ Feature: Hooks
     {{ page.text }}
     """
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Wrote document 0" in "_site/document-build.log"
diff --git a/features/include_tag.feature b/features/include_tag.feature
index c7e03de..c8ebf71 100644
--- a/features/include_tag.feature
+++ b/features/include_tag.feature
@@ -15,11 +15,12 @@ Feature: Include tags
       | Ignore params if unused             | 2013-03-21 | html | {% include ignore.html date="today" %}                                                                                  |
       | List multiple parameters            | 2013-03-21 | html | {% include params.html date="today" start="tomorrow" %}                                                                 |
       | Dont keep parameters                | 2013-03-21 | html | {% include ignore.html param="test" %}\n{% include header.html %}                                                       |
-      | Allow params with spaces and quotes | 2013-04-07 | html | {% include params.html cool="param with spaces" super="\"quoted\"" single='has "quotes"' escaped='\'single\' quotes' %} |
+      | Allow params with spaces and quotes | 2013-04-07 | html | {% include params.html cool="param with spaces" super="\\"quoted\\"" single='has "quotes"' escaped='\\'single\\' quotes' %} |
       | Parameter syntax                    | 2013-04-12 | html | {% include params.html param1_or_2="value" %}                                                                           |
       | Pass a variable                     | 2013-06-22 | html | {% assign var = 'some text' %}{% include params.html local=var title=page.title %}                                    |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<header>My awesome blog header: myparam</header>" in "_site/2013/03/21/include-files.html"
     And I should not see "myparam" in "_site/2013/03/21/ignore-params-if-unused.html"
     And I should see "<li>date = today</li>" in "_site/2013/03/21/list-multiple-parameters.html"
@@ -44,7 +45,8 @@ Feature: Include tags
     | include_file2 | parametrized.html |
     And I have an "index.html" page that contains "{% include {{site.include_file1}} %} that {% include {{site.include_file2}} what='parameters' %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "a snippet that works with parameters" in "_site/index.html"
 
   Scenario: Include a variable file in a loop
@@ -53,7 +55,8 @@ Feature: Include tags
     And I have an "_includes/two.html" file that contains "two"
     And I have an "index.html" page with files "[one.html, two.html]" that contains "{% for file in page.files %}{% include {{file}} %} {% endfor %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "one two" in "_site/index.html"
 
   Scenario: Include a file with variables and filters
@@ -64,7 +67,8 @@ Feature: Include tags
     | include_file | one   |
     And I have an "index.html" page that contains "{% include {{ site.include_file | append: '.html' }} %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "one included" in "_site/index.html"
 
   Scenario: Include a file with partial variables
@@ -75,5 +79,28 @@ Feature: Include tags
     | include_file | one   |
     And I have an "index.html" page that contains "{% include {{ site.include_file }}.html %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "one included" in "_site/index.html"
+
+  Scenario: Include a file and rebuild when include content is changed
+    Given I have an _includes directory
+    And I have an "_includes/one.html" file that contains "include"
+    And I have an "index.html" page that contains "{% include one.html %}"
+    When I run jekyll build
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "include" in "_site/index.html"
+    When I wait 1 second
+    Then I have an "_includes/one.html" file that contains "include content changed"
+    When I run jekyll build
+    Then I should see "include content changed" in "_site/index.html"
+
+  Scenario: Include a file with multiple variables
+    Given I have an _includes directory
+    And I have an "_includes/header-en.html" file that contains "include"
+    And I have an "index.html" page that contains "{% assign name = 'header' %}{% assign locale = 'en' %}{% include {{name}}-{{locale}}.html %}"
+    When I run jekyll build
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "include" in "_site/index.html"
diff --git a/features/incremental_rebuild.feature b/features/incremental_rebuild.feature
index fb95e0c..128f580 100644
--- a/features/incremental_rebuild.feature
+++ b/features/incremental_rebuild.feature
@@ -11,10 +11,12 @@ Feature: Incremental rebuild
       | Wargames | 2009-03-27 | default | The only winning move is not to play. |
     And I have a default layout that contains "Post Layout: {{ content }}"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post Layout: <p>The only winning move is not to play.</p>" in "_site/2009/03/27/wargames.html"
 
   Scenario: Generate a metadata file
@@ -25,12 +27,14 @@ Feature: Incremental rebuild
   Scenario: Rebuild when content is changed
     Given I have an "index.html" file that contains "Basic Site"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site" in "_site/index.html"
     When I wait 1 second
     Then I have an "index.html" file that contains "Bacon Site"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Bacon Site" in "_site/index.html"
 
   Scenario: Rebuild when layout is changed
@@ -38,12 +42,14 @@ Feature: Incremental rebuild
     And I have an "index.html" page with layout "default" that contains "Basic Site with Layout"
     And I have a default layout that contains "Page Layout: {{ content }}"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout: Basic Site with Layout" in "_site/index.html"
     When I wait 1 second
     Then I have a default layout that contains "Page Layout Changed: {{ content }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout Changed: Basic Site with Layout" in "_site/index.html"
 
   Scenario: Rebuild when an include is changed
@@ -51,10 +57,12 @@ Feature: Incremental rebuild
     And I have an "index.html" page that contains "Basic Site with include tag: {% include about.textile %}"
     And I have an "_includes/about.textile" file that contains "Generated by Jekyll"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site with include tag: Generated by Jekyll" in "_site/index.html"
     When I wait 1 second
     Then I have an "_includes/about.textile" file that contains "Regenerated by Jekyll"
     When I run jekyll build -I
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Basic Site with include tag: Regenerated by Jekyll" in "_site/index.html"
diff --git a/features/layout_data.feature b/features/layout_data.feature
new file mode 100644
index 0000000..c2af5b7
--- /dev/null
+++ b/features/layout_data.feature
@@ -0,0 +1,70 @@
+Feature: Layout data
+  As a hacker who likes to avoid repetition
+  I want to be able to embed data into my layouts
+  In order to make the layouts slightly dynamic
+
+  Scenario: Use custom layout data
+    Given I have a _layouts directory
+    And I have a "_layouts/custom.html" file with content:
+      """
+      ---
+      foo: my custom data
+      ---
+      {{ content }} foo: {{ layout.foo }}
+      """
+    And I have an "index.html" page with layout "custom" that contains "page content"
+    When I run jekyll build
+    Then the "_site/index.html" file should exist
+    And I should see "page content\n foo: my custom data" in "_site/index.html"
+
+  Scenario: Inherit custom layout data
+    Given I have a _layouts directory
+    And I have a "_layouts/custom.html" file with content:
+      """
+      ---
+      layout: base
+      foo: my custom data
+      ---
+      {{ content }}
+      """
+    And I have a "_layouts/base.html" file with content:
+      """
+      {{ content }} foo: {{ layout.foo }}
+      """
+    And I have an "index.html" page with layout "custom" that contains "page content"
+    When I run jekyll build
+    Then the "_site/index.html" file should exist
+    And I should see "page content\n foo: my custom data" in "_site/index.html"
+
+  Scenario: Inherit custom layout data and clear when not present
+    Given I have a _layouts directory
+    And I have a "_layouts/default.html" file with content:
+      """
+      ---
+      bar: i'm default
+      ---
+      {{ content }} foo: '{{ layout.foo }}' bar: '{{ layout.bar }}'
+      """
+    And I have a "_layouts/special.html" file with content:
+      """
+      ---
+      layout: default
+      foo: my special data
+      bar: im special
+      ---
+      {{ content }}
+      """
+    And I have a "_layouts/page.html" file with content:
+      """
+      ---
+      layout: default
+      bar: im page
+      ---
+      {{ content }}
+      """
+    And I have an "index.html" page with layout "special" that contains "page content"
+    And I have an "jekyll.html" page with layout "page" that contains "page content"
+    When I run jekyll build
+    Then the "_site/index.html" file should exist
+    And I should see "page content\n foo: 'my special data' bar: 'im special'" in "_site/index.html"
+    And I should see "page content\n foo: '' bar: 'im page'" in "_site/jekyll.html"
diff --git a/features/markdown.feature b/features/markdown.feature
index c0eeb25..3649a6d 100644
--- a/features/markdown.feature
+++ b/features/markdown.feature
@@ -11,7 +11,8 @@ Feature: Markdown
       | title   | date       | content    | type     |
       | Hackers | 2009-03-27 | # My Title | markdown |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Index" in "_site/index.html"
     And I should see "<h1 id=\"my-title\">My Title</h1>" in "_site/2009/03/27/hackers.html"
     And I should see "<h1 id=\"my-title\">My Title</h1>" in "_site/index.html"
@@ -27,6 +28,7 @@ Feature: Markdown
       | title   | date       | content    | type     |
       | Hackers | 2009-03-27 | # My Title | markdown |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Index" in "_site/index.html"
     And I should see "<h1 id=\"my-title\">My Title</h1>" in "_site/index.html"
diff --git a/features/permalinks.feature b/features/permalinks.feature
index 74f2e40..ca0482f 100644
--- a/features/permalinks.feature
+++ b/features/permalinks.feature
@@ -10,7 +10,8 @@ Feature: Fancy permalinks
       | None Permalink Schema | 2009-03-27 | Totally nothing. |
     And I have a configuration file with "permalink" set to "none"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally nothing." in "_site/none-permalink-schema.html"
 
   Scenario: Use pretty permalink schema
@@ -20,7 +21,8 @@ Feature: Fancy permalinks
       | Pretty Permalink Schema | 2009-03-27 | Totally wordpress. |
     And I have a configuration file with "permalink" set to "pretty"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally wordpress." in "_site/2009/03/27/pretty-permalink-schema/index.html"
 
   Scenario: Use pretty permalink schema for pages
@@ -29,7 +31,8 @@ Feature: Fancy permalinks
     And I have an "sitemap.xml" page that contains "Totally uhm, sitemap"
     And I have a configuration file with "permalink" set to "pretty"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally index" in "_site/index.html"
     And I should see "Totally awesome" in "_site/awesome/index.html"
     And I should see "Totally uhm, sitemap" in "_site/sitemap.xml"
@@ -41,7 +44,8 @@ Feature: Fancy permalinks
       | Custom Permalink Schema | stuff    | 2009-03-27 | Totally custom. |
     And I have a configuration file with "permalink" set to "/blog/:year/:month/:day/:title/"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally custom." in "_site/blog/2009/03/27/custom-permalink-schema/index.html"
 
   Scenario: Use custom permalink schema with category
@@ -51,7 +55,8 @@ Feature: Fancy permalinks
       | Custom Permalink Schema | stuff    | 2009-03-27 | Totally custom. |
     And I have a configuration file with "permalink" set to "/:categories/:title.html"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally custom." in "_site/stuff/custom-permalink-schema.html"
 
   Scenario: Use custom permalink schema with squished date
@@ -61,7 +66,8 @@ Feature: Fancy permalinks
       | Custom Permalink Schema | stuff    | 2009-03-27 | Totally custom. |
     And I have a configuration file with "permalink" set to "/:month-:day-:year/:title.html"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally custom." in "_site/03-27-2009/custom-permalink-schema.html"
 
   Scenario: Use custom permalink schema with date and time
@@ -74,7 +80,8 @@ Feature: Fancy permalinks
       | permalink   | "/:year:month:day:hour:minute:second.html" |
       | timezone    | UTC                |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally custom." in "_site/20090327223107.html"
 
   Scenario: Use per-post permalink
@@ -83,7 +90,8 @@ Feature: Fancy permalinks
       | title     | date       | permalink       | content |
       | Some post | 2013-04-14 | /custom/posts/1/ | bla bla |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the _site/custom/posts/1 directory should exist
     And I should see "bla bla" in "_site/custom/posts/1/index.html"
 
@@ -93,7 +101,8 @@ Feature: Fancy permalinks
       | title     | date       | permalink               | content |
       | Some post | 2013-04-14 | /custom/posts/some.html | bla bla |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the _site/custom/posts directory should exist
     And I should see "bla bla" in "_site/custom/posts/some.html"
 
@@ -102,7 +111,8 @@ Feature: Fancy permalinks
     And I have an "_posts/2009-03-27-Pretty-Permalink-Schema.md" page that contains "Totally wordpress"
     And I have a configuration file with "permalink" set to "pretty"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally wordpress." in "_site/2009/03/27/Pretty-Permalink-Schema/index.html"
 
   Scenario: Use custom permalink schema with cased file name
@@ -110,7 +120,8 @@ Feature: Fancy permalinks
     And I have an "_posts/2009-03-27-Custom-Schema.md" page with title "Custom Schema" that contains "Totally awesome"
     And I have a configuration file with "permalink" set to "/:year/:month/:day/:slug/"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally awesome" in "_site/2009/03/27/custom-schema/index.html"
 
   Scenario: Use pretty permalink schema with title containing underscore
@@ -118,5 +129,16 @@ Feature: Fancy permalinks
     And I have an "_posts/2009-03-27-Custom_Schema.md" page with title "Custom Schema" that contains "Totally awesome"
     And I have a configuration file with "permalink" set to "pretty"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Totally awesome" in "_site/2009/03/27/Custom_Schema/index.html"
+
+  Scenario: Use a non-HTML file extension in the permalink
+    Given I have a _posts directory
+    And I have an "_posts/2016-01-18-i-am-php.md" page with permalink "/2016/i-am-php.php" that contains "I am PHP"
+    And I have a "i-am-also-php.md" page with permalink "/i-am-also-php.php" that contains "I am also PHP"
+    When I run jekyll build
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "I am PHP" in "_site/2016/i-am-php.php"
+    And I should see "I am also PHP" in "_site/i-am-also-php.php"
diff --git a/features/plugins.feature b/features/plugins.feature
index a36c6c8..be01a4a 100644
--- a/features/plugins.feature
+++ b/features/plugins.feature
@@ -6,7 +6,8 @@ Feature: Configuring and using plugins
     Given I have an "index.html" file that contains "Whatever"
     And I have a configuration file with "gems" set to "[jekyll_test_plugin]"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Whatever" in "_site/index.html"
     And I should see "this is a test" in "_site/test.txt"
 
@@ -17,7 +18,8 @@ Feature: Configuring and using plugins
       | gems      | [jekyll_test_plugin] |
       | whitelist | []                   |
     When I run jekyll build --safe
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Whatever" in "_site/index.html"
     And the "_site/test.txt" file should not exist
 
@@ -28,7 +30,8 @@ Feature: Configuring and using plugins
       | gems      | [jekyll_test_plugin, jekyll_test_plugin_malicious] |
       | whitelist | [jekyll_test_plugin]                               |
     When I run jekyll build --safe
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Whatever" in "_site/index.html"
     And the "_site/test.txt" file should exist
     And I should see "this is a test" in "_site/test.txt"
diff --git a/features/post_data.feature b/features/post_data.feature
index 6ebfb27..79b92c2 100644
--- a/features/post_data.feature
+++ b/features/post_data.feature
@@ -11,7 +11,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post title: {{ page.title }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post title: Star Wars" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Use post.url variable
@@ -22,7 +23,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post url: {{ page.url }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post url: /2009/03/27/star-wars.html" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Use post.date variable
@@ -33,9 +35,24 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post date: {{ page.date | date_to_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post date: 27 Mar 2009" in "_site/2009/03/27/star-wars.html"
 
+  Scenario: Use post.date variable with invalid
+    Given I have a _posts directory
+    And I have a "_posts/2016-01-01-test.md" page with date "tuesday" that contains "I have a bad date."
+    When I run jekyll build
+    Then the _site directory should not exist
+    And I should see "Document '_posts/2016-01-01-test.md' does not have a valid date in the YAML front matter." in the build output
+
+  Scenario: Invalid date in filename
+    Given I have a _posts directory
+    And I have a "_posts/2016-22-01-test.md" page that contains "I have a bad date."
+    When I run jekyll build
+    Then the _site directory should not exist
+    And I should see "Document '_posts/2016-22-01-test.md' does not have a valid date in the filename." in the build output
+
   Scenario: Use post.id variable
     Given I have a _posts directory
     And I have a _layouts directory
@@ -44,7 +61,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post id: {{ page.id }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post id: /2009/03/27/star-wars" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Use post.content variable
@@ -55,7 +73,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post content: {{ content }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post content: <p>Luke, I am your father.</p>" in "_site/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in a folder
@@ -67,7 +86,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in a folder and has category in YAML
@@ -79,7 +99,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | film     | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/film/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in a folder and has categories in YAML
@@ -91,7 +112,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | [film, scifi]     | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/film/scifi/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in a folder and duplicated category is in YAML
@@ -103,7 +125,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | movies   | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.tags variable
@@ -114,7 +137,8 @@ Feature: Post data
       | Star Wars | 2009-05-18 | simple | twist | Luke, I am your father. |
     And I have a simple layout that contains "Post tags: {{ page.tags }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post tags: twist" in "_site/2009/05/18/star-wars.html"
 
   Scenario: Use post.categories variable when categories are in folders
@@ -127,7 +151,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post categories: scifi and movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when categories are in folders with mixed case
@@ -140,7 +165,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Luke, I am your father. |
     And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post categories: scifi and Movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in YAML
@@ -151,7 +177,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | movies   | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when category is in YAML and is mixed-case
@@ -162,7 +189,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Movies   | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: Movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when categories are in YAML
@@ -173,7 +201,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | ['scifi', 'movies'] | Luke, I am your father. |
     And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post categories: scifi and movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when categories are in YAML and are duplicated
@@ -184,7 +213,8 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | ['movies', 'movies'] | Luke, I am your father. |
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Superdirectories of _posts applied to post.categories
@@ -193,7 +223,8 @@ Feature: Post data
     And I have a _layouts directory
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Subdirectories of _posts not applied to post.categories
@@ -202,7 +233,8 @@ Feature: Post data
     And I have a _layouts directory
     And I have a simple layout that contains "Post category: {{ page.categories }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post category: movies" in "_site/movies/2009/03/27/star-wars.html"
 
   Scenario: Use post.categories variable when categories are in YAML with mixed case
@@ -214,7 +246,8 @@ Feature: Post data
       | Star Trek | 2013-03-17 | simple | ['SciFi', 'movies'] | Jean Luc, I am your father. |
     And I have a simple layout that contains "Post categories: {{ page.categories | array_to_sentence_string }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post categories: scifi and Movies" in "_site/scifi/movies/2009/03/27/star-wars.html"
     And I should see "Post categories: SciFi and movies" in "_site/scifi/movies/2013/03/17/star-trek.html"
 
@@ -224,7 +257,8 @@ Feature: Post data
       | title   | type | date       | content                      |
       | my-post | html | 2013-04-12 | Source path: {{ page.path }} |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Source path: <path_prefix>_posts/2013-04-12-my-post.html" in "_site/<dir>/2013/04/12/my-post.html"
 
     Examples:
@@ -233,14 +267,15 @@ Feature: Post data
       | dir        | dir/        |
       | dir/nested | dir/nested/ |
 
-  Scenario: Override page.path variable
+  Scenario: Cannot override page.path variable
     Given I have a _posts directory
     And I have the following post:
       | title    | date       | path               | content                      |
-      | override | 2013-04-12 | override-path.html | Custom path: {{ page.path }} |
+      | override | 2013-04-12 | override-path.html | Non-custom path: {{ page.path }} |
     When I run jekyll build
-    Then the _site directory should exist
-    And I should see "Custom path: override-path.html" in "_site/2013/04/12/override.html"
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "Non-custom path: _posts/2013-04-12-override.markdown" in "_site/2013/04/12/override.html"
 
   Scenario: Disable a post from being published
     Given I have a _posts directory
@@ -249,7 +284,8 @@ Feature: Post data
       | title     | date       | layout | published | content                 |
       | Star Wars | 2009-03-27 | simple | false     | Luke, I am your father. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/2009/03/27/star-wars.html" file should not exist
     And I should see "Published!" in "_site/index.html"
 
@@ -261,9 +297,22 @@ Feature: Post data
       | Star Wars | 2009-03-27 | simple | Darth Vader | Luke, I am your father. |
     And I have a simple layout that contains "Post author: {{ page.author }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Post author: Darth Vader" in "_site/2009/03/27/star-wars.html"
 
+  Scenario: Use a variable which is a reserved keyword in Ruby
+    Given I have a _posts directory
+    And I have a _layouts directory
+    And I have the following post:
+      | title   | date       | layout | class     | content                 |
+      | My post | 2016-01-21 | simple | kewl-post | Luke, I am your father. |
+    And I have a simple layout that contains "{{page.title}} has class {{page.class}}"
+    When I run jekyll build
+    Then I should get a zero exit status
+    And the _site directory should exist
+    And I should see "My post has class kewl-post" in "_site/2016/01/21/my-post.html"
+
   Scenario: Previous and next posts title
     Given I have a _posts directory
     And I have a _layouts directory
@@ -274,6 +323,7 @@ Feature: Post data
       | Terminator       | 2009-05-27 | ordered | Arnold      | Sayonara, baby          |
     And I have a ordered layout that contains "Previous post: {{ page.previous.title }} and next post: {{ page.next.title }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "next post: Some like it hot" in "_site/2009/03/27/star-wars.html"
     And I should see "Previous post: Some like it hot" in "_site/2009/05/27/terminator.html"
diff --git a/features/post_excerpts.feature b/features/post_excerpts.feature
index c66c527..7344000 100644
--- a/features/post_excerpts.feature
+++ b/features/post_excerpts.feature
@@ -12,7 +12,8 @@ Feature: Post excerpts
       | title  | date       | layout | content             |
       | entry1 | 2007-12-31 | post   | content for entry1. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see exactly "<p>content for entry1.</p>" in "_site/index.html"
 
   Scenario: An excerpt from a post with a layout
@@ -24,7 +25,8 @@ Feature: Post excerpts
       | title  | date       | layout | content             |
       | entry1 | 2007-12-31 | post   | content for entry1. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the _site/2007 directory should exist
     And the _site/2007/12 directory should exist
     And the _site/2007/12/31 directory should exist
@@ -41,7 +43,8 @@ Feature: Post excerpts
       | title  | date       | layout | content             |
       | entry1 | 2007-12-31 | post   | content for entry1. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the _site/2007 directory should exist
     And the _site/2007/12 directory should exist
     And the _site/2007/12/31 directory should exist
diff --git a/features/rendering.feature b/features/rendering.feature
index 01507cb..5031ef0 100644
--- a/features/rendering.feature
+++ b/features/rendering.feature
@@ -16,7 +16,8 @@ Feature: Rendering
     Given I have a "index.html" page with layout "simple" that contains "Hi there, Jekyll {{ jekyll.environment }}!"
     And I have a simple layout that contains "{{ content }}Ahoy, indeed!"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Hi there, Jekyll development!\nAhoy, indeed" in "_site/index.html"
 
   Scenario: Don't place asset files in layout
@@ -25,7 +26,8 @@ Feature: Rendering
     And I have a configuration file with "gems" set to "[jekyll-coffeescript]"
     And I have a simple layout that contains "{{ content }}Ahoy, indeed!"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should not see "Ahoy, indeed!" in "_site/index.css"
     And I should not see "Ahoy, indeed!" in "_site/index.js"
 
@@ -33,18 +35,21 @@ Feature: Rendering
     Given I have an "index.scss" page that contains ".foo-bar { color:{{site.color}}; }"
     And I have a configuration file with "color" set to "red"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see ".foo-bar {\n  color: red; }" in "_site/index.css"
 
   Scenario: Not render liquid in CoffeeScript without explicitly including jekyll-coffeescript
     Given I have an "index.coffee" page with animal "cicada" that contains "hey='for {{page.animal}}'"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/index.js" file should not exist
 
   Scenario: Render liquid in CoffeeScript with jekyll-coffeescript enabled
     Given I have an "index.coffee" page with animal "cicada" that contains "hey='for {{page.animal}}'"
     And I have a configuration file with "gems" set to "[jekyll-coffeescript]"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "hey = 'for cicada';" in "_site/index.js"
diff --git a/features/site_configuration.feature b/features/site_configuration.feature
index 379cea4..5c49535 100644
--- a/features/site_configuration.feature
+++ b/features/site_configuration.feature
@@ -8,7 +8,8 @@ Feature: Site configuration
     And I have an "_sourcedir/index.html" file that contains "Changing source directory"
     And I have a configuration file with "source" set to "_sourcedir"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Changing source directory" in "_site/index.html"
 
   Scenario: Change destination directory
@@ -66,27 +67,31 @@ Feature: Site configuration
     Given I have an "index.markdown" page that contains "[Google](http://google.com)"
     And I have a configuration file with "markdown" set to "rdiscount"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<a href=\"http://google.com\">Google</a>" in "_site/index.html"
 
   Scenario: Use Kramdown for markup
     Given I have an "index.markdown" page that contains "[Google](http://google.com)"
     And I have a configuration file with "markdown" set to "kramdown"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<a href=\"http://google.com\">Google</a>" in "_site/index.html"
 
   Scenario: Use Redcarpet for markup
     Given I have an "index.markdown" page that contains "[Google](http://google.com)"
     And I have a configuration file with "markdown" set to "redcarpet"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "<a href=\"http://google.com\">Google</a>" in "_site/index.html"
 
   Scenario: Highlight code with pygments
     Given I have an "index.html" page that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Hello world!" in "_site/index.html"
     And I should see "class=\"highlight\"" in "_site/index.html"
 
@@ -94,7 +99,8 @@ Feature: Site configuration
     Given I have an "index.html" page that contains "{% highlight ruby %} puts 'Hello world!' {% endhighlight %}"
     And I have a configuration file with "highlighter" set to "rouge"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Hello world!" in "_site/index.html"
     And I should see "class=\"highlight\"" in "_site/index.html"
 
@@ -122,7 +128,8 @@ Feature: Site configuration
       | entry1 | 2007-12-31 | post   | content for entry1. |
       | entry2 | 2020-01-31 | post   | content for entry2. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout: 1 on 2010-01-01" in "_site/index.html"
     And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
     And the "_site/2020/01/31/entry2.html" file should not exist
@@ -142,7 +149,8 @@ Feature: Site configuration
       | entry1 | 2007-12-31 | post   | content for entry1. |
       | entry2 | 2020-01-31 | post   | content for entry2. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout: 2 on 2010-01-01" in "_site/index.html"
     And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
     And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"
@@ -161,7 +169,8 @@ Feature: Site configuration
         | entry1    | 2013-04-09 23:22 -0400 | post    | content for entry1. |
         | entry2    | 2013-04-10 03:14 -0400 | post    | content for entry2. |
       When I run jekyll build
-      Then the _site directory should exist
+      Then I should get a zero exit status
+    And the _site directory should exist
       And I should see "Page Layout: 2" in "_site/index.html"
       And I should see "Post Layout: <p>content for entry1.</p>\n built at 2013-04-09T23:22:00-04:00" in "_site/2013/04/09/entry1.html"
       And I should see "Post Layout: <p>content for entry2.</p>\n built at 2013-04-10T03:14:00-04:00" in "_site/2013/04/10/entry2.html"
@@ -180,7 +189,8 @@ Feature: Site configuration
         | entry1    | 2013-04-09 23:22 +0400 | post    | content for entry1. |
         | entry2    | 2013-04-10 03:14 +0400 | post    | content for entry2. |
       When I run jekyll build
-      Then the _site directory should exist
+      Then I should get a zero exit status
+    And the _site directory should exist
       And I should see "Page Layout: 2" in "_site/index.html"
       And the "_site/2013/04/09/entry1.html" file should exist
       And the "_site/2013/04/09/entry2.html" file should exist
@@ -198,7 +208,8 @@ Feature: Site configuration
       | Oranges | 2009-04-01 | An article about oranges |
       | Bananas | 2009-04-05 | An article about bananas |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And the "_site/2009/04/05/bananas.html" file should exist
     And the "_site/2009/04/01/oranges.html" file should exist
     And the "_site/2009/03/27/apples.html" file should not exist
@@ -211,7 +222,8 @@ Feature: Site configuration
       | .gitignore |
       | .foo       |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see ".DS_Store" in "_site/.gitignore"
     And the "_site/.htaccess" file should not exist
 
@@ -231,7 +243,8 @@ Feature: Site configuration
       | entry1 | 2007-12-31 | post   | content for entry1. |
       | entry2 | 2020-01-31 | post   | content for entry2. |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Page Layout: 2 on 2010-01-01" in "_site/index.html"
     And I should see "Post Layout: <p>content for entry1.</p>" in "_site/2007/12/31/entry1.html"
     And I should see "Post Layout: <p>content for entry2.</p>" in "_site/2020/01/31/entry2.html"
@@ -240,6 +253,7 @@ Feature: Site configuration
     Given I have an "index.html" page with layout "page" that contains "FOO"
     And I have a "_config.yml" file that contains "layouts: '../../../../../../../../../../../../../../usr/include'"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "FOO" in "_site/index.html"
     And I should not see " " in "_site/index.html"
diff --git a/features/site_data.feature b/features/site_data.feature
index a7fadf3..e3c99a6 100644
--- a/features/site_data.feature
+++ b/features/site_data.feature
@@ -6,14 +6,16 @@ Feature: Site data
   Scenario: Use page variable in a page
     Given I have an "contact.html" page with title "Contact" that contains "{{ page.title }}: email at example.com"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Contact: email at example.com" in "_site/contact.html"
 
   Scenario Outline: Use page.path variable in a page
     Given I have a <dir> directory
     And I have a "<path>" page that contains "Source path: {{ page.path }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Source path: <path>" in "_site/<path>"
 
     Examples:
@@ -25,13 +27,15 @@ Feature: Site data
   Scenario: Override page.path
     Given I have an "override.html" page with path "custom-override.html" that contains "Custom path: {{ page.path }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Custom path: custom-override.html" in "_site/override.html"
 
   Scenario: Use site.time variable
     Given I have an "index.html" page that contains "{{ site.time }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see today's time in "_site/index.html"
 
   Scenario: Use site.posts variable for latest post
@@ -43,7 +47,8 @@ Feature: Site data
       | Second Post | 2009-03-26 | My Second Post |
       | Third Post  | 2009-03-27 | My Third Post  |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Third Post: /2009/03/27/third-post.html" in "_site/index.html"
 
   Scenario: Use site.posts variable in a loop
@@ -55,7 +60,8 @@ Feature: Site data
       | Second Post | 2009-03-26 | My Second Post |
       | Third Post  | 2009-03-27 | My Third Post  |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Third Post  Second Post  First Post" in "_site/index.html"
 
   Scenario: Use site.categories.code variable
@@ -66,7 +72,8 @@ Feature: Site data
       | Awesome Hack   | 2009-03-26 | code     | puts 'Hello World' |
       | Delicious Beer | 2009-03-26 | food     | 1) Yuengling       |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Awesome Hack" in "_site/index.html"
 
   Scenario: Use site.tags variable
@@ -76,7 +83,8 @@ Feature: Site data
       | title          | date       | tag  | content      |
       | Delicious Beer | 2009-03-26 | beer | 1) Yuengling |
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "Yuengling" in "_site/index.html"
 
   Scenario: Order Posts by name when on the same date
@@ -90,18 +98,21 @@ Feature: Site data
     | C     | 2009-03-26 | C       |
     | last  | 2009-04-26 | last    |
   When I run jekyll build
-  Then the _site directory should exist
+  Then I should get a zero exit status
+    And the _site directory should exist
   And I should see "last:C, C:B,last B:A,C A:first,B first:,A" in "_site/index.html"
 
   Scenario: Use configuration date in site payload
     Given I have an "index.html" page that contains "{{ site.url }}"
     And I have a configuration file with "url" set to "http://example.com"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "http://example.com" in "_site/index.html"
 
   Scenario: Access Jekyll version via jekyll.version
     Given I have an "index.html" page that contains "{{ jekyll.version }}"
     When I run jekyll build
-    Then the _site directory should exist
+    Then I should get a zero exit status
+    And the _site directory should exist
     And I should see "\d+\.\d+\.\d+" in "_site/index.html"
diff --git a/features/step_definitions.rb b/features/step_definitions.rb
new file mode 100644
index 0000000..f609076
--- /dev/null
+++ b/features/step_definitions.rb
@@ -0,0 +1,245 @@
+Before do
+  FileUtils.mkdir_p(Paths.test_dir) unless Paths.test_dir.directory?
+  Dir.chdir(Paths.test_dir)
+end
+
+#
+
+After do
+  Paths.test_dir.rmtree if Paths.test_dir.exist?
+  Paths.output_file.delete if Paths.output_file.exist?
+  Paths.status_file.delete if Paths.status_file.exist?
+  Dir.chdir(Paths.test_dir.parent)
+end
+
+#
+
+Given %r{^I have a blank site in "(.*)"$} do |path|
+  if !File.exist?(path)
+    then FileUtils.mkdir_p(path)
+  end
+end
+
+#
+
+Given %r{^I do not have a "(.*)" directory$} do |path|
+  Paths.test_dir.join(path).directory?
+end
+
+#
+
+Given %r{^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$} do |file, key, value, text|
+  File.write(file, Jekyll::Utils.strip_heredoc(<<-DATA))
+    ---
+    #{key || 'layout'}: #{value || 'nil'}
+    ---
+
+    #{text}
+  DATA
+end
+
+#
+
+Given %r{^I have an? "(.*)" file that contains "(.*)"$} do |file, text|
+  File.write(file, text)
+end
+
+#
+
+Given %r{^I have an? (.*) (layout|theme) that contains "(.*)"$} do |name, type, text|
+  folder = type == "layout" ? "_layouts" : "_theme"
+
+  destination_file = Pathname.new(File.join(folder, "#{name}.html"))
+  FileUtils.mkdir_p(destination_file.parent) unless destination_file.parent.directory?
+  File.write(destination_file, text)
+end
+
+#
+
+Given %r{^I have an? "(.*)" file with content:$} do |file, text|
+  File.write(file, text)
+end
+
+#
+
+Given %r{^I have an? (.*) directory$} do |dir|
+  if !File.directory?(dir)
+    then FileUtils.mkdir_p(dir)
+  end
+end
+
+#
+
+Given %r{^I have the following (draft|page|post)s?(?: (in|under) "([^"]+)")?:$} do |status, direction, folder, table|
+  table.hashes.each do |input_hash|
+    title = slug(input_hash["title"])
+    ext = input_hash["type"] || "markdown"
+    filename = filename = "#{title}.#{ext}" if %w(draft page).include?(status)
+    before, after = location(folder, direction)
+    dest_folder = "_drafts" if status == "draft"
+    dest_folder = "_posts"  if status ==  "post"
+    dest_folder = "" if status == "page"
+
+    if status == "post"
+      parsed_date = Time.xmlschema(input_hash['date']) rescue Time.parse(input_hash['date'])
+      filename = "#{parsed_date.strftime('%Y-%m-%d')}-#{title}.#{ext}"
+    end
+
+    path = File.join(before, dest_folder, after, filename)
+    File.write(path, file_content_from_hash(input_hash))
+  end
+end
+
+#
+
+Given %r{^I have a configuration file with "(.*)" set to "(.*)"$} do |key, value|
+  config = if source_dir.join("_config.yml").exist?
+    SafeYAML.load_file(source_dir.join("_config.yml"))
+  else
+    {}
+  end
+  config[key] = YAML.load(value)
+  File.write("_config.yml", YAML.dump(config))
+end
+
+#
+
+Given %r{^I have a configuration file with:$} do |table|
+  table.hashes.each do |row|
+    step %(I have a configuration file with "#{row["key"]}" set to "#{row["value"]}")
+  end
+end
+
+#
+
+Given %r{^I have a configuration file with "([^\"]*)" set to:$} do |key, table|
+  File.open("_config.yml", "w") do |f|
+    f.write("#{key}:\n")
+    table.hashes.each do |row|
+      f.write("- #{row["value"]}\n")
+    end
+  end
+end
+
+#
+
+Given %r{^I have fixture collections$} do
+  FileUtils.cp_r Paths.source_dir.join("test", "source", "_methods"), source_dir
+  FileUtils.cp_r Paths.source_dir.join("test", "source", "_thanksgiving"), source_dir
+end
+
+#
+
+Given %r{^I wait (\d+) second(s?)$} do |time, plural|
+  sleep(time.to_f)
+end
+
+#
+
+When %r{^I run jekyll(.*)$} do |args|
+  run_jekyll(args)
+  if args.include?("--verbose") || ENV["DEBUG"]
+    $stderr.puts "\n#{jekyll_run_output}\n"
+  end
+end
+
+#
+
+When %r{^I run bundle(.*)$} do |args|
+  run_bundle(args)
+  if args.include?("--verbose") || ENV['DEBUG']
+    $stderr.puts "\n#{jekyll_run_output}\n"
+  end
+end
+
+#
+
+When %r{^I change "(.*)" to contain "(.*)"$} do |file, text|
+  File.open(file, "a") do |f|
+    f.write(text)
+  end
+end
+
+#
+
+When %r{^I delete the file "(.*)"$} do |file|
+  File.delete(file)
+end
+
+#
+
+Then %r{^the (.*) directory should +(not )?exist$} do |dir, negative|
+  if negative.nil?
+    expect(Pathname.new(dir)).to exist
+  else
+    expect(Pathname.new(dir)).to_not exist
+  end
+end
+
+#
+Then %r{^I should (not )?see "(.*)" in "(.*)"$} do |negative, text, file|
+  step %(the "#{file}" file should exist)
+  regexp = Regexp.new(text, Regexp::MULTILINE)
+  if negative.nil? || negative.empty?
+    expect(file_contents(file)).to match regexp
+  else
+    expect(file_contents(file)).not_to match regexp
+  end
+end
+
+#
+
+Then %r{^I should see exactly "(.*)" in "(.*)"$} do |text, file|
+  step %(the "#{file}" file should exist)
+  expect(file_contents(file).strip).to eq text
+end
+
+#
+
+Then %r{^I should see escaped "(.*)" in "(.*)"$} do |text, file|
+  step %(I should see "#{Regexp.escape(text)}" in "#{file}")
+end
+
+#
+
+Then %r{^the "(.*)" file should +(not )?exist$} do |file, negative|
+  if negative.nil?
+    expect(Pathname.new(file)).to exist
+  else
+    expect(Pathname.new(file)).to_not exist
+  end
+end
+
+#
+
+Then %r{^I should see today's time in "(.*)"$} do |file|
+  step %(I should see "#{seconds_agnostic_time(Time.now)}" in "#{file}")
+end
+
+#
+
+Then %r{^I should see today's date in "(.*)"$} do |file|
+  step %(I should see "#{Date.today.to_s}" in "#{file}")
+end
+
+#
+
+Then %r{^I should (not )?see "(.*)" in the build output$} do |negative, text|
+  if negative.nil? || negative.empty?
+    expect(jekyll_run_output).to match Regexp.new(text)
+  else
+    expect(jekyll_run_output).not_to match Regexp.new(text)
+  end
+end
+
+#
+
+Then %r{^I should get a zero exit(?:\-| )status$} do
+  step %(I should see "EXIT STATUS: 0" in the build output)
+end
+
+#
+
+Then %r{^I should get a non-zero exit(?:\-| )status$} do
+  step %(I should not see "EXIT STATUS: 0" in the build output)
+end
diff --git a/features/step_definitions/jekyll_steps.rb b/features/step_definitions/jekyll_steps.rb
deleted file mode 100644
index 9164d54..0000000
--- a/features/step_definitions/jekyll_steps.rb
+++ /dev/null
@@ -1,234 +0,0 @@
-def file_content_from_hash(input_hash)
-  matter_hash = input_hash.reject { |k, v| k == "content" }
-  matter = matter_hash.map { |k, v| "#{k}: #{v}\n" }.join.chomp
-
-  content = if input_hash['input'] && input_hash['filter']
-    "{{ #{input_hash['input']} | #{input_hash['filter']} }}"
-  else
-    input_hash['content']
-  end
-
-  <<-EOF
----
-#{matter}
----
-#{content}
-EOF
-end
-
-Before do
-  FileUtils.mkdir_p(TEST_DIR) unless File.exist?(TEST_DIR)
-  Dir.chdir(TEST_DIR)
-end
-
-After do
-  FileUtils.rm_rf(TEST_DIR)   if File.exist?(TEST_DIR)
-  FileUtils.rm(JEKYLL_COMMAND_OUTPUT_FILE) if File.exist?(JEKYLL_COMMAND_OUTPUT_FILE)
-  FileUtils.rm(JEKYLL_COMMAND_STATUS_FILE) if File.exist?(JEKYLL_COMMAND_STATUS_FILE)
-  Dir.chdir(File.dirname(TEST_DIR))
-end
-
-World do
-  MinitestWorld.new
-end
-
-Given /^I have a blank site in "(.*)"$/ do |path|
-  FileUtils.mkdir_p(path) unless File.exist?(path)
-end
-
-Given /^I do not have a "(.*)" directory$/ do |path|
-  File.directory?("#{TEST_DIR}/#{path}")
-end
-
-# Like "I have a foo file" but gives a yaml front matter so jekyll actually processes it
-Given /^I have an? "(.*)" page(?: with (.*) "(.*)")? that contains "(.*)"$/ do |file, key, value, text|
-  File.open(file, 'w') do |f|
-    f.write <<-EOF
----
-#{key || 'layout'}: #{value || 'nil'}
----
-#{text}
-EOF
-  end
-end
-
-Given /^I have an? "(.*)" file that contains "(.*)"$/ do |file, text|
-  File.open(file, 'w') do |f|
-    f.write(text)
-  end
-end
-
-Given /^I have an? (.*) (layout|theme) that contains "(.*)"$/ do |name, type, text|
-  folder = if type == 'layout'
-    '_layouts'
-  else
-    '_theme'
-  end
-  destination_file = File.join(folder, name + '.html')
-  destination_path = File.dirname(destination_file)
-  unless File.exist?(destination_path)
-    FileUtils.mkdir_p(destination_path)
-  end
-  File.open(destination_file, 'w') do |f|
-    f.write(text)
-  end
-end
-
-Given /^I have an? "(.*)" file with content:$/ do |file, text|
-  File.open(file, 'w') do |f|
-    f.write(text)
-  end
-end
-
-Given /^I have an? (.*) directory$/ do |dir|
-  FileUtils.mkdir_p(dir)
-end
-
-Given /^I have the following (draft|page|post)s?(?: (in|under) "([^"]+)")?:$/ do |status, direction, folder, table|
-  table.hashes.each do |input_hash|
-    title = slug(input_hash['title'])
-    ext = input_hash['type'] || 'markdown'
-    before, after = location(folder, direction)
-
-    case status
-    when "draft"
-      dest_folder = '_drafts'
-      filename = "#{title}.#{ext}"
-    when "page"
-      dest_folder = ''
-      filename = "#{title}.#{ext}"
-    when "post"
-      parsed_date = Time.xmlschema(input_hash['date']) rescue Time.parse(input_hash['date'])
-      dest_folder = '_posts'
-      filename = "#{parsed_date.strftime('%Y-%m-%d')}-#{title}.#{ext}"
-    end
-
-    path = File.join(before, dest_folder, after, filename)
-    File.open(path, 'w') do |f|
-      f.write file_content_from_hash(input_hash)
-    end
-  end
-end
-
-Given /^I have a configuration file with "(.*)" set to "(.*)"$/ do |key, value|
-  File.open('_config.yml', 'w') do |f|
-    f.write("#{key}: #{value}\n")
-  end
-end
-
-Given /^I have a configuration file with:$/ do |table|
-  File.open('_config.yml', 'w') do |f|
-    table.hashes.each do |row|
-      f.write("#{row["key"]}: #{row["value"]}\n")
-    end
-  end
-end
-
-Given /^I have a configuration file with "([^\"]*)" set to:$/ do |key, table|
-  File.open('_config.yml', 'w') do |f|
-    f.write("#{key}:\n")
-    table.hashes.each do |row|
-      f.write("- #{row["value"]}\n")
-    end
-  end
-end
-
-Given /^I have fixture collections$/ do
-  FileUtils.cp_r File.join(JEKYLL_SOURCE_DIR, "test", "source", "_methods"), source_dir
-end
-
-Given /^I wait (\d+) second(s?)$/ do |time, plural|
-  sleep(time.to_f)
-end
-
-##################
-#
-# Changing stuff
-#
-##################
-
-When /^I run jekyll(.*)$/ do |args|
-  status = run_jekyll(args)
-  if args.include?("--verbose") || ENV['DEBUG']
-    puts jekyll_run_output
-  end
-end
-
-When /^I run bundle(.*)$/ do |args|
-  status = run_bundle(args)
-  if args.include?("--verbose") || ENV['DEBUG']
-    puts jekyll_run_output
-  end
-end
-
-When /^I change "(.*)" to contain "(.*)"$/ do |file, text|
-  File.open(file, 'a') do |f|
-    f.write(text)
-  end
-end
-
-When /^I delete the file "(.*)"$/ do |file|
-  File.delete(file)
-end
-
-##################
-#
-# Checking stuff
-#
-##################
-
-Then /^the (.*) directory should +exist$/ do |dir|
-  assert File.directory?(dir), "The directory \"#{dir}\" does not exist"
-end
-
-Then /^the (.*) directory should not exist$/ do |dir|
-  assert !File.directory?(dir), "The directory \"#{dir}\" exists"
-end
-
-Then /^I should see "(.*)" in "(.*)"$/ do |text, file|
-  assert_match Regexp.new(text, Regexp::MULTILINE), file_contents(file)
-end
-
-Then /^I should see exactly "(.*)" in "(.*)"$/ do |text, file|
-  assert_equal text, file_contents(file).strip
-end
-
-Then /^I should not see "(.*)" in "(.*)"$/ do |text, file|
-  refute_match Regexp.new(text, Regexp::MULTILINE), file_contents(file)
-end
-
-Then /^I should see escaped "(.*)" in "(.*)"$/ do |text, file|
-  assert_match Regexp.new(Regexp.escape(text)), file_contents(file)
-end
-
-Then /^the "(.*)" file should +exist$/ do |file|
-  file_does_exist = File.file?(file)
-  unless file_does_exist
-    all_steps_to_path(file).each do |dir|
-      STDERR.puts ""
-      STDERR.puts "Dir #{dir}:"
-      STDERR.puts Dir["#{dir}/**/*"]
-    end
-  end
-  assert file_does_exist, "The file \"#{file}\" does not exist.\n"
-end
-
-Then /^the "(.*)" file should not exist$/ do |file|
-  assert !File.exist?(file), "The file \"#{file}\" exists"
-end
-
-Then /^I should see today's time in "(.*)"$/ do |file|
-  assert_match Regexp.new(seconds_agnostic_time(Time.now)), file_contents(file)
-end
-
-Then /^I should see today's date in "(.*)"$/ do |file|
-  assert_match Regexp.new(Date.today.to_s), file_contents(file)
-end
-
-Then /^I should see "(.*)" in the build output$/ do |text|
-  assert_match Regexp.new(text), jekyll_run_output
-end
-
-Then /^I should get a non-zero exit(?:\-| )status$/ do
-  assert jekyll_run_status > 0
-end
diff --git a/features/support/env.rb b/features/support/env.rb
deleted file mode 100644
index 76a3e70..0000000
--- a/features/support/env.rb
+++ /dev/null
@@ -1,116 +0,0 @@
-require 'fileutils'
-require 'posix-spawn'
-require 'minitest/spec'
-require 'time'
-
-class MinitestWorld
-  extend Minitest::Assertions
-  attr_accessor :assertions
-
-  def initialize
-    self.assertions = 0
-  end
-end
-
-JEKYLL_SOURCE_DIR = File.dirname(File.dirname(File.dirname(__FILE__)))
-TEST_DIR    = File.expand_path(File.join('..', '..', 'tmp', 'jekyll'), File.dirname(__FILE__))
-JEKYLL_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', 'jekyll'))
-JEKYLL_COMMAND_OUTPUT_FILE = File.join(File.dirname(TEST_DIR), 'jekyll_output.txt')
-JEKYLL_COMMAND_STATUS_FILE = File.join(File.dirname(TEST_DIR), 'jekyll_status.txt')
-
-def source_dir(*files)
-  File.join(TEST_DIR, *files)
-end
-
-def all_steps_to_path(path)
-  source = Pathname.new(source_dir('_site')).expand_path
-  dest   = Pathname.new(path).expand_path
-  paths  = []
-  dest.ascend do |f|
-    break if f.eql? source
-    paths.unshift f.to_s
-  end
-  paths
-end
-
-def jekyll_output_file
-  JEKYLL_COMMAND_OUTPUT_FILE
-end
-
-def jekyll_status_file
-  JEKYLL_COMMAND_STATUS_FILE
-end
-
-def jekyll_run_output
-  File.read(jekyll_output_file) if File.file?(jekyll_output_file)
-end
-
-def jekyll_run_status
-  (File.read(jekyll_status_file) rescue 0).to_i
-end
-
-def run_bundle(args)
-  run_in_shell('bundle', *args.strip.split(' '))
-end
-
-def run_jekyll(args)
-  child = run_in_shell(JEKYLL_PATH, *args.strip.split(' '), "--trace")
-  child.status.exitstatus == 0
-end
-
-# -----------------------------------------------------------------------------
-# XXX: POSIX::Spawn::Child does not write output when the exit status is > 0
-#        for example when doing [:out, :err] => [file, "w"] it will skip
-#        writing the file entirely, we sould switch to Open.
-# -----------------------------------------------------------------------------
-
-def run_in_shell(*args)
-  spawned = POSIX::Spawn::Child.new(*args)
-  status = spawned.status.exitstatus
-  File.write(JEKYLL_COMMAND_STATUS_FILE, status)
-  File.open(JEKYLL_COMMAND_OUTPUT_FILE, "w+") do |file|
-    status == 0 ? file.write(spawned.out) : file.write(spawned.err)
-  end
-
-  spawned
-end
-
-def slug(title)
-  if title
-    title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
-  else
-    Time.now.strftime("%s%9N") # nanoseconds since the Epoch
-  end
-end
-
-def location(folder, direction)
-  if folder
-    before = folder if direction == "in"
-    after = folder if direction == "under"
-  end
-  [before || '.', after || '.']
-end
-
-def file_contents(path)
-  File.open(path) do |file|
-    file.readlines.join # avoid differences with \n and \r\n line endings
-  end
-end
-
-def seconds_agnostic_datetime(datetime = Time.now)
-  date, time, zone = datetime.to_s.split(" ")
-  time = seconds_agnostic_time(time)
-  [
-    Regexp.escape(date),
-    "#{time}:\\d{2}",
-    Regexp.escape(zone)
-  ].join("\\ ")
-end
-
-def seconds_agnostic_time(time)
-  if time.is_a? Time
-    time = time.strftime("%H:%M:%S")
-  end
-  hour, minutes, _ = time.split(":")
-  "#{hour}:#{minutes}"
-end
diff --git a/features/support/overview.rb b/features/support/formatter.rb
similarity index 55%
rename from features/support/overview.rb
rename to features/support/formatter.rb
index 8d414be..f399a3c 100644
--- a/features/support/overview.rb
+++ b/features/support/formatter.rb
@@ -2,140 +2,177 @@ require 'fileutils'
 require 'colorator'
 require 'cucumber/formatter/console'
 require 'cucumber/formatter/io'
-require 'gherkin/formatter/escaping'
-
-module Features
-  module Support
-    # The formatter used for <tt>--format pretty</tt> (the default formatter).
-    #
-    # This formatter prints features to plain text - exactly how they were parsed,
-    # just prettier. That means with proper indentation and alignment of table columns.
-    #
-    # If the output is STDOUT (and not a file), there are bright colours to watch too.
-    #
-    class Overview
+
+module Jekyll
+  module Cucumber
+    class Formatter
+      attr_accessor :indent, :runtime
+      include ::Cucumber::Formatter::Console
+      include ::Cucumber::Formatter::Io
       include FileUtils
-      include Cucumber::Formatter::Console
-      include Cucumber::Formatter::Io
-      include Gherkin::Formatter::Escaping
-      attr_writer :indent
-      attr_reader :runtime
+
+      CHARS = {
+        :failed    => "\u2718".red,
+        :pending   => "\u203D".yellow,
+        :undefined => "\u2718".red,
+        :passed    => "\u2714".green,
+        :skipped   => "\u203D".blue
+      }
+
+      #
 
       def initialize(runtime, path_or_io, options)
-        @runtime, @io, @options = runtime, ensure_io(path_or_io, "pretty"), options
-        @exceptions = []
-        @indent = 0
+        @runtime = runtime
+        @snippets_input = []
+        @io = ensure_io(path_or_io)
         @prefixes = options[:prefixes] || {}
         @delayed_messages = []
+        @options = options
+        @exceptions = []
+        @indent = 0
       end
 
+      #
+
       def before_features(features)
         print_profile_information
       end
 
+      #
+
       def after_features(features)
         @io.puts
         print_summary(features)
       end
 
+      #
+
       def before_feature(feature)
         @exceptions = []
         @indent = 0
       end
 
-      def comment_line(comment_line)
-      end
+      #
 
-      def after_tags(tags)
-      end
+      def tag_name(tag_name); end
+      def comment_line(comment_line); end
+      def after_feature_element(feature_element); end
+      def after_tags(tags); end
 
-      def tag_name(tag_name)
-      end
+      #
 
       def before_feature_element(feature_element)
         @indent = 2
         @scenario_indent = 2
       end
 
-      def after_feature_element(feature_element)
-      end
+      #
 
       def before_background(background)
-        @indent = 2
         @scenario_indent = 2
         @in_background = true
+        @indent = 2
       end
 
+      #
+
       def after_background(background)
         @in_background = nil
       end
 
-      def background_name(keyword, name, file_colon_line, source_indent)
-        print_feature_element_name(keyword, name, file_colon_line, source_indent)
+      #
+
+      def background_name(keyword, name, source_line, indend)
+        print_feature_element_name(
+          keyword, name, source_line, indend
+        )
       end
 
-      def scenario_name(keyword, name, file_colon_line, source_indent)
-        print_feature_element_name(keyword, name, file_colon_line, source_indent)
+      #
+
+      def scenario_name(keyword, name, source_line, indent)
+        print_feature_element_name(
+          keyword, name, source_line, indent
+        )
       end
 
+      #
+
       def before_step(step)
         @current_step = step
       end
 
-      def before_step_result(keyword, step_match, multiline_arg, status, exception, source_indent, background, file_colon_line)
+      #
+
+      def before_step_result(keyword, step_match, multiline_arg, status, exception, \
+          source_indent, background, file_colon_line)
+
         @hide_this_step = false
         if exception
           if @exceptions.include?(exception)
             @hide_this_step = true
             return
           end
+
           @exceptions << exception
         end
+
         if status != :failed && @in_background ^ background
           @hide_this_step = true
           return
         end
+
         @status = status
       end
 
-      CHARS = {
-        :failed    => "x".red,
-        :pending   => "?".yellow,
-        :undefined => "x".red,
-        :passed    => ".".green,
-        :skipped   => "-".blue
-      }
+      #
 
       def step_name(keyword, step_match, status, source_indent, background, file_colon_line)
         @io.print CHARS[status]
+        @io.print " "
       end
 
+      #
+
       def exception(exception, status)
         return if @hide_this_step
+
         @io.puts
         print_exception(exception, status, @indent)
         @io.flush
       end
 
-      private
+      #
+
+      def after_test_step(test_step, result)
+        collect_snippet_data(
+          test_step, result
+        )
+      end
 
-      def print_feature_element_name(keyword, name, file_colon_line, source_indent)
+      #
+
+      private
+      def print_feature_element_name(keyword, name, source_line, indent)
         @io.puts
-        names = name.empty? ? [name] : name.split("\n")
-        line = "  #{keyword}: #{names[0]}"
-        if @options[:source]
-          line_comment = "#{file_colon_line}"
-          @io.print(line_comment)
-        end
+
+        names = name.empty? ? [name] : name.each_line.to_a
+        line  = "  #{keyword}: #{names[0]}"
+
+        @io.print(source_line) if @options[:source]
         @io.print(line)
         @io.print " "
         @io.flush
       end
 
+      #
+
       def cell_prefix(status)
         @prefixes[status]
       end
 
+      #
+
       def print_summary(features)
         @io.puts
         print_stats(features, @options)
diff --git a/features/support/helpers.rb b/features/support/helpers.rb
new file mode 100644
index 0000000..b8334cf
--- /dev/null
+++ b/features/support/helpers.rb
@@ -0,0 +1,161 @@
+require "fileutils"
+require "jekyll/utils"
+require "open3"
+require "time"
+require "safe_yaml/load"
+
+class Paths
+  SOURCE_DIR = Pathname.new(File.expand_path("../..", __dir__))
+  def self.test_dir; source_dir.join("tmp", "jekyll"); end
+  def self.output_file; test_dir.join("jekyll_output.txt"); end
+  def self.status_file; test_dir.join("jekyll_status.txt"); end
+  def self.jekyll_bin; source_dir.join("bin", "jekyll"); end
+  def self.source_dir; SOURCE_DIR; end
+end
+
+#
+
+def file_content_from_hash(input_hash)
+  matter_hash = input_hash.reject { |k, v| k == "content" }
+  matter = matter_hash.map do |k, v| "#{k}: #{v}\n"
+  end
+
+  matter = matter.join.chomp
+  content = \
+  if !input_hash['input'] || !input_hash['filter']
+    then input_hash['content']
+    else "{{ #{input_hash['input']} | " \
+      "#{input_hash['filter']} }}"
+  end
+
+  Jekyll::Utils.strip_heredoc(<<-EOF)
+    ---
+    #{matter.gsub(
+      /\n/, "\n    "
+    )}
+    ---
+    #{content}
+  EOF
+end
+
+#
+
+def source_dir(*files)
+  return Paths.test_dir(*files)
+end
+
+#
+
+def all_steps_to_path(path)
+  source = source_dir
+  dest = Pathname.new(path).expand_path
+  paths  = []
+
+  dest.ascend do |f|
+    break if f == source
+    paths.unshift f.to_s
+  end
+
+  paths
+end
+
+#
+
+def jekyll_run_output
+  if Paths.output_file.file?
+    then return Paths.output_file.read
+  end
+end
+
+#
+
+def jekyll_run_status
+  if Paths.status_file.file?
+    then return Paths.status_file.read
+  end
+end
+
+#
+
+def run_bundle(args)
+  run_in_shell("bundle", *args.strip.split(' '))
+end
+
+#
+
+def run_jekyll(args)
+  args = args.strip.split(" ") # Shellwords?
+  process = run_in_shell(Paths.jekyll_bin.to_s, *args, "--trace")
+  process.exitstatus == 0
+end
+
+#
+
+def run_in_shell(*args)
+  i, o, e, p = Open3.popen3(*args)
+  out = o.read.strip
+  err = e.read.strip
+
+  [i, o, e].each do |m|
+    m.close
+  end
+
+  File.write(Paths.status_file, p.value.exitstatus)
+  File.open(Paths.output_file, "wb") do |f|
+    f.puts "$ " << args.join(" ")
+    f.puts out
+    f.puts err
+    f.puts "EXIT STATUS: #{p.value.exitstatus}"
+  end
+
+  p.value
+end
+
+#
+
+def slug(title = nil)
+  if !title
+    then Time.now.strftime("%s%9N") # nanoseconds since the Epoch
+    else title.downcase.gsub(/[^\w]/, " ").strip.gsub(/\s+/, '-')
+  end
+end
+
+#
+
+def location(folder, direction)
+  if folder
+    before = folder if direction ==    "in"
+    after  = folder if direction == "under"
+  end
+
+  [before || '.',
+    after || '.']
+end
+
+#
+
+def file_contents(path)
+  return Pathname.new(path).read
+end
+
+#
+
+def seconds_agnostic_datetime(datetime = Time.now)
+  date, time, zone = datetime.to_s.split(" ")
+  time = seconds_agnostic_time(time)
+
+  [
+    Regexp.escape(date),
+    "#{time}:\\d{2}",
+    Regexp.escape(zone)
+  ] \
+  .join("\\ ")
+end
+
+#
+
+def seconds_agnostic_time(time)
+  time = time.strftime("%H:%M:%S") if time.is_a?(Time)
+  hour, minutes, _ = time.split(":")
+  "#{hour}:#{minutes}"
+end
diff --git a/jekyll.gemspec b/jekyll.gemspec
index 470781c..167e424 100644
--- a/jekyll.gemspec
+++ b/jekyll.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
   s.homepage      = 'https://github.com/jekyll/jekyll'
 
   all_files       = `git ls-files -z`.split("\x0")
-  s.files         = all_files.grep(%r{^(bin|lib)/})
+  s.files         = all_files.grep(%r{^(bin|lib)/|^.rubocop.yml$})
   s.executables   = all_files.grep(%r{^bin/}) { |f| File.basename(f) }
   s.require_paths = ['lib']
 
diff --git a/lib/jekyll.rb b/lib/jekyll.rb
index 3e8e639..33994d0 100644
--- a/lib/jekyll.rb
+++ b/lib/jekyll.rb
@@ -1,4 +1,4 @@
-$:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
+$LOAD_PATH.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
 
 # Require all of the Ruby files in the given directory.
 #
@@ -7,7 +7,7 @@ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
 # Returns nothing.
 def require_all(path)
   glob = File.join(File.dirname(__FILE__), path, '*.rb')
-  Dir[glob].each do |f|
+  Dir[glob].sort.each do |f|
     require f
   end
 end
@@ -16,6 +16,7 @@ end
 require 'rubygems'
 
 # stdlib
+require 'forwardable'
 require 'fileutils'
 require 'time'
 require 'English'
@@ -32,7 +33,6 @@ require 'colorator'
 SafeYAML::OPTIONS[:suppress_warnings] = true
 
 module Jekyll
-
   # internal requires
   autoload :Cleaner,             'jekyll/cleaner'
   autoload :Collection,          'jekyll/collection'
@@ -96,17 +96,15 @@ module Jekyll
     #
     # Returns the final configuration Hash.
     def configuration(override = Hash.new)
-      config = Configuration[Configuration::DEFAULTS]
-      override = Configuration[override].stringify_keys
+      config = Configuration.new
       unless override.delete('skip_config_files')
         config = config.read_config_files(config.config_files(override))
       end
 
       # Merge DEFAULTS < _config.yml < override
-      config = Utils.deep_merge_hashes(config, override).stringify_keys
-      set_timezone(config['timezone']) if config['timezone']
-
-      config
+      Configuration.from(Utils.deep_merge_hashes(config, override)).tap do |config|
+        set_timezone(config['timezone']) if config['timezone']
+      end
     end
 
     # Public: Set the TZ environment variable to use the timezone specified
@@ -153,25 +151,28 @@ module Jekyll
     def sanitized_path(base_directory, questionable_path)
       return base_directory if base_directory.eql?(questionable_path)
 
+      questionable_path.insert(0, '/') if questionable_path.start_with?('~')
       clean_path = File.expand_path(questionable_path, "/")
-      clean_path = clean_path.sub(/\A\w\:\//, '/')
+      clean_path.sub!(/\A\w\:\//, '/')
 
-      unless clean_path.start_with?(base_directory.sub(/\A\w\:\//, '/'))
-        File.join(base_directory, clean_path)
-      else
+      if clean_path.start_with?(base_directory.sub(/\A\w\:\//, '/'))
         clean_path
+      else
+        File.join(base_directory, clean_path)
       end
     end
 
     # Conditional optimizations
     Jekyll::External.require_if_present('liquid-c')
-
   end
 end
 
+require "jekyll/drops/drop"
+require "jekyll/drops/document_drop"
 require_all 'jekyll/commands'
 require_all 'jekyll/converters'
 require_all 'jekyll/converters/markdown'
+require_all 'jekyll/drops'
 require_all 'jekyll/generators'
 require_all 'jekyll/tags'
 
diff --git a/lib/jekyll/cleaner.rb b/lib/jekyll/cleaner.rb
index d23da78..6c89e2b 100644
--- a/lib/jekyll/cleaner.rb
+++ b/lib/jekyll/cleaner.rb
@@ -13,7 +13,7 @@ module Jekyll
     # Cleans up the site's destination directory
     def cleanup!
       FileUtils.rm_rf(obsolete_files)
-      FileUtils.rm_rf(metadata_file) if !@site.incremental?
+      FileUtils.rm_rf(metadata_file) unless @site.incremental?
     end
 
     private
@@ -40,7 +40,7 @@ module Jekyll
       regex = keep_file_regex
       dirs = keep_dirs
 
-      Dir.glob(site.in_dest_dir("**", "*"), File::FNM_DOTMATCH) do |file|
+      Utils.safe_glob(site.in_dest_dir, ["**", "*"], File::FNM_DOTMATCH).each do |file|
         next if file =~ HIDDEN_FILE_REGEX || file =~ regex || dirs.include?(file)
         files << file
       end
diff --git a/lib/jekyll/collection.rb b/lib/jekyll/collection.rb
index 4363aee..f0e3333 100644
--- a/lib/jekyll/collection.rb
+++ b/lib/jekyll/collection.rb
@@ -32,7 +32,7 @@ module Jekyll
     # Override of method_missing to check in @data for the key.
     def method_missing(method, *args, &blck)
       if docs.respond_to?(method.to_sym)
-        Jekyll.logger.warn "Deprecation:", "Collection##{method} should be called on the #docs array directly."
+        Jekyll.logger.warn "Deprecation:", "#{label}.#{method} should be changed to #{label}.docs.#{method}."
         Jekyll.logger.warn "", "Called by #{caller.first}."
         docs.public_send(method.to_sym, *args, &blck)
       else
@@ -56,9 +56,13 @@ module Jekyll
         full_path = collection_dir(file_path)
         next if File.directory?(full_path)
         if Utils.has_yaml_header? full_path
-          doc = Jekyll::Document.new(full_path, { site: site, collection: self })
+          doc = Jekyll::Document.new(full_path, { :site => site, :collection => self })
           doc.read
-          docs << doc if site.publisher.publish?(doc) || !write?
+          if site.publisher.publish?(doc) || !write?
+            docs << doc
+          else
+            Jekyll.logger.debug "Skipped From Publishing:", doc.relative_path
+          end
         else
           relative_dir = Jekyll.sanitized_path(relative_directory, File.dirname(file_path)).chomp("/.")
           files << StaticFile.new(site, site.source, relative_dir, File.basename(full_path), self)
@@ -72,10 +76,11 @@ module Jekyll
     # Returns an Array of file paths to the documents in this collection
     #   relative to the collection's directory
     def entries
-      return Array.new unless exists?
+      return [] unless exists?
       @entries ||=
-        Dir.glob(collection_dir("**", "*.*")).map do |entry|
-          entry["#{collection_dir}/"] = ''; entry
+        Utils.safe_glob(collection_dir, ["**", "*.*"]).map do |entry|
+          entry["#{collection_dir}/"] = ''
+          entry
         end
     end
 
@@ -84,7 +89,7 @@ module Jekyll
     #
     # Returns a list of filtered entry paths.
     def filtered_entries
-      return Array.new unless exists?
+      return [] unless exists?
       @filtered_entries ||=
         Dir.chdir(directory) do
           entry_filter.filter(entries).reject do |f|
@@ -166,14 +171,7 @@ module Jekyll
     #
     # Returns a representation of this collection for use in Liquid.
     def to_liquid
-      metadata.merge({
-        "label"     => label,
-        "docs"      => docs,
-        "files"     => files,
-        "directory" => directory,
-        "output"    => write?,
-        "relative_directory" => relative_directory
-      })
+      Drops::CollectionDrop.new self
     end
 
     # Whether the collection's documents ought to be written as individual
@@ -188,8 +186,8 @@ module Jekyll
     #
     # Returns the URL template to render collection's documents at.
     def url_template
-      metadata.fetch('permalink') do
-          Utils.add_permalink_suffix("/:collection/:path", site.permalink_style)
+      @url_template ||= metadata.fetch('permalink') do
+        Utils.add_permalink_suffix("/:collection/:path", site.permalink_style)
       end
     end
 
@@ -198,7 +196,7 @@ module Jekyll
     # Returns the metadata for this collection
     def extract_metadata
       if site.config['collections'].is_a?(Hash)
-        site.config['collections'][label] || Hash.new
+        site.config['collections'][label] || {}
       else
         {}
       end
diff --git a/lib/jekyll/command.rb b/lib/jekyll/command.rb
index f3c89df..afe72a5 100644
--- a/lib/jekyll/command.rb
+++ b/lib/jekyll/command.rb
@@ -1,8 +1,6 @@
 module Jekyll
   class Command
-
     class << self
-
       # A list of subclasses of Jekyll::Command
       def subclasses
         @subclasses ||= []
@@ -62,8 +60,6 @@ module Jekyll
         c.option 'verbose', '-V', '--verbose', 'Print verbose output.'
         c.option 'incremental', '-I', '--incremental', 'Enable incremental rebuild.'
       end
-
     end
-
   end
 end
diff --git a/lib/jekyll/commands/build.rb b/lib/jekyll/commands/build.rb
index de0cc8b..baa4e88 100644
--- a/lib/jekyll/commands/build.rb
+++ b/lib/jekyll/commands/build.rb
@@ -1,9 +1,7 @@
 module Jekyll
   module Commands
     class Build < Command
-
       class << self
-
         # Create the Mercenary command for the Jekyll CLI for this Command
         def init_with_program(prog)
           prog.command(:build) do |c|
@@ -13,7 +11,7 @@ module Jekyll
 
             add_build_options(c)
 
-            c.action do |args, options|
+            c.action do |_, options|
               options["serving"] = false
               Jekyll::Commands::Build.process(options)
             end
@@ -35,7 +33,9 @@ module Jekyll
             build(site, options)
           end
 
-          if options.fetch('watch', false)
+          if options.fetch('detach', false)
+            Jekyll.logger.info "Auto-regeneration:", "disabled when running server detached."
+          elsif options.fetch('watch', false)
             watch(site, options)
           else
             Jekyll.logger.info "Auto-regeneration:", "disabled. Use --watch to enable."
@@ -67,13 +67,11 @@ module Jekyll
         # options - A Hash of options passed to the command
         #
         # Returns nothing.
-        def watch(site, options)
+        def watch(_site, options)
           External.require_with_graceful_fail 'jekyll-watch'
           Jekyll::Watcher.watch(options)
         end
-
       end # end of class << self
-
     end
   end
 end
diff --git a/lib/jekyll/commands/clean.rb b/lib/jekyll/commands/clean.rb
index bf05dbe..371b704 100644
--- a/lib/jekyll/commands/clean.rb
+++ b/lib/jekyll/commands/clean.rb
@@ -2,7 +2,6 @@ module Jekyll
   module Commands
     class Clean < Command
       class << self
-
         def init_with_program(prog)
           prog.command(:clean) do |c|
             c.syntax 'clean [subcommand]'
@@ -10,8 +9,8 @@ module Jekyll
 
             add_build_options(c)
 
-            c.action do |args, _|
-              Jekyll::Commands::Clean.process({})
+            c.action do |_, options|
+              Jekyll::Commands::Clean.process(options)
             end
           end
         end
@@ -37,7 +36,6 @@ module Jekyll
             Jekyll.logger.info "Nothing to do for #{metadata_file}."
           end
         end
-
       end
     end
   end
diff --git a/lib/jekyll/commands/doctor.rb b/lib/jekyll/commands/doctor.rb
index 6d7429e..3a26350 100644
--- a/lib/jekyll/commands/doctor.rb
+++ b/lib/jekyll/commands/doctor.rb
@@ -2,7 +2,6 @@ module Jekyll
   module Commands
     class Doctor < Command
       class << self
-
         def init_with_program(prog)
           prog.command(:doctor) do |c|
             c.syntax 'doctor'
@@ -11,7 +10,7 @@ module Jekyll
 
             c.option '--config CONFIG_FILE[,CONFIG_FILE2,...]', Array, 'Custom configuration file'
 
-            c.action do |args, options|
+            c.action do |_, options|
               Jekyll::Commands::Doctor.process(options)
             end
           end
@@ -32,14 +31,15 @@ module Jekyll
           [
             fsnotify_buggy?(site),
             !deprecated_relative_permalinks(site),
-            !conflicting_urls(site)
+            !conflicting_urls(site),
+            !urls_only_differ_by_case(site)
           ].all?
         end
 
         def deprecated_relative_permalinks(site)
           if site.config['relative_permalinks']
-            Jekyll::Deprecator.deprecation_message "Your site still uses relative" +
-                                " permalinks, which was removed in" +
+            Jekyll::Deprecator.deprecation_message "Your site still uses relative" \
+                                " permalinks, which was removed in" \
                                 " Jekyll v3.0.0."
             return true
           end
@@ -51,17 +51,16 @@ module Jekyll
           urls = collect_urls(urls, site.pages, site.dest)
           urls = collect_urls(urls, site.posts.docs, site.dest)
           urls.each do |url, paths|
-            if paths.size > 1
-              conflicting_urls = true
-              Jekyll.logger.warn "Conflict:", "The URL '#{url}' is the destination" +
-                " for the following pages: #{paths.join(", ")}"
-            end
+            next unless paths.size > 1
+            conflicting_urls = true
+            Jekyll.logger.warn "Conflict:", "The URL '#{url}' is the destination" \
+              " for the following pages: #{paths.join(", ")}"
           end
           conflicting_urls
         end
 
-        def fsnotify_buggy?(site)
-          return true if !Utils::Platforms.osx?
+        def fsnotify_buggy?(_site)
+          return true unless Utils::Platforms.osx?
           if Dir.pwd != `pwd`.strip
             Jekyll.logger.error "  " + <<-STR.strip.gsub(/\n\s+/, "\n  ")
               We have detected that there might be trouble using fsevent on your
@@ -76,6 +75,19 @@ module Jekyll
           true
         end
 
+        def urls_only_differ_by_case(site)
+          urls_only_differ_by_case = false
+          urls = case_insensitive_urls(site.pages + site.docs_to_write, site.dest)
+          urls.each do |case_insensitive_url, real_urls|
+            next unless real_urls.uniq.size > 1
+            urls_only_differ_by_case = true
+            Jekyll.logger.warn "Warning:", "The following URLs only differ" \
+              " by case. On a case-insensitive file system one of the URLs" \
+              " will be overwritten by the other: #{real_urls.join(", ")}"
+          end
+          urls_only_differ_by_case
+        end
+
         private
         def collect_urls(urls, things, destination)
           things.each do |thing|
@@ -89,8 +101,14 @@ module Jekyll
           urls
         end
 
+        def case_insensitive_urls(things, destination)
+          things.inject({}) do |memo, thing|
+            dest = thing.destination(destination)
+            (memo[dest.downcase] ||= []) << dest
+            memo
+          end
+        end
       end
-
     end
   end
 end
diff --git a/lib/jekyll/commands/help.rb b/lib/jekyll/commands/help.rb
index 421d87e..01bf328 100644
--- a/lib/jekyll/commands/help.rb
+++ b/lib/jekyll/commands/help.rb
@@ -2,7 +2,6 @@ module Jekyll
   module Commands
     class Help < Command
       class << self
-
         def init_with_program(prog)
           prog.command(:help) do |c|
             c.syntax 'help [subcommand]'
@@ -26,7 +25,6 @@ module Jekyll
           Jekyll.logger.error "Error:", "Hmm... we don't know what the '#{cmd}' command is."
           Jekyll.logger.info  "Valid commands:", prog.commands.keys.join(", ")
         end
-
       end
     end
   end
diff --git a/lib/jekyll/commands/serve.rb b/lib/jekyll/commands/serve.rb
index 111d670..4840f41 100644
--- a/lib/jekyll/commands/serve.rb
+++ b/lib/jekyll/commands/serve.rb
@@ -1,151 +1,205 @@
-# -*- encoding: utf-8 -*-
 module Jekyll
   module Commands
     class Serve < Command
-
       class << self
+        COMMAND_OPTIONS = {
+          "ssl_cert" => ["--ssl-cert [CERT]", "X.509 (SSL) certificate."],
+          "host"     => ["host", "-H", "--host [HOST]", "Host to bind to"],
+          "open_url" => ["-o", "--open-url", "Launch your browser with your site."],
+          "detach"   => ["-B", "--detach", "Run the server in the background (detach)"],
+          "ssl_key"  => ["--ssl-key [KEY]", "X.509 (SSL) Private Key."],
+          "port"     => ["-P", "--port [PORT]", "Port to listen on"],
+          "baseurl"  => ["-b", "--baseurl [URL]", "Base URL"],
+          "skip_initial_build" => ["skip_initial_build", "--skip-initial-build",
+            "Skips the initial site build which occurs before the server is started."]
+        }
+
+        #
 
         def init_with_program(prog)
-          prog.command(:serve) do |c|
-            c.syntax 'serve [options]'
-            c.description 'Serve your site locally'
-            c.alias :server
-            c.alias :s
-
-            add_build_options(c)
-
-            c.option 'detach', '-B', '--detach', 'Run the server in the background (detach)'
-            c.option 'port', '-P', '--port [PORT]', 'Port to listen on'
-            c.option 'host', '-H', '--host [HOST]', 'Host to bind to'
-            c.option 'baseurl', '-b', '--baseurl [URL]', 'Base URL'
-            c.option 'skip_initial_build', '--skip-initial-build', 'Skips the initial site build which occurs before the server is started.'
-
-            c.action do |args, options|
-              options["serving"] = true
-              options["watch"] = true unless options.key?("watch")
-              Jekyll::Commands::Build.process(options)
-              Jekyll::Commands::Serve.process(options)
+          prog.command(:serve) do |cmd|
+            cmd.description "Serve your site locally"
+            cmd.syntax "serve [options]"
+            cmd.alias :server
+            cmd.alias :s
+
+            add_build_options(cmd)
+            COMMAND_OPTIONS.each do |key, val|
+              cmd.option key, *val
+            end
+
+            cmd.action do |_, opts|
+              opts["serving"] = true
+              opts["watch"  ] = true unless opts.key?("watch")
+              Build.process(opts)
+              Serve.process(opts)
             end
           end
         end
 
-        # Boot up a WEBrick server which points to the compiled site's root.
-        def process(options)
-          options = configuration_from_options(options)
-          destination = options['destination']
-          setup(destination)
+        #
 
-          s = WEBrick::HTTPServer.new(webrick_options(options))
-          s.unmount("")
-
-          s.mount(
-            options['baseurl'],
-            custom_file_handler,
-            destination,
-            file_handler_options
-          )
-
-          Jekyll.logger.info "Server address:", server_address(s, options)
+        def process(opts)
+          opts = configuration_from_options(opts)
+          destination = opts["destination"]
+          setup(destination)
 
-          if options['detach'] # detach the server
-            pid = Process.fork { s.start }
-            Process.detach(pid)
-            Jekyll.logger.info "Server detached with pid '#{pid}'.", "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
-          else # create a new server thread, then join it with current terminal
-            t = Thread.new { s.start }
-            trap("INT") { s.shutdown }
-            t.join
-          end
+          server = WEBrick::HTTPServer.new(webrick_opts(opts)).tap { |o| o.unmount("") }
+          server.mount(opts["baseurl"], Servlet, destination, file_handler_opts)
+          Jekyll.logger.info "Server address:", server_address(server, opts)
+          launch_browser server, opts if opts["open_url"]
+          boot_or_detach server, opts
         end
 
+        # Do a base pre-setup of WEBRick so that everything is in place
+        # when we get ready to party, checking for an setting up an error page
+        # and making sure our destination exists.
+
+        private
         def setup(destination)
-          require 'webrick'
+          require_relative "serve/servlet"
 
           FileUtils.mkdir_p(destination)
-
-          # monkey patch WEBrick using custom 404 page (/404.html)
-          if File.exist?(File.join(destination, '404.html'))
+          if File.exist?(File.join(destination, "404.html"))
             WEBrick::HTTPResponse.class_eval do
               def create_error_page
-                @header['content-type'] = "text/html; charset=UTF-8"
-                @body = IO.read(File.join(@config[:DocumentRoot], '404.html'))
+                @header["Content-Type"] = "text/html; charset=UTF-8"
+                @body = IO.read(File.join(@config[:DocumentRoot], "404.html"))
               end
             end
           end
         end
 
-        def webrick_options(config)
+        #
+
+        private
+        def webrick_opts(opts)
           opts = {
-            :BindAddress        => config['host'],
-            :DirectoryIndex     => %w(index.html index.htm index.cgi index.rhtml index.xml),
-            :DocumentRoot       => config['destination'],
+            :JekyllOptions      => opts,
             :DoNotReverseLookup => true,
             :MimeTypes          => mime_types,
-            :Port               => config['port'],
-            :StartCallback      => start_callback(config['detach'])
+            :DocumentRoot       => opts["destination"],
+            :StartCallback      => start_callback(opts["detach"]),
+            :BindAddress        => opts["host"],
+            :Port               => opts["port"],
+            :DirectoryIndex     => %W(
+              index.htm
+              index.html
+              index.rhtml
+              index.cgi
+              index.xml
+            )
           }
 
-          if config['verbose']
-            opts.merge!({
-              :Logger => WEBrick::Log.new($stdout, WEBrick::Log::DEBUG)
-            })
-          else
-            opts.merge!({
-              :AccessLog => [],
-              :Logger => WEBrick::Log.new([], WEBrick::Log::WARN)
-            })
-          end
-
+          enable_ssl(opts)
+          enable_logging(opts)
           opts
         end
 
-        # Custom WEBrick FileHandler servlet for serving "/file.html" at "/file"
-        # when no exact match is found. This mirrors the behavior of GitHub
-        # Pages and many static web server configs.
-        def custom_file_handler
-          Class.new WEBrick::HTTPServlet::FileHandler do
-            def search_file(req, res, basename)
-              if file = super
-                file
-              else
-                super(req, res, "#{basename}.html")
-              end
+        # Recreate NondisclosureName under utf-8 circumstance
+
+        private
+        def file_handler_opts
+          WEBrick::Config::FileHandler.merge({
+            :FancyIndexing     => true,
+            :NondisclosureName => [
+              '.ht*', '~*'
+            ]
+          })
+        end
+
+        #
+
+        private
+        def server_address(server, opts)
+          "%{prefix}://%{address}:%{port}%{baseurl}" % {
+            :prefix => server.config[:SSLEnable] ? "https" : "http",
+            :baseurl => opts["baseurl"] ? "#{opts["baseurl"]}/" : "",
+            :address => server.config[:BindAddress],
+            :port => server.config[:Port]
+          }
+        end
+
+        #
+
+        private
+        def launch_browser(server, opts)
+          command =
+            if Utils::Platforms.windows?
+              "start"
+            elsif Utils::Platforms.osx?
+              "open"
+            else
+              "xdg-open"
             end
-          end
+          system command, server_address(server, opts)
         end
 
-        def start_callback(detached)
-          unless detached
-            Proc.new { Jekyll.logger.info "Server running...", "press ctrl-c to stop." }
+        # Keep in our area with a thread or detach the server as requested
+        # by the user.  This method determines what we do based on what you
+        # ask us to do.
+
+        private
+        def boot_or_detach(server, opts)
+          if opts["detach"]
+            pid = Process.fork do
+              server.start
+            end
+
+            Process.detach(pid)
+            Jekyll.logger.info "Server detached with pid '#{pid}'.", \
+              "Run `pkill -f jekyll' or `kill -9 #{pid}' to stop the server."
+          else
+            t = Thread.new { server.start }
+            trap("INT") { server.shutdown }
+            t.join
           end
         end
 
-        def mime_types
-          mime_types_file = File.expand_path('../mime.types', File.dirname(__FILE__))
-          WEBrick::HTTPUtils::load_mime_types(mime_types_file)
+        # Make the stack verbose if the user requests it.
+
+        private
+        def enable_logging(opts)
+          opts[:AccessLog] = []
+          level = WEBrick::Log.const_get(opts[:JekyllOptions]["verbose"] ? :DEBUG : :WARN)
+          opts[:Logger] = WEBrick::Log.new($stdout, level)
         end
 
-        def server_address(server, options)
-          baseurl = "#{options['baseurl']}/" if options['baseurl']
-          [
-            "http://",
-            server.config[:BindAddress],
-            ":",
-            server.config[:Port],
-            baseurl || ""
-          ].map(&:to_s).join("")
+        # Add SSL to the stack if the user triggers --enable-ssl and they
+        # provide both types of certificates commonly needed.  Raise if they
+        # forget to add one of the certificates.
+
+        private
+        def enable_ssl(opts)
+          return if !opts[:JekyllOptions]["ssl_cert"] && !opts[:JekyllOptions]["ssl_key"]
+          if !opts[:JekyllOptions]["ssl_cert"] || !opts[:JekyllOptions]["ssl_key"]
+            raise RuntimeError, "--ssl-cert or --ssl-key missing."
+          end
+
+          require "openssl"
+          require "webrick/https"
+          source_key = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_key" ])
+          source_certificate = Jekyll.sanitized_path(opts[:JekyllOptions]["source"], opts[:JekyllOptions]["ssl_cert"])
+          opts[:SSLCertificate] = OpenSSL::X509::Certificate.new(File.read(source_certificate))
+          opts[:SSLPrivateKey ] = OpenSSL::PKey::RSA.new(File.read(source_key))
+          opts[:SSLEnable] = true
         end
 
-        # recreate NondisclosureName under utf-8 circumstance
-        def file_handler_options
-          WEBrick::Config::FileHandler.merge({
-            :FancyIndexing     => true,
-            :NondisclosureName => ['.ht*','~*']
-          })
+        private
+        def start_callback(detached)
+          unless detached
+            proc do
+              Jekyll.logger.info("Server running...", "press ctrl-c to stop.")
+            end
+          end
         end
 
+        private
+        def mime_types
+          file = File.expand_path('../mime.types', File.dirname(__FILE__))
+          WEBrick::HTTPUtils.load_mime_types(file)
+        end
       end
-
     end
   end
 end
diff --git a/lib/jekyll/commands/serve/servlet.rb b/lib/jekyll/commands/serve/servlet.rb
new file mode 100644
index 0000000..bb4afe5
--- /dev/null
+++ b/lib/jekyll/commands/serve/servlet.rb
@@ -0,0 +1,61 @@
+require "webrick"
+
+module Jekyll
+  module Commands
+    class Serve
+      class Servlet < WEBrick::HTTPServlet::FileHandler
+        DEFAULTS = {
+          "Cache-Control" => "private, max-age=0, proxy-revalidate, " \
+            "no-store, no-cache, must-revalidate"
+        }
+
+        def initialize(server, root, callbacks)
+          # So we can access them easily.
+          @jekyll_opts = server.config[:JekyllOptions]
+          set_defaults
+          super
+        end
+
+        # Add the ability to tap file.html the same way that Nginx does on our
+        # Docker images (or on GitHub Pages.) The difference is that we might end
+        # up with a different preference on which comes first.
+
+        def search_file(req, res, basename)
+          # /file.* > /file/index.html > /file.html
+          super || super(req, res, "#{basename}.html")
+        end
+
+        #
+
+        def do_GET(req, res)
+          rtn = super
+          validate_and_ensure_charset(req, res)
+          res.header.merge!(@headers)
+          rtn
+        end
+
+        #
+
+        private
+        def validate_and_ensure_charset(_req, res)
+          key = res.header.keys.grep(/content-type/i).first
+          typ = res.header[key]
+
+          unless typ =~ /;\s*charset=/
+            res.header[key] = "#{typ}; charset=#{@jekyll_opts["encoding"]}"
+          end
+        end
+
+        #
+
+        private
+        def set_defaults
+          hash_ = @jekyll_opts.fetch("webrick", {}).fetch("headers", {})
+          DEFAULTS.each_with_object(@headers = hash_) do |(key, val), hash|
+            hash[key] = val unless hash.key?(key)
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/configuration.rb b/lib/jekyll/configuration.rb
index f57b3ae..82e9013 100644
--- a/lib/jekyll/configuration.rb
+++ b/lib/jekyll/configuration.rb
@@ -2,7 +2,6 @@
 
 module Jekyll
   class Configuration < Hash
-
     # Default options. Overridden by values in _config.yml.
     # Strings rather than symbols are used for compatibility with YAML.
     DEFAULTS = Configuration[{
@@ -19,7 +18,7 @@ module Jekyll
       'safe'          => false,
       'include'       => ['.htaccess'],
       'exclude'       => [],
-      'keep_files'    => ['.git','.svn'],
+      'keep_files'    => ['.git', '.svn'],
       'encoding'      => 'utf-8',
       'markdown_ext'  => 'markdown,mkdown,mkdn,mkd,md',
 
@@ -65,28 +64,37 @@ module Jekyll
 
       'kramdown' => {
         'auto_ids'       => true,
-        'footnote_nr'    => 1,
-        'entity_output'  => 'as_char',
         'toc_levels'     => '1..6',
+        'entity_output'  => 'as_char',
         'smart_quotes'   => 'lsquo,rsquo,ldquo,rdquo',
-        'enable_coderay' => false,
-
-        'coderay' => {
-          'coderay_wrap'              => 'div',
-          'coderay_line_numbers'      => 'inline',
-          'coderay_line_number_start' => 1,
-          'coderay_tab_width'         => 4,
-          'coderay_bold_every'        => 10,
-          'coderay_css'               => 'style'
-        }
+        'input'          => "GFM",
+        'hard_wrap'      => false,
+        'footnote_nr'    => 1
       }
-    }]
+    }.map { |k, v| [k, v.freeze] }].freeze
+
+    class << self
+      # Static: Produce a Configuration ready for use in a Site.
+      # It takes the input, fills in the defaults where values do not
+      # exist, and patches common issues including migrating options for
+      # backwards compatiblity. Except where a key or value is being fixed,
+      # the user configuration will override the defaults.
+      #
+      # user_config - a Hash or Configuration of overrides.
+      #
+      # Returns a Configuration filled with defaults and fixed for common
+      # problems and backwards-compatibility.
+      def from(user_config)
+        Utils.deep_merge_hashes(DEFAULTS, Configuration[user_config].stringify_keys).
+          fix_common_issues.add_default_collections
+      end
+    end
 
     # Public: Turn all keys into string
     #
     # Return a copy of the hash where all its keys are strings
     def stringify_keys
-      reduce({}) { |hsh,(k,v)| hsh.merge(k.to_s => v) }
+      reduce({}) { |hsh, (k, v)| hsh.merge(k.to_s => v) }
     end
 
     def get_config_value_with_override(config_key, override)
@@ -118,7 +126,7 @@ module Jekyll
         Jekyll::External.require_with_graceful_fail('toml') unless defined?(TOML)
         TOML.load_file(filename)
       when /\.ya?ml/i
-        SafeYAML.load_file(filename)
+        SafeYAML.load_file(filename) || {}
       else
         raise ArgumentError, "No parser for '#{filename}' is available. Use a .toml or .y(a)ml file instead."
       end
@@ -136,7 +144,7 @@ module Jekyll
       # Get configuration from <source>/_config.yml or <source>/<config_file>
       config_files = override.delete('config')
       if config_files.to_s.empty?
-        default = %w[yml yaml].find(Proc.new { 'yml' }) do |ext|
+        default = %w(yml yaml).find(-> { 'yml' }) do |ext|
           File.exist?(Jekyll.sanitized_path(source(override), "_config.#{ext}"))
         end
         config_files = Jekyll.sanitized_path(source(override), "_config.#{default}")
@@ -153,7 +161,7 @@ module Jekyll
     # Returns this configuration, overridden by the values in the file
     def read_config_file(file)
       next_config = safe_load_file(file)
-      raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow) unless next_config.is_a?(Hash)
+      check_config_is_hash!(next_config, file)
       Jekyll.logger.info "Configuration file:", file
       next_config
     rescue SystemCallError
@@ -177,11 +185,12 @@ module Jekyll
 
       begin
         files.each do |config_file|
+          next if config_file.nil? or config_file.empty?
           new_config = read_config_file(config_file)
           configuration = Utils.deep_merge_hashes(configuration, new_config)
         end
       rescue ArgumentError => err
-        Jekyll.logger.warn "WARNING:", "Error reading configuration. " +
+        Jekyll.logger.warn "WARNING:", "Error reading configuration. " \
                      "Using defaults (and options)."
         $stderr.puts "#{err}"
       end
@@ -206,16 +215,16 @@ module Jekyll
       config = clone
       # Provide backwards-compatibility
       if config.key?('auto') || config.key?('watch')
-        Jekyll::Deprecator.deprecation_message "Auto-regeneration can no longer" +
-                            " be set from your configuration file(s). Use the"+
+        Jekyll::Deprecator.deprecation_message "Auto-regeneration can no longer" \
+                            " be set from your configuration file(s). Use the"\
                             " --[no-]watch/-w command-line option instead."
         config.delete('auto')
         config.delete('watch')
       end
 
       if config.key? 'server'
-        Jekyll::Deprecator.deprecation_message "The 'server' configuration option" +
-                            " is no longer accepted. Use the 'jekyll serve'" +
+        Jekyll::Deprecator.deprecation_message "The 'server' configuration option" \
+                            " is no longer accepted. Use the 'jekyll serve'" \
                             " subcommand to serve your site with WEBrick."
         config.delete('server')
       end
@@ -226,37 +235,37 @@ module Jekyll
       renamed_key 'data_source', 'data_dir', config
 
       if config.key? 'pygments'
-        Jekyll::Deprecator.deprecation_message "The 'pygments' configuration option" +
-                            " has been renamed to 'highlighter'. Please update your" +
-                            " config file accordingly. The allowed values are 'rouge', " +
+        Jekyll::Deprecator.deprecation_message "The 'pygments' configuration option" \
+                            " has been renamed to 'highlighter'. Please update your" \
+                            " config file accordingly. The allowed values are 'rouge', " \
                             "'pygments' or null."
 
         config['highlighter'] = 'pygments' if config['pygments']
         config.delete('pygments')
       end
 
-      %w[include exclude].each do |option|
-        if config.fetch(option, []).is_a?(String)
-          Jekyll::Deprecator.deprecation_message "The '#{option}' configuration option" +
-            " must now be specified as an array, but you specified" +
-            " a string. For now, we've treated the string you provided" +
+      %w(include exclude).each do |option|
+        if config[option].is_a?(String)
+          Jekyll::Deprecator.deprecation_message "The '#{option}' configuration option" \
+            " must now be specified as an array, but you specified" \
+            " a string. For now, we've treated the string you provided" \
             " as a list of comma-separated values."
           config[option] = csv_to_array(config[option])
         end
-        config[option].map!(&:to_s)
+        config[option].map!(&:to_s) if config[option]
       end
 
       if (config['kramdown'] || {}).key?('use_coderay')
-        Jekyll::Deprecator.deprecation_message "Please change 'use_coderay'" +
+        Jekyll::Deprecator.deprecation_message "Please change 'use_coderay'" \
           " to 'enable_coderay' in your configuration file."
         config['kramdown']['use_coderay'] = config['kramdown'].delete('enable_coderay')
       end
 
       if config.fetch('markdown', 'kramdown').to_s.downcase.eql?("maruku")
-        Jekyll.logger.abort_with "Error:", "You're using the 'maruku' " +
-          "Markdown processor, which has been removed as of 3.0.0. " +
-          "We recommend you switch to Kramdown. To do this, replace " +
-          "`markdown: maruku` with `markdown: kramdown` in your " +
+        Jekyll.logger.abort_with "Error:", "You're using the 'maruku' " \
+          "Markdown processor, which has been removed as of 3.0.0. " \
+          "We recommend you switch to Kramdown. To do this, replace " \
+          "`markdown: maruku` with `markdown: kramdown` in your " \
           "`_config.yml` file."
       end
 
@@ -267,7 +276,7 @@ module Jekyll
       config = clone
 
       if config.key?('paginate') && (!config['paginate'].is_a?(Integer) || config['paginate'] < 1)
-        Jekyll.logger.warn "Config Warning:", "The `paginate` key must be a" +
+        Jekyll.logger.warn "Config Warning:", "The `paginate` key must be a" \
           " positive integer or nil. It's currently set to '#{config['paginate'].inspect}'."
         config['paginate'] = nil
       end
@@ -278,41 +287,62 @@ module Jekyll
     def add_default_collections
       config = clone
 
+      # It defaults to `{}`, so this is only if someone sets it to null manually.
       return config if config['collections'].nil?
 
+      # Ensure we have a hash.
       if config['collections'].is_a?(Array)
-        config['collections'] = Hash[config['collections'].map{|c| [c, {}]}]
+        config['collections'] = Hash[config['collections'].map { |c| [c, {}] }]
+      end
+
+      config['collections'] = Utils.deep_merge_hashes(
+        { 'posts' => {} }, config['collections']
+      ).tap do |collections|
+        collections['posts']['output'] = true
+        if config['permalink']
+          collections['posts']['permalink'] ||= style_to_permalink(config['permalink'])
+        end
       end
-      config['collections']['posts'] ||= {}
-      config['collections']['posts']['output'] = true
-      config['collections']['posts']['permalink'] = style_to_permalink(config['permalink'])
 
       config
     end
 
-    def renamed_key(old, new, config, allowed_values = nil)
+    def renamed_key(old, new, config, _ = nil)
       if config.key?(old)
-        Jekyll::Deprecator.deprecation_message "The '#{old}' configuration" +
-          "option has been renamed to '#{new}'. Please update your config " +
+        Jekyll::Deprecator.deprecation_message "The '#{old}' configuration" \
+          "option has been renamed to '#{new}'. Please update your config " \
           "file accordingly."
         config[new] = config.delete(old)
       end
     end
 
     private
+
     def style_to_permalink(permalink_style)
       case permalink_style.to_sym
       when :pretty
         "/:categories/:year/:month/:day/:title/"
       when :none
-        "/:categories/:title.html"
+        "/:categories/:title:output_ext"
       when :date
-        "/:categories/:year/:month/:day/:title.html"
+        "/:categories/:year/:month/:day/:title:output_ext"
       when :ordinal
-        "/:categories/:year/:y_day/:title.html"
+        "/:categories/:year/:y_day/:title:output_ext"
       else
         permalink_style.to_s
       end
     end
+
+    # Private: Checks if a given config is a hash
+    #
+    # extracted_config - the value to check
+    # file - the file from which the config was extracted
+    #
+    # Raises an ArgumentError if given config is not a hash
+    def check_config_is_hash!(extracted_config, file)
+      unless extracted_config.is_a?(Hash)
+        raise ArgumentError.new("Configuration file: (INVALID) #{file}".yellow)
+      end
+    end
   end
 end
diff --git a/lib/jekyll/converters/identity.rb b/lib/jekyll/converters/identity.rb
index 69171b0..9574769 100644
--- a/lib/jekyll/converters/identity.rb
+++ b/lib/jekyll/converters/identity.rb
@@ -5,7 +5,7 @@ module Jekyll
 
       priority :lowest
 
-      def matches(ext)
+      def matches(_ext)
         true
       end
 
diff --git a/lib/jekyll/converters/markdown.rb b/lib/jekyll/converters/markdown.rb
index 30c7ef3..aed906d 100644
--- a/lib/jekyll/converters/markdown.rb
+++ b/lib/jekyll/converters/markdown.rb
@@ -1,57 +1,62 @@
 module Jekyll
   module Converters
     class Markdown < Converter
-      safe true
-
       highlighter_prefix "\n"
       highlighter_suffix "\n"
+      safe true
 
       def setup
         return if @setup
-        @parser =
-          case @config['markdown'].downcase
-            when 'redcarpet' then RedcarpetParser.new(@config)
-            when 'kramdown'  then KramdownParser.new(@config)
-            when 'rdiscount' then RDiscountParser.new(@config)
-          else
-            # So they can't try some tricky bullshit or go down the ancestor chain, I hope.
-            if allowed_custom_class?(@config['markdown'])
-              self.class.const_get(@config['markdown']).new(@config)
-            else
-              Jekyll.logger.error "Invalid Markdown Processor:", "#{@config['markdown']}"
-              Jekyll.logger.error "", "Valid options are [ #{valid_processors.join(" | ")} ]"
-              raise Errors::FatalException, "Invalid Markdown Processor: #{@config['markdown']}"
-            end
-          end
+        unless (@parser = get_processor)
+          Jekyll.logger.error "Invalid Markdown processor given:", @config["markdown"]
+          Jekyll.logger.info  "", "Custom processors are not loaded in safe mode" if @config["safe"]
+          Jekyll.logger.error "", "Available processors are: #{valid_processors.join(", ")}"
+          raise Errors::FatalException, "Bailing out; invalid Markdown processor."
+        end
+
         @setup = true
       end
 
+      def get_processor
+        case @config["markdown"].downcase
+        when "redcarpet" then return RedcarpetParser.new(@config)
+        when "kramdown"  then return KramdownParser.new(@config)
+        when "rdiscount" then return RDiscountParser.new(@config)
+        else
+          get_custom_processor
+        end
+      end
+
+      # Public: Provides you with a list of processors, the ones we
+      # support internally and the ones that you have provided to us (if you
+      # are not in safe mode.)
+
       def valid_processors
-        %w[
-          rdiscount
-          kramdown
-          redcarpet
-        ] + third_party_processors
+        %W(rdiscount kramdown redcarpet) + third_party_processors
       end
 
+      # Public: A list of processors that you provide via plugins.
+      # This is really only available if you are not in safe mode, if you are
+      # in safe mode (re: GitHub) then there will be none.
+
       def third_party_processors
-        self.class.constants - %w[
-          KramdownParser
-          RDiscountParser
-          RedcarpetParser
-          PRIORITIES
-        ].map(&:to_sym)
+        self.class.constants - \
+        %w(KramdownParser RDiscountParser RedcarpetParser PRIORITIES).map(
+          &:to_sym
+        )
       end
 
       def extname_list
-        @extname_list ||= @config['markdown_ext'].split(',').map { |e| ".#{e.downcase}" }
+        @extname_list ||= @config['markdown_ext'].split(',').map do |e|
+          ".#{e.downcase}"
+        end
       end
 
       def matches(ext)
-        extname_list.include? ext.downcase
+        extname_list.include?(ext.downcase)
       end
 
-      def output_ext(ext)
+      def output_ext(_ext)
         ".html"
       end
 
@@ -61,16 +66,26 @@ module Jekyll
       end
 
       private
+      def get_custom_processor
+        converter_name = @config["markdown"]
+        if custom_class_allowed?(converter_name)
+          self.class.const_get(converter_name).new(@config)
+        end
+      end
 
-      # Private: Determine whether a class name is an allowed custom markdown
-      # class name
+      # Private: Determine whether a class name is an allowed custom
+      #   markdown class name.
       #
       # parser_name - the name of the parser class
       #
-      # Returns true if the parser name contains only alphanumeric characters
-      # and is defined within Jekyll::Converters::Markdown
-      def allowed_custom_class?(parser_name)
-        parser_name !~ /[^A-Za-z0-9]/ && self.class.constants.include?(parser_name.to_sym)
+      # Returns true if the parser name contains only alphanumeric
+      # characters and is defined within Jekyll::Converters::Markdown
+
+      private
+      def custom_class_allowed?(parser_name)
+        parser_name !~ /[^A-Za-z0-9_]/ && self.class.constants.include?(
+          parser_name.to_sym
+        )
       end
     end
   end
diff --git a/lib/jekyll/converters/markdown/kramdown_parser.rb b/lib/jekyll/converters/markdown/kramdown_parser.rb
index 40dfa87..93605cd 100644
--- a/lib/jekyll/converters/markdown/kramdown_parser.rb
+++ b/lib/jekyll/converters/markdown/kramdown_parser.rb
@@ -1,33 +1,116 @@
+# Frozen-string-literal: true
+# Encoding: utf-8
+
 module Jekyll
   module Converters
     class Markdown
       class KramdownParser
+        CODERAY_DEFAULTS = {
+          "css"               => "style",
+          "bold_every"        => 10,
+          "line_numbers"      => "inline",
+          "line_number_start" => 1,
+          "tab_width"         => 4,
+          "wrap"              => "div"
+        }.freeze
+
         def initialize(config)
-          require 'kramdown'
-          @config = config
-          # If kramdown supported highlighter enabled, use that
-          highlighter = @config['highlighter']
-          if highlighter == 'rouge' || highlighter == 'coderay'
-            @config['kramdown']['syntax_highlighter'] ||= highlighter
-          end
-        rescue LoadError
-          STDERR.puts 'You are missing a library required for Markdown. Please run:'
-          STDERR.puts '  $ [sudo] gem install kramdown'
-          raise Errors::FatalException.new("Missing dependency: kramdown")
+          Jekyll::External.require_with_graceful_fail "kramdown"
+          @main_fallback_highlighter = config["highlighter"] || "rouge"
+          @config = config["kramdown"] || {}
+          setup
+        end
+
+        # Setup and normalize the configuration:
+        #   * Create Kramdown if it doesn't exist.
+        #   * Set syntax_highlighter, detecting enable_coderay and merging highlighter if none.
+        #   * Merge kramdown[coderay] into syntax_highlighter_opts stripping coderay_.
+        #   * Make sure `syntax_highlighter_opts` exists.
+
+        def setup
+          @config["syntax_highlighter"] ||= highlighter
+          @config["syntax_highlighter_opts"] ||= {}
+          @config["coderay"] ||= {} # XXX: Legacy.
+          modernize_coderay_config
+          make_accessible
         end
 
         def convert(content)
-          # Check for use of coderay
-          if @config['kramdown']['enable_coderay']
-            %w[wrap line_numbers line_numbers_start tab_width bold_every css default_lang].each do |opt|
-              key = "coderay_#{opt}"
-              @config['kramdown'][key] = @config['kramdown']['coderay'][key] unless @config['kramdown'].key?(key)
+          Kramdown::Document.new(content, @config).to_html
+        end
+
+        private
+        def make_accessible(hash = @config)
+          proc_ = proc { |hash_, key| hash_[key.to_s] if key.is_a?(Symbol) }
+          hash.default_proc = proc_
+
+          hash.each do |_, val|
+            make_accessible val if val.is_a?(
+              Hash
+            )
+          end
+        end
+
+        # config[kramdown][syntax_higlighter] > config[kramdown][enable_coderay] > config[highlighter]
+        # Where `enable_coderay` is now deprecated because Kramdown
+        # supports Rouge now too.
+
+        private
+        def highlighter
+          return @highlighter if @highlighter
+
+          if @config["syntax_highlighter"]
+            return @highlighter = @config[
+              "syntax_highlighter"
+            ]
+          end
+
+          @highlighter = begin
+            if @config.key?("enable_coderay") && @config["enable_coderay"]
+              Jekyll::Deprecator.deprecation_message "You are using 'enable_coderay', " \
+                "use syntax_highlighter: coderay in your configuration file."
+
+              "coderay"
+            else
+              @main_fallback_highlighter
             end
           end
+        end
+
+        private
+        def strip_coderay_prefix(hash)
+          hash.each_with_object({}) do |(key, val), hsh|
+            cleaned_key = key.gsub(/\Acoderay_/, "")
+
+            if key != cleaned_key
+              Jekyll::Deprecator.deprecation_message(
+                "You are using '#{key}'. Normalizing to #{cleaned_key}."
+              )
+            end
 
-          Kramdown::Document.new(content, Utils.symbolize_hash_keys(@config['kramdown'])).to_html
+            hsh[cleaned_key] = val
+          end
         end
 
+        # If our highlighter is CodeRay we go in to merge the CodeRay defaults
+        # with your "coderay" key if it's there, deprecating it in the
+        # process of you using it.
+
+        private
+        def modernize_coderay_config
+          if highlighter == "coderay"
+            Jekyll::Deprecator.deprecation_message "You are using 'kramdown.coderay' in your configuration, " \
+              "please use 'syntax_highlighter_opts' instead."
+
+            @config["syntax_highlighter_opts"] = begin
+              strip_coderay_prefix(
+                @config["syntax_highlighter_opts"] \
+                  .merge(CODERAY_DEFAULTS) \
+                  .merge(@config["coderay"])
+              )
+            end
+          end
+        end
       end
     end
   end
diff --git a/lib/jekyll/converters/markdown/rdiscount_parser.rb b/lib/jekyll/converters/markdown/rdiscount_parser.rb
index fb5172e..daf8874 100644
--- a/lib/jekyll/converters/markdown/rdiscount_parser.rb
+++ b/lib/jekyll/converters/markdown/rdiscount_parser.rb
@@ -5,7 +5,7 @@ module Jekyll
         def initialize(config)
           Jekyll::External.require_with_graceful_fail "rdiscount"
           @config = config
-          @rdiscount_extensions = @config['rdiscount']['extensions'].map { |e| e.to_sym }
+          @rdiscount_extensions = @config['rdiscount']['extensions'].map(&:to_sym)
         end
 
         def convert(content)
diff --git a/lib/jekyll/converters/markdown/redcarpet_parser.rb b/lib/jekyll/converters/markdown/redcarpet_parser.rb
index 6788d96..79133a2 100644
--- a/lib/jekyll/converters/markdown/redcarpet_parser.rb
+++ b/lib/jekyll/converters/markdown/redcarpet_parser.rb
@@ -2,12 +2,12 @@ module Jekyll
   module Converters
     class Markdown
       class RedcarpetParser
-
         module CommonMethods
           def add_code_tags(code, lang)
             code = code.to_s
             code = code.sub(/<pre>/, "<pre><code class=\"language-#{lang}\" data-lang=\"#{lang}\">")
-            code = code.sub(/<\/pre>/,"</code></pre>")
+            code = code.sub(/<\/pre>/, "</code></pre>")
+            code
           end
         end
 
@@ -48,12 +48,11 @@ module Jekyll
           end
 
           protected
-          def rouge_formatter(lexer)
+          def rouge_formatter(_lexer)
             Rouge::Formatters::HTML.new(:wrap => false)
           end
         end
 
-
         def initialize(config)
           External.require_with_graceful_fail("redcarpet")
           @config = config
@@ -71,10 +70,10 @@ module Jekyll
             end
           when "rouge"
             Class.new(Redcarpet::Render::HTML) do
-              Jekyll::External.require_with_graceful_fail(%w[
+              Jekyll::External.require_with_graceful_fail(%w(
                 rouge
                 rouge/plugins/redcarpet
-              ])
+              ))
 
               unless Gem::Version.new(Rouge.version) > Gem::Version.new("1.3.0")
                 abort "Please install Rouge 1.3.0 or greater and try running Jekyll again."
diff --git a/lib/jekyll/converters/smartypants.rb b/lib/jekyll/converters/smartypants.rb
new file mode 100644
index 0000000..d1bc810
--- /dev/null
+++ b/lib/jekyll/converters/smartypants.rb
@@ -0,0 +1,34 @@
+class Kramdown::Parser::SmartyPants < Kramdown::Parser::Kramdown
+  def initialize(source, options)
+    super
+    @block_parsers = [:block_html]
+    @span_parsers =  [:smart_quotes, :html_entity, :typographic_syms, :span_html]
+  end
+end
+
+module Jekyll
+  module Converters
+    class SmartyPants < Converter
+      safe true
+      priority :low
+
+      def initialize(config)
+        Jekyll::External.require_with_graceful_fail "kramdown"
+        @config = config["kramdown"].dup || {}
+        @config[:input] = :SmartyPants
+      end
+
+      def matches(_)
+        false
+      end
+
+      def output_ext(_)
+        nil
+      end
+
+      def convert(content)
+        Kramdown::Document.new(content, @config).to_html.chomp
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/convertible.rb b/lib/jekyll/convertible.rb
index 1215139..74112f6 100644
--- a/lib/jekyll/convertible.rb
+++ b/lib/jekyll/convertible.rb
@@ -28,12 +28,6 @@ module Jekyll
       !(data.key?('published') && data['published'] == false)
     end
 
-    # Returns merged option hash for File.read of self.site (if exists)
-    # and a given param
-    def merged_file_read_opts(opts)
-      (site ? site.file_read_opts : {}).merge(opts)
-    end
-
     # Read the YAML frontmatter.
     #
     # base - The String path to the dir containing the file.
@@ -42,26 +36,39 @@ module Jekyll
     #
     # Returns nothing.
     def read_yaml(base, name, opts = {})
+      filename = File.join(base, name)
+
       begin
         self.content = File.read(site.in_source_dir(base, name),
-                                 merged_file_read_opts(opts))
+                                 Utils.merged_file_read_opts(site, opts))
         if content =~ /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
           self.content = $POSTMATCH
-          self.data = SafeYAML.load($1)
+          self.data = SafeYAML.load(Regexp.last_match(1))
         end
       rescue SyntaxError => e
-        Jekyll.logger.warn "YAML Exception reading #{File.join(base, name)}: #{e.message}"
+        Jekyll.logger.warn "YAML Exception reading #{filename}: #{e.message}"
       rescue Exception => e
-        Jekyll.logger.warn "Error reading file #{File.join(base, name)}: #{e.message}"
+        Jekyll.logger.warn "Error reading file #{filename}: #{e.message}"
       end
 
       self.data ||= {}
 
+      validate_data! filename
+      validate_permalink! filename
+
+      self.data
+    end
+
+    def validate_data!(filename)
       unless self.data.is_a?(Hash)
-        Jekyll.logger.abort_with "Fatal:", "Invalid YAML front matter in #{File.join(base, name)}"
+        raise Errors::InvalidYAMLFrontMatterError, "Invalid YAML front matter in #{filename}"
       end
+    end
 
-      self.data
+    def validate_permalink!(filename)
+      if self.data['permalink'] && self.data['permalink'].size == 0
+        raise Errors::InvalidPermalinkError, "Invalid permalink in #{filename}"
+      end
     end
 
     # Transform the contents based on the content type.
@@ -84,13 +91,7 @@ module Jekyll
     # Returns the String extension for the output file.
     #   e.g. ".html" for an HTML output file.
     def output_ext
-      if converters.all? { |c| c.is_a?(Jekyll::Converters::Identity) }
-        ext
-      else
-        converters.map { |c|
-          c.output_ext(ext) unless c.is_a?(Jekyll::Converters::Identity)
-        }.compact.last
-      end
+      Jekyll::Renderer.new(site, self).output_ext
     end
 
     # Determine which converter to use based on this convertible's
@@ -122,9 +123,9 @@ module Jekyll
     #
     # Returns the Hash representation of this Convertible.
     def to_liquid(attrs = nil)
-      further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map { |attribute|
+      further_data = Hash[(attrs || self.class::ATTRIBUTES_FOR_LIQUID).map do |attribute|
         [attribute, send(attribute)]
-      }]
+      end]
 
       defaults = site.frontmatter_defaults.all(relative_path, type)
       Utils.deep_merge_hashes defaults, Utils.deep_merge_hashes(data, further_data)
@@ -160,7 +161,7 @@ module Jekyll
     #
     # Returns true if extname == .sass or .scss, false otherwise.
     def sass_file?
-      %w[.sass .scss].include?(ext)
+      %w(.sass .scss).include?(ext)
     end
 
     # Determine whether the document is a CoffeeScript file.
@@ -208,9 +209,13 @@ module Jekyll
 
       used = Set.new([layout])
 
+      # Reset the payload layout data to ensure it starts fresh for each page.
+      payload["layout"] = nil
+
       while layout
         Jekyll.logger.debug "Rendering Layout:", path
-        payload = Utils.deep_merge_hashes(payload, {"content" => output, "page" => layout.data})
+        payload["content"] = output
+        payload["layout"]  = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
 
         self.output = render_liquid(layout.content,
                                          payload,
@@ -235,7 +240,7 @@ module Jekyll
 
     # Add any necessary layouts to this convertible document.
     #
-    # payload - The site payload Hash.
+    # payload - The site payload Drop or Hash.
     # layouts - A Hash of {"name" => "layout"}.
     #
     # Returns nothing.
@@ -244,7 +249,7 @@ module Jekyll
 
       Jekyll.logger.debug "Pre-Render Hooks:", self.relative_path
       Jekyll::Hooks.trigger hook_owner, :pre_render, self, payload
-      info = { :filters => [Jekyll::Filters], :registers => { :site => site, :page => payload['page'] } }
+      info = { :filters => [Jekyll::Filters], :registers => { :site => site, :page => payload["page"] } }
 
       # render and transform content (this becomes the final content of the object)
       payload["highlighter_prefix"] = converters.first.highlighter_prefix
diff --git a/lib/jekyll/deprecator.rb b/lib/jekyll/deprecator.rb
index 8fda510..2144940 100644
--- a/lib/jekyll/deprecator.rb
+++ b/lib/jekyll/deprecator.rb
@@ -21,8 +21,8 @@ module Jekyll
     end
 
     def no_subcommand(args)
-      if args.size > 0 && args.first =~ /^--/ && !%w[--help --version].include?(args.first)
-        deprecation_message "Jekyll now uses subcommands instead of just switches. Run `jekyll --help` to find out more."
+      if args.size > 0 && args.first =~ /^--/ && !%w(--help --version).include?(args.first)
+        deprecation_message "Jekyll now uses subcommands instead of just switches. Run `jekyll help` to find out more."
         abort
       end
     end
diff --git a/lib/jekyll/document.rb b/lib/jekyll/document.rb
index 528fed6..b9394a1 100644
--- a/lib/jekyll/document.rb
+++ b/lib/jekyll/document.rb
@@ -4,23 +4,25 @@ module Jekyll
   class Document
     include Comparable
 
-    attr_reader :path, :site, :extname, :output_ext, :content, :output, :collection
+    attr_reader :path, :site, :extname, :collection
+    attr_accessor :content, :output
 
     YAML_FRONT_MATTER_REGEXP = /\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)/m
-    DATELESS_FILENAME_MATCHER = /^(.*)(\.[^.]+)$/
+    DATELESS_FILENAME_MATCHER = /^(.+\/)*(.*)(\.[^.]+)$/
     DATE_FILENAME_MATCHER = /^(.+\/)*(\d+-\d+-\d+)-(.*)(\.[^.]+)$/
 
     # Create a new Document.
     #
-    # site - the Jekyll::Site instance to which this Document belongs
     # path - the path to the file
+    # relations - a hash with keys :site and :collection, the values of which
+    #             are the Jekyll::Site and Jekyll::Collection to which this
+    #             Document belong.
     #
     # Returns nothing.
-    def initialize(path, relations)
+    def initialize(path, relations = {})
       @site = relations[:site]
       @path = path
       @extname = File.extname(path)
-      @output_ext = Jekyll::Renderer.new(site, self).output_ext
       @collection = relations[:collection]
       @has_yaml_header = nil
 
@@ -30,35 +32,25 @@ module Jekyll
         categories_from_path(collection.relative_directory)
       end
 
-      data.default_proc = proc do |hash, key|
+      data.default_proc = proc do |_, key|
         site.frontmatter_defaults.find(relative_path, collection.label, key)
       end
 
       trigger_hooks(:post_init)
     end
 
-    def output=(output)
-      @to_liquid = nil
-      @output = output
-    end
-
-    def content=(content)
-      @to_liquid = nil
-      @content = content
-    end
-
     # Fetch the Document's data.
     #
     # Returns a Hash containing the data. An empty hash is returned if
     #   no data was read.
     def data
-      @data ||= Hash.new
+      @data ||= {}
     end
 
     # Merge some data in with this document's data.
     #
     # Returns the merged data.
-    def merge_data!(other)
+    def merge_data!(other, source: "YAML front matter")
       if other.key?('categories') && !other['categories'].nil?
         if other['categories'].is_a?(String)
           other['categories'] = other['categories'].split(" ").map(&:strip)
@@ -67,7 +59,10 @@ module Jekyll
       end
       Utils.deep_merge_hashes!(data, other)
       if data.key?('date') && !data['date'].is_a?(Time)
-         data['date'] = Utils.parse_date(data['date'].to_s, "Document '#{relative_path}' does not have a valid date in the YAML front matter.")
+        data['date'] = Utils.parse_date(
+          data['date'].to_s,
+          "Document '#{relative_path}' does not have a valid date in the #{source}."
+        )
       end
       data
     end
@@ -93,6 +88,13 @@ module Jekyll
       @relative_path ||= Pathname.new(path).relative_path_from(Pathname.new(site.source)).to_s
     end
 
+    # The output extension of the document.
+    #
+    # Returns the output extension
+    def output_ext
+      Jekyll::Renderer.new(site, self).output_ext
+    end
+
     # The base filename of the document, without the file extname.
     #
     # Returns the basename without the file extname.
@@ -120,14 +122,14 @@ module Jekyll
     # Returns the cleaned relative path of the document.
     def cleaned_relative_path
       @cleaned_relative_path ||=
-        relative_path[0 .. -extname.length - 1].sub(collection.relative_directory, "")
+        relative_path[0..-extname.length - 1].sub(collection.relative_directory, "")
     end
 
     # Determine whether the document is a YAML file.
     #
     # Returns true if the extname is either .yml or .yaml, false otherwise.
     def yaml_file?
-      %w[.yaml .yml].include?(extname)
+      %w(.yaml .yml).include?(extname)
     end
 
     # Determine whether the document is an asset file.
@@ -143,7 +145,7 @@ module Jekyll
     #
     # Returns true if extname == .sass or .scss, false otherwise.
     def sass_file?
-      %w[.sass .scss].include?(extname)
+      %w(.sass .scss).include?(extname)
     end
 
     # Determine whether the document is a CoffeeScript file.
@@ -181,27 +183,7 @@ module Jekyll
     #
     # Returns the Hash of key-value pairs for replacement in the URL.
     def url_placeholders
-      {
-        collection:  collection.label,
-        path:        cleaned_relative_path,
-        output_ext:  output_ext,
-        name:        Utils.slugify(basename_without_ext),
-        title:       Utils.slugify(data['slug'], mode: "pretty", cased: true) || Utils
-                       .slugify(basename_without_ext, mode: "pretty", cased: true),
-        slug:        Utils.slugify(data['slug']) || Utils.slugify(basename_without_ext),
-        year:        date.strftime("%Y"),
-        month:       date.strftime("%m"),
-        day:         date.strftime("%d"),
-        hour:        date.strftime("%H"),
-        minute:      date.strftime("%M"),
-        second:      date.strftime("%S"),
-        i_day:       date.strftime("%-d"),
-        i_month:     date.strftime("%-m"),
-        categories:  (data['categories'] || []).map { |c| c.to_s.downcase }.uniq.join('/'),
-        short_month: date.strftime("%b"),
-        short_year:  date.strftime("%y"),
-        y_day:       date.strftime("%j"),
-      }
+      @url_placeholders ||= Drops::UrlDrop.new(self)
     end
 
     # The permalink for this Document.
@@ -217,9 +199,9 @@ module Jekyll
     # Returns the computed URL for the document.
     def url
       @url = URL.new({
-        template:     url_template,
-        placeholders: url_placeholders,
-        permalink:    permalink
+        :template => url_template,
+        :placeholders => url_placeholders,
+        :permalink => permalink
       }).to_s
     end
 
@@ -235,8 +217,11 @@ module Jekyll
     def destination(base_directory)
       dest = site.in_dest_dir(base_directory)
       path = site.in_dest_dir(dest, URL.unescape_path(url))
-      path = File.join(path, "index.html") if url.end_with?("/")
-      path << output_ext unless path.end_with?(output_ext)
+      if url.end_with? "/"
+        path = File.join(path, "index.html")
+      else
+        path << output_ext unless path.end_with? output_ext
+      end
       path
     end
 
@@ -255,16 +240,6 @@ module Jekyll
       trigger_hooks(:post_write)
     end
 
-    # Returns merged option hash for File.read of self.site (if exists)
-    # and a given param
-    #
-    # opts - override options
-    #
-    # Return the file read options hash.
-    def merged_file_read_opts(opts)
-      site ? site.file_read_opts.merge(opts) : opts
-    end
-
     # Whether the file is published or not, as indicated in YAML front-matter
     #
     # Returns true if the 'published' key is specified in the YAML front-matter and not `false`.
@@ -278,49 +253,53 @@ module Jekyll
     #
     # Returns nothing.
     def read(opts = {})
-      @to_liquid = nil
-
       Jekyll.logger.debug "Reading:", relative_path
 
       if yaml_file?
         @data = SafeYAML.load_file(path)
       else
         begin
-          defaults = @site.frontmatter_defaults.all(url, collection.label.to_sym)
-          merge_data!(defaults) unless defaults.empty?
+          defaults = @site.frontmatter_defaults.all(relative_path, collection.label.to_sym)
+          merge_data!(defaults, source: "front matter defaults") unless defaults.empty?
 
-          self.content = File.read(path, merged_file_read_opts(opts))
+          self.content = File.read(path, Utils.merged_file_read_opts(site, opts))
           if content =~ YAML_FRONT_MATTER_REGEXP
             self.content = $POSTMATCH
-            data_file = SafeYAML.load($1)
-            merge_data!(data_file) if data_file
+            data_file = SafeYAML.load(Regexp.last_match(1))
+            merge_data!(data_file, source: "YAML front matter") if data_file
           end
 
           post_read
         rescue SyntaxError => e
-          puts "YAML Exception reading #{path}: #{e.message}"
+          Jekyll.logger.error "Error:", "YAML Exception reading #{path}: #{e.message}"
         rescue Exception => e
-          puts "Error reading file #{path}: #{e.message}"
+          if e.is_a? Jekyll::Errors::FatalException
+            raise e
+          end
+          Jekyll.logger.error "Error:", "could not read file #{path}: #{e.message}"
         end
       end
     end
 
     def post_read
-      if DATE_FILENAME_MATCHER =~ relative_path
-        m, cats, date, slug, ext = *relative_path.match(DATE_FILENAME_MATCHER)
-        merge_data!({
-          "slug" => slug,
-          "ext"  => ext
-        })
-        merge_data!({"date" => date}) if data['date'].nil? || data['date'].to_i == site.time.to_i
-        data['title'] ||= slug.split('-').select {|w| w.capitalize! || w }.join(' ')
+      if relative_path =~ DATE_FILENAME_MATCHER
+        date, slug, ext = $2, $3, $4
+        if !data['date'] || data['date'].to_i == site.time.to_i
+          merge_data!({"date" => date}, source: "filename")
+        end
+      elsif relative_path =~ DATELESS_FILENAME_MATCHER
+        slug, ext = $2, $3
       end
+
+      # Try to ensure the user gets a title.
+      data["title"] ||= Utils.titleize_slug(slug)
+      # Only overwrite slug & ext if they aren't specified.
+      data['slug'] ||= slug
+      data['ext']  ||= ext
+
       populate_categories
       populate_tags
-
-      if generate_excerpt?
-        data['excerpt'] ||= Jekyll::Excerpt.new(self)
-      end
+      generate_excerpt
     end
 
     # Add superdirectories of the special_dir to categories.
@@ -332,14 +311,14 @@ module Jekyll
       superdirs = relative_path.sub(/#{special_dir}(.*)/, '').split(File::SEPARATOR).reject do |c|
         c.empty? || c.eql?(special_dir) || c.eql?(basename)
       end
-      merge_data!({ 'categories' => superdirs })
+      merge_data!({ 'categories' => superdirs }, source: "file path")
     end
 
     def populate_categories
       merge_data!({
         'categories' => (
           Array(data['categories']) + Utils.pluralized_array_from_hash(data, 'category', 'categories')
-        ).map { |c| c.to_s }.flatten.uniq
+        ).map(&:to_s).flatten.uniq
       })
     end
 
@@ -353,21 +332,7 @@ module Jekyll
     #
     # Returns a Hash representing this Document's data.
     def to_liquid
-      @to_liquid ||= if data.is_a?(Hash)
-        Utils.deep_merge_hashes Utils.deep_merge_hashes({
-          "output"        => output,
-          "content"       => content,
-          "relative_path" => relative_path,
-          "path"          => relative_path,
-          "url"           => url,
-          "collection"    => collection.label,
-          "next"          => next_doc,
-          "previous"      => previous_doc,
-          "id"            => id,
-        }, data), { 'excerpt' => data['excerpt'].to_s }
-      else
-        data
-      end
+      @to_liquid ||= Drops::DocumentDrop.new(self)
     end
 
     # The inspect string for this document.
@@ -391,9 +356,9 @@ module Jekyll
     # Returns -1, 0, +1 or nil depending on whether this doc's path is less than,
     #   equal or greater than the other doc's path. See String#<=> for more details.
     def <=>(other)
-      return nil if !other.respond_to?(:data)
+      return nil unless other.respond_to?(:data)
       cmp = data['date'] <=> other.data['date']
-      cmp = path <=> other.path if cmp == 0
+      cmp = path <=> other.path if cmp.nil? || cmp == 0
       cmp
     end
 
@@ -422,7 +387,7 @@ module Jekyll
     end
 
     def next_doc
-      pos = collection.docs.index {|post| post.equal?(self) }
+      pos = collection.docs.index { |post| post.equal?(self) }
       if pos && pos < collection.docs.length - 1
         collection.docs[pos + 1]
       else
@@ -431,7 +396,7 @@ module Jekyll
     end
 
     def previous_doc
-      pos = collection.docs.index {|post| post.equal?(self) }
+      pos = collection.docs.index { |post| post.equal?(self) }
       if pos && pos > 0
         collection.docs[pos - 1]
       else
@@ -471,5 +436,12 @@ module Jekyll
         super
       end
     end
+
+    private # :nodoc:
+    def generate_excerpt
+      if generate_excerpt?
+        data["excerpt"] ||= Jekyll::Excerpt.new(self)
+      end
+    end
   end
 end
diff --git a/lib/jekyll/drops/collection_drop.rb b/lib/jekyll/drops/collection_drop.rb
new file mode 100644
index 0000000..5f5025b
--- /dev/null
+++ b/lib/jekyll/drops/collection_drop.rb
@@ -0,0 +1,22 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class CollectionDrop < Drop
+      extend Forwardable
+
+      mutable false
+
+      def_delegator :@obj, :write?, :output
+      def_delegators :@obj, :label, :docs, :files, :directory,
+                            :relative_directory
+
+      def to_s
+        docs.to_s
+      end
+
+      private
+      def_delegator :@obj, :metadata, :fallback_data
+    end
+  end
+end
diff --git a/lib/jekyll/drops/document_drop.rb b/lib/jekyll/drops/document_drop.rb
new file mode 100644
index 0000000..5ee136a
--- /dev/null
+++ b/lib/jekyll/drops/document_drop.rb
@@ -0,0 +1,60 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class DocumentDrop < Drop
+      extend Forwardable
+
+      NESTED_OBJECT_FIELD_BLACKLIST = %w{
+        content output excerpt next previous
+      }.freeze
+
+      mutable false
+
+      def_delegator :@obj, :relative_path, :path
+      def_delegators :@obj, :id, :output, :content, :to_s, :relative_path, :url
+
+      def collection
+        @obj.collection.label
+      end
+
+      def excerpt
+        fallback_data['excerpt'].to_s
+      end
+
+      def previous
+        @obj.previous_doc.to_liquid
+      end
+
+      def next
+        @obj.next_doc.to_liquid
+      end
+
+      # Generate a Hash for use in generating JSON.
+      # This is useful if fields need to be cleared before the JSON can generate.
+      #
+      # Returns a Hash ready for JSON generation.
+      def hash_for_json(state = nil)
+        to_h.tap do |hash|
+          if state && state.depth >= 2
+            hash["previous"] = collapse_document(hash["previous"]) if hash["previous"]
+            hash["next"]     = collapse_document(hash["next"]) if hash["next"]
+          end
+        end
+      end
+
+      # Generate a Hash which breaks the recursive chain.
+      # Certain fields which are normally available are omitted.
+      #
+      # Returns a Hash with only non-recursive fields present.
+      def collapse_document(doc)
+        doc.keys.each_with_object({}) do |(key, _), result|
+          result[key] = doc[key] unless NESTED_OBJECT_FIELD_BLACKLIST.include?(key)
+        end
+      end
+
+      private
+      def_delegator :@obj, :data, :fallback_data
+    end
+  end
+end
diff --git a/lib/jekyll/drops/drop.rb b/lib/jekyll/drops/drop.rb
new file mode 100644
index 0000000..14795f9
--- /dev/null
+++ b/lib/jekyll/drops/drop.rb
@@ -0,0 +1,200 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class Drop < Liquid::Drop
+      include Enumerable
+
+      NON_CONTENT_METHODS = [:fallback_data, :collapse_document].freeze
+
+      # Get or set whether the drop class is mutable.
+      # Mutability determines whether or not pre-defined fields may be
+      # overwritten.
+      #
+      # is_mutable - Boolean set mutability of the class (default: nil)
+      #
+      # Returns the mutability of the class
+      def self.mutable(is_mutable = nil)
+        if is_mutable
+          @is_mutable = is_mutable
+        else
+          @is_mutable = false
+        end
+      end
+
+      def self.mutable?
+        @is_mutable
+      end
+
+      # Create a new Drop
+      #
+      # obj - the Jekyll Site, Collection, or Document required by the
+      # drop.
+      #
+      # Returns nothing
+      def initialize(obj)
+        @obj = obj
+        @mutations = {} # only if mutable: true
+      end
+
+      # Access a method in the Drop or a field in the underlying hash data.
+      # If mutable, checks the mutations first. Then checks the methods,
+      # and finally check the underlying hash (e.g. document front matter)
+      # if all the previous places didn't match.
+      #
+      # key - the string key whose value to fetch
+      #
+      # Returns the value for the given key, or nil if none exists
+      def [](key)
+        if self.class.mutable? && @mutations.key?(key)
+          @mutations[key]
+        elsif self.class.invokable? key
+          public_send key
+        else
+          fallback_data[key]
+        end
+      end
+
+      # Set a field in the Drop. If mutable, sets in the mutations and
+      # returns. If not mutable, checks first if it's trying to override a
+      # Drop method and raises a DropMutationException if so. If not
+      # mutable and the key is not a method on the Drop, then it sets the
+      # key to the value in the underlying hash (e.g. document front
+      # matter)
+      #
+      # key - the String key whose value to set
+      # val - the Object to set the key's value to
+      #
+      # Returns the value the key was set to unless the Drop is not mutable
+      # and the key matches a method in which case it raises a
+      # DropMutationException.
+      def []=(key, val)
+        if respond_to?("#{key}=")
+          public_send("#{key}=", val)
+        elsif respond_to? key
+          if self.class.mutable?
+            @mutations[key] = val
+          else
+            raise Errors::DropMutationException, "Key #{key} cannot be set in the drop."
+          end
+        else
+          fallback_data[key] = val
+        end
+      end
+
+      # Generates a list of strings which correspond to content getter
+      # methods.
+      #
+      # Returns an Array of strings which represent method-specific keys.
+      def content_methods
+        @content_methods ||= (
+          self.class.instance_methods - Jekyll::Drops::Drop.instance_methods - NON_CONTENT_METHODS
+        ).map(&:to_s).reject do |method|
+          method.end_with?("=")
+        end
+      end
+
+      # Check if key exists in Drop
+      #
+      # key - the string key whose value to fetch
+      #
+      # Returns true if the given key is present
+      def key?(key)
+        if self.class.mutable && @mutations.key?(key)
+          true
+        else
+          respond_to?(key) || fallback_data.key?(key)
+        end
+      end
+
+      # Generates a list of keys with user content as their values.
+      # This gathers up the Drop methods and keys of the mutations and
+      # underlying data hashes and performs a set union to ensure a list
+      # of unique keys for the Drop.
+      #
+      # Returns an Array of unique keys for content for the Drop.
+      def keys
+        (content_methods |
+          @mutations.keys |
+          fallback_data.keys).flatten
+      end
+
+      # Generate a Hash representation of the Drop by resolving each key's
+      # value. It includes Drop methods, mutations, and the underlying object's
+      # data. See the documentation for Drop#keys for more.
+      #
+      # Returns a Hash with all the keys and values resolved.
+      def to_h
+        keys.each_with_object({}) do |(key, _), result|
+          result[key] = self[key]
+        end
+      end
+      alias_method :to_hash, :to_h
+
+      # Inspect the drop's keys and values through a JSON representation
+      # of its keys and values.
+      #
+      # Returns a pretty generation of the hash representation of the Drop.
+      def inspect
+        require 'json'
+        JSON.pretty_generate to_h
+      end
+
+      # Generate a Hash for use in generating JSON.
+      # This is useful if fields need to be cleared before the JSON can generate.
+      #
+      # Returns a Hash ready for JSON generation.
+      def hash_for_json(state = nil)
+        to_h
+      end
+
+      # Generate a JSON representation of the Drop.
+      #
+      # Returns a JSON representation of the Drop in a String.
+      def to_json(state = nil)
+        require 'json'
+        JSON.generate(hash_for_json(state), state)
+      end
+
+      # Collects all the keys and passes each to the block in turn.
+      #
+      # block - a block which accepts one argument, the key
+      #
+      # Returns nothing.
+      def each_key(&block)
+        keys.each(&block)
+      end
+
+      def each(&block)
+        each_key.each do |key|
+          yield key, self[key]
+        end
+      end
+
+      def merge(other, &block)
+        self.dup.tap do |me|
+          if block.nil?
+            me.merge!(other)
+          else
+            me.merge!(other, block)
+          end
+        end
+      end
+
+      def merge!(other)
+        other.each_key do |key|
+          if block_given?
+            self[key] = yield key, self[key], other[key]
+          else
+            if Utils.mergable?(self[key]) && Utils.mergable?(other[key])
+              self[key] = Utils.deep_merge_hashes(self[key], other[key])
+              next
+            end
+
+            self[key] = other[key] unless other[key].nil?
+          end
+        end
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/drops/excerpt_drop.rb b/lib/jekyll/drops/excerpt_drop.rb
new file mode 100644
index 0000000..c70712f
--- /dev/null
+++ b/lib/jekyll/drops/excerpt_drop.rb
@@ -0,0 +1,15 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class ExcerptDrop < DocumentDrop
+      def layout
+        @obj.doc.data['layout']
+      end
+
+      def excerpt
+        nil
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/drops/jekyll_drop.rb b/lib/jekyll/drops/jekyll_drop.rb
new file mode 100644
index 0000000..7ff19f9
--- /dev/null
+++ b/lib/jekyll/drops/jekyll_drop.rb
@@ -0,0 +1,33 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class JekyllDrop < Liquid::Drop
+      class << self
+        def global
+          @global ||= JekyllDrop.new
+        end
+      end
+
+      def version
+        Jekyll::VERSION
+      end
+
+      def environment
+        Jekyll.env
+      end
+
+      def to_h
+        @to_h ||= {
+          "version" => version,
+          "environment" => environment
+        }
+      end
+
+      def to_json(state = nil)
+        require 'json'
+        JSON.generate(to_h, state)
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/drops/site_drop.rb b/lib/jekyll/drops/site_drop.rb
new file mode 100644
index 0000000..7b08312
--- /dev/null
+++ b/lib/jekyll/drops/site_drop.rb
@@ -0,0 +1,38 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class SiteDrop < Drop
+      extend Forwardable
+
+      mutable false
+
+      def_delegator  :@obj, :site_data, :data
+      def_delegators :@obj, :time, :pages, :static_files, :documents,
+                            :tags, :categories
+
+      def [](key)
+        if @obj.collections.key?(key) && key != "posts"
+          @obj.collections[key].docs
+        else
+          super(key)
+        end
+      end
+
+      def posts
+        @site_posts ||= @obj.posts.docs.sort { |a, b| b <=> a }
+      end
+
+      def html_pages
+        @site_html_pages ||= @obj.pages.select { |page| page.html? || page.url.end_with?("/") }
+      end
+
+      def collections
+        @site_collections ||= @obj.collections.values.sort_by(&:label).map(&:to_liquid)
+      end
+
+      private
+      def_delegator :@obj, :config, :fallback_data
+    end
+  end
+end
diff --git a/lib/jekyll/drops/unified_payload_drop.rb b/lib/jekyll/drops/unified_payload_drop.rb
new file mode 100644
index 0000000..b642bda
--- /dev/null
+++ b/lib/jekyll/drops/unified_payload_drop.rb
@@ -0,0 +1,25 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class UnifiedPayloadDrop < Drop
+      mutable true
+
+      attr_accessor :page, :layout, :content, :paginator
+      attr_accessor :highlighter_prefix, :highlighter_suffix
+
+      def jekyll
+        JekyllDrop.global
+      end
+
+      def site
+        @site_drop ||= SiteDrop.new(@obj)
+      end
+
+      private
+      def fallback_data
+        @fallback_data ||= {}
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/drops/url_drop.rb b/lib/jekyll/drops/url_drop.rb
new file mode 100644
index 0000000..2815edf
--- /dev/null
+++ b/lib/jekyll/drops/url_drop.rb
@@ -0,0 +1,83 @@
+# encoding: UTF-8
+
+module Jekyll
+  module Drops
+    class UrlDrop < Drop
+      extend Forwardable
+
+      mutable false
+
+      def_delegator :@obj, :cleaned_relative_path, :path
+      def_delegator :@obj, :output_ext, :output_ext
+
+      def collection
+        @obj.collection.label
+      end
+
+      def name
+        Utils.slugify(@obj.basename_without_ext)
+      end
+
+      def title
+        Utils.slugify(@obj.data['slug'], :mode => "pretty", :cased => true) ||
+          Utils.slugify(@obj.basename_without_ext, :mode => "pretty", :cased => true)
+      end
+
+      def slug
+        Utils.slugify(@obj.data['slug']) || Utils.slugify(@obj.basename_without_ext)
+      end
+
+      def categories
+        category_set = Set.new
+        Array(@obj.data['categories']).each do |category|
+          category_set << category.to_s.downcase
+        end
+        category_set.to_a.join('/')
+      end
+
+      def year
+        @obj.date.strftime("%Y")
+      end
+
+      def month
+        @obj.date.strftime("%m")
+      end
+
+      def day
+        @obj.date.strftime("%d")
+      end
+
+      def hour
+        @obj.date.strftime("%H")
+      end
+
+      def minute
+        @obj.date.strftime("%M")
+      end
+
+      def second
+        @obj.date.strftime("%S")
+      end
+
+      def i_day
+        @obj.date.strftime("%-d")
+      end
+
+      def i_month
+        @obj.date.strftime("%-m")
+      end
+
+      def short_month
+        @obj.date.strftime("%b")
+      end
+
+      def short_year
+        @obj.date.strftime("%y")
+      end
+
+      def y_day
+        @obj.date.strftime("%j")
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/entry_filter.rb b/lib/jekyll/entry_filter.rb
index e427018..6d42c06 100644
--- a/lib/jekyll/entry_filter.rb
+++ b/lib/jekyll/entry_filter.rb
@@ -47,7 +47,7 @@ module Jekyll
 
     def excluded?(entry)
       excluded = glob_include?(site.exclude, relative_to_source(entry))
-      Jekyll.logger.debug "EntryFilter:", "excluded?(#{relative_to_source(entry)}) ==> #{excluded}"
+      Jekyll.logger.debug "EntryFilter:", "excluded #{relative_to_source(entry)}" if excluded
       excluded
     end
 
diff --git a/lib/jekyll/errors.rb b/lib/jekyll/errors.rb
index dc5238a..36b2643 100644
--- a/lib/jekyll/errors.rb
+++ b/lib/jekyll/errors.rb
@@ -1,9 +1,10 @@
 module Jekyll
   module Errors
-    class FatalException < RuntimeError
-    end
+    FatalException = Class.new(::RuntimeError)
 
-    class MissingDependencyException < FatalException
-    end
+    DropMutationException       = Class.new(FatalException)
+    InvalidPermalinkError       = Class.new(FatalException)
+    InvalidYAMLFrontMatterError = Class.new(FatalException)
+    MissingDependencyException  = Class.new(FatalException)
   end
 end
diff --git a/lib/jekyll/excerpt.rb b/lib/jekyll/excerpt.rb
index 36fcd11..8fef70e 100644
--- a/lib/jekyll/excerpt.rb
+++ b/lib/jekyll/excerpt.rb
@@ -1,5 +1,3 @@
-require 'forwardable'
-
 module Jekyll
   class Excerpt
     extend Forwardable
@@ -9,7 +7,7 @@ module Jekyll
     attr_writer   :output
 
     def_delegators :@doc, :site, :name, :ext, :relative_path, :extname,
-                          :render_with_liquid?, :collection, :related_posts
+                          :render_with_liquid?, :collection, :related_posts, :url
 
     # Initialize this Excerpt instance.
     #
@@ -61,10 +59,7 @@ module Jekyll
     end
 
     def to_liquid
-      doc.data['excerpt'] = nil
-      @to_liquid ||= doc.to_liquid
-      doc.data['excerpt'] = self
-      @to_liquid
+      Jekyll::Drops::ExcerptDrop.new(self)
     end
 
     # Returns the shorthand String identifier of this doc.
diff --git a/lib/jekyll/external.rb b/lib/jekyll/external.rb
index e41bce2..69b8d1e 100644
--- a/lib/jekyll/external.rb
+++ b/lib/jekyll/external.rb
@@ -1,16 +1,15 @@
 module Jekyll
   module External
     class << self
-
       #
       # Gems that, if installed, should be loaded.
       # Usually contain subcommands.
       #
       def blessed_gems
-        %w{
+        %w(
           jekyll-docs
           jekyll-import
-        }
+        )
       end
 
       #
@@ -18,12 +17,13 @@ module Jekyll
       #
       # names - a string gem name or array of gem names
       #
-      def require_if_present(names)
+      def require_if_present(names, &block)
         Array(names).each do |name|
           begin
             require name
           rescue LoadError
             Jekyll.logger.debug "Couldn't load #{name}. Skipping."
+            block.call(name) if block
             false
           end
         end
@@ -39,6 +39,7 @@ module Jekyll
       def require_with_graceful_fail(names)
         Array(names).each do |name|
           begin
+            Jekyll.logger.debug "Requiring:", "#{name}"
             require name
           rescue LoadError => e
             Jekyll.logger.error "Dependency Error:", <<-MSG
@@ -53,7 +54,6 @@ If you run into trouble, you can find helpful resources at http://jekyllrb.com/h
           end
         end
       end
-
     end
   end
 end
diff --git a/lib/jekyll/filters.rb b/lib/jekyll/filters.rb
index 7e2d30f..986bfde 100644
--- a/lib/jekyll/filters.rb
+++ b/lib/jekyll/filters.rb
@@ -15,6 +15,17 @@ module Jekyll
       converter.convert(input)
     end
 
+    # Convert a Markdown string into HTML output.
+    #
+    # input - The Markdown String to convert.
+    #
+    # Returns the HTML formatted String.
+    def smartify(input)
+      site = @context.registers[:site]
+      converter = site.find_converter_instance(Jekyll::Converters::SmartyPants)
+      converter.convert(input)
+    end
+
     # Convert a Sass string into CSS output.
     #
     # input - The Sass String to convert.
@@ -45,7 +56,7 @@ module Jekyll
     # Returns the given filename or title as a lowercase URL String.
     # See Utils.slugify for more detail.
     def slugify(input, mode=nil)
-      Utils.slugify(input, mode: mode)
+      Utils.slugify(input, :mode => mode)
     end
 
     # Format a date in short format e.g. "27 Jan 2011".
@@ -194,7 +205,7 @@ module Jekyll
         input.group_by do |item|
           item_property(item, property).to_s
         end.inject([]) do |memo, i|
-          memo << {"name" => i.first, "items" => i.last}
+          memo << { "name" => i.first, "items" => i.last }
         end
       else
         input
@@ -223,7 +234,7 @@ module Jekyll
     # Returns the filtered array of objects
     def sort(input, property = nil, nils = "first")
       if input.nil?
-          raise ArgumentError.new("Cannot sort a null object.")
+        raise ArgumentError.new("Cannot sort a null object.")
       end
       if property.nil?
         input.sort
@@ -234,11 +245,11 @@ module Jekyll
         when nils == "last"
           order = + 1
         else
-          raise ArgumentError.new("Invalid nils order: " +
+          raise ArgumentError.new("Invalid nils order: " \
             "'#{nils}' is not a valid nils order. It must be 'first' or 'last'.")
         end
 
-        input.sort { |apple, orange|
+        input.sort do |apple, orange|
           apple_property = item_property(apple, property)
           orange_property = item_property(orange, property)
 
@@ -249,7 +260,7 @@ module Jekyll
           else
             apple_property <=> orange_property
           end
-        }
+        end
       end
     end
 
@@ -281,6 +292,16 @@ module Jekyll
       new_ary
     end
 
+    def sample(input, num = 1)
+      return input unless input.respond_to?(:sample)
+      n = num.to_i rescue 1
+      if n == 1
+        input.sample
+      else
+        input.sample(n)
+      end
+    end
+
     # Convert an object into its String representation for debugging
     #
     # input - The Object to be converted
@@ -327,7 +348,7 @@ module Jekyll
         pairs = item.map { |k, v| as_liquid([k, v]) }
         Hash[pairs]
       when Array
-        item.map{ |i| as_liquid(i) }
+        item.map { |i| as_liquid(i) }
       else
         if item.respond_to?(:to_liquid)
           liquidated = item.to_liquid
diff --git a/lib/jekyll/frontmatter_defaults.rb b/lib/jekyll/frontmatter_defaults.rb
index d6cb173..877f517 100644
--- a/lib/jekyll/frontmatter_defaults.rb
+++ b/lib/jekyll/frontmatter_defaults.rb
@@ -13,20 +13,28 @@ module Jekyll
     def update_deprecated_types(set)
       return set unless set.key?('scope') && set['scope'].key?('type')
 
-      set['scope']['type'] = case set['scope']['type']
-      when 'page'
-        Deprecator.defaults_deprecate_type('page', 'pages')
-        'pages'
-      when 'post'
-        Deprecator.defaults_deprecate_type('post', 'posts')
-        'posts'
-      when 'draft'
-        Deprecator.defaults_deprecate_type('draft', 'drafts')
-        'drafts'
-      else
-        set['scope']['type']
-      end
+      set['scope']['type'] =
+        case set['scope']['type']
+        when 'page'
+          Deprecator.defaults_deprecate_type('page', 'pages')
+          'pages'
+        when 'post'
+          Deprecator.defaults_deprecate_type('post', 'posts')
+          'posts'
+        when 'draft'
+          Deprecator.defaults_deprecate_type('draft', 'drafts')
+          'drafts'
+        else
+          set['scope']['type']
+        end
+
+      set
+    end
 
+    def ensure_time!(set)
+      return set unless set.key?('values') && set['values'].key?('date')
+      return set if set['values']['date'].is_a?(Time)
+      set['values']['date'] = Utils.parse_date(set['values']['date'], "An invalid date format was found in a front-matter default set: #{set}")
       set
     end
 
@@ -83,7 +91,7 @@ module Jekyll
     end
 
     def applies_path?(scope, path)
-      return true if !scope.has_key?('path') || scope['path'].empty?
+      return true if !scope.key?('path') || scope['path'].empty?
 
       scope_path = Pathname.new(scope['path'])
       Pathname.new(sanitize_path(path)).ascend do |path|
@@ -143,7 +151,7 @@ module Jekyll
     # Returns an array of hashes
     def matching_sets(path, type)
       valid_sets.select do |set|
-        !set.has_key?('scope') || applies?(set['scope'], path, type)
+        !set.key?('scope') || applies?(set['scope'], path, type)
       end
     end
 
@@ -159,7 +167,7 @@ module Jekyll
 
       sets.map do |set|
         if valid?(set)
-          update_deprecated_types(set)
+          ensure_time!(update_deprecated_types(set))
         else
           Jekyll.logger.warn "Defaults:", "An invalid front-matter default set was found:"
           Jekyll.logger.warn "#{set}"
diff --git a/lib/jekyll/generator.rb b/lib/jekyll/generator.rb
index 57973a7..bf7c0f1 100644
--- a/lib/jekyll/generator.rb
+++ b/lib/jekyll/generator.rb
@@ -1,4 +1,3 @@
 module Jekyll
-  class Generator < Plugin
-  end
+  Generator = Class.new(Plugin)
 end
diff --git a/lib/jekyll/hooks.rb b/lib/jekyll/hooks.rb
index a9a5e73..869bcc1 100644
--- a/lib/jekyll/hooks.rb
+++ b/lib/jekyll/hooks.rb
@@ -4,38 +4,38 @@ module Jekyll
 
     # compatibility layer for octopress-hooks users
     PRIORITY_MAP = {
-      low: 10,
-      normal: 20,
-      high: 30,
+      :low => 10,
+      :normal => 20,
+      :high => 30
     }.freeze
 
     # initial empty hooks
     @registry = {
       :site => {
-        after_reset: [],
-        post_read: [],
-        pre_render: [],
-        post_render: [],
-        post_write: [],
+        :after_reset => [],
+        :post_read => [],
+        :pre_render => [],
+        :post_render => [],
+        :post_write => []
       },
       :pages => {
-        post_init: [],
-        pre_render: [],
-        post_render: [],
-        post_write: [],
+        :post_init => [],
+        :pre_render => [],
+        :post_render => [],
+        :post_write => []
       },
       :posts => {
-        post_init: [],
-        pre_render: [],
-        post_render: [],
-        post_write: [],
+        :post_init => [],
+        :pre_render => [],
+        :post_render => [],
+        :post_write => []
       },
       :documents => {
-        post_init: [],
-        pre_render: [],
-        post_render: [],
-        post_write: [],
-      },
+        :post_init => [],
+        :pre_render => [],
+        :post_render => [],
+        :post_write => []
+      }
     }
 
     # map of all hooks and their priorities
@@ -60,14 +60,14 @@ module Jekyll
     # register a single hook to be called later, internal API
     def self.register_one(owner, event, priority, &block)
       @registry[owner] ||={
-        post_init: [],
-        pre_render: [],
-        post_render: [],
-        post_write: [],
+        :post_init => [],
+        :pre_render => [],
+        :post_render => [],
+        :post_write => []
       }
 
       unless @registry[owner][event]
-        raise NotAvailable, "Invalid hook. #{owner} supports only the " <<
+        raise NotAvailable, "Invalid hook. #{owner} supports only the " \
           "following hooks #{@registry[owner].keys.inspect}"
       end
 
diff --git a/lib/jekyll/liquid_renderer.rb b/lib/jekyll/liquid_renderer.rb
index 0edeb44..70f7b0d 100644
--- a/lib/jekyll/liquid_renderer.rb
+++ b/lib/jekyll/liquid_renderer.rb
@@ -15,7 +15,7 @@ module Jekyll
     def file(filename)
       filename = @site.in_source_dir(filename).sub(/\A#{Regexp.escape(@site.source)}\//, '')
 
-      LiquidRenderer::File.new(self, filename).tap do |file|
+      LiquidRenderer::File.new(self, filename).tap do
         @stats[filename] ||= {}
         @stats[filename][:count] ||= 0
         @stats[filename][:count] += 1
diff --git a/lib/jekyll/liquid_renderer/file.rb b/lib/jekyll/liquid_renderer/file.rb
index f91a5a2..7dcca1b 100644
--- a/lib/jekyll/liquid_renderer/file.rb
+++ b/lib/jekyll/liquid_renderer/file.rb
@@ -8,7 +8,7 @@ module Jekyll
 
       def parse(content)
         measure_time do
-          @template = Liquid::Template.parse(content)
+          @template = Liquid::Template.parse(content, line_numbers: true)
         end
 
         self
diff --git a/lib/jekyll/liquid_renderer/table.rb b/lib/jekyll/liquid_renderer/table.rb
index 32b09cb..e3e0c8a 100644
--- a/lib/jekyll/liquid_renderer/table.rb
+++ b/lib/jekyll/liquid_renderer/table.rb
@@ -69,10 +69,10 @@ module Jekyll
     end
 
     def data_for_table(n)
-      sorted = @stats.sort_by{ |filename, file_stats| -file_stats[:time] }
+      sorted = @stats.sort_by { |_, file_stats| -file_stats[:time] }
       sorted = sorted.slice(0, n)
 
-      table = [[ 'Filename', 'Count', 'Bytes', 'Time' ]]
+      table = [%w(Filename Count Bytes Time)]
 
       sorted.each do |filename, file_stats|
         row = []
diff --git a/lib/jekyll/page.rb b/lib/jekyll/page.rb
index ca5bb26..6c402ee 100644
--- a/lib/jekyll/page.rb
+++ b/lib/jekyll/page.rb
@@ -7,14 +7,27 @@ module Jekyll
     attr_accessor :name, :ext, :basename
     attr_accessor :data, :content, :output
 
+    alias_method :extname, :ext
+
+    FORWARD_SLASH = '/'.freeze
+
     # Attributes for Liquid templates
-    ATTRIBUTES_FOR_LIQUID = %w[
+    ATTRIBUTES_FOR_LIQUID = %w(
       content
       dir
       name
       path
       url
-    ]
+    )
+
+    # A set of extensions that are considered HTML or HTML-like so we
+    # should not alter them,  this includes .xhtml through XHTM5.
+
+    HTML_EXTENSIONS = %W(
+      .html
+      .xhtml
+      .htm
+    )
 
     # Initialize a new Page.
     #
@@ -28,11 +41,10 @@ module Jekyll
       @dir  = dir
       @name = name
 
-
       process(name)
       read_yaml(File.join(base, dir), name)
 
-      data.default_proc = proc do |hash, key|
+      data.default_proc = proc do |_, key|
         site.frontmatter_defaults.find(File.join(dir, name), type, key)
       end
 
@@ -45,7 +57,12 @@ module Jekyll
     #
     # Returns the String destination directory.
     def dir
-      url[-1, 1] == '/' ? url : File.dirname(url)
+      if url.end_with?(FORWARD_SLASH)
+        url
+      else
+        url_dir = File.dirname(url)
+        url_dir.end_with?(FORWARD_SLASH) ? url_dir : "#{url_dir}/"
+      end
     end
 
     # The full path and filename of the post. Defined in the YAML of the post
@@ -53,8 +70,7 @@ module Jekyll
     #
     # Returns the String permalink or nil if none has been set.
     def permalink
-      return nil if data.nil? || data['permalink'].nil?
-      data['permalink']
+      data.nil? ? nil : data['permalink']
     end
 
     # The template of the permalink.
@@ -98,7 +114,7 @@ module Jekyll
     # Returns nothing.
     def process(name)
       self.ext = File.extname(name)
-      self.basename = name[0 .. -ext.length - 1]
+      self.basename = name[0..-ext.length - 1]
     end
 
     # Add any necessary layouts to this post
@@ -108,12 +124,10 @@ module Jekyll
     #
     # Returns nothing.
     def render(layouts, site_payload)
-      payload = Utils.deep_merge_hashes({
-        "page" => to_liquid,
-        'paginator' => pager.to_liquid
-      }, site_payload)
+      site_payload["page"] = to_liquid
+      site_payload["paginator"] = pager.to_liquid
 
-      do_layout(payload, layouts)
+      do_layout(site_payload, layouts)
     end
 
     # The path to the source file
@@ -135,8 +149,8 @@ module Jekyll
     # Returns the destination file path String.
     def destination(dest)
       path = site.in_dest_dir(dest, URL.unescape_path(url))
-      path = File.join(path, "index.html") if url.end_with?("/")
-      path << output_ext unless path.end_with?(output_ext)
+      path = File.join(path, "index") if url.end_with?("/")
+      path << output_ext unless path.end_with? output_ext
       path
     end
 
@@ -147,12 +161,20 @@ module Jekyll
 
     # Returns the Boolean of whether this Page is HTML or not.
     def html?
-      output_ext == '.html'
+      HTML_EXTENSIONS.include?(output_ext)
     end
 
     # Returns the Boolean of whether this Page is an index file or not.
     def index?
       basename == 'index'
     end
+
+    def trigger_hooks(hook_name, *args)
+      Jekyll::Hooks.trigger :pages, hook_name, self, *args
+    end
+
+    def write?
+      true
+    end
   end
 end
diff --git a/lib/jekyll/plugin.rb b/lib/jekyll/plugin.rb
index 0207314..e2a9516 100644
--- a/lib/jekyll/plugin.rb
+++ b/lib/jekyll/plugin.rb
@@ -1,20 +1,39 @@
 module Jekyll
   class Plugin
-    PRIORITIES = { :lowest => -100,
-                   :low => -10,
-                   :normal => 0,
-                   :high => 10,
-                   :highest => 100 }
+    PRIORITIES = {
+      :low => -10,
+      :highest => 100,
+      :lowest => -100,
+      :normal => 0,
+      :high => 10
+    }
 
-    # Fetch all the subclasses of this class and its subclasses' subclasses.
     #
-    # Returns an array of descendant classes.
-    def self.descendants
-      descendants = []
-      ObjectSpace.each_object(singleton_class) do |k|
-        descendants.unshift k unless k == self
+
+    def self.inherited(const)
+      return catch_inheritance(const) do |const_|
+        catch_inheritance(const_)
+      end
+    end
+
+    #
+
+    def self.catch_inheritance(const)
+      const.define_singleton_method :inherited do |const_|
+        (@children ||= Set.new).add const_
+        if block_given?
+          yield const_
+        end
       end
-      descendants
+    end
+
+    #
+
+    def self.descendants
+      @children ||= Set.new
+      out = @children.map(&:descendants)
+      out << self unless superclass == Plugin
+      Set.new(out).flatten
     end
 
     # Get or set the priority of this plugin. When called without an
diff --git a/lib/jekyll/plugin_manager.rb b/lib/jekyll/plugin_manager.rb
index bc54161..68fdebc 100644
--- a/lib/jekyll/plugin_manager.rb
+++ b/lib/jekyll/plugin_manager.rb
@@ -24,12 +24,7 @@ module Jekyll
     #
     # Returns nothing.
     def require_gems
-      site.gems.each do |gem|
-        if plugin_allowed?(gem)
-          Jekyll.logger.debug("PluginManager:", "Requiring #{gem}")
-          require gem
-        end
-      end
+      Jekyll::External.require_with_graceful_fail(site.gems.select { |gem| plugin_allowed?(gem) })
     end
 
     def self.require_from_bundler
@@ -70,10 +65,9 @@ module Jekyll
     # Returns nothing.
     def require_plugin_files
       unless site.safe
-        plugins_path.each do |plugins|
-          Dir[File.join(plugins, "**", "*.rb")].sort.each do |f|
-            require f
-          end
+        plugins_path.each do |plugin_search_path|
+          plugin_files = Utils.safe_glob(plugin_search_path, File.join("**", "*.rb"))
+          Jekyll::External.require_with_graceful_fail(plugin_files)
         end
       end
     end
@@ -82,7 +76,7 @@ module Jekyll
     #
     # Returns an Array of plugin search paths
     def plugins_path
-      if (site.config['plugins_dir'] == Jekyll::Configuration::DEFAULTS['plugins_dir'])
+      if site.config['plugins_dir'].eql? Jekyll::Configuration::DEFAULTS['plugins_dir']
         [site.in_source_dir(site.config['plugins_dir'])]
       else
         Array(site.config['plugins_dir']).map { |d| File.expand_path(d) }
@@ -92,11 +86,10 @@ module Jekyll
     def deprecation_checks
       pagination_included = (site.config['gems'] || []).include?('jekyll-paginate') || defined?(Jekyll::Paginate)
       if site.config['paginate'] && !pagination_included
-        Jekyll::Deprecator.deprecation_message "You appear to have pagination " +
-          "turned on, but you haven't included the `jekyll-paginate` gem. " +
+        Jekyll::Deprecator.deprecation_message "You appear to have pagination " \
+          "turned on, but you haven't included the `jekyll-paginate` gem. " \
           "Ensure you have `gems: [jekyll-paginate]` in your configuration file."
       end
     end
-
   end
 end
diff --git a/lib/jekyll/reader.rb b/lib/jekyll/reader.rb
index 45a2042..c9ded56 100644
--- a/lib/jekyll/reader.rb
+++ b/lib/jekyll/reader.rb
@@ -22,7 +22,7 @@ module Jekyll
 
     # Sorts posts, pages, and static files.
     def sort_files!
-      site.collections.values.each{|c| c.docs.sort!}
+      site.collections.values.each { |c| c.docs.sort! }
       site.pages.sort_by!(&:name)
       site.static_files.sort_by!(&:relative_path)
     end
@@ -38,9 +38,9 @@ module Jekyll
       base = site.in_source_dir(dir)
 
       dot = Dir.chdir(base) { filter_entries(Dir.entries('.'), base) }
-      dot_dirs = dot.select{ |file| File.directory?(@site.in_source_dir(base,file)) }
+      dot_dirs = dot.select { |file| File.directory?(@site.in_source_dir(base, file)) }
       dot_files = (dot - dot_dirs)
-      dot_pages = dot_files.select{ |file| Utils.has_yaml_header?(@site.in_source_dir(base,file)) }
+      dot_pages = dot_files.select { |file| Utils.has_yaml_header?(@site.in_source_dir(base, file)) }
       dot_static_files = dot_files - dot_pages
 
       retrieve_posts(dir)
@@ -67,12 +67,12 @@ module Jekyll
     # dot_dirs - The Array of subdirectories in the dir.
     #
     # Returns nothing.
-    def retrieve_dirs(base, dir, dot_dirs)
-      dot_dirs.map { |file|
-        dir_path = site.in_source_dir(dir,file)
+    def retrieve_dirs(_base, dir, dot_dirs)
+      dot_dirs.map do |file|
+        dir_path = site.in_source_dir(dir, file)
         rel_path = File.join(dir, file)
         @site.reader.read_directories(rel_path) unless @site.dest.sub(/\/$/, '') == dir_path
-      }
+      end
     end
 
     # Retrieve all the pages from the current directory,
diff --git a/lib/jekyll/readers/collection_reader.rb b/lib/jekyll/readers/collection_reader.rb
index 6a54321..062be42 100644
--- a/lib/jekyll/readers/collection_reader.rb
+++ b/lib/jekyll/readers/collection_reader.rb
@@ -1,6 +1,6 @@
 module Jekyll
   class CollectionReader
-    SPECIAL_COLLECTIONS = %w{posts data}.freeze
+    SPECIAL_COLLECTIONS = %w(posts data).freeze
 
     attr_reader :site, :content
     def initialize(site)
@@ -16,6 +16,5 @@ module Jekyll
         collection.read unless SPECIAL_COLLECTIONS.include?(collection.label)
       end
     end
-
   end
 end
diff --git a/lib/jekyll/readers/data_reader.rb b/lib/jekyll/readers/data_reader.rb
index cbb24be..870fc2d 100644
--- a/lib/jekyll/readers/data_reader.rb
+++ b/lib/jekyll/readers/data_reader.rb
@@ -50,13 +50,13 @@ module Jekyll
     # Returns the contents of the data file.
     def read_data_file(path)
       case File.extname(path).downcase
-        when '.csv'
-          CSV.read(path, {
-                           :headers => true,
-                           :encoding => site.config['encoding']
-                       }).map(&:to_hash)
-        else
-          SafeYAML.load_file(path)
+      when '.csv'
+        CSV.read(path, {
+                         :headers => true,
+                         :encoding => site.config['encoding']
+                     }).map(&:to_hash)
+      else
+        SafeYAML.load_file(path)
       end
     end
 
diff --git a/lib/jekyll/readers/page_reader.rb b/lib/jekyll/readers/page_reader.rb
index 099ebf1..97748c0 100644
--- a/lib/jekyll/readers/page_reader.rb
+++ b/lib/jekyll/readers/page_reader.rb
@@ -4,7 +4,7 @@ module Jekyll
     def initialize(site, dir)
       @site = site
       @dir = dir
-      @unfiltered_content = Array.new
+      @unfiltered_content = []
     end
 
     # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
@@ -14,8 +14,8 @@ module Jekyll
     #
     # Returns an array of static pages.
     def read(files)
-      files.map{ |page| @unfiltered_content << Page.new(@site, @site.source, @dir, page) }
-      @unfiltered_content.select{ |page| site.publisher.publish?(page) }
+      files.map { |page| @unfiltered_content << Page.new(@site, @site.source, @dir, page) }
+      @unfiltered_content.select { |page| site.publisher.publish?(page) }
     end
   end
 end
diff --git a/lib/jekyll/readers/post_reader.rb b/lib/jekyll/readers/post_reader.rb
index c41ef10..1bf8ca2 100644
--- a/lib/jekyll/readers/post_reader.rb
+++ b/lib/jekyll/readers/post_reader.rb
@@ -53,8 +53,8 @@ module Jekyll
         next unless entry =~ matcher
         path = @site.in_source_dir(File.join(dir, magic_dir, entry))
         Document.new(path, {
-          site: @site,
-          collection: @site.posts
+          :site => @site,
+          :collection => @site.posts
         })
       end.reject(&:nil?)
     end
diff --git a/lib/jekyll/readers/static_file_reader.rb b/lib/jekyll/readers/static_file_reader.rb
index 279bea4..8def136 100644
--- a/lib/jekyll/readers/static_file_reader.rb
+++ b/lib/jekyll/readers/static_file_reader.rb
@@ -4,7 +4,7 @@ module Jekyll
     def initialize(site, dir)
       @site = site
       @dir = dir
-      @unfiltered_content = Array.new
+      @unfiltered_content = []
     end
 
     # Read all the files in <source>/<dir>/ for Yaml header and create a new Page
@@ -14,7 +14,7 @@ module Jekyll
     #
     # Returns an array of static files.
     def read(files)
-      files.map{ |file| @unfiltered_content << StaticFile.new(@site, @site.source, @dir, file)}
+      files.map { |file| @unfiltered_content << StaticFile.new(@site, @site.source, @dir, file) }
       @unfiltered_content
     end
   end
diff --git a/lib/jekyll/regenerator.rb b/lib/jekyll/regenerator.rb
index 2d84ee3..2052235 100644
--- a/lib/jekyll/regenerator.rb
+++ b/lib/jekyll/regenerator.rb
@@ -62,7 +62,6 @@ module Jekyll
       clear_cache
     end
 
-
     # Clear just the cache
     #
     # Returns nothing
@@ -70,13 +69,12 @@ module Jekyll
       @cache = {}
     end
 
-
     # Checks if the source has been modified or the
     # destination is missing
     #
     # returns a boolean
     def source_modified_or_dest_missing?(source_path, dest_path)
-      modified?(source_path) || (dest_path and !File.exist?(dest_path))
+      modified?(source_path) || (dest_path && !File.exist?(dest_path))
     end
 
     # Checks if a path's (or one of its dependencies)
@@ -90,7 +88,7 @@ module Jekyll
       return true if path.nil?
 
       # Check for path in cache
-      if cache.has_key? path
+      if cache.key? path
         return cache[path]
       end
 
@@ -117,9 +115,9 @@ module Jekyll
     #
     # Returns nothing.
     def add_dependency(path, dependency)
-      return if (metadata[path].nil? || @disabled)
+      return if metadata[path].nil? || @disabled
 
-      if !metadata[path]["deps"].include? dependency
+      unless metadata[path]["deps"].include? dependency
         metadata[path]["deps"] << dependency
         add(dependency) unless metadata.include?(dependency)
       end
@@ -157,20 +155,21 @@ module Jekyll
     #
     # Returns the read metadata.
     def read_metadata
-      @metadata = if !disabled? && File.file?(metadata_file)
-        content = File.binread(metadata_file)
-
-        begin
-          Marshal.load(content)
-        rescue TypeError
-          SafeYAML.load(content)
-        rescue ArgumentError => e
-          Jekyll.logger.warn("Failed to load #{metadata_file}: #{e}")
+      @metadata =
+        if !disabled? && File.file?(metadata_file)
+          content = File.binread(metadata_file)
+
+          begin
+            Marshal.load(content)
+          rescue TypeError
+            SafeYAML.load(content)
+          rescue ArgumentError => e
+            Jekyll.logger.warn("Failed to load #{metadata_file}: #{e}")
+            {}
+          end
+        else
           {}
         end
-      else
-        {}
-      end
     end
   end
 end
diff --git a/lib/jekyll/related_posts.rb b/lib/jekyll/related_posts.rb
index fbc2837..51ae8d8 100644
--- a/lib/jekyll/related_posts.rb
+++ b/lib/jekyll/related_posts.rb
@@ -1,6 +1,5 @@
 module Jekyll
   class RelatedPosts
-
     class << self
       attr_accessor :lsi
     end
@@ -24,7 +23,6 @@ module Jekyll
       end
     end
 
-
     def build_index
       self.class.lsi ||= begin
         lsi = ClassifierReborn::LSI.new(:auto_rebuild => false)
diff --git a/lib/jekyll/renderer.rb b/lib/jekyll/renderer.rb
index 529ff84..b0eb1cb 100644
--- a/lib/jekyll/renderer.rb
+++ b/lib/jekyll/renderer.rb
@@ -2,13 +2,12 @@
 
 module Jekyll
   class Renderer
-
-    attr_reader :document, :site, :site_payload
+    attr_reader :document, :site, :payload
 
     def initialize(site, document, site_payload = nil)
-      @site         = site
-      @document     = document
-      @site_payload = site_payload
+      @site     = site
+      @document = document
+      @payload  = site_payload || site.site_payload
     end
 
     # Determine which converters to use based on this document's
@@ -23,7 +22,7 @@ module Jekyll
     #
     # Returns the output extname including the leading period.
     def output_ext
-      @output_ext ||= converters.first.output_ext(document.extname)
+      @output_ext ||= (permalink_ext || converter_output_ext)
     end
 
     ######################
@@ -33,26 +32,28 @@ module Jekyll
     def run
       Jekyll.logger.debug "Rendering:", document.relative_path
 
-      payload = Utils.deep_merge_hashes({
-        "page" => document.to_liquid
-      }, site_payload || site.site_payload)
+      payload["page"] = document.to_liquid
+
+      if document.respond_to? :pager
+        payload["paginator"] = document.pager.to_liquid
+      end
 
-      if document.collection.label == 'posts' && document.is_a?(Document)
+      if document.is_a?(Document) && document.collection.label == 'posts'
         payload['site']['related_posts'] = document.related_posts
       end
 
+      # render and transform content (this becomes the final content of the object)
+      payload['highlighter_prefix'] = converters.first.highlighter_prefix
+      payload['highlighter_suffix'] = converters.first.highlighter_suffix
+
       Jekyll.logger.debug "Pre-Render Hooks:", document.relative_path
       document.trigger_hooks(:pre_render, payload)
 
       info = {
-        filters:   [Jekyll::Filters],
-        registers: { :site => site, :page => payload['page'] }
+        :filters   => [Jekyll::Filters],
+        :registers => { :site => site, :page => payload['page'] }
       }
 
-      # render and transform content (this becomes the final content of the object)
-      payload["highlighter_prefix"] = converters.first.highlighter_prefix
-      payload["highlighter_suffix"] = converters.first.highlighter_suffix
-
       output = document.content
 
       if document.render_with_liquid?
@@ -134,15 +135,13 @@ module Jekyll
 
       used   = Set.new([layout])
 
+      # Reset the payload layout data to ensure it starts fresh for each page.
+      payload["layout"] = nil
+
       while layout
-        payload = Utils.deep_merge_hashes(
-          payload,
-          {
-            "content" => output,
-            "page"    => document.to_liquid,
-            "layout"  => layout.data
-          }
-        )
+        payload['content'] = output
+        payload['page']    = document.to_liquid
+        payload['layout']  = Utils.deep_merge_hashes(layout.data, payload["layout"] || {})
 
         output = render_liquid(
           layout.content,
@@ -169,5 +168,27 @@ module Jekyll
       output
     end
 
+    private
+
+    def permalink_ext
+      if document.permalink && !document.permalink.end_with?("/")
+        permalink_ext = File.extname(document.permalink)
+        permalink_ext unless permalink_ext.empty?
+      end
+    end
+
+    def converter_output_ext
+      if output_exts.size == 1
+        output_exts.last
+      else
+        output_exts[-2]
+      end
+    end
+
+    def output_exts
+      @output_exts ||= converters.map do |c|
+        c.output_ext(document.extname)
+      end.compact
+    end
   end
 end
diff --git a/lib/jekyll/site.rb b/lib/jekyll/site.rb
index 5e9402f..6533cab 100644
--- a/lib/jekyll/site.rb
+++ b/lib/jekyll/site.rb
@@ -19,8 +19,8 @@ module Jekyll
     def initialize(config)
       @config = config.clone
 
-      %w[safe lsi highlighter baseurl exclude include future unpublished
-        show_drafts limit_posts keep_files gems].each do |opt|
+      %w(safe lsi highlighter baseurl exclude include future unpublished
+        show_drafts limit_posts keep_files gems).each do |opt|
         self.send("#{opt}=", config[opt])
       end
 
@@ -165,7 +165,7 @@ module Jekyll
 
       Jekyll::Hooks.trigger :site, :pre_render, self, payload
 
-      collections.each do |label, collection|
+      collections.each do |_, collection|
         collection.docs.each do |document|
           if regenerator.regenerate?(document)
             document.output = Jekyll::Renderer.new(self, document, payload).run
@@ -176,7 +176,8 @@ module Jekyll
 
       pages.flatten.each do |page|
         if regenerator.regenerate?(page)
-          page.render(layouts, payload)
+          page.output = Jekyll::Renderer.new(self, page, payload).run
+          page.trigger_hooks(:post_render)
         end
       end
 
@@ -196,9 +197,9 @@ module Jekyll
     #
     # Returns nothing.
     def write
-      each_site_file { |item|
+      each_site_file do |item|
         item.write(dest) if regenerator.regenerate?(item)
-      }
+      end
       regenerator.write_metadata
       Jekyll::Hooks.trigger :site, :post_write, self
     end
@@ -224,7 +225,7 @@ module Jekyll
       # Build a hash map based on the specified post attribute ( post attr =>
       # array of posts ) then sort each array in reverse order.
       hash = Hash.new { |h, key| h[key] = [] }
-      posts.docs.each { |p| p.data[post_attr].each { |t| hash[t] << p } }
+      posts.docs.each { |p| p.data[post_attr].each { |t| hash[t] << p } if p.data[post_attr] }
       hash.values.each { |posts| posts.sort!.reverse! }
       hash
     end
@@ -259,47 +260,26 @@ module Jekyll
     #   "tags"       - The Hash of tag values and Posts.
     #                  See Site#post_attr_hash for type info.
     def site_payload
-      {
-        "jekyll" => {
-          "version" => Jekyll::VERSION,
-          "environment" => Jekyll.env
-        },
-        "site"   => Utils.deep_merge_hashes(config,
-          Utils.deep_merge_hashes(Hash[collections.map{|label, coll| [label, coll.docs]}], {
-            "time"         => time,
-            "posts"        => posts.docs.sort { |a, b| b <=> a },
-            "pages"        => pages,
-            "static_files" => static_files,
-            "html_pages"   => pages.select { |page| page.html? || page.url.end_with?("/") },
-            "categories"   => post_attr_hash('categories'),
-            "tags"         => post_attr_hash('tags'),
-            "collections"  => collections.values.map(&:to_liquid),
-            "documents"    => documents,
-            "data"         => site_data
-        }))
-      }
+      Drops::UnifiedPayloadDrop.new self
     end
+    alias_method :to_liquid, :site_payload
 
     # Get the implementation class for the given Converter.
-    #
-    # klass - The Class of the Converter to fetch.
-    #
     # Returns the Converter instance implementing the given Converter.
+    # klass - The Class of the Converter to fetch.
+
     def find_converter_instance(klass)
-      converters.find { |c| c.class == klass } || proc { raise "No converter for #{klass}" }.call
+      converters.find { |klass_| klass_.instance_of?(klass) } || \
+        raise("No Converters found for #{klass}")
     end
 
+    # klass - class or module containing the subclasses.
+    # Returns array of instances of subclasses of parameter.
     # Create array of instances of the subclasses of the class or module
-    #   passed in as argument.
-    #
-    # klass - class or module containing the subclasses which should be
-    #         instantiated
-    #
-    # Returns array of instances of subclasses of parameter
+    # passed in as argument.
+
     def instantiate_subclasses(klass)
-      klass.descendants.select do |c|
-        !safe || c.safe
-      end.sort.map do |c|
+      klass.descendants.select { |c| !safe || c.safe }.sort.map do |c|
         c.new(config)
       end
     end
@@ -310,10 +290,10 @@ module Jekyll
     # Returns
     def relative_permalinks_are_deprecated
       if config['relative_permalinks']
-        Jekyll.logger.abort_with "Since v3.0, permalinks for pages" +
-                                " in subfolders must be relative to the" +
-                                " site source directory, not the parent" +
-                                " directory. Check http://jekyllrb.com/docs/upgrading/"+
+        Jekyll.logger.abort_with "Since v3.0, permalinks for pages" \
+                                " in subfolders must be relative to the" \
+                                " site source directory, not the parent" \
+                                " directory. Check http://jekyllrb.com/docs/upgrading/"\
                                 " for more info."
       end
     end
diff --git a/lib/jekyll/static_file.rb b/lib/jekyll/static_file.rb
index 48fa34c..0ed0fbf 100644
--- a/lib/jekyll/static_file.rb
+++ b/lib/jekyll/static_file.rb
@@ -1,7 +1,7 @@
 module Jekyll
   class StaticFile
     # The cache of last modification times [path] -> mtime.
-    @@mtimes = Hash.new
+    @@mtimes = {}
 
     attr_reader :relative_path, :extname
 
@@ -75,7 +75,7 @@ module Jekyll
     def write(dest)
       dest_path = destination(dest)
 
-      return false if File.exist?(dest_path) and !modified?
+      return false if File.exist?(dest_path) && !modified?
       @@mtimes[path] = mtime
 
       FileUtils.mkdir_p(File.dirname(dest_path))
@@ -90,7 +90,7 @@ module Jekyll
     #
     # Returns nothing.
     def self.reset_cache
-      @@mtimes = Hash.new
+      @@mtimes = {}
       nil
     end
 
@@ -104,12 +104,12 @@ module Jekyll
 
     def placeholders
       {
-        collection: @collection.label,
-        path: relative_path[
+        :collection => @collection.label,
+        :path => relative_path[
           @collection.relative_directory.size..relative_path.size],
-        output_ext: '',
-        name: '',
-        title: '',
+        :output_ext => '',
+        :name => '',
+        :title => ''
       }
     end
 
@@ -118,13 +118,13 @@ module Jekyll
     # be overriden in the collection's configuration in _config.yml.
     def url
       @url ||= if @collection.nil?
-        relative_path
-      else
-        ::Jekyll::URL.new({
-          template:  @collection.url_template,
-          placeholders: placeholders,
-        })
-      end.to_s.gsub /\/$/, ''
+                 relative_path
+               else
+                 ::Jekyll::URL.new({
+                   :template => @collection.url_template,
+                   :placeholders => placeholders
+                 })
+               end.to_s.gsub(/\/$/, '')
     end
 
     # Returns the type of the collection if present, nil otherwise.
diff --git a/lib/jekyll/stevenson.rb b/lib/jekyll/stevenson.rb
index 9a9f412..d6dd543 100644
--- a/lib/jekyll/stevenson.rb
+++ b/lib/jekyll/stevenson.rb
@@ -5,7 +5,7 @@ module Jekyll
       @level = DEBUG
       @default_formatter = Formatter.new
       @logdev = $stdout
-      @formatter = proc do |severity, datetime, progname, msg|
+      @formatter = proc do |_, _, _, msg|
         "#{msg}"
       end
     end
@@ -14,7 +14,7 @@ module Jekyll
       severity ||= UNKNOWN
       @logdev = set_logdevice(severity)
 
-      if @logdev.nil? or severity < @level
+      if @logdev.nil? || severity < @level
         return true
       end
       progname ||= @progname
diff --git a/lib/jekyll/tags/highlight.rb b/lib/jekyll/tags/highlight.rb
index 454c09a..a7dbd51 100644
--- a/lib/jekyll/tags/highlight.rb
+++ b/lib/jekyll/tags/highlight.rb
@@ -13,21 +13,21 @@ module Jekyll
       def initialize(tag_name, markup, tokens)
         super
         if markup.strip =~ SYNTAX
-          @lang = $1.downcase
-          @options = {}
-          if defined?($2) && $2 != ''
+          @lang = Regexp.last_match(1).downcase
+          @highlight_options = {}
+          if defined?(Regexp.last_match(2)) && Regexp.last_match(2) != ''
             # Split along 3 possible forms -- key="<quoted list>", key=value, or key
-            $2.scan(/(?:\w="[^"]*"|\w=\w|\w)+/) do |opt|
+            Regexp.last_match(2).scan(/(?:\w="[^"]*"|\w=\w|\w)+/) do |opt|
               key, value = opt.split('=')
               # If a quoted list, convert to array
               if value && value.include?("\"")
-                  value.gsub!(/"/, "")
+                value.delete!('"')
                   value = value.split
               end
-              @options[key.to_sym] = value || true
+              @highlight_options[key.to_sym] = value || true
             end
           end
-          @options[:linenos] = "inline" if @options.key?(:linenos) and @options[:linenos] == true
+          @highlight_options[:linenos] = "inline" if @highlight_options.key?(:linenos) && @highlight_options[:linenos] == true
         else
           raise SyntaxError.new <<-eos
 Syntax Error in tag 'highlight' while parsing the following markup:
@@ -68,7 +68,7 @@ eos
             [:linenos,     opts.fetch(:linenos, nil)],
             [:encoding,    opts.fetch(:encoding, 'utf-8')],
             [:cssclass,    opts.fetch(:cssclass, nil)]
-          ].reject {|f| f.last.nil? }]
+          ].reject { |f| f.last.nil? }]
         else
           opts
         end
@@ -80,7 +80,7 @@ eos
         highlighted_code = Pygments.highlight(
           code,
           :lexer   => @lang,
-          :options => sanitized_opts(@options, is_safe)
+          :options => sanitized_opts(@highlight_options, is_safe)
         )
 
         if highlighted_code.nil?
@@ -88,7 +88,7 @@ eos
           puts
           Jekyll.logger.error code
           puts
-          Jekyll.logger.error "While attempting to convert the above code, Pygments.rb" +
+          Jekyll.logger.error "While attempting to convert the above code, Pygments.rb" \
             " returned an unacceptable value."
           Jekyll.logger.error "This is usually a timeout problem solved by running `jekyll build` again."
           raise ArgumentError.new("Pygments.rb returned an unacceptable value when attempting to highlight some code.")
@@ -99,7 +99,7 @@ eos
 
       def render_rouge(code)
         Jekyll::External.require_with_graceful_fail('rouge')
-        formatter = Rouge::Formatters::HTML.new(line_numbers: @options[:linenos], wrap: false)
+        formatter = Rouge::Formatters::HTML.new(:line_numbers => @highlight_options[:linenos], :wrap => false)
         lexer = Rouge::Lexer.find_fancy(@lang, code) || Rouge::Lexers::PlainText
         formatter.format(lexer.lex(code))
       end
@@ -110,12 +110,11 @@ eos
 
       def add_code_tag(code)
         code_attributes = [
-          "class=\"language-#{@lang.to_s.gsub('+', '-')}\"",
-          "data-lang=\"#{@lang.to_s}\""
+          "class=\"language-#{@lang.to_s.tr('+', '-')}\"",
+          "data-lang=\"#{@lang}\""
         ].join(" ")
         "<figure class=\"highlight\"><pre><code #{code_attributes}>#{code.chomp}</code></pre></figure>"
       end
-
     end
   end
 end
diff --git a/lib/jekyll/tags/include.rb b/lib/jekyll/tags/include.rb
index 92ce7c6..847e663 100644
--- a/lib/jekyll/tags/include.rb
+++ b/lib/jekyll/tags/include.rb
@@ -12,11 +12,10 @@ module Jekyll
     end
 
     class IncludeTag < Liquid::Tag
-
       attr_reader :includes_dir
 
       VALID_SYNTAX = /([\w-]+)\s*=\s*(?:"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|([\w\.-]+))/
-      VARIABLE_SYNTAX = /(?<variable>[^{]*\{\{\s*(?<name>[\w\-\.]+)\s*(\|.*)?\}\}[^\s}]*)(?<params>.*)/
+      VARIABLE_SYNTAX = /(?<variable>[^{]*(\{\{\s*[\w\-\.]+\s*(\|.*)?\}\}[^\s{}]*)+)(?<params>.*)/
 
       def initialize(tag_name, markup, tokens)
         super
@@ -25,7 +24,7 @@ module Jekyll
           @file = matched['variable'].strip
           @params = matched['params'].strip
         else
-          @file, @params = markup.strip.split(' ', 2);
+          @file, @params = markup.strip.split(' ', 2)
         end
         validate_params if @params
         @tag_name = tag_name
@@ -43,12 +42,12 @@ module Jekyll
           markup = markup[match.end(0)..-1]
 
           value = if match[2]
-            match[2].gsub(/\\"/, '"')
-          elsif match[3]
-            match[3].gsub(/\\'/, "'")
-          elsif match[4]
-            context[match[4]]
-          end
+                    match[2].gsub(/\\"/, '"')
+                  elsif match[3]
+                    match[3].gsub(/\\'/, "'")
+                  elsif match[4]
+                    context[match[4]]
+                  end
 
           params[match[1]] = value
         end
@@ -57,7 +56,7 @@ module Jekyll
 
       def validate_file_name(file)
         if file !~ /^[a-zA-Z0-9_\/\.-]+$/ || file =~ /\.\// || file =~ /\/\./
-            raise ArgumentError.new <<-eos
+          raise ArgumentError.new <<-eos
 Invalid syntax for include tag. File contains invalid characters or sequences:
 
   #{file}
@@ -115,7 +114,7 @@ eos
         validate_path(path, dir, site.safe)
 
         # Add include to dependency tree
-        if context.registers[:page] and context.registers[:page].has_key? "path"
+        if context.registers[:page] && context.registers[:page].key?("path")
           site.regenerator.add_dependency(
             site.in_source_dir(context.registers[:page]["path"]),
             path
@@ -123,7 +122,7 @@ eos
         end
 
         begin
-          partial = site.liquid_renderer.file(path).parse(read_file(path, context))
+          partial = load_cached_partial(path, context)
 
           context.stack do
             context['include'] = parse_params(context) if @params
@@ -134,6 +133,17 @@ eos
         end
       end
 
+      def load_cached_partial(path, context)
+        context.registers[:cached_partials] ||= {}
+        cached_partial = context.registers[:cached_partials]
+
+        if cached_partial.key?(path)
+          cached_partial[path]
+        else
+          cached_partial[path] = context.registers[:site].liquid_renderer.file(path).parse(read_file(path, context))
+        end
+      end
+
       def resolved_includes_dir(context)
         context.registers[:site].in_source_dir(@includes_dir)
       end
diff --git a/lib/jekyll/tags/post_url.rb b/lib/jekyll/tags/post_url.rb
index 5b0d647..6c4c9f8 100644
--- a/lib/jekyll/tags/post_url.rb
+++ b/lib/jekyll/tags/post_url.rb
@@ -60,22 +60,19 @@ eos
         site = context.registers[:site]
 
         site.posts.docs.each do |p|
-          if @post == p
-            return p.url
-          end
+          return p.url if @post == p
         end
 
         # New matching method did not match, fall back to old method
         # with deprecation warning if this matches
 
         site.posts.docs.each do |p|
-          if @post.deprecated_equality p
-            Jekyll::Deprecator.deprecation_message "A call to '{{ post_url #{@post.name} }}' did not match " +
-              "a post using the new matching method of checking name " +
-              "(path-date-slug) equality. Please make sure that you " +
-              "change this tag to match the post's name exactly."
-            return p.url
-          end
+          next unless @post.deprecated_equality p
+          Jekyll::Deprecator.deprecation_message "A call to '{{ post_url #{@post.name} }}' did not match " \
+            "a post using the new matching method of checking name " \
+            "(path-date-slug) equality. Please make sure that you " \
+            "change this tag to match the post's name exactly."
+          return p.url
         end
 
         raise ArgumentError.new <<-eos
diff --git a/lib/jekyll/url.rb b/lib/jekyll/url.rb
index 14b7063..09975e3 100644
--- a/lib/jekyll/url.rb
+++ b/lib/jekyll/url.rb
@@ -11,7 +11,6 @@ require 'uri'
 #
 module Jekyll
   class URL
-
     # options - One of :permalink or :template must be supplied.
     #           :template     - The String used as template for URL generation,
     #                           for example "/:path/:basename:output_ext", where
@@ -59,6 +58,14 @@ module Jekyll
     #
     # Returns the unsanitized String URL
     def generate_url(template)
+      if @placeholders.is_a? Drops::UrlDrop
+        generate_url_from_drop(template)
+      else
+        generate_url_from_hash(template)
+      end
+    end
+
+    def generate_url_from_hash(template)
       @placeholders.inject(template) do |result, token|
         break result if result.index(':').nil?
         if token.last.nil?
@@ -70,20 +77,22 @@ module Jekyll
       end
     end
 
-    # Returns a sanitized String URL
-    def sanitize_url(in_url)
-      url = in_url \
-        # Remove all double slashes
-        .gsub(/\/\//, '/') \
-        # Remove every URL segment that consists solely of dots
-        .split('/').reject{ |part| part =~ /^\.+$/ }.join('/') \
-        # Always add a leading slash
-        .gsub(/\A([^\/])/, '/\1')
+    def generate_url_from_drop(template)
+      template.gsub(/:([a-z_]+)/.freeze) do |match|
+        replacement = @placeholders.public_send(match.sub(':'.freeze, ''.freeze))
+        if replacement.nil?
+          ''.freeze
+        else
+          self.class.escape_path(replacement)
+        end
+      end.gsub(/\/\//.freeze, '/'.freeze)
+    end
 
-      # Append a trailing slash to the URL if the unsanitized URL had one
-      url << "/" if in_url.end_with?("/")
+    # Returns a sanitized String URL, stripping "../../" and multiples of "/",
+    # as well as the beginning "/" so we can enforce and ensure it.
 
-      url
+    def sanitize_url(str)
+      "/" + str.gsub(/\/{2,}/, "/").gsub(/\.+\/|\A\/+/, "")
     end
 
     # Escapes a path to be a valid URL path segment
diff --git a/lib/jekyll/utils.rb b/lib/jekyll/utils.rb
index 7d2490a..149da92 100644
--- a/lib/jekyll/utils.rb
+++ b/lib/jekyll/utils.rb
@@ -1,13 +1,29 @@
 module Jekyll
-  module Utils extend self
+  module Utils
+    extend self
     autoload :Platforms, 'jekyll/utils/platforms'
+    autoload :Ansi, "jekyll/utils/ansi"
 
     # Constants for use in #slugify
-    SLUGIFY_MODES = %w{raw default pretty}
+    SLUGIFY_MODES = %w(raw default pretty)
     SLUGIFY_RAW_REGEXP = Regexp.new('\\s+').freeze
     SLUGIFY_DEFAULT_REGEXP = Regexp.new('[^[:alnum:]]+').freeze
     SLUGIFY_PRETTY_REGEXP = Regexp.new("[^[:alnum:]._~!$&'()+,;=@]+").freeze
 
+    # Takes an indented string and removes the preceding spaces on each line
+
+    def strip_heredoc(str)
+      str.gsub(/^[ \t]{#{(str.scan(/^[ \t]*(?=\S)/).min || "").size}}/, "")
+    end
+
+    # Takes a slug and turns it into a simple title.
+
+    def titleize_slug(slug)
+      slug.split("-").map! do |val|
+        val.capitalize
+      end.join(" ")
+    end
+
     # Non-destructive version of deep_merge_hashes! See that method.
     #
     # Returns the merged hashes.
@@ -25,22 +41,38 @@ module Jekyll
     #
     # Thanks to whoever made it.
     def deep_merge_hashes!(target, overwrite)
-      overwrite.each_key do |key|
-        if overwrite[key].is_a? Hash and target[key].is_a? Hash
-          target[key] = Utils.deep_merge_hashes(target[key], overwrite[key])
-          next
+      target.merge!(overwrite) do |key, old_val, new_val|
+        if new_val.nil?
+          old_val
+        else
+          mergable?(old_val) && mergable?(new_val) ? deep_merge_hashes(old_val, new_val) : new_val
         end
-
-        target[key] = overwrite[key]
       end
 
-      if target.default_proc.nil?
+      if target.respond_to?(:default_proc) && overwrite.respond_to?(:default_proc) && target.default_proc.nil?
         target.default_proc = overwrite.default_proc
       end
 
+      target.each do |key, val|
+        target[key] = val.dup if val.frozen? && duplicable?(val)
+      end
+
       target
     end
 
+    def mergable?(value)
+      value.is_a?(Hash) || value.is_a?(Drops::Drop)
+    end
+
+    def duplicable?(obj)
+      case obj
+      when nil, false, true, Symbol, Numeric
+        false
+      else
+        true
+      end
+    end
+
     # Read array from the supplied hash favouring the singular key
     # and then the plural key, and handling any nil entries.
     #
@@ -56,7 +88,7 @@ module Jekyll
     end
 
     def value_from_singular_key(hash, key)
-      hash[key] if (hash.key?(key) || (hash.default_proc && hash[key]))
+      hash[key] if hash.key?(key) || (hash.default_proc && hash[key])
     end
 
     def value_from_plural_key(hash, key)
@@ -114,7 +146,9 @@ module Jekyll
     #
     # Returns true if the YAML front matter is present.
     def has_yaml_header?(file)
-      !!(File.open(file, 'rb') { |f| f.read(5) } =~ /\A---\r?\n/)
+      !!(File.open(file, 'rb') { |f| f.readline } =~ /\A---\s*\r?\n/)
+    rescue EOFError
+      false
     end
 
     # Slugify a filename or title.
@@ -158,24 +192,26 @@ module Jekyll
       end
 
       # Replace each character sequence with a hyphen
-      re = case mode
-      when 'raw'
-        SLUGIFY_RAW_REGEXP
-      when 'default'
-        SLUGIFY_DEFAULT_REGEXP
-      when 'pretty'
-        # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL
-        # and is allowed in both extN and NTFS.
-        SLUGIFY_PRETTY_REGEXP
-      end
+      re =
+        case mode
+        when 'raw'
+          SLUGIFY_RAW_REGEXP
+        when 'default'
+          SLUGIFY_DEFAULT_REGEXP
+        when 'pretty'
+          # "._~!$&'()+,;=@" is human readable (not URI-escaped) in URL
+          # and is allowed in both extN and NTFS.
+          SLUGIFY_PRETTY_REGEXP
+        end
+
+      # Strip according to the mode
+      slug = string.gsub(re, '-')
 
-      slug = string.
-        # Strip according to the mode
-        gsub(re, '-').
-        # Remove leading/trailing hyphen
-        gsub(/^\-|\-$/i, '')
+      # Remove leading/trailing hyphen
+      slug.gsub!(/^\-|\-$/i, '')
 
-      cased ? slug : slug.downcase
+      slug.downcase! unless cased
+      slug
     end
 
     # Add an appropriate suffix to template so that it matches the specified
@@ -218,5 +254,47 @@ module Jekyll
       template
     end
 
+    # Work the same way as Dir.glob but seperating the input into two parts
+    # ('dir' + '/' + 'pattern') to make sure the first part('dir') does not act
+    # as a pattern.
+    #
+    # For example, Dir.glob("path[/*") always returns an empty array,
+    # because the method fails to find the closing pattern to '[' which is ']'
+    #
+    # Examples:
+    #   safe_glob("path[", "*")
+    #   # => ["path[/file1", "path[/file2"]
+    #
+    #   safe_glob("path", "*", File::FNM_DOTMATCH)
+    #   # => ["path/.", "path/..", "path/file1"]
+    #
+    #   safe_glob("path", ["**", "*"])
+    #   # => ["path[/file1", "path[/folder/file2"]
+    #
+    # dir      - the dir where glob will be executed under
+    #           (the dir will be included to each result)
+    # patterns - the patterns (or the pattern) which will be applied under the dir
+    # flags    - the flags which will be applied to the pattern
+    #
+    # Returns matched pathes
+    def safe_glob(dir, patterns, flags = 0)
+      return [] unless Dir.exist?(dir)
+      pattern = File.join(Array patterns)
+      return [dir] if pattern.empty?
+      Dir.chdir(dir) do
+        Dir.glob(pattern, flags).map { |f| File.join(dir, f) }
+      end
+    end
+
+    # Returns merged option hash for File.read of self.site (if exists)
+    # and a given param
+    def merged_file_read_opts(site, opts)
+      merged = (site ? site.file_read_opts : {}).merge(opts)
+      if merged["encoding"] && !merged["encoding"].start_with?("bom|")
+        merged["encoding"].insert(0, "bom|")
+      end
+      merged
+    end
+
   end
 end
diff --git a/lib/jekyll/utils/ansi.rb b/lib/jekyll/utils/ansi.rb
new file mode 100644
index 0000000..933b432
--- /dev/null
+++ b/lib/jekyll/utils/ansi.rb
@@ -0,0 +1,59 @@
+# Frozen-string-literal: true
+# Copyright: 2015 Jekyll - MIT License
+# Encoding: utf-8
+
+module Jekyll
+  module Utils
+    module Ansi
+      extend self
+
+      ESCAPE = format("%c", 27)
+      MATCH = /#{ESCAPE}\[(?:\d+)(?:;\d+)*(j|k|m|s|u|A|B|G)|\e\(B\e\[m/ix.freeze
+      COLORS = {
+        :red => 31,
+        :green => 32,
+        :black => 30,
+        :magenta => 35,
+        :yellow => 33,
+        :white => 37,
+        :blue => 34,
+        :cyan => 36
+      }
+
+      # Strip ANSI from the current string.  It also strips cursor stuff,
+      # well some of it, and it also strips some other stuff that a lot of
+      # the other ANSI strippers don't.
+
+      def strip(str)
+        str.gsub MATCH, ""
+      end
+
+      #
+
+      def has?(str)
+        !!(str =~ MATCH)
+      end
+
+      # Reset the color back to the default color so that you do not leak any
+      # colors when you move onto the next line. This is probably normally
+      # used as part of a wrapper so that we don't leak colors.
+
+      def reset(str = "")
+        @ansi_reset ||= format("%c[0m", 27)
+        "#{@ansi_reset}#{str}"
+      end
+
+      # SEE: `self::COLORS` for a list of methods.  They are mostly
+      # standard base colors supported by pretty much any xterm-color, we do
+      # not need more than the base colors so we do not include them.
+      # Actually... if I'm honest we don't even need most of the
+      # base colors.
+
+      COLORS.each do |color, num|
+        define_method color do |str|
+          "#{format("%c", 27)}[#{num}m#{str}#{reset}"
+        end
+      end
+    end
+  end
+end
diff --git a/lib/jekyll/utils/platforms.rb b/lib/jekyll/utils/platforms.rb
index 83858a0..d431021 100644
--- a/lib/jekyll/utils/platforms.rb
+++ b/lib/jekyll/utils/platforms.rb
@@ -1,6 +1,7 @@
 module Jekyll
   module Utils
-    module Platforms extend self
+    module Platforms
+      extend self
 
       # Provides jruby? and mri? which respectively detect these two types of
       # tested Engines we support, in the future we might probably support the
@@ -18,7 +19,6 @@ module Jekyll
 
       { :windows? => /mswin|mingw|cygwin/, :linux? => /linux/, \
           :osx? => /darwin|mac os/, :unix? => /solaris|bsd/ }.each do |k, v|
-
         define_method k do
           !!(
             RbConfig::CONFIG["host_os"] =~ v
diff --git a/lib/jekyll/version.rb b/lib/jekyll/version.rb
index 7907aaa..65a1431 100644
--- a/lib/jekyll/version.rb
+++ b/lib/jekyll/version.rb
@@ -1,3 +1,3 @@
 module Jekyll
-  VERSION = '3.0.1'
+  VERSION = '3.1.6'
 end
diff --git a/lib/site_template/_includes/head.html b/lib/site_template/_includes/head.html
index 41340ae..1598d6f 100644
--- a/lib/site_template/_includes/head.html
+++ b/lib/site_template/_includes/head.html
@@ -3,7 +3,7 @@
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1">
 
-  <title>{% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %}</title>
+  <title>{% if page.title %}{{ page.title | escape }}{% else %}{{ site.title | escape }}{% endif %}</title>
   <meta name="description" content="{% if page.excerpt %}{{ page.excerpt | strip_html | strip_newlines | truncate: 160 }}{% else %}{{ site.description }}{% endif %}">
 
   <link rel="stylesheet" href="{{ "/css/main.css" | prepend: site.baseurl }}">
diff --git a/rake/docs.rake b/rake/docs.rake
new file mode 100644
index 0000000..aec162b
--- /dev/null
+++ b/rake/docs.rake
@@ -0,0 +1,23 @@
+#############################################################################
+#
+# Packaging tasks for jekyll-docs
+#
+#############################################################################
+
+namespace :docs do
+  desc "Release #{docs_name} v#{version}"
+  task :release => :build do
+    unless `git branch` =~ /^\* master$/
+      puts "You must be on the master branch to release!"
+      exit!
+    end
+    sh "gem push pkg/#{docs_name}-#{version}.gem"
+  end
+
+  desc "Build #{docs_name} v#{version} into pkg/"
+  task :build do
+    mkdir_p "pkg"
+    sh "gem build #{docs_name}.gemspec"
+    sh "mv #{docs_name}-#{version}.gem pkg"
+  end
+end
diff --git a/rake/release.rake b/rake/release.rake
new file mode 100644
index 0000000..44f5942
--- /dev/null
+++ b/rake/release.rake
@@ -0,0 +1,25 @@
+#############################################################################
+#
+# Packaging tasks
+#
+#############################################################################
+
+desc "Release #{name} v#{version}"
+task :release => :build do
+  unless `git branch` =~ /^\* 3\.1-stable$/
+    puts "You must be on the master branch to release!"
+    exit!
+  end
+  sh "git commit --allow-empty -m 'Release :gem: #{version}'"
+  sh "git tag v#{version}"
+  sh "git push origin master"
+  sh "git push origin v#{version}"
+  sh "gem push pkg/#{name}-#{version}.gem"
+end
+
+desc "Build #{name} v#{version} into pkg/"
+task :build do
+  mkdir_p "pkg"
+  sh "gem build #{gemspec_file}"
+  sh "mv #{gem_file} pkg"
+end
diff --git a/Rakefile b/rake/site.rake
similarity index 55%
copy from Rakefile
copy to rake/site.rake
index ff473e6..08ad12b 100644
--- a/Rakefile
+++ b/rake/site.rake
@@ -1,130 +1,3 @@
-require 'rubygems'
-require 'rake'
-require 'rdoc'
-require 'date'
-require 'yaml'
-
-$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), *%w[lib]))
-require 'jekyll/version'
-
-#############################################################################
-#
-# Helper functions
-#
-#############################################################################
-
-def name
-  'jekyll'.freeze
-end
-
-def version
-  Jekyll::VERSION
-end
-
-def gemspec_file
-  "#{name}.gemspec"
-end
-
-def gem_file
-  "#{name}-#{Gem::Version.new(version).to_s}.gem"
-end
-
-def normalize_bullets(markdown)
-  markdown.gsub(/\n\s{2}\*{1}/, "\n-")
-end
-
-def linkify_prs(markdown)
-  markdown.gsub(/#(\d+)/) do |word|
-    "[#{word}]({{ site.repository }}/issues/#{word.delete("#")})"
-  end
-end
-
-def linkify_users(markdown)
-  markdown.gsub(/(@\w+)/) do |username|
-    "[#{username}](https://github.com/#{username.delete("@")})"
-  end
-end
-
-def linkify(markdown)
-  linkify_users(linkify_prs(markdown))
-end
-
-def liquid_escape(markdown)
-  markdown.gsub(/(`{[{%].+[}%]}`)/, "{% raw %}\\1{% endraw %}")
-end
-
-def custom_release_header_anchors(markdown)
-  header_regexp = /^(\d{1,2})\.(\d{1,2})\.(\d{1,2}) \/ \d{4}-\d{2}-\d{2}/
-  section_regexp = /^### \w+ \w+$/
-  markdown.split(/^##\s/).map do |release_notes|
-    _, major, minor, patch = *release_notes.match(header_regexp)
-    release_notes
-      .gsub(header_regexp, "\\0\n{: #v\\1-\\2-\\3}")
-      .gsub(section_regexp) { |section| "#{section}\n{: ##{sluffigy(section)}-v#{major}-#{minor}-#{patch}}" }
-  end.join("\n## ")
-end
-
-def sluffigy(header)
-  header.gsub(/#/, '').strip.downcase.gsub(/\s+/, '-')
-end
-
-def remove_head_from_history(markdown)
-  index = markdown =~ /^##\s+\d+\.\d+\.\d+/
-  markdown[index..-1]
-end
-
-def converted_history(markdown)
-  remove_head_from_history(
-    custom_release_header_anchors(
-      liquid_escape(
-        linkify(
-          normalize_bullets(markdown)))))
-end
-
-#############################################################################
-#
-# Standard tasks
-#
-#############################################################################
-
-multitask :default => [:test, :features]
-
-task :spec => :test
-require 'rake/testtask'
-Rake::TestTask.new(:test) do |test|
-  test.libs << 'lib' << 'test'
-  test.pattern = 'test/**/test_*.rb'
-  test.verbose = true
-end
-
-require 'rdoc/task'
-Rake::RDocTask.new do |rdoc|
-  rdoc.rdoc_dir = 'rdoc'
-  rdoc.title = "#{name} #{version}"
-  rdoc.rdoc_files.include('README*')
-  rdoc.rdoc_files.include('lib/**/*.rb')
-end
-
-begin
-  require 'cucumber/rake/task'
-  Cucumber::Rake::Task.new(:features) do |t|
-    t.profile = "travis"
-  end
-  Cucumber::Rake::Task.new(:"features:html", "Run Cucumber features and produce HTML output") do |t|
-    t.profile = "html_report"
-  end
-rescue LoadError
-  desc 'Cucumber rake task not available'
-  task :features do
-    abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin'
-  end
-end
-
-desc "Open an irb session preloaded with this library"
-task :console do
-  sh "irb -rubygems -r ./lib/#{name}.rb"
-end
-
 #############################################################################
 #
 # Site tasks - http://jekyllrb.com
@@ -132,8 +5,10 @@ end
 #############################################################################
 
 namespace :site do
+  task :generated_pages => [:history, :version_file, :conduct]
+
   desc "Generate and view the site locally"
-  task :preview do
+  task :preview => :generated_pages do
     require "launchy"
     require "jekyll"
 
@@ -158,13 +33,14 @@ namespace :site do
   end
 
   desc "Generate the site"
-  task :generate => [:history, :version_file] do
+  task :generate => :generated_pages do
     require "jekyll"
     Jekyll::Commands::Build.process({
       "source"      => File.expand_path("site"),
       "destination" => File.expand_path("site/_site")
     })
   end
+  task :build => :generate
 
   desc "Update normalize.css library to the latest version and minify"
   task :update_normalize_css do
@@ -176,7 +52,7 @@ namespace :site do
   end
 
   desc "Commit the local site to the gh-pages branch and publish to GitHub Pages"
-  task :publish => [:history, :version_file] do
+  task :publish => :generated_pages do
     # Ensure the gh-pages dir exists so we can generate into it.
     puts "Checking for gh-pages dir..."
     unless File.exist?("./gh-pages")
@@ -245,6 +121,25 @@ namespace :site do
     end
   end
 
+  desc "Copy the Code of Conduct"
+  task :conduct do
+    code_of_conduct = File.read("CONDUCT.markdown")
+    header, _, body = code_of_conduct.partition("\n\n")
+    front_matter = {
+      "layout"        => "docs",
+      "title"         => header.sub('# Contributor ', ''),
+      "permalink"     => "/docs/conduct/",
+      "redirect_from" => "/conduct/index.html",
+      "editable"      => false
+    }
+    Dir.chdir('site/_docs') do
+      File.open("conduct.md", "w") do |file|
+        file.write("#{front_matter.to_yaml}---\n\n")
+        file.write(body)
+      end
+    end
+  end
+
   desc "Write the site latest_version.txt file"
   task :version_file do
     File.open('site/latest_version.txt', 'wb') { |f| f.puts(version) } unless version =~ /(beta|rc|alpha)/i
@@ -275,29 +170,3 @@ namespace :site do
     end
   end
 end
-
-#############################################################################
-#
-# Packaging tasks
-#
-#############################################################################
-
-desc "Release #{name} v#{version}"
-task :release => :build do
-  unless `git branch` =~ /^\* master$/
-    puts "You must be on the master branch to release!"
-    exit!
-  end
-  sh "git commit --allow-empty -m 'Release :gem: #{version}'"
-  sh "git tag v#{version}"
-  sh "git push origin master"
-  sh "git push origin v#{version}"
-  sh "gem push pkg/#{name}-#{version}.gem"
-end
-
-desc "Build #{name} v#{version} into pkg/"
-task :build do
-  mkdir_p "pkg"
-  sh "gem build #{gemspec_file}"
-  sh "mv #{gem_file} pkg"
-end
diff --git a/script/cibuild b/script/cibuild
index afafd7d..d30fd36 100755
--- a/script/cibuild
+++ b/script/cibuild
@@ -2,6 +2,8 @@
 
 script/branding
 
+set -e
+
 if [[ -z "$TEST_SUITE" ]]
 then
   script/test  ci
diff --git a/script/cucumber b/script/cucumber
index 13508c8..0f0ef0f 100755
--- a/script/cucumber
+++ b/script/cucumber
@@ -1,11 +1,4 @@
 #!/usr/bin/env bash
 
-if ruby --version | grep -q "jruby"
-then
-  echo "Move along, we are not testing features on JRuby right now."
-  exit 0
-else
-  time ruby -S bundle exec cucumber \
-    -f Features::Support::Overview \
-    "$@"
-fi
+time ruby -S bundle exec cucumber \
+  -f Jekyll::Cucumber::Formatter "$@"
diff --git a/script/proof b/script/proof
index c8fff90..01da501 100755
--- a/script/proof
+++ b/script/proof
@@ -27,7 +27,7 @@ bundle install -j8 > /dev/null || bundle install > /dev/null
 
 # 2.
 msg "Building..."
-bundle exec jekyll build -s $SOURCE -d $DESTINATION --full-rebuild --trace
+bundle exec jekyll build -s $SOURCE -d $DESTINATION --trace
 
 # 3.
 msg "Proofing..."
diff --git a/script/rebund b/script/rebund
deleted file mode 100755
index d2ff790..0000000
--- a/script/rebund
+++ /dev/null
@@ -1,140 +0,0 @@
-#!/usr/bin/env bash
-#
-# rebund(1)
-#
-# Author: Julien Letessier
-# Homepage: https://github.com/mezis/rebund
-# License:
-#
-# Copyright (c) 2014 HouseTrip Ltd
-#
-# MIT License
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-
-# Configuration
-: ${REBUND_CREDENTIALS:=user:secret}
-: ${REBUND_ENDPOINT=http://keyfile-production.herokuapp.com}
-: ${REBUND_TARBALL:=bundle.tbz}
-: ${REBUND_BUNDLE_DIR:=vendor/bundle}
-
-
-
-log() {
-  echo "rebund: $*" > /dev/stderr
-}
-
-die() {
-  echo "fatal: $*" > /dev/stderr
-  exit 1
-}
-
-success() {
-  log "$*"
-  exit 0
-}
-
-on_error() {
-  die 'unknown error.'
-}
-
-get_ruby_version() {
-  bundle exec ruby --version
-}
-
-get_gemfile() {
-  bundle exec sh -c 'echo $BUNDLE_GEMFILE'
-}
-
-calculate_hash() {
-  (get_ruby_version ; cat $(get_gemfile)) | openssl sha256 | sed -e 's/.* //'
-}
-
-build_tarball() {
-  test -e $REBUND_BUNDLE_DIR || die "cannot find bundle directory in ${REBUND_BUNDLE_DIR}"
-  test -e $REBUND_TARBALL && success 'bundle already uploaded'
-  tar jcf $REBUND_TARBALL $REBUND_BUNDLE_DIR
-}
-
-upload_tarball() {
-  curl --fail \
-    -F filedata=@${REBUND_TARBALL} \
-    --digest --user $REBUND_CREDENTIALS \
-    ${REBUND_ENDPOINT}/$(calculate_hash) \
-  || success "could not upload bundle"
-}
-
-expand_tarball() {
-  test -e $REBUND_TARBALL || success "no tarball"
-  tar jxf $REBUND_TARBALL
-}
-
-download_tarball() {
-  curl --fail \
-    --location \
-    -o ${REBUND_TARBALL} \
-    --digest --user $REBUND_CREDENTIALS \
-    ${REBUND_ENDPOINT}/$(calculate_hash) \
-    || success "could not download bundle"
-}
-
-rebund_upload() {
-  build_tarball
-  upload_tarball
-}
-
-rebund_download() {
-  download_tarball
-  expand_tarball
-}
-
-rebund_usage() {
-  success "usage: $0 [-v] [upload|download]"
-}
-
-# cath errors
-trap on_error ERR
-
-# inherit the ERR trap in subprocesses
-set -E
-
-while test $# -gt 0 ; do
-  case $1 in
-    -v)
-      set -x
-      ;;
-    upload)
-      rebund_upload
-      exit 0
-      ;;
-    download)
-      rebund_download
-      exit 0
-      ;;
-    *)
-      rebund_usage
-      exit 1
-      ;;
-  esac
-  shift
-done
-
-rebund_usage
diff --git a/script/stackprof b/script/stackprof
index 3399616..1c83314 100755
--- a/script/stackprof
+++ b/script/stackprof
@@ -2,15 +2,21 @@
 
 set -e
 
+case "$1" in
+  cpu|object) STACKPROF_MODE="$1"; shift ;;
+  *) STACKPROF_MODE="cpu" ;;
+esac
+
 export BENCHMARK=true
 command -v stackprof > /dev/null || script/bootstrap
 
 TEST_SCRIPT="Jekyll::Commands::Build.process({'source' => 'site'})"
-PROF_OUTPUT_FILE=tmp/stackprof-$(date +%Y%m%d%H%M).dump
+PROF_OUTPUT_FILE=tmp/stackprof-${STACKPROF_MODE}-$(date +%Y%m%d%H%M).dump
 
+echo Stackprof Mode: $STACKPROF_MODE
 test -f "$PROF_OUTPUT_FILE" || {
   bundle exec ruby -r./lib/jekyll -rstackprof \
-    -e "StackProf.run(mode: :cpu, interval: 100, out: '${PROF_OUTPUT_FILE}') { ${TEST_SCRIPT} }"
+    -e "StackProf.run(mode: :${STACKPROF_MODE}, interval: 100, out: '${PROF_OUTPUT_FILE}') { ${TEST_SCRIPT} }"
 }
 
 bundle exec stackprof $PROF_OUTPUT_FILE $@
diff --git a/script/travis b/script/travis
new file mode 100644
index 0000000..4d62fa9
--- /dev/null
+++ b/script/travis
@@ -0,0 +1,40 @@
+#!/bin/sh
+# Usage: script/travis [ruby-version [file]]
+# Example: script/travis 2.0 test/failing_test.rb
+# Example: script/travis 2.3.0
+set -e
+
+mkdir -p vendor/docker
+docker rm -fv docker-travis > /dev/null 2>&1 || true
+docker run --volume=$(pwd):/home/travis/builds/jekyll/jekyll \
+  --workdir=/home/travis/builds/jekyll/jekyll \
+  --volume=$(pwd)/vendor/docker:/home/travis/builds/jekyll/jekyll/vendor/bundle \
+  --user=travis --name=docker-travis -dit quay.io/travisci/travis-ruby \
+      bash > /dev/null
+
+status=0
+if [ $# -eq 2 ]; then
+  docker exec -it docker-travis bash -ilc " \
+    rvm use --install --binary --fuzzy $1
+    bundle install --path vendor/bundle -j 12 \\
+      --without benchmark:site:development
+    bundle clean
+    script/test $2
+  " || status=$?
+
+elif [ $# -eq 1 ]; then
+  docker exec -it docker-travis bash -ilc " \
+    rvm use --install --binary --fuzzy $1
+    bundle install --path vendor/bundle -j 12 \\
+      --without benchmark:site:development
+    bundle clean
+    bundle exec rake
+  " || status=$?
+
+else
+  docker exec -it docker-travis \
+    bash -il || status=$?
+fi
+
+docker rm -fv docker-travis > /dev/null
+exit $status
diff --git a/site/_config.yml b/site/_config.yml
index d1cd536..241c5b0 100644
--- a/site/_config.yml
+++ b/site/_config.yml
@@ -9,6 +9,8 @@ google_analytics_id: UA-50755011-1
 repository: https://github.com/jekyll/jekyll
 help_url: https://github.com/jekyll/jekyll-help
 
+timezone: America/Los_Angeles
+
 collections:
   docs:
     output: true
@@ -19,3 +21,5 @@ url: http://jekyllrb.com
 
 gems:
   - jekyll-feed
+  - jekyll-redirect-from
+  - jemoji
diff --git a/site/_data/docs.yml b/site/_data/docs.yml
index bcdf352..7cb8519 100644
--- a/site/_data/docs.yml
+++ b/site/_data/docs.yml
@@ -39,9 +39,11 @@
   - troubleshooting
   - sites
   - resources
-  - upgrading
+  - upgrading/0-to-2
+  - upgrading/2-to-3
 
 - title: Meta
   docs:
   - contributing
+  - conduct
   - history
diff --git a/site/_docs/assets.md b/site/_docs/assets.md
index 202ade0..10f094b 100644
--- a/site/_docs/assets.md
+++ b/site/_docs/assets.md
@@ -83,9 +83,10 @@ here, too.
 
 ## Coffeescript
 
-To enable Coffeescript in Jekyll 3.0 and up you must 
- * Install the `jekyll-coffeescript` gem
- * Ensure that your `_config.yml` is up-to-date and includes the following
+To enable Coffeescript in Jekyll 3.0 and up you must
+
+* Install the `jekyll-coffeescript` gem
+* Ensure that your `_config.yml` is up-to-date and includes the following:
 
 {% highlight yaml %}
 gems:
diff --git a/site/_docs/conduct.md b/site/_docs/conduct.md
new file mode 100644
index 0000000..d25c32c
--- /dev/null
+++ b/site/_docs/conduct.md
@@ -0,0 +1,55 @@
+---
+layout: docs
+title: Code of Conduct
+permalink: "/docs/conduct/"
+redirect_from: "/conduct/index.html"
+editable: false
+---
+
+As contributors and maintainers of this project, and in the interest of
+fostering an open and welcoming community, we pledge to respect all people who
+contribute through reporting issues, posting feature requests, updating
+documentation, submitting pull requests or patches, and other activities.
+
+We are committed to making participation in this project a harassment-free
+experience for everyone, regardless of level of experience, gender, gender
+identity and expression, sexual orientation, disability, personal appearance,
+body size, race, ethnicity, age, religion, or nationality.
+
+Examples of unacceptable behavior by participants include:
+
+* The use of sexualized language or imagery
+* Personal attacks
+* Trolling or insulting/derogatory comments
+* Public or private harassment
+* Publishing other's private information, such as physical or electronic
+  addresses, without explicit permission
+* Other unethical or unprofessional conduct
+
+Project maintainers have the right and responsibility to remove, edit, or
+reject comments, commits, code, wiki edits, issues, and other contributions
+that are not aligned to this Code of Conduct, or to ban temporarily or
+permanently any contributor for other behaviors that they deem inappropriate,
+threatening, offensive, or harmful.
+
+By adopting this Code of Conduct, project maintainers commit themselves to
+fairly and consistently applying these principles to every aspect of managing
+this project. Project maintainers who do not follow or enforce the Code of
+Conduct may be permanently removed from the project team.
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community.
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported by opening an issue or contacting a project maintainer. All complaints
+will be reviewed and investigated and will result in a response that is deemed
+necessary and appropriate to the circumstances. Maintainers are obligated to
+maintain confidentiality with regard to the reporter of an incident.
+
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 1.3.0, available at
+[http://contributor-covenant.org/version/1/3/0/][version]
+
+[homepage]: http://contributor-covenant.org
+[version]: http://contributor-covenant.org/version/1/3/0/
diff --git a/site/_docs/configuration.md b/site/_docs/configuration.md
index 2bb65e8..5704418 100644
--- a/site/_docs/configuration.md
+++ b/site/_docs/configuration.md
@@ -120,7 +120,7 @@ class="flag">flags</code> (specified on the command-line) that control them.
       <td>
         <p class="name"><strong>Encoding</strong></p>
         <p class="description">
-            Set the encoding of files by name. Only available for Ruby
+            Set the encoding of files by name (only available for Ruby
             1.9 or later).
             The default value is <code>utf-8</code> starting in 2.0.0,
             and <code>nil</code> before 2.0.0, which will yield the Ruby
@@ -198,6 +198,7 @@ class="flag">flags</code> (specified on the command-line) that control them.
         <p class="description">Process and render draft posts.</p>
       </td>
       <td class="align-center">
+        <p><code class="option">show_drafts: BOOL</code></p>
         <p><code class="flag">--drafts</code></p>
       </td>
     </tr>
@@ -352,6 +353,24 @@ before your site is served.
         <p><code class="flag">--skip-initial-build</code></p>
       </td>
     </tr>
+    <tr class="setting">
+      <td>
+        <p class="name"><strong>X.509 (SSL) Private Key</strong></p>
+        <p class="description">SSL Private Key.</p>
+      </td>
+      <td class="align-center">
+        <p><code class="flag">--ssl-key</code></p>
+      </td>
+    </tr>
+    <tr class="setting">
+      <td>
+        <p class="name"><strong>X.509 (SSL) Certificate</strong></p>
+        <p class="description">SSL Public certificate.</p>
+      </td>
+      <td class="align-center">
+        <p><code class="flag">--ssl-cert</code></p>
+      </td>
+    </tr>
   </tbody>
 </table>
 </div>
@@ -364,6 +383,24 @@ before your site is served.
   </p>
 </div>
 
+## Custom WEBRick Headers
+
+You can provide custom headers for your site by adding them to `_config.yml`
+
+{% highlight yaml %}
+# File: _config.yml
+webrick:
+  headers:
+    My-Header: My-Value
+    My-Other-Header: My-Other-Value
+{% endhighlight %}
+
+### Defaults
+
+We only provide one default and that's a Content-Type header that disables
+caching in development so that you don't have to fight with Chrome's aggressive
+caching when you are in development mode.
+
 ## Specifying a Jekyll environment at build time
 
 In the build (or serve) arguments, you can specify a Jekyll environment and value. The build will then apply this value in any conditional statements in your content.
@@ -452,7 +489,7 @@ With these defaults, all posts would use the `my-site` layout. Any html files th
 {% highlight yaml %}
 collections:
   - my_collection:
-    output: true
+      output: true
 
 defaults:
   -
@@ -463,13 +500,14 @@ defaults:
       layout: "default"
 {% endhighlight %}
 
-In this example the `layout` is set to `default` inside the [collection](../collections/) with the name `my_collection`.
+In this example, the `layout` is set to `default` inside the
+[collection](../collections/) with the name `my_collection`.
 
 ### Precedence
 
 Jekyll will apply all of the configuration settings you specify in the `defaults` section of your `_config.yml` file. However, you can choose to override settings from other scope/values pair by specifying a more specific path for the scope.
 
-You can see that in the last example above. First, we set the default layout to `my-site`. Then, using a more specific path, we set the default layout for files in the `projects/` path to `project`. This can be done with any value that you would set in the page or post front matter.
+You can see that in the second to last example above. First, we set the default layout to `my-site`. Then, using a more specific path, we set the default layout for files in the `projects/` path to `project`. This can be done with any value that you would set in the page or post front matter.
 
 Finally, if you set defaults in the site configuration by adding a `defaults` section to your `_config.yml` file, you can override those settings in a post or page file. All you need to do is specify the settings in the post or page front matter. For example:
 
@@ -641,7 +679,7 @@ extensions are:
 ### Kramdown
 
 In addition to the defaults mentioned above, you can also turn on recognition
-of Github Flavored Markdown by passing an `input` option with a value of "GFM".
+of GitHub Flavored Markdown by passing an `input` option with a value of "GFM".
 
 For example, in your `_config.yml`:
 
@@ -669,9 +707,41 @@ class Jekyll::Converters::Markdown::MyCustomProcessor
 end
 {% endhighlight %}
 
-Once you've created your class and have it properly setup either as a plugin in
-the `_plugins` folder or as a gem, specify it in your `_config.yml`:
+Once you've created your class and have it properly set up either as a plugin
+in the `_plugins` folder or as a gem, specify it in your `_config.yml`:
 
 {% highlight yaml %}
 markdown: MyCustomProcessor
 {% endhighlight %}
+
+## Incremental Regeneration
+<div class="note warning">
+  <h5>Incremental regeneration is still an experimental feature</h5>
+  <p>
+    While incremental regeneration will work for the most common cases, it will
+    not work correctly in every scenario. Please be extremely cautious when
+    using the feature, and report any problems not listed below by
+    <a href="https://github.com/jekyll/jekyll/issues/new">opening an issue on GitHub</a>.
+  </p>
+</div>
+
+Incremental regeneration helps shorten build times by only generating documents
+and pages that were updated since the previous build. It does this by keeping
+track of both file modification times and inter-document dependencies in the
+`.jekyll-metadata` file.
+
+Under the current implementation, incremental regeneration will only generate a
+document or page if either it, or one of its dependencies, is modified. Currently,
+the only types of dependencies tracked are includes (using the
+{% raw %}`{% include %}`{% endraw %} tag) and layouts. This means that plain
+references to other documents (for example, the common case of iterating over
+`site.posts` in a post listings page) will not be detected as a dependency.
+
+To remedy some of these shortfalls, putting `regenerate: true` in the front-matter
+of a document will force Jekyll to regenerate it regardless of whether it has been
+modified. Note that this will generate the specified document only; references
+to other documents' contents will not work since they won't be re-rendered.
+
+Incremental regeneration can be enabled via the `--incremental` flag (`-I` for
+short) from the command-line or by setting `incremental: true` in your
+configuration file.
diff --git a/site/_docs/contributing.md b/site/_docs/contributing.md
index 1feec0d..224f52f 100644
--- a/site/_docs/contributing.md
+++ b/site/_docs/contributing.md
@@ -43,7 +43,7 @@ Test Dependencies
 -----------------
 
 To run the test suite and build the gem you'll need to install Jekyll's
-dependencies. Simply run this command to get all setup:
+dependencies. Simply run this command to get all set up:
 
 <figure class="highlight"><pre><code>$ script/bootstrap</code></pre></figure>
 
diff --git a/site/_docs/datafiles.md b/site/_docs/datafiles.md
index afa54b8..4fd85b4 100644
--- a/site/_docs/datafiles.md
+++ b/site/_docs/datafiles.md
@@ -33,8 +33,8 @@ of code in your Jekyll templates:
 In `_data/members.yml`:
 
 {% highlight yaml %}
-- name: Tom Preston-Werner
-  github: mojombo
+- name: Eric Mill
+  github: konklone
 
 - name: Parker Moore
   github: parkr
@@ -47,7 +47,7 @@ Or `_data/members.csv`:
 
 {% highlight text %}
 name,github
-Tom Preston-Werner,mojombo
+Eric Mill,konklone
 Parker Moore,parkr
 Liu Fengyun,liufengyun
 {% endhighlight %}
diff --git a/site/_docs/deployment-methods.md b/site/_docs/deployment-methods.md
index c1040b2..7e77ce1 100644
--- a/site/_docs/deployment-methods.md
+++ b/site/_docs/deployment-methods.md
@@ -90,7 +90,7 @@ Setup steps are fully documented
 
 ### Rake
 
-Another way to deploy your Jekyll site is to use [Rake](https://github.com/jimweirich/rake), [HighLine](https://github.com/JEG2/highline), and
+Another way to deploy your Jekyll site is to use [Rake](https://github.com/ruby/rake), [HighLine](https://github.com/JEG2/highline), and
 [Net::SSH](https://github.com/net-ssh/net-ssh). A more complex example of deploying Jekyll with Rake that deals with multiple branches can be found in [Git Ready](https://github.com/gitready/gitready/blob/cdfbc4ec5321ff8d18c3ce936e9c749dbbc4f190/Rakefile).
 
 
@@ -102,64 +102,77 @@ Once you’ve generated the `_site` directory, you can easily scp it using a `ta
 
 Once you’ve generated the `_site` directory, you can easily rsync it using a `tasks/deploy` shell script similar to [this deploy script here](https://github.com/vitalyrepin/vrepinblog/blob/master/transfer.sh). You’d obviously need to change the values to reflect your site’s details.
 
-#### Step 1: Install rrsync to your home folder (server-side)
+Certificate-based authorization is another way to simplify the publishing
+process. It makes sense to restrict rsync access only to the directory which it is supposed to sync. This can be done using rrsync.
 
-We will use certificate-based authorization to simplify the publishing process. It makes sense to restrict rsync access only to the directory which it is supposed to sync.
+#### Step 1: Install rrsync to your home folder (server-side)
 
-That's why rrsync wrapper shall be installed. If it is not already installed by your hoster you can do it yourself:
+If it is not already installed by your host, you can do it yourself:
 
-- [download rrsync](http://ftp.samba.org/pub/unpacked/rsync/support/rrsync)
-- Put it to the bin subdirectory of your home folder  (```~/bin```)
-- Make it executable (```chmod +x```)
+- [Download rrsync](http://ftp.samba.org/pub/unpacked/rsync/support/rrsync)
+- Place it in the `bin` subdirectory of your home folder  (`~/bin`)
+- Make it executable (`chmod +x`)
 
-#### Step 2: Setup certificate-based ssh access (server side)
+#### Step 2: Set up certificate-based SSH access (server side)
 
-[This process is described in a lot of places in the net](https://wiki.gentoo.org/wiki/SSH#Passwordless_Authentication). We will not cover it here. What is different from usual approach is to put the restriction to certificate-based authorization in ```~/.ssh/authorized_keys```). We will launch ```rrsync``` utility and supply it with the folder it shall have read-write access to:
+This [process](https://wiki.gentoo.org/wiki/SSH#Passwordless_Authentication) is
+described in several places online. What is different from the typical approach
+is to put the restriction to certificate-based authorization in
+`~/.ssh/authorized_keys`. Then, launch `rrsync` and supply
+it with the folder it shall have read-write access to:
 
-```
+{% highlight bash %}
 command="$HOME/bin/rrsync <folder>",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa <cert>
-```
+{% endhighlight %}
 
-```<folder>``` is the path to your site. E.g., ```~/public_html/you.org/blog-html/```.
+`<folder>` is the path to your site. E.g., `~/public_html/you.org/blog-html/`.
 
-#### Step 3: Rsync! (client-side)
+#### Step 3: Rsync (client-side)
 
-Add the script ```deploy``` to the web site source folder:
+Add the `deploy` script to the site source folder:
 
 {% highlight bash %}
 #!/bin/sh
 
-rsync -avr --rsh='ssh -p2222' --delete-after --delete-excluded   <folder> <user>@<site>:
+rsync -crvz --rsh=ssh -p2222' --delete-after --delete-excluded   <folder> <user>@<site>:
 {% endhighlight %}
 
 Command line parameters are:
 
-- ```--rsh='ssh -p2222'``` It is needed if your hoster provides ssh access using ssh port different from default one (e.g., this is what hostgator is doing)
-- ```<folder>``` is the name of the local folder with generated web content. By default it is ```_site/``` for Jekyll
-- ```<user>``` — ssh user name for your hosting account
-- ```<site>``` — your hosting server
+- `--rsh=ssh -p2222` — The port for SSH access. It is required if
+your host uses a different port than the default (e.g, HostGator)
+- `<folder>` — The name of the local output folder (defaults to `_site`)
+- `<user>` — The username for your hosting account
+- `<site>` — Your hosting server
 
-Example command line is:
+Using this setup, you might run the following command:
 
 {% highlight bash %}
-rsync -avr --rsh='ssh -p2222' --delete-after --delete-excluded   _site/ hostuser at vrepin.org:
+rsync -crvz --rsh='ssh -p2222' --delete-after --delete-excluded   _site/ hostuser at example.org:
 {% endhighlight %}
 
-Don't forget column ':' after server name!
+Don't forget the column `:` after server name!
+
+#### Step 4 (Optional): Exclude the transfer script from being copied to the output folder.
 
-#### Optional step 4: exclude transfer.sh from being copied to the output folder by Jekyll
+This step is recommended if you use these instructions to deploy your site. If
+you put the `deploy` script in the root folder of your project, Jekyll will
+copy it to the output folder. This behavior can be changed in `_config.yml`.
 
-This step is recommended if you use this how-to to deploy Jekyll-based web site. If you put ```deploy``` script to the root folder of your project, Jekyll copies it to the output folder.
-This behavior can be changed in ```_config.yml```. Just add the following line there:
+Just add the following line:
 
 {% highlight yaml %}
-# Do not copy these file to the output directory
+# Do not copy these files to the output directory
 exclude: ["deploy"]
 {% endhighlight %}
 
-#### We are done!
+Alternatively, you can use an `rsync-exclude.txt` file to control which files will be transferred to your server.
 
-Now it's possible to publish your web site by launching ```deploy``` script. If your ssh certificate  is [passphrase-protected](https://martin.kleppmann.com/2013/05/24/improving-security-of-ssh-private-keys.html), you are asked to enter the password.
+#### Done!
+
+Now it's possible to publish your website simply by running the  `deploy` 
+script. If your SSH certificate  is [passphrase-protected](https://martin.kleppmann.com/2013/05/24/improving-security-of-ssh-private-keys.html), you will be asked to enter it when the
+script executes.
 
 ## Rack-Jekyll
 
@@ -190,3 +203,11 @@ for that](https://github.com/openshift-cartridges/openshift-jekyll-cartridge).
   <h5>ProTip™: Use GitHub Pages for zero-hassle Jekyll hosting</h5>
   <p>GitHub Pages are powered by Jekyll behind the scenes, so if you’re looking for a zero-hassle, zero-cost solution, GitHub Pages are a great way to <a href="../github-pages/">host your Jekyll-powered website for free</a>.</p>
 </div>
+
+## Kickster
+
+Use [Kickster](http://kickster.nielsenramon.com/) for easy (automated) deploys to GitHub Pages when using unsupported plugins on GitHub Pages.
+
+Kickster provides a basic Jekyll project setup packed with web best practises and useful optimization tools increasing your overall project quality. Kickster ships with automated and worry-free deployment scripts for GitHub Pages.
+
+Setting up Kickster is very easy, just install the gem and you are good to go. More documentation can here found [here](https://github.com/nielsenramon/kickster#kickster). If you do not want to use the gem or start a new project you can just copy paste the deployment scripts for [Travis CI](https://github.com/nielsenramon/kickster/tree/master/snippets/travis) or [Circle CI](https://github.com/nielsenramon/kickster#automated-deployment-with-circle-ci).
diff --git a/site/_docs/extras.md b/site/_docs/extras.md
index 2af6a30..24bcafa 100644
--- a/site/_docs/extras.md
+++ b/site/_docs/extras.md
@@ -9,7 +9,13 @@ may want to install, depending on how you plan to use Jekyll.
 
 ## Math Support
 
-Kramdown comes with optional support for LaTeX to PNG rendering via [MathJax](http://www.mathjax.org/) within math blocks. See the Kramdown documentation on [math blocks](http://kramdown.gettalong.org/syntax.html#math-blocks) and [math support](http://kramdown.gettalong.org/converter/html.html#math-support) for more details.
+Kramdown comes with optional support for LaTeX to PNG rendering via [MathJax](http://www.mathjax.org/) within math blocks. See the Kramdown documentation on [math blocks](http://kramdown.gettalong.org/syntax.html#math-blocks) and [math support](http://kramdown.gettalong.org/converter/html.html#math-support) for more details. MathJax requires you to include JavaScript or CSS to render the LaTeX, e.g.
+
+{% highlight html %}
+<script src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"></script>
+{% endhighlight %}
+
+For more information about getting started, check out [this excellent blog post](http://gastonsanchez.com/opinion/2014/02/16/Mathjax-with-jekyll/).
 
 ## Alternative Markdown Processors
 
diff --git a/site/_docs/github-pages.md b/site/_docs/github-pages.md
index c9a4644..add661c 100644
--- a/site/_docs/github-pages.md
+++ b/site/_docs/github-pages.md
@@ -10,6 +10,31 @@ organizations, and repositories, that are freely hosted on GitHub's
 powered by Jekyll behind the scenes, so in addition to supporting regular HTML
 content, they’re also a great way to host your Jekyll-powered website for free.
 
+Never built a website with GitHub Pages before? [See this marvelous guide by
+Jonathan McGlone to get you up and running](http://jmcglone.com/guides/github-pages/).
+This guide will teach you what you need to know about Git, GitHub, and Jekyll to
+create your very own website on GitHub Pages.
+
+### Project Page URL Structure
+
+Sometimes it's nice to preview your Jekyll site before you push your `gh-pages`
+branch to GitHub. However, the subdirectory-like URL structure GitHub uses for
+Project Pages complicates the proper resolution of URLs. In order to assure your
+site builds properly, use `site.github.url` in your URL's.
+
+{% highlight html %}
+{% raw %}
+<!-- Useful for styles with static names... -->
+<link href="{{ site.github.url }}/path/to/css.css" rel="stylesheet">
+<!-- and for documents/pages whose URL's can change... -->
+<a href="{{ page.url | prepend: site.github.url }}">{{ page.title }}</a>
+{% endraw %}
+{% endhighlight %}
+
+This way you can preview your site locally from the site root on localhost,
+but when GitHub generates your pages from the gh-pages branch all the URLs
+will resolve properly.
+
 ## Deploying Jekyll to GitHub Pages
 
 GitHub Pages work by looking at certain branches of repositories on GitHub.
@@ -92,42 +117,16 @@ branch]({{ site.repository }}/tree/gh-pages) of the same repository.
 <div class="note warning">
   <h5>Source Files Must be in the Root Directory</h5>
   <p>
-Github Pages <a href="https://help.github.com/articles/troubleshooting-github-pages-build-failures#source-setting">overrides</a> the <a href="http://jekyllrb.com/docs/configuration/#global-configuration">“Site Source”</a> configuration value, so if you locate your files anywhere other than the root directory, your site may not build correctly.
+GitHub Pages <a href="https://help.github.com/articles/troubleshooting-github-pages-build-failures#source-setting">overrides</a> the <a href="http://jekyllrb.com/docs/configuration/#global-configuration">“Site Source”</a> configuration value, so if you locate your files anywhere other than the root directory, your site may not build correctly.
   </p>
 </div>
 
-
-### Project Page URL Structure
-
-Sometimes it's nice to preview your Jekyll site before you push your `gh-pages`
-branch to GitHub. However, the subdirectory-like URL structure GitHub uses for
-Project Pages complicates the proper resolution of URLs. Here is an approach to
-utilizing the GitHub Project Page URL structure (`username.github.io/project-name/`)
-whilst maintaining the ability to preview your Jekyll site locally.
-
-1. In `_config.yml`, set the `baseurl` option to `/project-name` -- note the
-   leading slash and the **absence** of a trailing slash.
-2. When referencing JS or CSS files, do it like this:
-   `{% raw %}{{ site.baseurl }}/path/to/css.css{% endraw %}` -- note the slash
-   immediately following the variable (just before "path").
-3. When doing permalinks or internal links, do it like this:
-   `{% raw %}{{ site.baseurl }}{{ post.url }}{% endraw %}` -- note that there
-   is **no** slash between the two variables.
-4. Finally, if you'd like to preview your site before committing/deploying
-   using `jekyll serve`, be sure to pass an **empty string** to the `--baseurl`
-   option, so that you can view everything at `localhost:4000` normally
-   (without `/project-name` at the beginning): `jekyll serve --baseurl ''`
-
-This way you can preview your site locally from the site root on localhost,
-but when GitHub generates your pages from the gh-pages branch all the URLs
-will start with `/project-name` and resolve properly.
-
 <div class="note">
   <h5>GitHub Pages Documentation, Help, and Support</h5>
   <p>
     For more information about what you can do with GitHub Pages, as well as for
     troubleshooting guides, you should check out <a
-    href="https://help.github.com/categories/20/articles">GitHub’s Pages Help
+    href="https://help.github.com/categories/github-pages-basics/">GitHub’s Pages Help
     section</a>. If all else fails, you should contact <a
     href="https://github.com/contact">GitHub Support</a>.
   </p>
diff --git a/site/_docs/history.md b/site/_docs/history.md
index 6a64040..7f68843 100644
--- a/site/_docs/history.md
+++ b/site/_docs/history.md
@@ -4,6 +4,223 @@ title: History
 permalink: "/docs/history/"
 ---
 
+## 3.1.6 / 2016-05-19
+{: #v3-1-6}
+
+### Bug Fixes
+{: #bug-fixes-v3-1-6}
+
+- Add ability to `jsonify` Drops such that, e.g. `site | jsonify`, works. ([#4914]({{ site.repository }}/issues/4914))
+
+
+## 3.1.5 / 2016-05-18
+{: #v3-1-5}
+
+### Bug Fixes
+{: #bug-fixes-v3-1-5}
+
+- Sort the results of the `require_all` glob (affects Linux only). ([#4912]({{ site.repository }}/issues/4912))
+
+
+## 3.1.4 / 2016-05-18
+{: #v3-1-4}
+
+### Bug Fixes
+{: #bug-fixes-v3-1-4}
+
+- Add `ExcerptDrop` and remove excerpt's ability to refer to itself in Liquid ([#4907]({{ site.repository }}/issues/4907))
+- Configuration permalink fix where `collections.posts.permalink` inherits properly from `permalink` only when it doesn't exist ([#4910]({{ site.repository }}/issues/4910))
+- Add `Configuration.from` to make it easier to build configs from just a hash
+- Sorting `site.collections` in Liquid by label ([#4910]({{ site.repository }}/issues/4910))
+- Fix bug where `layout` in Liquid would inherit from previously-rendered layouts' metadatas ([#4909]({{ site.repository }}/issues/4909))
+- Fix bug where `layout` in Liquid would override in the wrong direction (more-specific layouts' data were overwritten by their parent layouts' data; this has now been reversed) ([#4909]({{ site.repository }}/issues/4909))
+
+
+## 3.1.2 / 2016-02-19
+{: #v3-1-2}
+
+### Minor Enhancements
+{: #minor-enhancements-v3-1-2}
+
+- Include `.rubocop.yml` in Gem ([#4437]({{ site.repository }}/issues/4437))
+- `LiquidRenderer#parse`: parse with line numbers. ([#4452]({{ site.repository }}/issues/4452))
+- Add consistency to the no-subcommand deprecation message ([#4505]({{ site.repository }}/issues/4505))
+
+### Bug Fixes
+{: #bug-fixes-v3-1-2}
+
+- Fix syntax highlighting in kramdown by making `[@config](https://github.com/config)` accessible in the Markdown converter. ([#4428]({{ site.repository }}/issues/4428))
+- `Jekyll.sanitized_path`: sanitizing a questionable path should handle tildes ([#4492]({{ site.repository }}/issues/4492))
+- Fix `titleize` so already capitalized words are not dropped ([#4525]({{ site.repository }}/issues/4525))
+- Permalinks which end in a slash should always output HTML ([#4546]({{ site.repository }}/issues/4546))
+
+### Development Fixes
+{: #development-fixes-v3-1-2}
+
+- Require at least cucumber version 2.1.0 ([#4514]({{ site.repository }}/issues/4514))
+
+### Site Enhancements
+{: #site-enhancements-v3-1-2}
+
+- Add jekyll-toc plugin ([#4429]({{ site.repository }}/issues/4429))
+- Docs: Quickstart - added documentation about the `--force` option ([#4410]({{ site.repository }}/issues/4410))
+- Fix broken links to the Code of Conduct ([#4436]({{ site.repository }}/issues/4436))
+- Upgrade notes: mention trailing slash in permalink; fixes [#4440]({{ site.repository }}/issues/4440) ([#4455]({{ site.repository }}/issues/4455))
+- Add hooks to the plugin categories toc ([#4463]({{ site.repository }}/issues/4463))
+- [add note] Jekyll 3 requires newer version of Ruby. ([#4461]({{ site.repository }}/issues/4461))
+- Fix typo in upgrading docs ([#4473]({{ site.repository }}/issues/4473))
+- Add note about upgrading documentation on jekyllrb.com/help/ ([#4484]({{ site.repository }}/issues/4484))
+- Update Rake link ([#4496]({{ site.repository }}/issues/4496))
+- Update & prune the short list of example sites ([#4374]({{ site.repository }}/issues/4374))
+- Added amp-jekyll plugin to plugins docs ([#4517]({{ site.repository }}/issues/4517))
+- A few grammar fixes ([#4512]({{ site.repository }}/issues/4512))
+- Correct a couple mistakes in structure.md ([#4522]({{ site.repository }}/issues/4522))
+
+
+## 3.1.1 / 2016-01-29
+{: #v3-1-1}
+
+### Meta
+
+- Update the Code of Conduct to the latest version ([#4402]({{ site.repository }}/issues/4402))
+
+### Bug Fixes
+{: #bug-fixes-v3-1-1}
+
+- `Page#dir`: ensure it ends in a slash ([#4403]({{ site.repository }}/issues/4403))
+- Add `Utils.merged_file_read_opts` to unify reading & strip the BOM ([#4404]({{ site.repository }}/issues/4404))
+- `Renderer#output_ext`: honor folders when looking for ext ([#4401]({{ site.repository }}/issues/4401))
+
+### Development Fixes
+{: #development-fixes-v3-1-1}
+
+- Suppress stdout in liquid profiling test ([#4409]({{ site.repository }}/issues/4409))
+
+
+## 3.1.0 / 2016-01-23
+{: #v3-1-0}
+
+### Minor Enhancements
+{: #minor-enhancements-v3-1-0}
+
+- Use `Liquid::Drop`s instead of `Hash`es in `#to_liquid` ([#4277]({{ site.repository }}/issues/4277))
+- Add 'sample' Liquid filter Equivalent to Array#sample functionality ([#4223]({{ site.repository }}/issues/4223))
+- Cache parsed include file to save liquid parsing time. ([#4120]({{ site.repository }}/issues/4120))
+- Slightly speed up url sanitization and handle multiples of ///. ([#4168]({{ site.repository }}/issues/4168))
+- Print debug message when a document is skipped from reading ([#4180]({{ site.repository }}/issues/4180))
+- Include tag should accept multiple variables in the include name ([#4183]({{ site.repository }}/issues/4183))
+- Add `-o` option to serve command which opens server URL ([#4144]({{ site.repository }}/issues/4144))
+- Add CodeClimate platform for better code quality. ([#4220]({{ site.repository }}/issues/4220))
+- General improvements for WEBrick via jekyll serve such as SSL & custom headers ([#4224]({{ site.repository }}/issues/4224), [#4228]({{ site.repository }}/issues/4228))
+- Add a default charset to content-type on webrick. ([#4231]({{ site.repository }}/issues/4231))
+- Switch `PluginManager` to use `require_with_graceful_fail` for better UX ([#4233]({{ site.repository }}/issues/4233))
+- Allow quoted date in front matter defaults ([#4184]({{ site.repository }}/issues/4184))
+- Add a Jekyll doctor warning for URLs that only differ by case ([#3171]({{ site.repository }}/issues/3171))
+- drops: create one base Drop class which can be set as mutable or not ([#4285]({{ site.repository }}/issues/4285))
+- drops: provide `#to_h` to allow for hash introspection ([#4281]({{ site.repository }}/issues/4281))
+- Shim subcommands with indication of gem possibly required so users know how to use them ([#4254]({{ site.repository }}/issues/4254))
+- Add smartify Liquid filter for SmartyPants ([#4323]({{ site.repository }}/issues/4323))
+- Raise error on empty permalink ([#4361]({{ site.repository }}/issues/4361))
+- Refactor Page#permalink method ([#4389]({{ site.repository }}/issues/4389))
+
+### Bug Fixes
+{: #bug-fixes-v3-1-0}
+
+- Pass build options into `clean` command ([#4177]({{ site.repository }}/issues/4177))
+- Allow users to use .htm and .xhtml (XHTML5.) ([#4160]({{ site.repository }}/issues/4160))
+- Prevent Shell Injection. ([#4200]({{ site.repository }}/issues/4200))
+- Convertible should make layout data accessible via `layout` instead of `page` ([#4205]({{ site.repository }}/issues/4205))
+- Avoid using `Dir.glob` with absolute path to allow special characters in the path ([#4150]({{ site.repository }}/issues/4150))
+- Handle empty config files ([#4052]({{ site.repository }}/issues/4052))
+- Rename `[@options](https://github.com/options)` so that it does not impact Liquid. ([#4173]({{ site.repository }}/issues/4173))
+- utils/drops: update Drop to support `Utils.deep_merge_hashes` ([#4289]({{ site.repository }}/issues/4289))
+- Make sure jekyll/drops/drop is loaded first. ([#4292]({{ site.repository }}/issues/4292))
+- Convertible/Page/Renderer: use payload hash accessor & setter syntax for backwards-compatibility ([#4311]({{ site.repository }}/issues/4311))
+- Drop: fix hash setter precendence ([#4312]({{ site.repository }}/issues/4312))
+- utils: `has_yaml_header?` should accept files with extraneous spaces ([#4290]({{ site.repository }}/issues/4290))
+- Escape html from site.title and page.title in site template ([#4307]({{ site.repository }}/issues/4307))
+- Allow custom file extensions if defined in `permalink` YAML front matter ([#4314]({{ site.repository }}/issues/4314))
+- Fix deep_merge_hashes! handling of drops and hashes ([#4359]({{ site.repository }}/issues/4359))
+- Page should respect output extension of its permalink ([#4373]({{ site.repository }}/issues/4373))
+- Disable auto-regeneration when running server detached ([#4376]({{ site.repository }}/issues/4376))
+- Drop#[]: only use public_send for keys in the content_methods array ([#4388]({{ site.repository }}/issues/4388))
+- Extract title from filename successfully when no date. ([#4195]({{ site.repository }}/issues/4195))
+
+### Development Fixes
+{: #development-fixes-v3-1-0}
+
+- `jekyll-docs` should be easily release-able ([#4152]({{ site.repository }}/issues/4152))
+- Allow use of Cucumber 2.1 or greater ([#4181]({{ site.repository }}/issues/4181))
+- Modernize Kramdown for Markdown converter. ([#4109]({{ site.repository }}/issues/4109))
+- Change TestDoctorCommand to JekyllUnitTest... ([#4263]({{ site.repository }}/issues/4263))
+- Create namespaced rake tasks in separate `.rake` files under `lib/tasks` ([#4282]({{ site.repository }}/issues/4282))
+- markdown: refactor for greater readability & efficiency ([#3771]({{ site.repository }}/issues/3771))
+- Fix many Rubocop style errors ([#4301]({{ site.repository }}/issues/4301))
+- Fix spelling of "GitHub" in docs and history ([#4322]({{ site.repository }}/issues/4322))
+- Reorganize and cleanup the Gemfile, shorten required depends. ([#4318]({{ site.repository }}/issues/4318))
+- Remove script/rebund. ([#4341]({{ site.repository }}/issues/4341))
+- Implement codeclimate platform ([#4340]({{ site.repository }}/issues/4340))
+- Remove ObectSpace dumping and start using inherited, it's faster. ([#4342]({{ site.repository }}/issues/4342))
+- Add script/travis so all people can play with Travis-CI images. ([#4338]({{ site.repository }}/issues/4338))
+- Move Cucumber to using RSpec-Expections and furthering JRuby support. ([#4343]({{ site.repository }}/issues/4343))
+- Rearrange Cucumber and add some flair. ([#4347]({{ site.repository }}/issues/4347))
+- Remove old FIXME ([#4349]({{ site.repository }}/issues/4349))
+- Clean up the Gemfile (and keep all the necessary dependencies) ([#4350]({{ site.repository }}/issues/4350))
+
+### Site Enhancements
+{: #site-enhancements-v3-1-0}
+
+- Add three plugins to directory ([#4163]({{ site.repository }}/issues/4163))
+- Add upgrading docs from 2.x to 3.x ([#4157]({{ site.repository }}/issues/4157))
+- Add `protect_email` to the plugins index. ([#4169]({{ site.repository }}/issues/4169))
+- Add `jekyll-deploy` to list of third-party plugins ([#4179]({{ site.repository }}/issues/4179))
+- Clarify plugin docs ([#4154]({{ site.repository }}/issues/4154))
+- Add Kickster to deployment methods in documentation ([#4190]({{ site.repository }}/issues/4190))
+- Add DavidBurela's tutorial for Windows to Windows docs page ([#4210]({{ site.repository }}/issues/4210))
+- Change GitHub code block to highlight tag to avoid it overlaps parent div ([#4121]({{ site.repository }}/issues/4121))
+- Update FormKeep link to be something more specific to Jekyll ([#4243]({{ site.repository }}/issues/4243))
+- Remove example Roger Chapman site, as the domain doesn't exist ([#4249]({{ site.repository }}/issues/4249))
+- Added configuration options for `draft_posts` to configuration docs ([#4251]({{ site.repository }}/issues/4251))
+- Fix checklist in `_assets.md` ([#4259]({{ site.repository }}/issues/4259))
+- Add Markdown examples to Pages docs ([#4275]({{ site.repository }}/issues/4275))
+- Add jekyll-paginate-category to list of third-party plugins ([#4273]({{ site.repository }}/issues/4273))
+- Add `jekyll-responsive_image` to list of third-party plugins ([#4286]({{ site.repository }}/issues/4286))
+- Add `jekyll-commonmark` to list of third-party plugins ([#4299]({{ site.repository }}/issues/4299))
+- Add documentation for incremental regeneration ([#4293]({{ site.repository }}/issues/4293))
+- Add note about removal of relative permalink support in upgrading docs ([#4303]({{ site.repository }}/issues/4303))
+- Add Pro Tip to use front matter variable to create clean URLs ([#4296]({{ site.repository }}/issues/4296))
+- Fix grammar in the documentation for posts. ([#4330]({{ site.repository }}/issues/4330))
+- Add documentation for smartify Liquid filter ([#4333]({{ site.repository }}/issues/4333))
+- Fixed broken link to blog on using mathjax with jekyll ([#4344]({{ site.repository }}/issues/4344))
+- Documentation: correct reference in Precedence section of Configuration docs ([#4355]({{ site.repository }}/issues/4355))
+- Add [@jmcglone](https://github.com/jmcglone)'s guide to github-pages doc page ([#4364]({{ site.repository }}/issues/4364))
+- Added the Wordpress2Jekyll Wordpress plugin ([#4377]({{ site.repository }}/issues/4377))
+- Add Contentful Extension to list of third-party plugins ([#4390]({{ site.repository }}/issues/4390))
+- Correct Minor spelling error ([#4394]({{ site.repository }}/issues/4394))
+
+
+## 3.0.3 / 2016-02-08
+{: #v3-0-3}
+
+### Bug Fixes
+{: #bug-fixes-v3-0-3}
+
+- Fix extension weirdness with folders ([#4493]({{ site.repository }}/issues/4493))
+- EntryFilter: only include 'excluded' log on excluded files ([#4479]({{ site.repository }}/issues/4479))
+- `Jekyll.sanitized_path`: escape tildes before sanitizing a questionable path ([#4468]({{ site.repository }}/issues/4468))
+- `LiquidRenderer#parse`: parse with line numbers ([#4453]({{ site.repository }}/issues/4453))
+- `Document#<=>`: protect against nil comparison in dates. ([#4446]({{ site.repository }}/issues/4446))
+
+
+## 3.0.2 / 2016-01-20
+{: #v3-0-2}
+
+### Bug Fixes
+{: #bug-fixes-v3-0-2}
+
+- Document: throw a useful error when an invalid date is given ([#4378]({{ site.repository }}/issues/4378))
+
+
 ## 3.0.1 / 2015-11-17
 {: #v3-0-1}
 
@@ -87,8 +304,7 @@ permalink: "/docs/history/"
 - Perf: `Markdown#matches` should avoid regexp ([#3321]({{ site.repository }}/issues/3321))
 - Perf: Use frozen regular expressions for `Utils#slugify` ([#3321]({{ site.repository }}/issues/3321))
 - Split off Textile support into jekyll-textile-converter ([#3319]({{ site.repository }}/issues/3319))
-- Improve the navigation menu alignment in the site template on small
-    screens ([#3331]({{ site.repository }}/issues/3331))
+- Improve the navigation menu alignment in the site template on small screens ([#3331]({{ site.repository }}/issues/3331))
 - Show the regeneration time after the initial generation ([#3378]({{ site.repository }}/issues/3378))
 - Site template: Switch default font to Helvetica Neue ([#3376]({{ site.repository }}/issues/3376))
 - Make the `include` tag a teensy bit faster. ([#3391]({{ site.repository }}/issues/3391))
@@ -120,8 +336,7 @@ permalink: "/docs/history/"
 - Set log level to debug when verbose flag is set ([#3665]({{ site.repository }}/issues/3665))
 - Added a mention on the Gemfile to complete the instructions ([#3671]({{ site.repository }}/issues/3671))
 - Perf: Cache `Document#to_liquid` and invalidate where necessary ([#3693]({{ site.repository }}/issues/3693))
-- Perf: `Jekyll::Cleaner#existing_files`: Call `keep_file_regex` and
-    `keep_dirs` only once, not once per iteration ([#3696]({{ site.repository }}/issues/3696))
+- Perf: `Jekyll::Cleaner#existing_files`: Call `keep_file_regex` and `keep_dirs` only once, not once per iteration ([#3696]({{ site.repository }}/issues/3696))
 - Omit jekyll/jekyll-help from list of resources. ([#3698]({{ site.repository }}/issues/3698))
 - Add basic `jekyll doctor` test to detect fsnotify (OSX) anomalies. ([#3704]({{ site.repository }}/issues/3704))
 - Added talk.jekyllrb.com to "Have questions?" ([#3694]({{ site.repository }}/issues/3694))
@@ -423,8 +638,7 @@ permalink: "/docs/history/"
 - Strip newlines in site template `<meta>` description. ([#2982]({{ site.repository }}/issues/2982))
 - Add link to atom feed in `head` of site template files ([#2996]({{ site.repository }}/issues/2996))
 - Performance optimizations ([#2994]({{ site.repository }}/issues/2994))
-- Use `Hash#each_key` instead of `Hash#keys.each` to speed up iteration
-    over hash keys. ([#3017]({{ site.repository }}/issues/3017))
+- Use `Hash#each_key` instead of `Hash#keys.each` to speed up iteration over hash keys. ([#3017]({{ site.repository }}/issues/3017))
 - Further minor performance enhancements. ([#3022]({{ site.repository }}/issues/3022))
 - Add 'b' and 's' aliases for build and serve, respectively ([#3065]({{ site.repository }}/issues/3065))
 
@@ -432,8 +646,7 @@ permalink: "/docs/history/"
 {: #bug-fixes-v2-5-0}
 
 - Fix Rouge's RedCarpet plugin interface integration ([#2951]({{ site.repository }}/issues/2951))
-- Remove `--watch` from the site template blog post since it defaults
-    to watching in in 2.4.0 ([#2922]({{ site.repository }}/issues/2922))
+- Remove `--watch` from the site template blog post since it defaults to watching in in 2.4.0 ([#2922]({{ site.repository }}/issues/2922))
 - Fix code for media query mixin in site template ([#2946]({{ site.repository }}/issues/2946))
 - Allow post URL's to have `.htm` extensions ([#2925]({{ site.repository }}/issues/2925))
 - `Utils.slugify`: Don't create new objects when gsubbing ([#2997]({{ site.repository }}/issues/2997))
@@ -463,7 +676,7 @@ permalink: "/docs/history/"
 - Add Big Footnotes for Kramdown plugin to list of third-party plugins ([#2916]({{ site.repository }}/issues/2916))
 - Remove warning regarding GHP use of singular types for front matter defaults ([#2919]({{ site.repository }}/issues/2919))
 - Fix quote character typo in site documentation for templates ([#2917]({{ site.repository }}/issues/2917))
-- Point Liquid links to Liquid’s Github wiki ([#2887]({{ site.repository }}/issues/2887))
+- Point Liquid links to Liquid’s GitHub wiki ([#2887]({{ site.repository }}/issues/2887))
 - Add HTTP Basic Auth (.htaccess) plugin to list of third-party plugins ([#2931]({{ site.repository }}/issues/2931))
 - (Minor) Grammar & `_config.yml` filename fixes ([#2911]({{ site.repository }}/issues/2911))
 - Added `mathml.rb` to the list of third-party plugins. ([#2937]({{ site.repository }}/issues/2937))
@@ -519,11 +732,9 @@ permalink: "/docs/history/"
 
 - Document the `name` variable for collection permalinks ([#2829]({{ site.repository }}/issues/2829))
 - Adds info about installing jekyll in current dir ([#2839]({{ site.repository }}/issues/2839))
-- Remove deprecated `jekyll-projectlist` plugin from list of third-party
-    plugins ([#2742]({{ site.repository }}/issues/2742))
+- Remove deprecated `jekyll-projectlist` plugin from list of third-party plugins ([#2742]({{ site.repository }}/issues/2742))
 - Remove tag plugins that are built in to Jekyll ([#2751]({{ site.repository }}/issues/2751))
-- Add `markdown-writer` package for Atom Editor to list of third-party
-    plugins ([#2763]({{ site.repository }}/issues/2763))
+- Add `markdown-writer` package for Atom Editor to list of third-party plugins ([#2763]({{ site.repository }}/issues/2763))
 - Fix typo in site documentation for collections ([#2764]({{ site.repository }}/issues/2764))
 - Fix minor typo on plugins docs page ([#2765]({{ site.repository }}/issues/2765))
 - Replace markdown with HTML in `sass_dir` note on assets page ([#2791]({{ site.repository }}/issues/2791))
@@ -623,8 +834,7 @@ permalink: "/docs/history/"
 {: #site-enhancements-v2-2-0}
 
 - Update Kramdown urls ([#2588]({{ site.repository }}/issues/2588))
-- Add `Jekyll::AutolinkEmail` and `Jekyll::GitMetadata` to the list of
-    third-party plugins ([#2596]({{ site.repository }}/issues/2596))
+- Add `Jekyll::AutolinkEmail` and `Jekyll::GitMetadata` to the list of third-party plugins ([#2596]({{ site.repository }}/issues/2596))
 - Fix a bunch of broken links in the site ([#2601]({{ site.repository }}/issues/2601))
 - Replace dead links with working links ([#2611]({{ site.repository }}/issues/2611))
 - Add jekyll-hook to deployment methods ([#2617]({{ site.repository }}/issues/2617))
@@ -668,12 +878,10 @@ permalink: "/docs/history/"
 - Allow subdirectories in `_data` ([#2395]({{ site.repository }}/issues/2395))
 - Extract Pagination Generator into gem: `jekyll-paginate` ([#2455]({{ site.repository }}/issues/2455))
 - Utilize `date_to_rfc822` filter in site template ([#2437]({{ site.repository }}/issues/2437))
-- Add categories, last build datetime, and generator to site template
-    feed ([#2438]({{ site.repository }}/issues/2438))
+- Add categories, last build datetime, and generator to site template feed ([#2438]({{ site.repository }}/issues/2438))
 - Configurable, replaceable Logger-compliant logger ([#2444]({{ site.repository }}/issues/2444))
 - Extract `gist` tag into a separate gem ([#2469]({{ site.repository }}/issues/2469))
-- Add `collection` attribute to `Document#to_liquid` to access the
-    document's collection label. ([#2436]({{ site.repository }}/issues/2436))
+- Add `collection` attribute to `Document#to_liquid` to access the document's collection label. ([#2436]({{ site.repository }}/issues/2436))
 - Upgrade listen to `2.7.6 <= x < 3.0.0` ([#2492]({{ site.repository }}/issues/2492))
 - Allow configuration of different Twitter and GitHub usernames in site template ([#2485]({{ site.repository }}/issues/2485))
 - Bump Pygments to v0.6.0 ([#2504]({{ site.repository }}/issues/2504))
@@ -699,8 +907,7 @@ permalink: "/docs/history/"
 - Allow front matter defaults to set post categories ([#2373]({{ site.repository }}/issues/2373))
 - Fix command in subcommand deprecation warning ([#2457]({{ site.repository }}/issues/2457))
 - Keep all parent directories of files/dirs in `keep_files` ([#2458]({{ site.repository }}/issues/2458))
-- When using RedCarpet and Rouge without Rouge installed, fixed erroneous
-    error which stated that redcarpet was missing, not rouge. ([#2464]({{ site.repository }}/issues/2464))
+- When using RedCarpet and Rouge without Rouge installed, fixed erroneous error which stated that redcarpet was missing, not rouge. ([#2464]({{ site.repository }}/issues/2464))
 - Ignore *all* directories and files that merit it on auto-generation ([#2459]({{ site.repository }}/issues/2459))
 - Before copying file, explicitly remove the old one ([#2535]({{ site.repository }}/issues/2535))
 - Merge file system categories with categories from YAML. ([#2531]({{ site.repository }}/issues/2531))
@@ -731,8 +938,7 @@ permalink: "/docs/history/"
 - Prevent table from extending parent width in permalink style table ([#2424]({{ site.repository }}/issues/2424))
 - Add collections to info about pagination support ([#2389]({{ site.repository }}/issues/2389))
 - Add `jekyll_github_sample` plugin to list of third-party plugins ([#2463]({{ site.repository }}/issues/2463))
-- Clarify documentation around front matter defaults and add details
-    about defaults for collections. ([#2439]({{ site.repository }}/issues/2439))
+- Clarify documentation around front matter defaults and add details about defaults for collections. ([#2439]({{ site.repository }}/issues/2439))
 - Add Jekyll Project Version Tag to list of third-party plugins ([#2468]({{ site.repository }}/issues/2468))
 - Use `https` for GitHub links across whole site ([#2470]({{ site.repository }}/issues/2470))
 - Add StickerMule + Jekyll post ([#2476]({{ site.repository }}/issues/2476))
@@ -751,13 +957,11 @@ permalink: "/docs/history/"
 ### Bug Fixes
 {: #bug-fixes-v2-0-3}
 
-- Properly prefix links in site template with URL or baseurl depending upon
-    need. ([#2319]({{ site.repository }}/issues/2319))
+- Properly prefix links in site template with URL or baseurl depending upon need. ([#2319]({{ site.repository }}/issues/2319))
 - Update gist tag comments and error message to require username ([#2326]({{ site.repository }}/issues/2326))
 - Fix `permalink` setting in site template ([#2331]({{ site.repository }}/issues/2331))
 - Don't fail if any of the path objects are nil ([#2325]({{ site.repository }}/issues/2325))
-- Instantiate all descendants for converters and generators, not just
-    direct subclasses ([#2334]({{ site.repository }}/issues/2334))
+- Instantiate all descendants for converters and generators, not just direct subclasses ([#2334]({{ site.repository }}/issues/2334))
 - Replace all instances of `site.name` with `site.title` in site template ([#2324]({{ site.repository }}/issues/2324))
 - `Jekyll::Filters#time` now accepts UNIX timestamps in string or number form ([#2339]({{ site.repository }}/issues/2339))
 - Use `item_property` for `where` filter so it doesn't break on collections ([#2359]({{ site.repository }}/issues/2359))
@@ -804,17 +1008,16 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v2-0-0}
+
 - Add "Collections" feature ([#2199]({{ site.repository }}/issues/2199))
 - Add gem-based plugin whitelist to safe mode ([#1657]({{ site.repository }}/issues/1657))
-- Replace the commander command line parser with a more robust
-    solution for our needs called `mercenary` ([#1706]({{ site.repository }}/issues/1706))
+- Replace the commander command line parser with a more robust solution for our needs called `mercenary` ([#1706]({{ site.repository }}/issues/1706))
 - Remove support for Ruby 1.8.x ([#1780]({{ site.repository }}/issues/1780))
 - Move to jekyll/jekyll from mojombo/jekyll ([#1817]({{ site.repository }}/issues/1817))
 - Allow custom markdown processors ([#1872]({{ site.repository }}/issues/1872))
 - Provide support for the Rouge syntax highlighter ([#1859]({{ site.repository }}/issues/1859))
 - Provide support for Sass ([#1932]({{ site.repository }}/issues/1932))
-- Provide a 300% improvement when generating sites that use
-    `Post#next` or `Post#previous` ([#1983]({{ site.repository }}/issues/1983))
+- Provide a 300% improvement when generating sites that use `Post#next` or `Post#previous` ([#1983]({{ site.repository }}/issues/1983))
 - Provide support for CoffeeScript ([#1991]({{ site.repository }}/issues/1991))
 - Replace Maruku with Kramdown as Default Markdown Processor ([#1988]({{ site.repository }}/issues/1988))
 - Expose `site.static_files` to Liquid ([#2075]({{ site.repository }}/issues/2075))
@@ -826,10 +1029,9 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v2-0-0}
-- Move the EntryFilter class into the Jekyll module to avoid polluting the
-    global namespace ([#1800]({{ site.repository }}/issues/1800))
-- Add `group_by` Liquid filter create lists of items grouped by a common
-    property's value ([#1788]({{ site.repository }}/issues/1788))
+
+- Move the EntryFilter class into the Jekyll module to avoid polluting the global namespace ([#1800]({{ site.repository }}/issues/1800))
+- Add `group_by` Liquid filter create lists of items grouped by a common property's value ([#1788]({{ site.repository }}/issues/1788))
 - Add support for Maruku's `fenced_code_blocks` option ([#1799]({{ site.repository }}/issues/1799))
 - Update Redcarpet dependency to ~> 3.0 ([#1815]({{ site.repository }}/issues/1815))
 - Automatically sort all pages by name ([#1848]({{ site.repository }}/issues/1848))
@@ -840,12 +1042,10 @@ permalink: "/docs/history/"
 - Bump dependency `safe_yaml` to `~> 1.0` ([#1886]({{ site.repository }}/issues/1886))
 - Allow sorting of content by custom properties ([#1849]({{ site.repository }}/issues/1849))
 - Add `--quiet` flag to silence output during build and serve ([#1898]({{ site.repository }}/issues/1898))
-- Add a `where` filter to filter arrays based on a key/value pair
-    ([#1875]({{ site.repository }}/issues/1875))
+- Add a `where` filter to filter arrays based on a key/value pair ([#1875]({{ site.repository }}/issues/1875))
 - Route 404 errors to a custom 404 page in development ([#1899]({{ site.repository }}/issues/1899))
 - Excludes are now relative to the site source ([#1916]({{ site.repository }}/issues/1916))
-- Bring MIME Types file for `jekyll serve` to complete parity with GH Pages
-    servers ([#1993]({{ site.repository }}/issues/1993))
+- Bring MIME Types file for `jekyll serve` to complete parity with GH Pages servers ([#1993]({{ site.repository }}/issues/1993))
 - Adding Breakpoint to make new site template more responsive ([#2038]({{ site.repository }}/issues/2038))
 - Default to using the UTF-8 encoding when reading files. ([#2031]({{ site.repository }}/issues/2031))
 - Update Redcarpet dependency to ~> 3.1 ([#2044]({{ site.repository }}/issues/2044))
@@ -863,13 +1063,11 @@ permalink: "/docs/history/"
 - Add support for unpublished drafts ([#2164]({{ site.repository }}/issues/2164))
 - Add `force_polling` option to the `serve` command ([#2165]({{ site.repository }}/issues/2165))
 - Clean up the `<head>` in the site template ([#2186]({{ site.repository }}/issues/2186))
-- Permit YAML blocks to end with three dots to better conform with the
-    YAML spec ([#2110]({{ site.repository }}/issues/2110))
+- Permit YAML blocks to end with three dots to better conform with the YAML spec ([#2110]({{ site.repository }}/issues/2110))
 - Use `File.exist?` instead of deprecated `File.exists?` ([#2214]({{ site.repository }}/issues/2214))
 - Require newline after start of YAML Front Matter header ([#2211]({{ site.repository }}/issues/2211))
 - Add the ability for pages to be marked as `published: false` ([#1492]({{ site.repository }}/issues/1492))
-- Add `Jekyll::LiquidExtensions` with `.lookup_variable` method for easy
-    looking up of variable values in a Liquid context. ([#2253]({{ site.repository }}/issues/2253))
+- Add `Jekyll::LiquidExtensions` with `.lookup_variable` method for easy looking up of variable values in a Liquid context. ([#2253]({{ site.repository }}/issues/2253))
 - Remove literal lang name from class ([#2292]({{ site.repository }}/issues/2292))
 - Return `utf-8` encoding in header for webrick error page response ([#2289]({{ site.repository }}/issues/2289))
 - Make template site easier to customize ([#2268]({{ site.repository }}/issues/2268))
@@ -879,13 +1077,12 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v2-0-0}
+
 - Don't allow nil entries when loading posts ([#1796]({{ site.repository }}/issues/1796))
-- Remove the scrollbar that's always displayed in new sites generated
-    from the site template ([#1805]({{ site.repository }}/issues/1805))
+- Remove the scrollbar that's always displayed in new sites generated from the site template ([#1805]({{ site.repository }}/issues/1805))
 - Add `#path` to required methods in `Jekyll::Convertible` ([#1866]({{ site.repository }}/issues/1866))
 - Default Maruku fenced code blocks to ON for 2.0.0-dev ([#1831]({{ site.repository }}/issues/1831))
-- Change short opts for host and port for `jekyll docs` to be consistent with
-    other subcommands ([#1877]({{ site.repository }}/issues/1877))
+- Change short opts for host and port for `jekyll docs` to be consistent with other subcommands ([#1877]({{ site.repository }}/issues/1877))
 - Fix typos ([#1910]({{ site.repository }}/issues/1910))
 - Lock Maruku at 0.7.0 to prevent bugs caused by Maruku 0.7.1 ([#1958]({{ site.repository }}/issues/1958))
 - Fixes full path leak to source directory when using include tag ([#1951]({{ site.repository }}/issues/1951))
@@ -898,8 +1095,7 @@ permalink: "/docs/history/"
 - Sanitize paths uniformly, in a Windows-friendly way ([#2065]({{ site.repository }}/issues/2065), [#2109]({{ site.repository }}/issues/2109))
 - Update gem build steps to work correctly on Windows ([#2118]({{ site.repository }}/issues/2118))
 - Remove obsolete `normalize_options` method call from `bin/jekyll` ([#2121]({{ site.repository }}/issues/2121)).
-- Remove `+` characters from Pygments lexer names when adding as a CSS
-    class ([#994]({{ site.repository }}/issues/994))
+- Remove `+` characters from Pygments lexer names when adding as a CSS class ([#994]({{ site.repository }}/issues/994))
 - Remove some code that caused Ruby interpreter warnings ([#2178]({{ site.repository }}/issues/2178))
 - Only strip the drive name if it begins the string ([#2175]({{ site.repository }}/issues/2175))
 - Remove default post with invalid date from site template ([#2200]({{ site.repository }}/issues/2200))
@@ -915,14 +1111,14 @@ permalink: "/docs/history/"
 
 ### Development Fixes
 {: #development-fixes-v2-0-0}
+
 - Add a link to the site in the README.md file ([#1795]({{ site.repository }}/issues/1795))
 - Add in History and site changes from `v1-stable` branch ([#1836]({{ site.repository }}/issues/1836))
 - Testing additions on the Excerpt class ([#1893]({{ site.repository }}/issues/1893))
 - Fix the `highlight` tag feature ([#1859]({{ site.repository }}/issues/1859))
 - Test Jekyll under Ruby 2.1.0 ([#1900]({{ site.repository }}/issues/1900))
 - Add script/cibuild for fun and profit ([#1912]({{ site.repository }}/issues/1912))
-- Use `Forwardable` for delegation between `Excerpt` and `Post`
-    ([#1927]({{ site.repository }}/issues/1927))
+- Use `Forwardable` for delegation between `Excerpt` and `Post` ([#1927]({{ site.repository }}/issues/1927))
 - Rename `read_things` to `read_content` ([#1928]({{ site.repository }}/issues/1928))
 - Add `script/branding` script for ASCII art lovin' ([#1936]({{ site.repository }}/issues/1936))
 - Update the README to reflect the repo move ([#1943]({{ site.repository }}/issues/1943))
@@ -951,11 +1147,11 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v2-0-0}
+
 - Document Kramdown's GFM parser option ([#1791]({{ site.repository }}/issues/1791))
 - Move CSS to includes & update normalize.css to v2.1.3 ([#1787]({{ site.repository }}/issues/1787))
 - Minify CSS only in production ([#1803]({{ site.repository }}/issues/1803))
-- Fix broken link to installation of Ruby on Mountain Lion blog post on
-    Troubleshooting docs page ([#1797]({{ site.repository }}/issues/1797))
+- Fix broken link to installation of Ruby on Mountain Lion blog post on Troubleshooting docs page ([#1797]({{ site.repository }}/issues/1797))
 - Fix issues with 1.4.1 release blog post ([#1804]({{ site.repository }}/issues/1804))
 - Add note about deploying to OpenShift ([#1812]({{ site.repository }}/issues/1812))
 - Collect all Windows-related docs onto one page ([#1818]({{ site.repository }}/issues/1818))
@@ -970,8 +1166,7 @@ permalink: "/docs/history/"
 - Add jekyll-compass to the plugin list ([#1923]({{ site.repository }}/issues/1923))
 - Add note in Posts docs about stripping `<p>` tags from excerpt ([#1933]({{ site.repository }}/issues/1933))
 - Add additional info about the new exclude behavior ([#1938]({{ site.repository }}/issues/1938))
-- Linkify 'awesome contributors' to point to the contributors graph on
-    GitHub ([#1940]({{ site.repository }}/issues/1940))
+- Linkify 'awesome contributors' to point to the contributors graph on GitHub ([#1940]({{ site.repository }}/issues/1940))
 - Update `docs/sites.md` link to GitHub Training materials ([#1949]({{ site.repository }}/issues/1949))
 - Update `master` with the release info from 1.4.3 ([#1947]({{ site.repository }}/issues/1947))
 - Define docs nav in datafile ([#1953]({{ site.repository }}/issues/1953))
@@ -988,8 +1183,7 @@ permalink: "/docs/history/"
 - Update link to rack-jekyll on "Deployment Methods" page ([#2047]({{ site.repository }}/issues/2047))
 - Fix typo in /docs/configuration ([#2073]({{ site.repository }}/issues/2073))
 - Fix count in docs for `site.static_files` ([#2077]({{ site.repository }}/issues/2077))
-- Update configuration docs to indicate utf-8 is the default for 2.0.0
-    and ASCII for 1.9.3 ([#2074]({{ site.repository }}/issues/2074))
+- Update configuration docs to indicate utf-8 is the default for 2.0.0 and ASCII for 1.9.3 ([#2074]({{ site.repository }}/issues/2074))
 - Add info about unreleased feature to the site ([#2061]({{ site.repository }}/issues/2061))
 - Add whitespace to liquid example in GitHub Pages docs ([#2084]({{ site.repository }}/issues/2084))
 - Clarify the way Sass and CoffeeScript files are read in and output ([#2067]({{ site.repository }}/issues/2067))
@@ -1006,8 +1200,7 @@ permalink: "/docs/history/"
 - Some HTML tidying ([#2130]({{ site.repository }}/issues/2130))
 - Remove modernizr and use html5shiv.js directly for IE less than v9 ([#2131]({{ site.repository }}/issues/2131))
 - Remove unused images ([#2187]({{ site.repository }}/issues/2187))
-- Use `array_to_sentence_string` filter when outputting news item
-    categories ([#2191]({{ site.repository }}/issues/2191))
+- Use `array_to_sentence_string` filter when outputting news item categories ([#2191]({{ site.repository }}/issues/2191))
 - Add link to Help repo in primary navigation bar ([#2177]({{ site.repository }}/issues/2177))
 - Switch to using an ico file for the shortcut icon ([#2193]({{ site.repository }}/issues/2193))
 - Use numbers to specify font weights and only bring in font weights used ([#2185]({{ site.repository }}/issues/2185))
@@ -1068,6 +1261,7 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-4-3}
+
 - Patch show-stopping security vulnerabilities ([#1944]({{ site.repository }}/issues/1944))
 
 
@@ -1076,6 +1270,7 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-4-2}
+
 - Turn on Maruku fenced code blocks by default ([#1830]({{ site.repository }}/issues/1830))
 
 
@@ -1084,6 +1279,7 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-4-1}
+
 - Don't allow nil entries when loading posts ([#1796]({{ site.repository }}/issues/1796))
 
 
@@ -1092,25 +1288,30 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-4-0}
+
 - Add support for TOML config files ([#1765]({{ site.repository }}/issues/1765))
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-4-0}
+
 - Sort plugins as a way to establish a load order ([#1682]({{ site.repository }}/issues/1682))
 - Update Maruku to 0.7.0 ([#1775]({{ site.repository }}/issues/1775))
 
 ### Bug Fixes
 {: #bug-fixes-v1-4-0}
+
 - Add a space between two words in a Pagination warning message ([#1769]({{ site.repository }}/issues/1769))
 - Upgrade `toml` gem to `v0.1.0` to maintain compat with Ruby 1.8.7 ([#1778]({{ site.repository }}/issues/1778))
 
 ### Development Fixes
 {: #development-fixes-v1-4-0}
+
 - Remove some whitespace in the code ([#1755]({{ site.repository }}/issues/1755))
 - Remove some duplication in the reading of posts and drafts ([#1779]({{ site.repository }}/issues/1779))
 
 ### Site Enhancements
 {: #site-enhancements-v1-4-0}
+
 - Fixed case of a word in the Jekyll v1.3.0 release post ([#1762]({{ site.repository }}/issues/1762))
 - Fixed the mime type for the favicon ([#1772]({{ site.repository }}/issues/1772))
 
@@ -1120,19 +1321,20 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-3-1}
+
 - Add a `--prefix` option to passthrough for the importers ([#1669]({{ site.repository }}/issues/1669))
-- Push the paginator plugin lower in the plugin priority order so
-    other plugins run before it ([#1759]({{ site.repository }}/issues/1759))
+- Push the paginator plugin lower in the plugin priority order so other plugins run before it ([#1759]({{ site.repository }}/issues/1759))
 
 ### Bug Fixes
 {: #bug-fixes-v1-3-1}
+
 - Fix the include tag when ran in a loop ([#1726]({{ site.repository }}/issues/1726))
 - Fix errors when using `--watch` on 1.8.7 ([#1730]({{ site.repository }}/issues/1730))
-- Specify where the include is called from if an included file is
-    missing ([#1746]({{ site.repository }}/issues/1746))
+- Specify where the include is called from if an included file is missing ([#1746]({{ site.repository }}/issues/1746))
 
 ### Development Fixes
 {: #development-fixes-v1-3-1}
+
 - Extract `Site#filter_entries` into its own object ([#1697]({{ site.repository }}/issues/1697))
 - Enable Travis' bundle caching ([#1734]({{ site.repository }}/issues/1734))
 - Remove trailing whitespace in some files ([#1736]({{ site.repository }}/issues/1736))
@@ -1140,11 +1342,10 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-3-1}
+
 - Update link to example Rakefile to point to specific commit ([#1741]({{ site.repository }}/issues/1741))
-- Fix drafts docs to indicate that draft time is based on file modification
-    time, not `Time.now` ([#1695]({{ site.repository }}/issues/1695))
-- Add `jekyll-monthly-archive-plugin` and `jekyll-category-archive-plugin` to
-    list of third-party plugins ([#1693]({{ site.repository }}/issues/1693))
+- Fix drafts docs to indicate that draft time is based on file modification time, not `Time.now` ([#1695]({{ site.repository }}/issues/1695))
+- Add `jekyll-monthly-archive-plugin` and `jekyll-category-archive-plugin` to list of third-party plugins ([#1693]({{ site.repository }}/issues/1693))
 - Add `jekyll-asset-path-plugin` to list of third-party plugins ([#1670]({{ site.repository }}/issues/1670))
 - Add `emoji-for-jekyll` to list of third-part plugins ([#1708]({{ site.repository }}/issues/1708))
 - Fix previous section link on plugins page to point to pagination page ([#1707]({{ site.repository }}/issues/1707))
@@ -1159,47 +1360,43 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-3-0}
-- Add support for adding data as YAML files under a site's `_data`
-    directory ([#1003]({{ site.repository }}/issues/1003))
+
+- Add support for adding data as YAML files under a site's `_data` directory ([#1003]({{ site.repository }}/issues/1003))
 - Allow variables to be used with `include` tags ([#1495]({{ site.repository }}/issues/1495))
 - Allow using gems for plugin management ([#1557]({{ site.repository }}/issues/1557))
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-3-0}
+
 - Decrease the specificity in the site template CSS ([#1574]({{ site.repository }}/issues/1574))
 - Add `encoding` configuration option ([#1449]({{ site.repository }}/issues/1449))
-- Provide better error handling for Jekyll's custom Liquid tags
-    ([#1514]({{ site.repository }}/issues/1514))
-- If an included file causes a Liquid error, add the path to the
-    include file that caused the error to the error message ([#1596]({{ site.repository }}/issues/1596))
-- If a layout causes a Liquid error, change the error message so that
-    we know it comes from the layout ([#1601]({{ site.repository }}/issues/1601))
+- Provide better error handling for Jekyll's custom Liquid tags ([#1514]({{ site.repository }}/issues/1514))
+- If an included file causes a Liquid error, add the path to the include file that caused the error to the error message ([#1596]({{ site.repository }}/issues/1596))
+- If a layout causes a Liquid error, change the error message so that we know it comes from the layout ([#1601]({{ site.repository }}/issues/1601))
 - Update Kramdown dependency to `~> 1.2` ([#1610]({{ site.repository }}/issues/1610))
 - Update `safe_yaml` dependency to `~> 0.9.7` ([#1602]({{ site.repository }}/issues/1602))
 - Allow layouts to be in subfolders like includes ([#1622]({{ site.repository }}/issues/1622))
 - Switch to listen for site watching while serving ([#1589]({{ site.repository }}/issues/1589))
 - Add a `json` liquid filter to be used in sites ([#1651]({{ site.repository }}/issues/1651))
-- Point people to the migration docs when the `jekyll-import` gem is
-    missing ([#1662]({{ site.repository }}/issues/1662))
+- Point people to the migration docs when the `jekyll-import` gem is missing ([#1662]({{ site.repository }}/issues/1662))
 
 ### Bug Fixes
 {: #bug-fixes-v1-3-0}
-- Fix up matching against source and destination when the two
-    locations are similar ([#1556]({{ site.repository }}/issues/1556))
+
+- Fix up matching against source and destination when the two locations are similar ([#1556]({{ site.repository }}/issues/1556))
 - Fix the missing `pathname` require in certain cases ([#1255]({{ site.repository }}/issues/1255))
 - Use `+` instead of `Array#concat` when building `Post` attribute list ([#1571]({{ site.repository }}/issues/1571))
 - Print server address when launching a server ([#1586]({{ site.repository }}/issues/1586))
 - Downgrade to Maruku `~> 0.6.0` in order to avoid changes in rendering ([#1598]({{ site.repository }}/issues/1598))
 - Fix error with failing include tag when variable was file name ([#1613]({{ site.repository }}/issues/1613))
 - Downcase lexers before passing them to pygments ([#1615]({{ site.repository }}/issues/1615))
-- Capitalize the short verbose switch because it conflicts with the
-    built-in Commander switch ([#1660]({{ site.repository }}/issues/1660))
+- Capitalize the short verbose switch because it conflicts with the built-in Commander switch ([#1660]({{ site.repository }}/issues/1660))
 - Fix compatibility with 1.8.x ([#1665]({{ site.repository }}/issues/1665))
-- Fix an error with the new file watching code due to library version
-    incompatibilities ([#1687]({{ site.repository }}/issues/1687))
+- Fix an error with the new file watching code due to library version incompatibilities ([#1687]({{ site.repository }}/issues/1687))
 
 ### Development Fixes
 {: #development-fixes-v1-3-0}
+
 - Add coverage reporting with Coveralls ([#1539]({{ site.repository }}/issues/1539))
 - Refactor the Liquid `include` tag ([#1490]({{ site.repository }}/issues/1490))
 - Update launchy dependency to `~> 2.3` ([#1608]({{ site.repository }}/issues/1608))
@@ -1217,6 +1414,7 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-3-0}
+
 - Fix params for `JekyllImport::WordPress.process` arguments ([#1554]({{ site.repository }}/issues/1554))
 - Add `jekyll-suggested-tweet` to list of third-party plugins ([#1555]({{ site.repository }}/issues/1555))
 - Link to Liquid's docs for tags and filters ([#1553]({{ site.repository }}/issues/1553))
@@ -1224,8 +1422,7 @@ permalink: "/docs/history/"
 - Simplify/generalize pagination docs ([#1577]({{ site.repository }}/issues/1577))
 - Add documentation for the new data sources feature ([#1503]({{ site.repository }}/issues/1503))
 - Add more information on how to create generators ([#1590]({{ site.repository }}/issues/1590), [#1592]({{ site.repository }}/issues/1592))
-- Improve the instructions for mimicking GitHub Flavored Markdown
-    ([#1614]({{ site.repository }}/issues/1614))
+- Improve the instructions for mimicking GitHub Flavored Markdown ([#1614]({{ site.repository }}/issues/1614))
 - Add `jekyll-import` warning note of missing dependencies ([#1626]({{ site.repository }}/issues/1626))
 - Fix grammar in the Usage section ([#1635]({{ site.repository }}/issues/1635))
 - Add documentation for the use of gems as plugins ([#1656]({{ site.repository }}/issues/1656))
@@ -1240,6 +1437,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-2-1}
+
 - Print better messages for detached server. Mute output on detach. ([#1518]({{ site.repository }}/issues/1518))
 - Disable reverse lookup when running `jekyll serve` ([#1363]({{ site.repository }}/issues/1363))
 - Upgrade RedCarpet dependency to `~> 2.3.0` ([#1515]({{ site.repository }}/issues/1515))
@@ -1247,17 +1445,20 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-2-1}
+
 - Fix file discrepancy in gemspec ([#1522]({{ site.repository }}/issues/1522))
 - Force rendering of Include tag ([#1525]({{ site.repository }}/issues/1525))
 
 ### Development Fixes
 {: #development-fixes-v1-2-1}
+
 - Add a rake task to generate a new release post ([#1404]({{ site.repository }}/issues/1404))
 - Mute LSI output in tests ([#1531]({{ site.repository }}/issues/1531))
 - Update contributor documentation ([#1537]({{ site.repository }}/issues/1537))
 
 ### Site Enhancements
 {: #site-enhancements-v1-2-1}
+
 - Fix a couple of validation errors on the site ([#1511]({{ site.repository }}/issues/1511))
 - Make navigation menus reusable ([#1507]({{ site.repository }}/issues/1507))
 - Fix link to History page from Release v1.2.0 notes post.
@@ -1270,45 +1471,41 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-2-0}
+
 - Disable automatically-generated excerpts when `excerpt_separator` is `""`. ([#1386]({{ site.repository }}/issues/1386))
 - Add checking for URL conflicts when running `jekyll doctor` ([#1389]({{ site.repository }}/issues/1389))
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-2-0}
+
 - Catch and fix invalid `paginate` values ([#1390]({{ site.repository }}/issues/1390))
-- Remove superfluous `div.container` from the default html template for
-    `jekyll new` ([#1315]({{ site.repository }}/issues/1315))
+- Remove superfluous `div.container` from the default html template for `jekyll new` ([#1315]({{ site.repository }}/issues/1315))
 - Add `-D` short-form switch for the drafts option ([#1394]({{ site.repository }}/issues/1394))
 - Update the links in the site template for Twitter and GitHub ([#1400]({{ site.repository }}/issues/1400))
 - Update dummy email address to example.com domain ([#1408]({{ site.repository }}/issues/1408))
-- Update normalize.css to v2.1.2 and minify; add rake task to update
-    normalize.css with greater ease. ([#1430]({{ site.repository }}/issues/1430))
-- Add the ability to detach the server ran by `jekyll serve` from it's
-    controlling terminal ([#1443]({{ site.repository }}/issues/1443))
+- Update normalize.css to v2.1.2 and minify; add rake task to update normalize.css with greater ease. ([#1430]({{ site.repository }}/issues/1430))
+- Add the ability to detach the server ran by `jekyll serve` from it's controlling terminal ([#1443]({{ site.repository }}/issues/1443))
 - Improve permalink generation for URLs with special characters ([#944]({{ site.repository }}/issues/944))
-- Expose the current Jekyll version to posts and pages via a new
-    `jekyll.version` variable ([#1481]({{ site.repository }}/issues/1481))
+- Expose the current Jekyll version to posts and pages via a new `jekyll.version` variable ([#1481]({{ site.repository }}/issues/1481))
 
 ### Bug Fixes
 {: #bug-fixes-v1-2-0}
+
 - Markdown extension matching matches only exact matches ([#1382]({{ site.repository }}/issues/1382))
 - Fixed NoMethodError when message passed to `Stevenson#message` is nil ([#1388]({{ site.repository }}/issues/1388))
 - Use binary mode when writing file ([#1364]({{ site.repository }}/issues/1364))
-- Fix 'undefined method `encoding` for "mailto"' errors w/ Ruby 1.8 and
-    Kramdown > 0.14.0 ([#1397]({{ site.repository }}/issues/1397))
+- Fix 'undefined method `encoding` for "mailto"' errors w/ Ruby 1.8 and Kramdown > 0.14.0 ([#1397]({{ site.repository }}/issues/1397))
 - Do not force the permalink to be a dir if it ends on .html ([#963]({{ site.repository }}/issues/963))
 - When a Liquid Exception is caught, show the full path rel. to site source ([#1415]({{ site.repository }}/issues/1415))
-- Properly read in the config options when serving the docs locally
-    ([#1444]({{ site.repository }}/issues/1444))
+- Properly read in the config options when serving the docs locally ([#1444]({{ site.repository }}/issues/1444))
 - Fixed `--layouts` option for `build` and `serve` commands ([#1458]({{ site.repository }}/issues/1458))
 - Remove kramdown as a runtime dependency since it's optional ([#1498]({{ site.repository }}/issues/1498))
-- Provide proper error handling for invalid file names in the include
-    tag ([#1494]({{ site.repository }}/issues/1494))
+- Provide proper error handling for invalid file names in the include tag ([#1494]({{ site.repository }}/issues/1494))
 
 ### Development Fixes
 {: #development-fixes-v1-2-0}
-- Remove redundant argument to
-    Jekyll::Commands::New#scaffold_post_content ([#1356]({{ site.repository }}/issues/1356))
+
+- Remove redundant argument to Jekyll::Commands::New#scaffold_post_content ([#1356]({{ site.repository }}/issues/1356))
 - Add new dependencies to the README ([#1360]({{ site.repository }}/issues/1360))
 - Fix link to contributing page in README ([#1424]({{ site.repository }}/issues/1424))
 - Update TomDoc in Pager#initialize to match params ([#1441]({{ site.repository }}/issues/1441))
@@ -1319,6 +1516,7 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-2-0}
+
 - Add info about new releases ([#1353]({{ site.repository }}/issues/1353))
 - Update plugin list with jekyll-rss plugin ([#1354]({{ site.repository }}/issues/1354))
 - Update the site list page with Ruby's official site ([#1358]({{ site.repository }}/issues/1358))
@@ -1346,6 +1544,7 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-1-2}
+
 - Require Liquid 2.5.1 ([#1349]({{ site.repository }}/issues/1349))
 
 
@@ -1354,26 +1553,26 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-1-1}
+
 - Remove superfluous `table` selector from main.css in `jekyll new` template ([#1328]({{ site.repository }}/issues/1328))
 - Abort with non-zero exit codes ([#1338]({{ site.repository }}/issues/1338))
 
 ### Bug Fixes
 {: #bug-fixes-v1-1-1}
+
 - Fix up the rendering of excerpts ([#1339]({{ site.repository }}/issues/1339))
 
 ### Site Enhancements
 {: #site-enhancements-v1-1-1}
+
 - Add Jekyll Image Tag to the plugins list ([#1306]({{ site.repository }}/issues/1306))
 - Remove erroneous statement that `site.pages` are sorted alphabetically.
-- Add info about the `_drafts` directory to the directory structure
-    docs ([#1320]({{ site.repository }}/issues/1320))
-- Improve the layout of the plugin listing by organizing it into
-    categories ([#1310]({{ site.repository }}/issues/1310))
+- Add info about the `_drafts` directory to the directory structure docs ([#1320]({{ site.repository }}/issues/1320))
+- Improve the layout of the plugin listing by organizing it into categories ([#1310]({{ site.repository }}/issues/1310))
 - Add generator-jekyllrb and grunt-jekyll to plugins page ([#1330]({{ site.repository }}/issues/1330))
 - Mention Kramdown as option for markdown parser on Extras page ([#1318]({{ site.repository }}/issues/1318))
 - Update Quick-Start page to include reminder that all requirements must be installed ([#1327]({{ site.repository }}/issues/1327))
-- Change filename in `include` example to an HTML file so as not to indicate that Jekyll
-    will automatically convert them. ([#1303]({{ site.repository }}/issues/1303))
+- Change filename in `include` example to an HTML file so as not to indicate that Jekyll will automatically convert them. ([#1303]({{ site.repository }}/issues/1303))
 - Add an RSS feed for commits to Jekyll ([#1343]({{ site.repository }}/issues/1343))
 
 
@@ -1382,34 +1581,33 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-1-0}
+
 - Add `docs` subcommand to read Jekyll's docs when offline. ([#1046]({{ site.repository }}/issues/1046))
 - Support passing parameters to templates in `include` tag ([#1204]({{ site.repository }}/issues/1204))
 - Add support for Liquid tags to post excerpts ([#1302]({{ site.repository }}/issues/1302))
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-1-0}
-- Search the hierarchy of pagination path up to site root to determine template page for
-    pagination. ([#1198]({{ site.repository }}/issues/1198))
+
+- Search the hierarchy of pagination path up to site root to determine template page for pagination. ([#1198]({{ site.repository }}/issues/1198))
 - Add the ability to generate a new Jekyll site without a template ([#1171]({{ site.repository }}/issues/1171))
-- Use redcarpet as the default markdown engine in newly generated
-    sites ([#1245]({{ site.repository }}/issues/1245), [#1247]({{ site.repository }}/issues/1247))
-- Add `redcarpet` as a runtime dependency so `jekyll build` works out-of-the-box for new
-    sites. ([#1247]({{ site.repository }}/issues/1247))
-- In the generated site, remove files that will be replaced by a
-    directory ([#1118]({{ site.repository }}/issues/1118))
+- Use redcarpet as the default markdown engine in newly generated sites ([#1245]({{ site.repository }}/issues/1245), [#1247]({{ site.repository }}/issues/1247))
+- Add `redcarpet` as a runtime dependency so `jekyll build` works out-of-the-box for new sites. ([#1247]({{ site.repository }}/issues/1247))
+- In the generated site, remove files that will be replaced by a directory ([#1118]({{ site.repository }}/issues/1118))
 - Fail loudly if a user-specified configuration file doesn't exist ([#1098]({{ site.repository }}/issues/1098))
 - Allow for all options for Kramdown HTML Converter ([#1201]({{ site.repository }}/issues/1201))
 
 ### Bug Fixes
 {: #bug-fixes-v1-1-0}
+
 - Fix pagination in subdirectories. ([#1198]({{ site.repository }}/issues/1198))
-- Fix an issue with directories and permalinks that have a plus sign
-    (+) in them ([#1215]({{ site.repository }}/issues/1215))
+- Fix an issue with directories and permalinks that have a plus sign (+) in them ([#1215]({{ site.repository }}/issues/1215))
 - Provide better error reporting when generating sites ([#1253]({{ site.repository }}/issues/1253))
 - Latest posts first in non-LSI `related_posts` ([#1271]({{ site.repository }}/issues/1271))
 
 ### Development Fixes
 {: #development-fixes-v1-1-0}
+
 - Merge the theme and layout Cucumber steps into one step ([#1151]({{ site.repository }}/issues/1151))
 - Restrict activesupport dependency to pre-4.0.0 to maintain compatibility with `<= 1.9.2`
 - Include/exclude deprecation handling simplification ([#1284]({{ site.repository }}/issues/1284))
@@ -1418,22 +1616,20 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-1-0}
+
 - Add "News" section for release notes, along with an RSS feed ([#1093]({{ site.repository }}/issues/1093), [#1285]({{ site.repository }}/issues/1285), [#1286]({{ site.repository }}/issues/1286))
 - Add "History" page.
 - Restructured docs sections to include "Meta" section.
-- Add message to "Templates" page that specifies that Python must be installed in order
-    to use Pygments. ([#1182]({{ site.repository }}/issues/1182))
+- Add message to "Templates" page that specifies that Python must be installed in order to use Pygments. ([#1182]({{ site.repository }}/issues/1182))
 - Update link to the official Maruku repo ([#1175]({{ site.repository }}/issues/1175))
 - Add documentation about `paginate_path` to "Templates" page in docs ([#1129]({{ site.repository }}/issues/1129))
 - Give the quick-start guide its own page ([#1191]({{ site.repository }}/issues/1191))
-- Update ProTip on Installation page in docs to point to all the info about Pygments and
-    the 'highlight' tag. ([#1196]({{ site.repository }}/issues/1196))
+- Update ProTip on Installation page in docs to point to all the info about Pygments and the 'highlight' tag. ([#1196]({{ site.repository }}/issues/1196))
 - Run `site/img` through ImageOptim (thanks [@qrush](https://github.com/qrush)!) ([#1208]({{ site.repository }}/issues/1208))
 - Added Jade Converter to `site/docs/plugins` ([#1210]({{ site.repository }}/issues/1210))
 - Fix location of docs pages in Contributing pages ([#1214]({{ site.repository }}/issues/1214))
 - Add ReadInXMinutes plugin to the plugin list ([#1222]({{ site.repository }}/issues/1222))
-- Remove plugins from the plugin list that have equivalents in Jekyll
-    proper ([#1223]({{ site.repository }}/issues/1223))
+- Remove plugins from the plugin list that have equivalents in Jekyll proper ([#1223]({{ site.repository }}/issues/1223))
 - Add jekyll-assets to the plugin list ([#1225]({{ site.repository }}/issues/1225))
 - Add jekyll-pandoc-mulitple-formats to the plugin list ([#1229]({{ site.repository }}/issues/1229))
 - Remove dead link to "Using Git to maintain your blog" ([#1227]({{ site.repository }}/issues/1227))
@@ -1447,13 +1643,11 @@ permalink: "/docs/history/"
 - Add `jekyll-timeago` to list of third-party plugins. ([#1260]({{ site.repository }}/issues/1260))
 - Add `jekyll-swfobject` to list of third-party plugins. ([#1263]({{ site.repository }}/issues/1263))
 - Add `jekyll-picture-tag` to list of third-party plugins. ([#1280]({{ site.repository }}/issues/1280))
-- Update the GitHub Pages documentation regarding relative URLs
-    ([#1291]({{ site.repository }}/issues/1291))
+- Update the GitHub Pages documentation regarding relative URLs ([#1291]({{ site.repository }}/issues/1291))
 - Update the S3 deployment documentation ([#1294]({{ site.repository }}/issues/1294))
 - Add suggestion for Xcode CLT install to troubleshooting page in docs ([#1296]({{ site.repository }}/issues/1296))
 - Add 'Working with drafts' page to docs ([#1289]({{ site.repository }}/issues/1289))
-- Add information about time zones to the documentation for a page's
-    date ([#1304]({{ site.repository }}/issues/1304))
+- Add information about time zones to the documentation for a page's date ([#1304]({{ site.repository }}/issues/1304))
 
 
 ## 1.0.3 / 2013-06-07
@@ -1461,6 +1655,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-0-3}
+
 - Add support to gist tag for private gists. ([#1189]({{ site.repository }}/issues/1189))
 - Fail loudly when Maruku errors out ([#1190]({{ site.repository }}/issues/1190))
 - Move the building of related posts into their own class ([#1057]({{ site.repository }}/issues/1057))
@@ -1470,17 +1665,17 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-0-3}
+
 - Fix typo in Stevenson constant "ERROR". ([#1166]({{ site.repository }}/issues/1166))
 - Rename Jekyll::Logger to Jekyll::Stevenson to fix inheritance issue ([#1106]({{ site.repository }}/issues/1106))
 - Exit with a non-zero exit code when dealing with a Liquid error ([#1121]({{ site.repository }}/issues/1121))
-- Make the `exclude` and `include` options backwards compatible with
-    versions of Jekyll prior to 1.0 ([#1114]({{ site.repository }}/issues/1114))
+- Make the `exclude` and `include` options backwards compatible with versions of Jekyll prior to 1.0 ([#1114]({{ site.repository }}/issues/1114))
 - Fix pagination on Windows ([#1063]({{ site.repository }}/issues/1063))
-- Fix the application of Pygments' Generic Output style to Go code
-    ([#1156]({{ site.repository }}/issues/1156))
+- Fix the application of Pygments' Generic Output style to Go code ([#1156]({{ site.repository }}/issues/1156))
 
 ### Site Enhancements
 {: #site-enhancements-v1-0-3}
+
 - Add a Pro Tip to docs about front matter variables being optional ([#1147]({{ site.repository }}/issues/1147))
 - Add changelog to site as History page in /docs/ ([#1065]({{ site.repository }}/issues/1065))
 - Add note to Upgrading page about new config options in 1.0.x ([#1146]({{ site.repository }}/issues/1146))
@@ -1494,13 +1689,13 @@ permalink: "/docs/history/"
 - Fix logic for `relative_permalinks` instructions on Upgrading page ([#1101]({{ site.repository }}/issues/1101))
 - Add docs for post excerpt ([#1072]({{ site.repository }}/issues/1072))
 - Add docs for gist tag ([#1072]({{ site.repository }}/issues/1072))
-- Add docs indicating that Pygments does not need to be installed
-    separately ([#1099]({{ site.repository }}/issues/1099), [#1119]({{ site.repository }}/issues/1119))
+- Add docs indicating that Pygments does not need to be installed separately ([#1099]({{ site.repository }}/issues/1099), [#1119]({{ site.repository }}/issues/1119))
 - Update the migrator docs to be current ([#1136]({{ site.repository }}/issues/1136))
 - Add the Jekyll Gallery Plugin to the plugin list ([#1143]({{ site.repository }}/issues/1143))
 
 ### Development Fixes
 {: #development-fixes-v1-0-3}
+
 - Use Jekyll.logger instead of Jekyll::Stevenson to log things ([#1149]({{ site.repository }}/issues/1149))
 - Fix pesky Cucumber infinite loop ([#1139]({{ site.repository }}/issues/1139))
 - Do not write posts with timezones in Cucumber tests ([#1124]({{ site.repository }}/issues/1124))
@@ -1512,11 +1707,13 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-0-2}
+
 - Add `jekyll doctor` command to check site for any known compatibility problems ([#1081]({{ site.repository }}/issues/1081))
 - Backwards-compatibilize relative permalinks ([#1081]({{ site.repository }}/issues/1081))
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-0-2}
+
 - Add a `data-lang="<lang>"` attribute to Redcarpet code blocks ([#1066]({{ site.repository }}/issues/1066))
 - Deprecate old config `server_port`, match to `port` if `port` isn't set ([#1084]({{ site.repository }}/issues/1084))
 - Update pygments.rb version to 0.5.0 ([#1061]({{ site.repository }}/issues/1061))
@@ -1524,11 +1721,13 @@ permalink: "/docs/history/"
 
 ### Bug Fixes
 {: #bug-fixes-v1-0-2}
+
 - Fix issue when categories are numbers ([#1078]({{ site.repository }}/issues/1078))
 - Catching that Redcarpet gem isn't installed ([#1059]({{ site.repository }}/issues/1059))
 
 ### Site Enhancements
 {: #site-enhancements-v1-0-2}
+
 - Add documentation about `relative_permalinks` ([#1081]({{ site.repository }}/issues/1081))
 - Remove pygments-installation instructions, as pygments.rb is bundled with it ([#1079]({{ site.repository }}/issues/1079))
 - Move pages to be Pages for realz ([#985]({{ site.repository }}/issues/985))
@@ -1540,12 +1739,14 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-0-1}
+
 - Do not force use of `toc_token` when using `generate_tok` in RDiscount ([#1048]({{ site.repository }}/issues/1048))
 - Add newer `language-` class name prefix to code blocks ([#1037]({{ site.repository }}/issues/1037))
 - Commander error message now preferred over process abort with incorrect args ([#1040]({{ site.repository }}/issues/1040))
 
 ### Bug Fixes
 {: #bug-fixes-v1-0-1}
+
 - Make Redcarpet respect the pygments configuration option ([#1053]({{ site.repository }}/issues/1053))
 - Fix the index build with LSI ([#1045]({{ site.repository }}/issues/1045))
 - Don't print deprecation warning when no arguments are specified. ([#1041]({{ site.repository }}/issues/1041))
@@ -1553,6 +1754,7 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-0-1}
+
 - Changed https to http in the GitHub Pages link ([#1051]({{ site.repository }}/issues/1051))
 - Remove CSS cruft, fix typos, fix HTML errors ([#1028]({{ site.repository }}/issues/1028))
 - Removing manual install of Pip and Distribute ([#1025]({{ site.repository }}/issues/1025))
@@ -1560,6 +1762,7 @@ permalink: "/docs/history/"
 
 ### Development Fixes
 {: #development-fixes-v1-0-1}
+
 - Markdownify history file ([#1027]({{ site.repository }}/issues/1027))
 - Update links on README to point to new jekyllrb.com ([#1018]({{ site.repository }}/issues/1018))
 
@@ -1569,6 +1772,7 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v1-0-0}
+
 - Add `jekyll new` subcommand: generate a Jekyll scaffold ([#764]({{ site.repository }}/issues/764))
 - Refactored Jekyll commands into subcommands: build, serve, and migrate. ([#690]({{ site.repository }}/issues/690))
 - Removed importers/migrators from main project, migrated to jekyll-import sub-gem ([#793]({{ site.repository }}/issues/793))
@@ -1577,6 +1781,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v1-0-0}
+
 - Site template HTML5-ified ([#964]({{ site.repository }}/issues/964))
 - Use post's directory path when matching for the `post_url` tag ([#998]({{ site.repository }}/issues/998))
 - Loosen dependency on Pygments so it's only required when it's needed ([#1015]({{ site.repository }}/issues/1015))
@@ -1616,8 +1821,7 @@ permalink: "/docs/history/"
 - Massively accelerate LSI performance ([#664]({{ site.repository }}/issues/664))
 - Truncate post slugs when importing from Tumblr ([#496]({{ site.repository }}/issues/496))
 - Add glob support to include, exclude option ([#743]({{ site.repository }}/issues/743))
-- Layout of Page or Post defaults to 'page' or 'post', respectively ([#580]({{ site.repository }}/issues/580))
-    REPEALED by ([#977]({{ site.repository }}/issues/977))
+- Layout of Page or Post defaults to 'page' or 'post', respectively ([#580]({{ site.repository }}/issues/580)) REPEALED by ([#977]({{ site.repository }}/issues/977))
 - "Keep files" feature ([#685]({{ site.repository }}/issues/685))
 - Output full path & name for files that don't parse ([#745]({{ site.repository }}/issues/745))
 - Add source and destination directory protection ([#535]({{ site.repository }}/issues/535))
@@ -1643,8 +1847,7 @@ permalink: "/docs/history/"
 - Fixed Page#dir and Page#url for edge cases ([#536]({{ site.repository }}/issues/536))
 - Fix broken `post_url` with posts with a time in their YAML front matter ([#831]({{ site.repository }}/issues/831))
 - Look for plugins under the source directory ([#654]({{ site.repository }}/issues/654))
-- Tumblr Migrator: finds `_posts` dir correctly, fixes truncation of long
-      post names ([#775]({{ site.repository }}/issues/775))
+- Tumblr Migrator: finds `_posts` dir correctly, fixes truncation of long post names ([#775]({{ site.repository }}/issues/775))
 - Force Categories to be Strings ([#767]({{ site.repository }}/issues/767))
 - Safe YAML plugin to prevent vulnerability ([#777]({{ site.repository }}/issues/777))
 - Add SVG support to Jekyll/WEBrick. ([#407]({{ site.repository }}/issues/407), [#406]({{ site.repository }}/issues/406))
@@ -1652,6 +1855,7 @@ permalink: "/docs/history/"
 
 ### Site Enhancements
 {: #site-enhancements-v1-0-0}
+
 - Responsify ([#860]({{ site.repository }}/issues/860))
 - Fix spelling, punctuation and phrasal errors ([#989]({{ site.repository }}/issues/989))
 - Update quickstart instructions with `new` command ([#966]({{ site.repository }}/issues/966))
@@ -1663,15 +1867,14 @@ permalink: "/docs/history/"
 
 ### Development Fixes
 {: #development-fixes-v1-0-0}
+
 - Exclude Cucumber 1.2.4, which causes tests to fail in 1.9.2 ([#938]({{ site.repository }}/issues/938))
-- Added "features:html" rake task for debugging purposes, cleaned up
-      Cucumber profiles ([#832]({{ site.repository }}/issues/832))
+- Added "features:html" rake task for debugging purposes, cleaned up Cucumber profiles ([#832]({{ site.repository }}/issues/832))
 - Explicitly require HTTPS rubygems source in Gemfile ([#826]({{ site.repository }}/issues/826))
 - Changed Ruby version for development to 1.9.3-p374 from p362 ([#801]({{ site.repository }}/issues/801))
 - Including a link to the GitHub Ruby style guide in CONTRIBUTING.md ([#806]({{ site.repository }}/issues/806))
 - Added script/bootstrap ([#776]({{ site.repository }}/issues/776))
-- Running Simplecov under 2 conditions: ENV(COVERAGE)=true and with Ruby version
-      of greater than 1.9 ([#771]({{ site.repository }}/issues/771))
+- Running Simplecov under 2 conditions: ENV(COVERAGE)=true and with Ruby version of greater than 1.9 ([#771]({{ site.repository }}/issues/771))
 - Switch to Simplecov for coverage report ([#765]({{ site.repository }}/issues/765))
 
 
@@ -1680,6 +1883,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-12-1}
+
 - Update Kramdown version to 0.14.1 ([#744]({{ site.repository }}/issues/744))
 - Test Enhancements
 - Update Rake version to 10.0.3 ([#744]({{ site.repository }}/issues/744))
@@ -1692,6 +1896,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-12-0}
+
 - Add ability to explicitly specify included files ([#261]({{ site.repository }}/issues/261))
 - Add `--default-mimetype` option ([#279]({{ site.repository }}/issues/279))
 - Allow setting of RedCloth options ([#284]({{ site.repository }}/issues/284))
@@ -1713,12 +1918,14 @@ permalink: "/docs/history/"
 
 ## 0.11.2 / 2011-12-27
 {: #v0-11-2}
+
 - Bug Fixes
 - Fix gemspec
 
 
 ## 0.11.1 / 2011-12-27
 {: #v0-11-1}
+
 - Bug Fixes
 - Fix extra blank line in highlight blocks ([#409]({{ site.repository }}/issues/409))
 - Update dependencies
@@ -1729,6 +1936,7 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-11-0}
+
 - Add command line importer functionality ([#253]({{ site.repository }}/issues/253))
 - Add Redcarpet Markdown support ([#318]({{ site.repository }}/issues/318))
 - Make markdown/textile extensions configurable ([#312]({{ site.repository }}/issues/312))
@@ -1736,6 +1944,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-11-0}
+
 - Switch to Albino gem
 - Bundler support
 - Use English library to avoid hoops ([#292]({{ site.repository }}/issues/292))
@@ -1751,6 +1960,7 @@ permalink: "/docs/history/"
 
 ## 0.10.0 / 2010-12-16
 {: #v0-10-0}
+
 - Bug Fixes
 - Add `--no-server` option.
 
@@ -1760,6 +1970,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-9-0}
+
 - Use OptionParser's `[no-]` functionality for better boolean parsing.
 - Add Drupal migrator ([#245]({{ site.repository }}/issues/245))
 - Complain about YAML and Liquid errors ([#249]({{ site.repository }}/issues/249))
@@ -1772,6 +1983,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-8-0}
+
 - Add wordpress.com importer ([#207]({{ site.repository }}/issues/207))
 - Add `--limit-posts` cli option ([#212]({{ site.repository }}/issues/212))
 - Add `uri_escape` filter ([#234]({{ site.repository }}/issues/234))
@@ -1789,6 +2001,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-7-0}
+
 - Add support for rdiscount extensions ([#173]({{ site.repository }}/issues/173))
 - Bug Fixes
 - Highlight should not be able to render local files
@@ -1797,6 +2010,7 @@ permalink: "/docs/history/"
 
 ## 0.6.2 / 2010-06-25
 {: #v0-6-2}
+
 - Bug Fixes
 - Fix Rakefile 'release' task (tag pushing was missing origin)
 - Ensure that RedCloth is loaded when textilize filter is used ([#183]({{ site.repository }}/issues/183))
@@ -1806,6 +2020,7 @@ permalink: "/docs/history/"
 
 ## 0.6.1 / 2010-06-24
 {: #v0-6-1}
+
 - Bug Fixes
 - Fix Markdown Pygments prefix and suffix ([#178]({{ site.repository }}/issues/178))
 
@@ -1815,19 +2030,18 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-6-0}
+
 - Proper plugin system ([#19]({{ site.repository }}/issues/19), [#100]({{ site.repository }}/issues/100))
 - Add safe mode so unsafe converters/generators can be added
-- Maruku is now the only processor dependency installed by default.
-      Other processors will be lazy-loaded when necessary (and prompt the
-      user to install them when necessary) ([#57]({{ site.repository }}/issues/57))
+- Maruku is now the only processor dependency installed by default. Other processors will be lazy-loaded when necessary (and prompt the user to install them when necessary) ([#57]({{ site.repository }}/issues/57))
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-6-0}
+
 - Inclusion/exclusion of future dated posts ([#59]({{ site.repository }}/issues/59))
 - Generation for a specific time ([#59]({{ site.repository }}/issues/59))
 - Allocate `site.time` on render not per site_payload invocation ([#59]({{ site.repository }}/issues/59))
-- Pages now present in the site payload and can be used through the
-      `site.pages` and `site.html_pages` variables
+- Pages now present in the site payload and can be used through the `site.pages` and `site.html_pages` variables
 - Generate phase added to site#process and pagination is now a generator
 - Switch to RakeGem for build/test process
 - Only regenerate static files when they have changed ([#142]({{ site.repository }}/issues/142))
@@ -1847,24 +2061,26 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-5-7}
+
 - Allow overriding of post date in the front matter ([#62]({{ site.repository }}/issues/62), [#38]({{ site.repository }}/issues/38))
 - Bug Fixes
 - Categories isn't always an array ([#73]({{ site.repository }}/issues/73))
 - Empty tags causes error in read_posts ([#84]({{ site.repository }}/issues/84))
 - Fix pagination to adhere to read/render/write paradigm
 - Test Enhancement
-- Cucumber features no longer use site.posts.first where a better
-      alternative is available
+- Cucumber features no longer use site.posts.first where a better alternative is available
 
 
 ## 0.5.6 / 2010-01-08
 {: #v0-5-6}
+
 - Bug Fixes
 - Require redcloth >= 4.2.1 in tests ([#92]({{ site.repository }}/issues/92))
 - Don't break on triple dashes in yaml front matter ([#93]({{ site.repository }}/issues/93))
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-5-6}
+
 - Allow .mkd as markdown extension
 - Use $stdout/err instead of constants ([#99]({{ site.repository }}/issues/99))
 - Properly wrap code blocks ([#91]({{ site.repository }}/issues/91))
@@ -1873,52 +2089,42 @@ permalink: "/docs/history/"
 
 ## 0.5.5 / 2010-01-08
 {: #v0-5-5}
+
 - Bug Fixes
 - Fix pagination % 0 bug ([#78]({{ site.repository }}/issues/78))
-- Ensure all posts are processed first ([#71]({{ site.repository }}/issues/71))
-
-
-## NOTE
-- After this point I will no longer be giving credit in the history;
-    that is what the commit log is for.
+- Ensure all posts are processed first ([#71]({{ site.repository }}/issues/71)) ## NOTE
+- After this point I will no longer be giving credit in the history; that is what the commit log is for.
 
 
 ## 0.5.4 / 2009-08-23
 {: #v0-5-4}
+
 - Bug Fixes
 - Do not allow symlinks (security vulnerability)
 
 
 ## 0.5.3 / 2009-07-14
 {: #v0-5-3}
+
 - Bug Fixes
-- Solving the permalink bug where non-html files wouldn't work
-      ([@jeffrydegrande](https://github.com/jeffrydegrande))
+- Solving the permalink bug where non-html files wouldn't work ([@jeffrydegrande](https://github.com/jeffrydegrande))
 
 
 ## 0.5.2 / 2009-06-24
 {: #v0-5-2}
+
 - Enhancements
-- Added --paginate option to the executable along with a paginator object
-      for the payload ([@calavera](https://github.com/calavera))
-- Upgraded RedCloth to 4.2.1, which makes `<notextile>` tags work once
-      again.
-- Configuration options set in config.yml are now available through the
-      site payload ([@vilcans](https://github.com/vilcans))
-- Posts can now have an empty YAML front matter or none at all
-      (@ bahuvrihi)
+- Added --paginate option to the executable along with a paginator object for the payload ([@calavera](https://github.com/calavera))
+- Upgraded RedCloth to 4.2.1, which makes `<notextile>` tags work once again.
+- Configuration options set in config.yml are now available through the site payload ([@vilcans](https://github.com/vilcans))
+- Posts can now have an empty YAML front matter or none at all (@ bahuvrihi)
 - Bug Fixes
-- Fixing Ruby 1.9 issue that requires `#to_s` on the err object
-      ([@Chrononaut](https://github.com/Chrononaut))
+- Fixing Ruby 1.9 issue that requires `#to_s` on the err object ([@Chrononaut](https://github.com/Chrononaut))
 - Fixes for pagination and ordering posts on the same day ([@ujh](https://github.com/ujh))
-- Made pages respect permalinks style and permalinks in yml front matter
-      ([@eugenebolshakov](https://github.com/eugenebolshakov))
-- Index.html file should always have index.html permalink
-      ([@eugenebolshakov](https://github.com/eugenebolshakov))
-- Added trailing slash to pretty permalink style so Apache is happy
-      ([@eugenebolshakov](https://github.com/eugenebolshakov))
-- Bad markdown processor in config fails sooner and with better message
-      (@ gcnovus)
+- Made pages respect permalinks style and permalinks in yml front matter ([@eugenebolshakov](https://github.com/eugenebolshakov))
+- Index.html file should always have index.html permalink ([@eugenebolshakov](https://github.com/eugenebolshakov))
+- Added trailing slash to pretty permalink style so Apache is happy ([@eugenebolshakov](https://github.com/eugenebolshakov))
+- Bad markdown processor in config fails sooner and with better message (@ gcnovus)
 - Allow CRLFs in yaml front matter ([@juretta](https://github.com/juretta))
 - Added Date#xmlschema for Ruby versions < 1.9
 
@@ -1928,16 +2134,15 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-5-1}
+
 - Next/previous posts in site payload ([@pantulis](https://github.com/pantulis), [@tomo](https://github.com/tomo))
 - Permalink templating system
 - Moved most of the README out to the GitHub wiki
-- Exclude option in configuration so specified files won't be brought over
-      with generated site ([@duritong](https://github.com/duritong))
+- Exclude option in configuration so specified files won't be brought over with generated site ([@duritong](https://github.com/duritong))
 - Bug Fixes
 - Making sure config.yaml references are all gone, using only config.yml
 - Fixed syntax highlighting breaking for UTF-8 code ([@henrik](https://github.com/henrik))
-- Worked around RDiscount bug that prevents Markdown from getting parsed
-      after highlight ([@henrik](https://github.com/henrik))
+- Worked around RDiscount bug that prevents Markdown from getting parsed after highlight ([@henrik](https://github.com/henrik))
 - CGI escaped post titles ([@Chrononaut](https://github.com/Chrononaut))
 
 
@@ -1946,6 +2151,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-5-0}
+
 - Ability to set post categories via YAML ([@qrush](https://github.com/qrush))
 - Ability to set prevent a post from publishing via YAML ([@qrush](https://github.com/qrush))
 - Add textilize filter ([@willcodeforfoo](https://github.com/willcodeforfoo))
@@ -1967,6 +2173,7 @@ permalink: "/docs/history/"
 
 ### Minor Enhancements
 {: #minor-enhancements-v--}
+
 - Changed date format on wordpress converter (zeropadding) ([@dysinger](https://github.com/dysinger))
 - Bug Fixes
 - Add Jekyll binary as executable to gemspec ([@dysinger](https://github.com/dysinger))
@@ -1977,10 +2184,12 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-4-0}
+
 - Switch to Jeweler for packaging tasks
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-4-0}
+
 - Type importer ([@codeslinger](https://github.com/codeslinger))
 - `site.topics` accessor ([@baz](https://github.com/baz))
 - Add `array_to_sentence_string` filter ([@mchung](https://github.com/mchung))
@@ -2002,43 +2211,46 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-3-0}
-- Added `--server` option to start a simple WEBrick server on destination
-      directory ([@johnreilly](https://github.com/johnreilly) and [@mchung](https://github.com/mchung))
+
+- Added `--server` option to start a simple WEBrick server on destination directory ([@johnreilly](https://github.com/johnreilly) and [@mchung](https://github.com/mchung))
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-3-0}
+
 - Added post categories based on directories containing `_posts` ([@mreid](https://github.com/mreid))
 - Added post topics based on directories underneath `_posts`
 - Added new date filter that shows the full month name ([@mreid](https://github.com/mreid))
 - Merge Post's YAML front matter into its to_liquid payload ([@remi](https://github.com/remi))
 - Restrict includes to regular files underneath `_includes`
 - Bug Fixes
-- Change YAML delimiter matcher so as to not chew up 2nd level markdown
-      headers ([@mreid](https://github.com/mreid))
-- Fix bug that meant page data (such as the date) was not available in
-      templates ([@mreid](https://github.com/mreid))
+- Change YAML delimiter matcher so as to not chew up 2nd level markdown headers ([@mreid](https://github.com/mreid))
+- Fix bug that meant page data (such as the date) was not available in templates ([@mreid](https://github.com/mreid))
 - Properly reject directories in `_layouts`
 
 
 ## 0.2.1 / 2008-12-15
 {: #v0-2-1}
+
 - Major Changes
 - Use Maruku (pure Ruby) for Markdown by default ([@mreid](https://github.com/mreid))
 - Allow use of RDiscount with `--rdiscount` flag
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-2-1}
+
 - Don't load directory_watcher unless it's needed ([@pjhyett](https://github.com/pjhyett))
 
 
 ## 0.2.0 / 2008-12-14
 {: #v0-2-0}
+
 - Major Changes
 - related_posts is now found in `site.related_posts`
 
 
 ## 0.1.6 / 2008-12-13
 {: #v0-1-6}
+
 - Major Features
 - Include files in `_includes` with {% raw %}`{% include x.textile %}`{% endraw %}
 
@@ -2048,11 +2260,13 @@ permalink: "/docs/history/"
 
 ### Major Enhancements
 {: #major-enhancements-v0-1-5}
+
 - Code highlighting with Pygments if `--pygments` is specified
 - Disable true LSI by default, enable with `--lsi`
 
 ### Minor Enhancements
 {: #minor-enhancements-v0-1-5}
+
 - Output informative message if RDiscount is not available ([@JackDanger](https://github.com/JackDanger))
 - Bug Fixes
 - Prevent Jekyll from picking up the output directory as a source ([@JackDanger](https://github.com/JackDanger))
@@ -2061,12 +2275,14 @@ permalink: "/docs/history/"
 
 ## 0.1.4 / 2008-12-08
 {: #v0-1-4}
+
 - Bug Fixes
 - DATA does not work properly with rubygems
 
 
 ## 0.1.3 / 2008-12-06
 {: #v0-1-3}
+
 - Major Features
 - Markdown support ([@vanpelt](https://github.com/vanpelt))
 - Mephisto and CSV converters ([@vanpelt](https://github.com/vanpelt))
@@ -2078,21 +2294,23 @@ permalink: "/docs/history/"
 
 ## 0.1.2 / 2008-11-22
 {: #v0-1-2}
+
 - Major Features
 - Add a real "related posts" implementation using Classifier
 - Command Line Changes
-- Allow cli to be called with 0, 1, or 2 args intuiting dir paths
-      if they are omitted
+- Allow cli to be called with 0, 1, or 2 args intuiting dir paths if they are omitted
 
 
 ## 0.1.1 / 2008-11-22
 {: #v0-1-1}
+
 - Minor Additions
 - Posts now support introspectional data e.g. {% raw %}`{{ page.url }}`{% endraw %}
 
 
 ## 0.1.0 / 2008-11-05
 {: #v0-1-0}
+
 - First release
 - Converts posts written in Textile
 - Converts regular site pages
@@ -2101,4 +2319,5 @@ permalink: "/docs/history/"
 
 ## 0.0.0 / 2008-10-19
 {: #v0-0-0}
+
 - Birthday!
diff --git a/site/_docs/index.md b/site/_docs/index.md
index bbb1808..ceae474 100644
--- a/site/_docs/index.md
+++ b/site/_docs/index.md
@@ -2,6 +2,7 @@
 layout: docs
 title: Welcome
 permalink: /docs/home/
+redirect_from: /docs/index.html
 ---
 
 This site aims to be a comprehensive guide to Jekyll. We’ll cover topics such
diff --git a/site/_docs/installation.md b/site/_docs/installation.md
index f0c091f..3720d04 100644
--- a/site/_docs/installation.md
+++ b/site/_docs/installation.md
@@ -4,10 +4,10 @@ title: Installation
 permalink: /docs/installation/
 ---
 
-Getting Jekyll installed and ready-to-go should only take a few minutes. If it
-ever becomes a pain in the ass, please [file an
-issue]({{ site.repository }}/issues/new) (or submit a pull request)
-describing the issue you encountered and how we might make the process easier.
+Getting Jekyll installed and ready-to-go should only take a few minutes.
+If it ever becomes a pain, please [file an issue]({{ site.repository }}/issues/new)
+(or submit a pull request) describing the issue you
+encountered and how we might make the process easier
 
 ### Requirements
 
diff --git a/site/_docs/pages.md b/site/_docs/pages.md
index fa76a9f..32f7f9b 100644
--- a/site/_docs/pages.md
+++ b/site/_docs/pages.md
@@ -27,12 +27,14 @@ homepage of your Jekyll-generated site.
 
 ## Where additional pages live
 
-Where you put HTML files for pages depends on how you want the pages to work.
+Where you put HTML or [Markdown](http://daringfireball.net/projects/markdown/)
+files for pages depends on how you want the pages to work.
 There are two main ways of creating pages:
 
-- Place named HTML files for each page in your site's root folder.
+- Place named HTML or [Markdown](http://daringfireball.net/projects/markdown/)
+files for each page in your site's root folder.
 - Create a folder in the site's root for each page, and place an index.html
-file in each page folder.
+or index.md file in each page folder.
 
 Both methods work fine (and can be used in conjunction with each other),
 with the only real difference being the resulting URLs.
@@ -53,6 +55,7 @@ and associated URLs might look like:
 |-- _site/
 |-- about.html    # => http://example.com/about.html
 |-- index.html    # => http://example.com/
+|-- other.md      # => http://example.com/other.html
 └── contact.html  # => http://example.com/contact.html
 {% endhighlight %}
 
@@ -77,8 +80,21 @@ might look like:
 |   └── index.html  # => http://example.com/about/
 ├── contact/
 |   └── index.html  # => http://example.com/contact/
+|── other/
+|   └── index.md    # => http://example.com/other/
 └── index.html      # => http://example.com/
 {% endhighlight %}
 
 This approach may not suit everyone, but for people who like clean URLs it’s
-simple and it works. In the end the decision is yours!
+simple and it works. In the end, the decision is yours!
+
+<div class="note">
+  <h5>ProTip™: Use permalink Front Matter Variable</h5>
+  <p>
+    Clean URLs can also be achieved using the <code>permalink</code> front
+    matter variable. In the example above, using the first method, you can
+    get URL <code>http://example.com/other</code> for the file
+    <code>other.md</code> by setting this at the top of the file:
+    <code>permalink: /other</code>
+  </p>
+</div>
diff --git a/site/_docs/pagination.md b/site/_docs/pagination.md
index 2c0ae2b..25482d0 100644
--- a/site/_docs/pagination.md
+++ b/site/_docs/pagination.md
@@ -4,10 +4,13 @@ title: Pagination
 permalink: /docs/pagination/
 ---
 
-With many websites—especially blogs—it’s very common to break the main listing
-of posts up into smaller lists and display them over multiple pages. Jekyll has
-pagination built-in, so you can automatically generate the appropriate files
-and folders you need for paginated listings.
+With many websites — especially blogs — it’s very common to
+break the main listing of posts up into smaller lists and display them over
+multiple pages. Jekyll offers a pagination plugin, so you can automatically
+generate the appropriate files and folders you need for paginated listings.
+
+For Jekyll 3, include the `jekyll-paginate` plugin in your Gemfile and in
+your `_config.yml` under `gems`. For Jekyll 2, this is standard.
 
 <div class="note info">
   <h5>Pagination only works within HTML files</h5>
diff --git a/site/_docs/permalinks.md b/site/_docs/permalinks.md
index 5aa0449..9ccf270 100644
--- a/site/_docs/permalinks.md
+++ b/site/_docs/permalinks.md
@@ -79,7 +79,7 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
       </td>
       <td>
         <p>
-          Hour of the day, 24-hour clock, zero-padded from the Post’s filename. (00..23)
+          Hour of the day, 24-hour clock, zero-padded from the post’s <code>date</code> front matter. (00..23)
         </p>
       </td>
     </tr>
@@ -89,7 +89,7 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
       </td>
       <td>
         <p>
-          Minute of the hour from the Post’s filename. (00..59)
+          Minute of the hour from the post’s <code>date</code> front matter. (00..59)
         </p>
       </td>
     </tr>
@@ -99,7 +99,8 @@ permalink is defined according to the format `/:categories/:year/:month/:day/:ti
       </td>
       <td>
         <p>
-          Second of the minute from the Post’s filename. (00..60)
+          Second of the minute from the post’s <code>date</code> front matter. (00..59)
+        </p>
         </p>
       </td>
     </tr>
diff --git a/site/_docs/plugins.md b/site/_docs/plugins.md
index 7cd7c3f..3236c03 100644
--- a/site/_docs/plugins.md
+++ b/site/_docs/plugins.md
@@ -32,10 +32,10 @@ Jekyll generates your site.
 values of the gem names of the plugins you'd like to use. An example:
 
 
-        gems: [jekyll-test-plugin, jekyll-jsonify, jekyll-assets]
+        gems: [jekyll-coffeescript, jekyll-watch, jekyll-assets]
         # This will require each of these gems automatically.
 
-    Then install your plugins using `gem install jekyll-test-plugin jekyll-jsonify jekyll-assets`
+    Then install your plugins using `gem install jekyll-coffeescript jekyll-watch jekyll-assets`
 
 3. Add the relevant plugins to a Bundler group in your `Gemfile`. An
     example:
@@ -60,12 +60,13 @@ values of the gem names of the plugins you'd like to use. An example:
   </p>
 </div>
 
-In general, plugins you make will fall into one of four categories:
+In general, plugins you make will fall into one of five categories:
 
 1. [Generators](#generators)
 2. [Converters](#converters)
 3. [Commands](#commands)
 4. [Tags](#tags)
+5. [Hooks](#hooks)
 
 ## Generators
 
@@ -736,6 +737,8 @@ LESS.js files during generation.
 - [Jekyll Portfolio Generator by Shannon Babincsak](https://github.com/codeinpink/jekyll-portfolio-generator): Generates project pages and computes related projects out of project data files.
 - [Jekyll-Umlauts by Arne Gockeln](https://github.com/webchef/jekyll-umlauts): This generator replaces all german umlauts (äöüß) case sensitive with html.
 - [Jekyll Flickr Plugin](https://github.com/lawmurray/indii-jekyll-flickr) by [Lawrence Murray](http://www.indii.org): Generates posts for photos uploaded to a Flickr photostream.
+- [Jekyll::Paginate::Category](https://github.com/midnightSuyama/jekyll-paginate-category): Pagination Generator for Jekyll Category.
+- [AMP-Jekyll by Juuso Mikkonen](https://github.com/juusaw/amp-jekyll): Generate [Accelerated Mobile Pages](https://www.ampproject.org) of Jekyll posts.
 
 #### Converters
 
@@ -760,6 +763,7 @@ LESS.js files during generation.
 - [Bigfootnotes Plugin](https://github.com/TheFox/jekyll-bigfootnotes): Enables big footnotes for Kramdown.
 - [AsciiDoc Plugin](https://github.com/asciidoctor/jekyll-asciidoc): AsciiDoc convertor for Jekyll using [Asciidoctor](http://asciidoctor.org/).
 - [Lazy Tweet Embedding](https://github.com/takuti/jekyll-lazy-tweet-embedding): Automatically convert tweet urls into twitter cards.
+- [jekyll-commonmark](https://github.com/pathawks/jekyll-commonmark): Markdown converter that uses [libcmark](https://github.com/jgm/CommonMark), the reference parser for CommonMark.
 
 #### Filters
 
@@ -773,6 +777,7 @@ LESS.js files during generation.
 - [pluralize](https://github.com/bdesham/pluralize): Easily combine a number and a word into a grammatically-correct amount like “1 minute” or “2 minute**s**”.
 - [reading_time](https://github.com/bdesham/reading_time): Count words and estimate reading time for a piece of text, ignoring HTML elements that are unlikely to contain running text.
 - [Table of Content Generator](https://github.com/dafi/jekyll-toc-generator): Generate the HTML code containing a table of content (TOC), the TOC can be customized in many way, for example you can decide which pages can be without TOC.
+- [jekyll-toc](https://github.com/toshimaru/jekyll-toc): A liquid filter plugin for Jekyll which generates a table of contents.
 - [jekyll-humanize](https://github.com/23maverick23/jekyll-humanize): This is a port of the Django app humanize which adds a "human touch" to data. Each method represents a Fluid type filter that can be used in your Jekyll site templates. Given that Jekyll produces static sites, some of the original methods do not make logical sense to port (e.g. naturaltime).
 - [Jekyll-Ordinal](https://github.com/PatrickC8t/Jekyll-Ordinal): Jekyll liquid filter to output a date ordinal such as "st", "nd", "rd", or "th".
 - [Deprecated articles keeper](https://github.com/kzykbys/JekyllPlugins) by [Kazuya Kobayashi](http://blog.kazuya.co/): A simple Jekyll filter which monitor how old an article is.
@@ -780,6 +785,9 @@ LESS.js files during generation.
 - [Jekyll Thumbnail Filter](https://github.com/matallo/jekyll-thumbnail-filter): Related posts thumbnail filter.
 - [Jekyll-Smartify](https://github.com/pathawks/jekyll-smartify): SmartyPants filter. Make "quotes" “curly”
 - [liquid-md5](https://github.com/pathawks/liquid-md5): Returns an MD5 hash. Helpful for generating Gravatars in templates.
+- [jekyll-roman](https://github.com/paulrobertlloyd/jekyll-roman): A liquid filter for Jekyll that converts numbers into Roman numerals.
+- [jekyll-typogrify](https://github.com/myles/jekyll-typogrify): A Jekyll plugin that brings the functions of [typogruby](http://avdgaag.github.io/typogruby/).
+- [Jekyll Email Protect](https://github.com/vwochnik/jekyll-email-protect): Email protection liquid filter for Jekyll
 
 #### Tags
 
@@ -813,6 +821,7 @@ LESS.js files during generation.
 - [Jekyll-swfobject](https://github.com/sectore/jekyll-swfobject): Liquid plugin for embedding Adobe Flash files (.swf) using [SWFObject](http://code.google.com/p/swfobject/).
 - [Jekyll Picture Tag](https://github.com/robwierzbowski/jekyll-picture-tag): Easy responsive images for Jekyll. Based on the proposed [`<picture>`](https://html.spec.whatwg.org/multipage/embedded-content.html#the-picture-element) element, polyfilled with Scott Jehl’s [Picturefill](https://github.com/scottjehl/picturefill).
 - [Jekyll Image Tag](https://github.com/robwierzbowski/jekyll-image-tag): Better images for Jekyll. Save image presets, generate resized images, and add classes, alt text, and other attributes.
+- [Jekyll Responsive Image](https://github.com/wildlyinaccurate/jekyll-responsive-image): Responsive images for Jekyll. Automatically resizes images, supports all responsive methods (`<picture>`, `srcset`, Imager.js, etc), super-flexible configuration.
 - [Ditaa Tag](https://github.com/matze/jekyll-ditaa) by [matze](https://github.com/matze): Renders ASCII diagram art into PNG images and inserts a figure tag.
 - [Jekyll Suggested Tweet](https://github.com/davidensinger/jekyll-suggested-tweet) by [David Ensinger](https://github.com/davidensinger/): A Liquid tag for Jekyll that allows for the embedding of suggested tweets via Twitter’s Web Intents API.
 - [Jekyll Date Chart](https://github.com/GSI/jekyll_date_chart) by [GSI](https://github.com/GSI): Block that renders date line charts based on textile-formatted tables.
@@ -822,7 +831,7 @@ LESS.js files during generation.
 - [Lychee Gallery Tag](https://gist.github.com/tobru/9171700) by [tobru](https://github.com/tobru): Include [Lychee](http://lychee.electerious.com/) albums into a post. For an introduction, see [Jekyll meets Lychee - A Liquid Tag plugin](https://tobrunet.ch/articles/jekyll-meets-lychee-a-liquid-tag-plugin/)
 - [Image Set/Gallery Tag](https://github.com/callmeed/jekyll-image-set) by [callmeed](https://github.com/callmeed): Renders HTML for an image gallery from a folder in your Jekyll site. Just pass it a folder name and class/tag options.
 - [jekyll_figure](https://github.com/lmullen/jekyll_figure): Generate figures and captions with links to the figure in a variety of formats
-- [Jekyll Github Sample Tag](https://github.com/bwillis/jekyll-github-sample): A liquid tag to include a sample of a github repo file in your Jekyll site.
+- [Jekyll GitHub Sample Tag](https://github.com/bwillis/jekyll-github-sample): A liquid tag to include a sample of a github repo file in your Jekyll site.
 - [Jekyll Project Version Tag](https://github.com/rob-murray/jekyll-version-plugin): A Liquid tag plugin that renders a version identifier for your Jekyll site sourced from the git repository containing your code.
 - [Piwigo Gallery](https://github.com/AlessandroLorenzi/piwigo_gallery) by [Alessandro Lorenzi](http://www.alorenzi.eu/): Jekyll plugin to generate thumbnails from a Piwigo gallery and display them with a Liquid tag
 - [mathml.rb](https://github.com/tmthrgd/jekyll-plugins) by Tom Thorogood: A plugin to convert TeX mathematics into MathML for display.
@@ -831,12 +840,11 @@ LESS.js files during generation.
 - [inline\_highlight](https://github.com/bdesham/inline_highlight): A tag for inline syntax highlighting.
 - [jekyll-mermaid](https://github.com/jasonbellamy/jekyll-mermaid): Simplify the creation of mermaid diagrams and flowcharts in your posts and pages.
 - [twa](https://github.com/Ezmyrelda/twa): Twemoji Awesome plugin for Jekyll. Liquid tag allowing you to use twitter emoji in your jekyll pages.
-- [jekyll-files](https://github.com/x43x61x69/jekyll-files) by [Zhi-Wei Cai](http://vox.vg/): Output relative path strings and other info regarding specific assets.
 - [Fetch remote file content](https://github.com/dimitri-koenig/jekyll-plugins) by [Dimitri König](https://www.dimitrikoenig.net/): Using `remote_file_content` tag you can fetch the content of a remote file and include it as if you would put the content right into your markdown file yourself. Very useful for including code from github repo's to always have a current repo version.
 - [jekyll-asciinema](https://github.com/mnuessler/jekyll-asciinema): A tag for embedding asciicasts recorded with [asciinema](https://asciinema.org) in your Jekyll pages.
 - [Jekyll-Youtube](https://github.com/dommmel/jekyll-youtube)  A Liquid tag that embeds Youtube videos. The default emded markup is responsive but you can also specify your own by using an include/partial.
 - [Jekyll Flickr Plugin](https://github.com/lawmurray/indii-jekyll-flickr) by [Lawrence Murray](http://www.indii.org): Embeds Flickr photosets (albums) as a gallery of thumbnails, with lightbox links to larger images.
-
+- [jekyll-figure](https://github.com/paulrobertlloyd/jekyll-figure): A liquid tag for Jekyll that generates `<figure>` elements.
 
 #### Collections
 
@@ -852,6 +860,7 @@ LESS.js files during generation.
 - [Growl Notification Generator by Tate Johnson](https://gist.github.com/490101): Send Jekyll notifications to Growl.
 - [Growl Notification Hook by Tate Johnson](https://gist.github.com/525267): Better alternative to the above, but requires his “hook” fork.
 - [Related Posts by Lawrence Woodman](https://github.com/LawrenceWoodman/related_posts-jekyll_plugin): Overrides `site.related_posts` to use categories to assess relationship.
+- [jekyll-tagging-related_posts](https://github.com/toshimaru/jekyll-tagging-related_posts): Jekyll related_posts function based on tags (works on Jekyll3).
 - [Tiered Archives by Eli Naeher](https://gist.github.com/88cda643aa7e3b0ca1e5): Create tiered template variable that allows you to group archives by year and month.
 - [Jekyll-localization](https://github.com/blackwinter/jekyll-localization): Jekyll plugin that adds localization features to the rendering engine.
 - [Jekyll-rendering](https://github.com/blackwinter/jekyll-rendering): Jekyll plugin to provide alternative rendering engines.
@@ -864,15 +873,17 @@ LESS.js files during generation.
 - [File compressor](https://gist.github.com/2758691) by [mytharcher](https://github.com/mytharcher): Compress HTML and JavaScript files on site build.
 - [Jekyll-minibundle](https://github.com/tkareine/jekyll-minibundle): Asset bundling and cache busting using external minification tool of your choice. No gem dependencies.
 - [Singlepage-jekyll](https://github.com/JCB-K/singlepage-jekyll) by [JCB-K](https://github.com/JCB-K): Turns Jekyll into a dynamic one-page website.
-- [generator-jekyllrb](https://github.com/robwierzbowski/generator-jekyllrb): A generator that wraps Jekyll in [Yeoman](http://yeoman.io/), a tool collection and workflow for builing modern web apps.
+- [generator-jekyllrb](https://github.com/robwierzbowski/generator-jekyllrb): A generator that wraps Jekyll in [Yeoman](http://yeoman.io/), a tool collection and workflow for building modern web apps.
 - [grunt-jekyll](https://github.com/dannygarcia/grunt-jekyll): A straightforward [Grunt](http://gruntjs.com/) plugin for Jekyll.
 - [jekyll-postfiles](https://github.com/indirect/jekyll-postfiles): Add `_postfiles` directory and {% raw %}`{{ postfile }}`{% endraw %} tag so the files a post refers to will always be right there inside your repo.
-- [A layout that compresses HTML](http://jch.penibelst.de/): Github Pages compatible, configurable way to compress HTML files on site build.
+- [A layout that compresses HTML](http://jch.penibelst.de/): GitHub Pages compatible, configurable way to compress HTML files on site build.
 - [Jekyll CO₂](https://github.com/wdenton/jekyll-co2): Generates HTML showing the monthly change in atmospheric CO₂ at the Mauna Loa observatory in Hawaii.
 - [remote-include](http://www.northfieldx.co.uk/remote-include/): Includes files using remote URLs
 - [jekyll-minifier](https://github.com/digitalsparky/jekyll-minifier): Minifies HTML, XML, CSS, and Javascript both inline and as separate files utilising yui-compressor and htmlcompressor.
 - [Jekyll views router](https://bitbucket.org/nyufac/jekyll-views-router): Simple router between generator plugins and templates.
 - [Jekyll Language Plugin](https://github.com/vwochnik/jekyll-language-plugin): Jekyll 3.0-compatible multi-language plugin for posts, pages and includes.
+- [Jekyll Deploy](https://github.com/vwochnik/jekyll-deploy): Adds a `deploy` sub-command to Jekyll.
+- [Official Contentful Jekyll Plugin](https://github.com/contentful/jekyll-contentful-data-import): Adds a `contentful` sub-command to Jekyll to import data from Contentful.
 
 #### Editors
 
@@ -880,6 +891,7 @@ LESS.js files during generation.
 - [vim-jekyll](https://github.com/parkr/vim-jekyll): A vim plugin to generate
   new posts and run `jekyll build` all without leaving vim.
 - [markdown-writer](https://atom.io/packages/markdown-writer): An Atom package for Jekyll. It can create new posts/drafts, manage tags/categories, insert link/images and add many useful key mappings.
+- [Wordpress2Jekyll](https://wordpress.org/plugins/wp2jekyll/): A Wordpress plugin that allows you to use Wordpress as your editor and (automatically) export content in to Jekyll. WordPress2Jekyll attempts to marry these two systems together in order to make a site that can be easily managed from all devices.
 
 <div class="note info">
   <h5>Jekyll Plugins Wanted</h5>
diff --git a/site/_docs/posts.md b/site/_docs/posts.md
index ee02d06..1b3e322 100644
--- a/site/_docs/posts.md
+++ b/site/_docs/posts.md
@@ -6,10 +6,10 @@ permalink: /docs/posts/
 
 One of Jekyll’s best aspects is that it is “blog aware”. What does this mean,
 exactly? Well, simply put, it means that blogging is baked into Jekyll’s
-functionality. If you write articles and publish them online, this means that
-you can publish and maintain a blog simply by managing a folder of text-files on
-your computer. Compared to the hassle of configuring and maintaining databases
-and web-based CMS systems, this will be a welcome change!
+functionality. If you write articles and publish them online, you can publish
+and maintain a blog simply by managing a folder of text-files on your computer.
+Compared to the hassle of configuring and maintaining databases and web-based
+CMS systems, this will be a welcome change!
 
 ## The Posts Folder
 
@@ -23,7 +23,7 @@ static site.
 
 ### Creating Post Files
 
-To create a new post, all you need to do is create a new file in the `_posts`
+To create a new post, all you need to do is create a file in the `_posts`
 directory. How you name files in this folder is important. Jekyll requires blog
 post files to be named according to the following format:
 
@@ -84,21 +84,21 @@ One common solution is to create a folder in the root of the project directory
 called something like `assets` or `downloads`, into which any images, downloads
 or other resources are placed. Then, from within any post, they can be linked
 to using the site’s root as the path for the asset to include. Again, this will
-depend on the way your site’s (sub)domain and path are configured, but here
+depend on the way your site’s (sub)domain and path are configured, but here are
 some examples (in Markdown) of how you could do this using the `site.url`
 variable in a post.
 
 Including an image asset in a post:
 
 {% highlight text %}
-… which is shown in the screenshot below:
+... which is shown in the screenshot below:
 ![My helpful screenshot]({% raw %}{{ site.url }}{% endraw %}/assets/screenshot.jpg)
 {% endhighlight %}
 
 Linking to a PDF for readers to download:
 
 {% highlight text %}
-… you can [get the PDF]({% raw %}{{ site.url }}{% endraw %}/assets/mydoc.pdf) directly.
+... you can [get the PDF]({% raw %}{{ site.url }}{% endraw %}/assets/mydoc.pdf) directly.
 {% endhighlight %}
 
 <div class="note">
diff --git a/site/_docs/quickstart.md b/site/_docs/quickstart.md
index d8ad551..8a63cb3 100644
--- a/site/_docs/quickstart.md
+++ b/site/_docs/quickstart.md
@@ -14,8 +14,7 @@ For the impatient, here's how to get a boilerplate Jekyll site up and running.
 # => Now browse to http://localhost:4000
 {% endhighlight %}
 
-If you wish to install jekyll into the current directory, you can do so by
-alternatively running `jekyll new .` instead of a new directory name.
+If you wish to install jekyll into an existing directory, you can do so by running `jekyll new .` from within the directory instead of creating a new one. If the existing directory isn't empty, you'll also have to pass the `--force` option like so `jekyll new . --force`.
 
 That's nothing, though. The real magic happens when you start creating blog
 posts, using the front matter to control templates and layouts, and taking
diff --git a/site/_docs/resources.md b/site/_docs/resources.md
index 8ede6a6..2ba5f25 100644
--- a/site/_docs/resources.md
+++ b/site/_docs/resources.md
@@ -6,41 +6,33 @@ permalink: /docs/resources/
 
 Jekyll’s growing use is producing a wide variety of tutorials, frameworks, extensions, examples, and other resources that can be very helpful. Below is a collection of links to some of the most popular Jekyll resources.
 
-### Jekyll tips & tricks, and examples
-
-- [Tips for working with GitHub Pages Integration](https://gist.github.com/2890453)
-
-  Code example reuse, and keeping documentation up to date.
-
-- [Use FormKeep for Jekyll form backend and webhooks](https://formkeep.com/)
-- [Use Simple Form to integrate a simple contact
-  form](http://getsimpleform.com/)
-- [JekyllBootstrap.com](http://jekyllbootstrap.com)
-
-  Provides detailed explanations, examples, and helper-code to make
-  getting started with Jekyll easier.
-
-### Tutorials
-
-#### Integrating Jekyll with Git
+### Useful Guides
 
+- [“Creating and Hosting a Personal Site on GitHub”](http://jmcglone.com/guides/github-pages/)
+- [‘Build A Blog With Jekyll And GitHub Pages’ on Smashing Magazine](http://www.smashingmagazine.com/2014/08/01/build-blog-jekyll-github-pages/)
+- Publishing to GitHub Pages? [Check out our documentation page for just that purpose](/docs/github-pages/).
 - [Blogging with Git, Emacs and Jekyll](http://metajack.im/2009/01/23/blogging-with-git-emacs-and-jekyll/)
+- [Tips for working with GitHub Pages Integration](https://gist.github.com/jedschneider/2890453)
 
-#### Other hacks
+### Integrations 
 
+- [Use FormKeep as a backend for forms (contact forms, hiring forms, etc.)](https://formkeep.com/guides/how-to-make-a-contact-form-in-jekyll?utm_source=github&utm_medium=jekyll-docs&utm_campaign=contact-form-jekyll)
+- [Use Simple Form to add a simple contact form](http://getsimpleform.com/)
+- [Jekyll Bootstrap](http://jekyllbootstrap.com), 0 to Blog in 3 minutes. Provides detailed explanations, examples, and helper-code to make getting started with Jekyll easier.
 - [Integrating Twitter with Jekyll](http://www.justkez.com/integrating-twitter-with-jekyll/)
   > “Having migrated Justkez.com to be based on Jekyll, I was pondering how I might include my recent twitterings on the front page of the site. In the WordPress world, this would have been done via a plugin which may or may not have hung the loading of the page, might have employed caching, but would certainly have had some overheads. … Not in Jekyll.”
+
+### Other commentary
+
 - [‘My Jekyll Fork’, by Mike West](http://mikewest.org/2009/11/my-jekyll-fork)
+
   > “Jekyll is a well-architected throwback to a time before WordPress, when men were men, and HTML was static. I like the ideas it espouses, and have made a few improvements to it’s core. Here, I’ll point out some highlights of my fork in the hopes that they see usage beyond this site.”
+
 - [‘About this Website’, by Carter Allen](http://cartera.me/2010/08/12/about-this-website/)
+
   > “Jekyll is everything that I ever wanted in a blogging engine. Really. It isn’t perfect, but what’s excellent about it is that if there’s something wrong, I know exactly how it works and how to fix it. It runs on the your machine only, and is essentially an added”build" step between you and the browser. I coded this entire site in TextMate using standard HTML5 and CSS3, and then at the end I added just a few little variables to the markup. Presto-chango, my site is built and I am at  [...]
-- [‘Build A Blog With Jekyll And GitHub Pages’, by Barry Clark](http://www.smashingmagazine.com/2014/08/01/build-blog-jekyll-github-pages/)
-  > “I recently migrated my blog from WordPress to Jekyll, a fantastic website generator that’s designed for building minimal, static blogs to be hosted on GitHub Pages. The simplicity of Jekyll’s theming layer and writing workflow is fantastic; however, setting up my website took a lot longer than expected. In this article we'll walk through: the quickest way to set up a Jekyll powered blog, how to avoid common problems with using Jekyll, how to import your content from Wordpress, and more.”
-- [Generating a Tag Cloud in Jekyll](http://www.justkez.com/generating-a-tag-cloud-in-jekyll/)
-A guide to implementing a tag cloud and per-tag content pages using Jekyll.
 
+- [Generating a Tag Cloud in Jekyll](http://www.justkez.com/generating-a-tag-cloud-in-jekyll/) – A guide to implementing a tag cloud and per-tag content pages using Jekyll.
 - A way to [extend Jekyll](https://github.com/rfelix/jekyll_ext) without forking and modifying the Jekyll gem codebase and some [portable Jekyll extensions](https://wiki.github.com/rfelix/jekyll_ext/extensions) that can be reused and shared.
-
 - [Using your Rails layouts in Jekyll](http://numbers.brighterplanet.com/2010/08/09/sharing-rails-views-with-jekyll)
-
 - [Adding Ajax pagination to Jekyll](https://eduardoboucas.com/blog/2014/11/10/adding-ajax-pagination-to-jekyll.html)
diff --git a/site/_docs/sites.md b/site/_docs/sites.md
index 42d0492..f0b1a9b 100644
--- a/site/_docs/sites.md
+++ b/site/_docs/sites.md
@@ -10,16 +10,10 @@ learning purposes.
 
 - [Tom Preston-Werner](http://tom.preston-werner.com/)
     ([source](https://github.com/mojombo/mojombo.github.io))
-- [Nick Quaranto](http://quaran.to/)
-    ([source](https://github.com/qrush/qrush.github.com))
-- [Roger Chapman](http://rogchap.com/)
-    ([source](https://github.com/rogchap/rogchap.github.com))
 - [GitHub Official Teaching Materials](http://training.github.com)
-    ([source](https://github.com/github/training.github.com/tree/7049d7532a6856411e34046aedfce43a4afaf424))
+    ([source](https://github.com/github/training-kit))
 - [Rasmus Andersson](http://rsms.me/)
     ([source](https://github.com/rsms/rsms.github.com))
-- [Scott Chacon](http://schacon.github.com)
-    ([source](https://github.com/schacon/schacon.github.com))
 - [Leonard Lamprecht](http://leo.im)
     ([source](https://github.com/leo/leo.github.io))
 
diff --git a/site/_docs/structure.md b/site/_docs/structure.md
index eb6a089..d4ba3ad 100644
--- a/site/_docs/structure.md
+++ b/site/_docs/structure.md
@@ -7,9 +7,9 @@ permalink: /docs/structure/
 Jekyll is, at its core, a text transformation engine. The concept behind the
 system is this: you give it text written in your favorite markup language, be
 that Markdown, Textile, or just plain HTML, and it churns that through a layout
-or series of layout files. Throughout that process you can tweak how you want
+or a series of layout files. Throughout that process you can tweak how you want
 the site URLs to look, what data gets displayed in the layout, and more. This
-is all done through editing text files, and the static web site is the final
+is all done through editing text files; the static web site is the final
 product.
 
 A basic Jekyll site usually looks something like this:
@@ -132,7 +132,7 @@ An overview of what each of these does:
       <td>
         <p>
 
-          Well-formatted site data should be placed here. The jekyll engine
+          Well-formatted site data should be placed here. The Jekyll engine
           will autoload all YAML files in this directory (using either the
           <code>.yml</code>, <code>.yaml</code>, <code>.json</code> or
           <code>.csv</code> formats and extensions) and they will be
diff --git a/site/_docs/templates.md b/site/_docs/templates.md
index 7a4ed04..0ebd35f 100644
--- a/site/_docs/templates.md
+++ b/site/_docs/templates.md
@@ -188,6 +188,17 @@ common tasks easier.
     </tr>
     <tr>
       <td>
+        <p class="name"><strong>Smartify</strong></p>
+        <p>Convert "quotes" into “smart quotes.”</p>
+      </td>
+      <td class="align-center">
+        <p>
+         <code class="filter">{% raw %}{{ page.title | smartify }}{% endraw %}</code>
+        </p>
+      </td>
+    </tr>
+    <tr>
+      <td>
         <p class="name"><strong>Converting Sass/SCSS</strong></p>
         <p>Convert a Sass- or SCSS-formatted string into CSS.</p>
       </td>
@@ -246,6 +257,20 @@ common tasks easier.
         </p>
       </td>
     </tr>
+    <tr>
+      <td>
+        <p class="name"><strong>Sample</strong></p>
+        <p>Pick a random value from an array. Optional: pick multiple values.</p>
+      </td>
+      <td class="align-center">
+        <p>
+         <code class="filter">{% raw %}{{ site.pages | sample }}{% endraw %}</code>
+        </p>
+        <p>
+         <code class="filter">{% raw %}{{ site.pages | sample:2 }}{% endraw %}</code>
+        </p>
+      </td>
+    </tr>
   </tbody>
 </table>
 </div>
@@ -317,16 +342,16 @@ such as using variables.
 
 ### Code snippet highlighting
 
-Jekyll has built in support for syntax highlighting of [over 100
-languages](http://pygments.org/languages/) thanks to
-[Pygments](http://pygments.org/). To use Pygments, you must have Python installed
-on your system and set `highlighter` to `pygments` in your site's configuration
-file.
+Jekyll has built in support for syntax highlighting of over 60 languages
+thanks to [Rouge](http://rouge.jneen.net). Rouge is the default highlighter
+in Jekyll 3 and above. To use it in Jekyll 2, set `highlighter` to `rouge`
+and ensure the `rouge` gem is installed properly.
 
-Alternatively, you can use [Rouge](https://github.com/jayferd/rouge) to highlight
-your code snippets. It doesn't support as many languages as Pygments, however it
-should suit most use cases. Also, since [Rouge](https://github.com/jayferd/rouge)
-is written in pure Ruby, you don't need Python on your system!
+Alternatively, you can use [Pygments](http://pygments.org) to highlight
+your code snippets. To use Pygments, you must have Python installed on your
+system, have the `pygments.rb` gem installed and set `highlighter` to
+`pygments` in your site's configuration file. Pygments supports [over 100
+languages](http://pygments.org/languages/)
 
 To render a code block with syntax highlighting, surround your code as follows:
 
@@ -342,9 +367,9 @@ end
 
 The argument to the `highlight` tag (`ruby` in the example above) is the
 language identifier. To find the appropriate identifier to use for the language
-you want to highlight, look for the “short name” on the [Pygments' Lexers
-page](http://pygments.org/docs/lexers/) or the [Rouge
-wiki](https://github.com/jayferd/rouge/wiki/List-of-supported-languages-and-lexers).
+you want to highlight, look for the “short name” on the [Rouge
+wiki](https://github.com/jayferd/rouge/wiki/List-of-supported-languages-and-lexers)
+or the [Pygments' Lexers page](http://pygments.org/docs/lexers/).
 
 #### Line numbers
 
@@ -422,4 +447,5 @@ You may also optionally specify the filename in the gist to display:
 {% endraw %}
 {% endhighlight %}
 
-To use the `gist` tag, you'll need to add the [jekyll-gist](https://github.com/jekyll/jekyll-gist) gem to your project. 
+To use the `gist` tag, you'll need to add the
+[jekyll-gist](https://github.com/jekyll/jekyll-gist) gem to your project.
diff --git a/site/_docs/upgrading.md b/site/_docs/upgrading.md
index 51fe67a..a128067 100644
--- a/site/_docs/upgrading.md
+++ b/site/_docs/upgrading.md
@@ -4,137 +4,7 @@ title: Upgrading
 permalink: /docs/upgrading/
 ---
 
-Upgrading from an older version of Jekyll? A few things have changed in 1.0
-that you'll want to know about.
+Upgrading from an older version of Jekyll? Upgrading to a new major version of Jekyll (e.g. from v2.x to v3.x) may cause some headaches. Take the following guides to aid your upgrade:
 
-Before we dive in, go ahead and fetch the latest version of Jekyll:
-
-{% highlight bash %}
-$ gem update jekyll
-{% endhighlight %}
-
-<div class="note feature">
-  <h5 markdown="1">Diving in</h5>
-  <p markdown="1">Want to get a new Jekyll site up and running quickly? Simply
-   run <code>jekyll new SITENAME</code> to create a new folder with a bare bones
-   Jekyll site.</p>
-</div>
-
-### The Jekyll Command
-
-For better clarity, Jekyll now accepts the commands `build` and `serve`.
-Whereas before you might simply run the command `jekyll` to generate a site
-and `jekyll --server` to view it locally, in v2.0 (and later) you should
-use the subcommands `jekyll build` and `jekyll serve` to build and preview
-your site.
-
-<div class="note info">
-  <h5>Watching and Serving</h5>
-  <p markdown="1">With the new subcommands, the way sites are previewed locally
-   changed a bit. Instead of specifying `server: true` in the site's
-   configuration file, use `jekyll serve`. The same holds true for
-   `watch: true`. Instead, use the `--watch` flag with either `jekyll serve`
-    or `jekyll build`.</p>
-</div>
-
-### Absolute Permalinks
-
-In Jekyll v1.0, we introduced absolute permalinks for pages in
-subdirectories. Starting with v2.0, absolute permalinks are opt-out,
-meaning Jekyll will default to using absolute permalinks instead of
-relative permalinks. Relative permalink backwards-compatibility was removed in v3.0.
-
-<div class="note warning" id="absolute-permalinks-warning">
-  <h5 markdown="1">Absolute permalinks will be required in v3.0 and on</h5>
-  <p markdown="1">
-    Starting with Jekyll v3.0, relative permalinks functionality will be removed and thus unavailable for use.
-  </p>
-</div>
-
-### Draft Posts
-
-Jekyll now lets you write draft posts, and allows you to easily preview how
-they will look prior to publishing. To start a draft, simply create a folder
-called `_drafts` in your site's source directory (e.g., alongside `_posts`),
-and add a new markdown file to it. To preview your new post, simply run the
-`jekyll serve` command with the `--drafts` flag.
-
-<div class="note info">
-  <h5 markdown="1">Drafts don't have dates</h5>
-  <p markdown="1">
-    Unlike posts, drafts don't have a date, since they haven't
-    been published yet. Rather than naming your draft something like
-    `2013-07-01-my-draft-post.md`, simply name the file what you'd like your
-    post to eventually be titled, here `my-draft-post.md`.</p>
-</div>
-
-### Custom Config File
-
-Rather than passing individual flags via the command line, you can now pass
-an entire custom Jekyll config file. This helps to distinguish between
-environments, or lets you programmatically override user-specified
-defaults. Simply add the `--config` flag to the `jekyll` command, followed
-by the path to one or more config files (comma-delimited, no spaces).
-
-#### As a result, the following command line flags are now deprecated:
-
-* `--no-server`
-* `--no-auto` (now `--no-watch`)
-* `--auto` (now `--watch`)
-* `--server`
-* `--url=`
-* `--maruku`, `--rdiscount`, and `--redcarpet`
-* `--pygments`
-* `--permalink=`
-* `--paginate`
-
-<div class="note info">
-  <h5>The config flag explicitly specifies your configuration file(s)</h5>
-  <p markdown="1">If you use the `--config` flag, Jekyll will ignore your
-    `_config.yml` file. Want to merge a custom configuration with the normal
-    configuration? No problem. Jekyll will accept more than one custom config
-    file via the command line. Config files cascade from right to left, such
-    that if I run `jekyll serve --config _config.yml,_config-dev.yml`,
-    the values in the config files on the right (`_config-dev.yml`) overwrite
-    those on the left (`_config.yml`) when both contain the same key.</p>
-</div>
-
-### New Config File Options
-
-Jekyll 1.0 introduced several new config file options. Before you upgrade,
-you should check to see if any of these are present in your pre-1.0 config
-file, and if so, make sure that you're using them properly:
-
-* `excerpt_separator`
-* `host`
-* `include`
-* `keep_files`
-* `layouts`
-* `show_drafts`
-* `timezone`
-* `url`
-
-### Baseurl
-
-Often, you'll want the ability to run a Jekyll site in multiple places,
-such as previewing locally before pushing to GitHub Pages. Jekyll 1.0 makes
-that easier with the new `--baseurl` flag. To take advantage of this
-feature, first add the production `baseurl` to your site's `_config.yml`
-file. Then, throughout the site, simply prefix relative URLs
-with `{% raw %}{{ site.baseurl }}{% endraw %}`.
-When you're ready to preview your site locally, pass along the `--baseurl`
-flag with your local baseurl (most likely `/`) to `jekyll serve` and Jekyll
-will swap in whatever you've passed along, ensuring all your links work as
-you'd expect in both environments.
-
-
-<div class="note warning">
-  <h5 markdown="1">All page and post URLs contain leading slashes</h5>
-  <p markdown="1">If you use the method described above, please remember
-  that the URLs for all posts and pages contain a leading slash. Therefore,
-  concatenating the site baseurl and the post/page url where
-  `site.baseurl = /` and `post.url = /2013/06/05/my-fun-post/` will
-  result in two leading slashes, which will break links. It is thus
-  suggested that prefixing with `site.baseurl` only be used when the
-  `baseurl` is something other than the default of `/`.</p>
-</div>
+- [From 0.x to 1.x and 2.x](/docs/upgrading/0-to-2/)
+- [From 2.x to 3.x](/docs/upgrading/2-to-3/)
diff --git a/site/_docs/upgrading.md b/site/_docs/upgrading.md~HEAD
similarity index 100%
copy from site/_docs/upgrading.md
copy to site/_docs/upgrading.md~HEAD
diff --git a/site/_docs/upgrading.md~upstream b/site/_docs/upgrading.md~upstream
new file mode 100644
index 0000000..a128067
--- /dev/null
+++ b/site/_docs/upgrading.md~upstream
@@ -0,0 +1,10 @@
+---
+layout: docs
+title: Upgrading
+permalink: /docs/upgrading/
+---
+
+Upgrading from an older version of Jekyll? Upgrading to a new major version of Jekyll (e.g. from v2.x to v3.x) may cause some headaches. Take the following guides to aid your upgrade:
+
+- [From 0.x to 1.x and 2.x](/docs/upgrading/0-to-2/)
+- [From 2.x to 3.x](/docs/upgrading/2-to-3/)
diff --git a/site/_docs/upgrading.md b/site/_docs/upgrading/0-to-2.md
similarity index 98%
copy from site/_docs/upgrading.md
copy to site/_docs/upgrading/0-to-2.md
index 51fe67a..84ec90e 100644
--- a/site/_docs/upgrading.md
+++ b/site/_docs/upgrading/0-to-2.md
@@ -1,11 +1,11 @@
 ---
 layout: docs
-title: Upgrading
-permalink: /docs/upgrading/
+title: Upgrading from 0.x to 2.x
+permalink: /docs/upgrading/0-to-2/
 ---
 
 Upgrading from an older version of Jekyll? A few things have changed in 1.0
-that you'll want to know about.
+and 2.0 that you'll want to know about.
 
 Before we dive in, go ahead and fetch the latest version of Jekyll:
 
diff --git a/site/_docs/upgrading/2-to-3.md b/site/_docs/upgrading/2-to-3.md
new file mode 100644
index 0000000..330228d
--- /dev/null
+++ b/site/_docs/upgrading/2-to-3.md
@@ -0,0 +1,126 @@
+---
+layout: docs
+title: Upgrading from 2.x to 3.x
+permalink: /docs/upgrading/2-to-3/
+---
+
+Upgrading from an older version of Jekyll? A few things have changed in 3.0
+that you'll want to know about.
+
+Before we dive in, go ahead and fetch the latest version of Jekyll:
+
+{% highlight bash %}
+$ gem update jekyll
+{% endhighlight %}
+
+Please note: Jekyll 3 requires Ruby version >= 2.0.0.
+
+<div class="note feature">
+  <h5 markdown="1">Diving in</h5>
+  <p markdown="1">Want to get a new Jekyll site up and running quickly? Simply
+   run <code>jekyll new SITENAME</code> to create a new folder with a bare bones
+   Jekyll site.</p>
+</div>
+
+### site.collections has changed
+
+In 2.x, your iterations over `site.collections` yielded an array with the collection
+label and the collection object as the first and second items, respectively. In 3.x,
+this complication has been removed and iterations now yield simply the collection object.
+A simple conversion must be made in your templates:
+
+- `collection[0]` becomes `collection.label`
+- `collection[1]` becomes `collection`
+
+When iterating over `site.collections`, ensure the above conversions are made.
+
+For `site.collections.myCollection` in Jekyll 2, you now do:
+
+{% highlight liquid %}
+{% raw %}
+{% assign myCollection = site.collections | where: "label", "myCollection" | first %}
+{% endraw %}
+{% endhighlight %}
+
+This is a bit cumbersome at first, but is easier than a big `for` loop.
+
+### Dropped dependencies
+
+We dropped a number of dependencies the Core Team felt were optional. As such, in 3.0, they must be explicitly installed and included if you use any of the features. They are:
+
+- jekyll-paginate – Jekyll's pagination solution from days past
+- jekyll-coffeescript – processing of CoffeeScript
+- jekyll-gist – the `gist` Liquid tag
+- pygments.rb – the Pygments highlighter
+- redcarpet – the Markdown processor
+- toml – an alternative to YAML for configuration files
+- classifier-reborn – for `site.related_posts`
+
+### Future posts
+
+A seeming feature regression in 2.x, the `--future` flag was automatically _enabled_.
+The future flag allows post authors to give the post a date in the future and to have
+it excluded from the build until the system time is equal or after the post time.
+In Jekyll 3, this has been corrected. **Now, `--future` is disabled by default.**
+This means you will need to include `--future` if you want your future-dated posts to
+generate when running `jekyll build` or `jekyll serve`.
+
+### Layout metadata
+
+Introducing: `layout`. In Jekyll 2 and below, any metadata in the layout was merged onto
+the `page` variable in Liquid. This caused a lot of confusion in the way the data was
+merged and some unexpected behaviour. In Jekyll 3, all layout data is accessible via `layout`
+in Liquid. For example, if your layout has `class: my-layout` in its YAML front matter,
+then the layout can access that via `{% raw %}{{ layout.class }}{% endraw %}`.
+
+### Syntax highlighter changed
+
+For the first time, the default syntax highlighter has changed for the
+`highlight` tag and for backtick code blocks. Instead of [Pygments.rb](https://github.com/tmm1/pygments.rb),
+it's now [Rouge](http://rouge.jneen.net/). If you were using the `highlight` tag with certain
+options, such as `hl_lines`, they may not be available when using Rouge. To
+go back to using Pygments, set `highlighter: pygments` in your
+`_config.yml` file and run `gem install pygments.rb` or add
+`gem 'pygments.rb'` to your project's `Gemfile`.
+
+### Relative Permalink support removed
+
+In Jekyll 3 and above, relative permalinks have been deprecated. If you
+created your site using Jekyll 2 and below, you may receive the following
+error when trying to **serve** or **build**:
+
+{% highlight text %}
+Since v3.0, permalinks for pages in subfolders must be relative to the site
+source directory, not the parent directory. Check
+http://jekyllrb.com/docs/upgrading/ for more info.
+{% endhighlight %}
+
+This can be fixed by removing the following line from your `_config.yml` file:
+
+{% highlight yaml %}
+relative_permalinks: true
+{% endhighlight %}
+
+### Permalinks no longer automatically add a trailing slash
+
+In Jekyll 2, any URL constructed from the `permalink:` field had a trailing slash (`/`) added to it automatically.  Jekyll 3 no longer adds a trailing slash automatically to `permalink:` URLs. This can potentially result in old links to pages returning a 404 error. For example, suppose a page previously contained the YAML `permalink: /:year-:month-:day-:title` that resulted in the URL `example.com/2016-02-01-test/` (notice the trailing slash), Jekyll internally generates a folder named ` [...]
+
+### All my posts are gone! Where'd they go!
+
+Try adding `future: true` to your `_config.yml` file. Are they showing up now? If they are, then you were ensnared by an issue with the way Ruby parses times. Each of your posts is being read in a different timezone than you might expect and, when compared to the computer's current time, is "in the future." The fix for this is to add [a timezone offset](https://en.wikipedia.org/wiki/List_of_UTC_time_offsets) to each post (and make sure you remove `future: true` from your `_config.yml` fi [...]
+
+{% highlight yaml %}
+---
+date: 2016-02-06 19:32:10
+---
+{% endhighlight %}
+
+to this (note the offset):
+
+{% highlight yaml %}
+---
+date: 2016-02-06 19:32:10 -0800
+---
+{% endhighlight %}
+
+_Did we miss something? Please click "Improve this page" above and add a section. Thanks!_
diff --git a/site/_docs/variables.md b/site/_docs/variables.md
index d4fb529..33b99fa 100644
--- a/site/_docs/variables.md
+++ b/site/_docs/variables.md
@@ -106,7 +106,7 @@ following is a reference of the available data.
         related Posts. By default, these are the ten most recent posts.
         For high quality but slow to compute results, run the
         <code>jekyll</code> command with the <code>--lsi</code> (latent semantic
-        indexing) option. Also note Github pages does not support the <code>lsi</code> option when generating sites.
+        indexing) option. Also note GitHub Pages does not support the <code>lsi</code> option when generating sites.
 
       </p></td>
     </tr>
diff --git a/site/_docs/windows.md b/site/_docs/windows.md
index a3e6b5f..ddb0892 100644
--- a/site/_docs/windows.md
+++ b/site/_docs/windows.md
@@ -11,9 +11,11 @@ knowledge and lessons that have been unearthed by Windows users.
 ## Installation
 
 Julian Thilo has written up instructions to get
-[Jekyll running on Windows][windows-installation] and it seems to work for most.
-The instructions were written for Ruby 2.0.0, but should work for later versions
-[prior to 2.2][hitimes-issue].
+[Jekyll running on Windows][windows-installation] and it seems to work for most
+people. The instructions were written for Ruby 2.0.0, but should work for later
+versions [prior to 2.2][hitimes-issue].
+
+Alternatively David Burela has written instructions on [how to install Jekyll via Chocolately with 3 command prompt entries](https://davidburela.wordpress.com/2015/11/28/easily-install-jekyll-on-windows-with-3-command-prompt-entries-and-chocolatey/).
 
 ## Encoding
 
diff --git a/site/_includes/docs_ul.html b/site/_includes/docs_ul.html
index 7cc5417..34b6278 100644
--- a/site/_includes/docs_ul.html
+++ b/site/_includes/docs_ul.html
@@ -10,12 +10,8 @@
     {% assign c = "" %}
   {% endif %}
 
-  {% for p in site.docs %}
-    {% if p.url == item_url %}
-      <li class="{{ c }}"><a href="{{ site.url }}{{ p.url }}">{{ p.title }}</a></li>
-      {% break %}
-    {% endif %}
-  {% endfor %}
+  {% assign p = site.docs | where:"url",item_url | first %}
+  <li class="{{ c }}"><a href="{{ site.url }}{{ p.url }}">{{ p.title }}</a></li>
 
 {% endfor %}
 </ul>
diff --git a/site/_includes/footer.html b/site/_includes/footer.html
index 09bab73..4893510 100644
--- a/site/_includes/footer.html
+++ b/site/_includes/footer.html
@@ -1,7 +1,7 @@
 <footer role="contentinfo">
   <div class="grid">
     <div class="unit one-third center-on-mobiles">
-      <p>The contents of this website are © {{ site.time | date: '%Y' }} <a href="http://tom.preston-werner.com/">Tom Preston-Werner</a> under the terms of the <a href="{{ site.repository }}/blob/master/LICENSE">MIT License</a>.</p>
+      <p>The contents of this website are <br />© {{ site.time | date: '%Y' }} under the terms of the <a href="{{ site.repository }}/blob/master/LICENSE">MIT License</a>.</p>
     </div>
     <div class="unit two-thirds align-right center-on-mobiles">
       <p>
diff --git a/site/_posts/2015-10-26-jekyll-3-0-released.markdown b/site/_posts/2015-10-26-jekyll-3-0-released.markdown
index 0d27a45..e7cf9db 100644
--- a/site/_posts/2015-10-26-jekyll-3-0-released.markdown
+++ b/site/_posts/2015-10-26-jekyll-3-0-released.markdown
@@ -22,7 +22,7 @@ The much-anticipated Jekyll 3.0 has been released! Key changes:
 - Lots of performance improvements
 - ... and lots more!
 
-We also added a [Code of Conduct]({{ site.repository }}/blob/master/CONDUCT.md) to encourage a happier, nicer community where contributions and discussion is protected from negative behaviour.
+We also added a [Code of Conduct](/docs/conduct/) to encourage a happier, nicer community where contributions and discussion is protected from negative behaviour.
 
 A huge shout-out to the amazing Jekyll Core Team members Jordon Bedwell, Alfred Xing, and Matt Rogers for all their hard work in making Jekyll 3 the best release yet.
 
diff --git a/site/_posts/2016-01-20-jekyll-3-0-2-released.markdown b/site/_posts/2016-01-20-jekyll-3-0-2-released.markdown
new file mode 100644
index 0000000..88f8888
--- /dev/null
+++ b/site/_posts/2016-01-20-jekyll-3-0-2-released.markdown
@@ -0,0 +1,19 @@
+---
+layout: news_item
+title: 'Jekyll 3.0.2 Released'
+date: 2016-01-20 14:08:18 -0800
+author: parkr
+version: 3.0.2
+categories: [release]
+---
+
+A crucial bug was found in v3.0.1 which caused invalid post dates to go
+unnoticed in the build chain until the error that popped up was unhelpful.
+v3.0.2 [throws errors as you'd expect](https://github.com/jekyll/jekyll/issues/4375)
+when there is a post like `_posts/2016-22-01-future.md` or a post has an
+invalid date like `date: "tuesday"` in their front matter.
+
+This should make the experience of working with Jekyll just a little
+better.
+
+Happy Jekylling!
diff --git a/site/_posts/2016-01-24-jekyll-3-1-0-released.markdown b/site/_posts/2016-01-24-jekyll-3-1-0-released.markdown
new file mode 100644
index 0000000..42768b9
--- /dev/null
+++ b/site/_posts/2016-01-24-jekyll-3-1-0-released.markdown
@@ -0,0 +1,50 @@
+---
+layout: news_item
+title: 'Jekyll 3.1.0 Released'
+date: 2016-01-24 13:16:12 -0800
+author: parkr
+version: 3.1.0
+categories: [release]
+---
+
+Happy weekend! To make your weekend all the better, we have just released
+v3.1.0 of Jekyll.
+
+There are _lots_ of great performance improvements, including a huge one
+which is to use Liquid drops instead of hashes. Much of the slowness in
+Jekyll is due to Jekyll making lots of objects it doesn't need to make.
+By making these objects only as they're needed, we can speed up Jekyll
+considerably!
+
+Some other highlights:
+
+* Fix: `permalink`s with non-HTML extensions will not be honored
+* Fix: `jekyll clean` now accepts build flags like `--source`.
+* Enhancement: `include` tags can now accept multiple liquid variables
+* Feature: adds new `sample` liquid tag which gets random element from an array
+* Fix: Jekyll will read in files with YAML front matter that has extraneous
+spaces after the first line
+* Enhancement: extract the `title` attribute from the filename for
+collection items without a date
+* Fix: gracefully handle empty configuration files
+
+... and [a whole bunch more](/docs/history/#v3-1-0)!
+
+Please [file a bug]({{ site.repository }}/issues/new?title=Jekyll+3.1.0+Issue:)
+if you encounter any issues! As always, [Jekyll Talk](https://talk.jekyllrb.com)
+is the best place to get help if you're encountering a problem.
+
+Special thanks to all our amazing contributors who helped make v3.1.0 a
+possibility:
+
+Alex J Best, Alexander Köplinger, Alfred Xing, Alistair Calder, Atul
+Bhosale, Ben Orenstein, Chi Trung Nguyen, Conor O'Callaghan, Craig P.
+Motlin, Dan K, David Burela, David Litvak Bruno, Decider UI, Ducksan Cho,
+Florian Thomas, James Wen, Jordon Bedwell, Joseph Wynn, Kakoma, Liam
+Bowers, Mike Neumegen, Nick Quaranto, Nielsen Ramon, Olivér Falvai, Pat
+Hawks, Paul Robert Lloyd, Pedro Euko, Peter Suschlik, Sam Volin, Samuel
+Wright, Sasha Friedenberg, Tim Cuthbertson, Vincent Wochnik, William
+Entriken, Zshawn Syed, chrisfinazzo, ducksan cho, leethomas,
+midnightSuyama, musoke, and rebornix
+
+Happy Jekylling!
diff --git a/site/_posts/2016-01-28-jekyll-3-1-1-released.markdown b/site/_posts/2016-01-28-jekyll-3-1-1-released.markdown
new file mode 100644
index 0000000..b5932b0
--- /dev/null
+++ b/site/_posts/2016-01-28-jekyll-3-1-1-released.markdown
@@ -0,0 +1,33 @@
+---
+layout: news_item
+title: 'Jekyll 3.1.1 Released'
+date: 2016-01-28 17:21:50 -0800
+author: parkr
+version: 3.1.1
+categories: [release]
+---
+
+This release squashes a few bugs :bug: :bug: :bug: noticed by a few
+wonderful Jekyll users:
+
+* If your `permalink` ended with a `/`, your URL didn't have any extension,
+even if you wanted one
+* We now strip the BOM by default per Ruby's `IO.open`.
+* `page.dir` will not always end in a slash.
+
+We also updated our [Code of Conduct](/docs/conduct/) to the latest version of
+the Contributor Covenant. The update includes language to ensure that the
+reporter of the incident remains confidential to non-maintainers and that
+all complaints will result in an appropriate response. I care deeply about
+Jekyll's community and will do everything in my power to ensure it is a
+welcoming community. Feel free to reach out to me directly if you feel
+there is a way we can improve the community for everyone! If you're
+interested in more details, [there is a diff for
+that](https://github.com/ContributorCovenant/contributor_covenant/blob/v1_4/diffs/1_3_vs_1_4.patch).
+
+See links to the PR's on [the history page](/docs/history/#v3-1-1).
+
+Thanks to Jordon Bedwell, chrisfinazzo, Kroum Tzanev, David Celis, and
+Alfred Xing for their commits on this latest release! :sparkles:
+
+Happy Jekylling!
diff --git a/site/_posts/2016-02-08-jekyll-3-0-3-released.markdown b/site/_posts/2016-02-08-jekyll-3-0-3-released.markdown
new file mode 100644
index 0000000..0c260cc
--- /dev/null
+++ b/site/_posts/2016-02-08-jekyll-3-0-3-released.markdown
@@ -0,0 +1,32 @@
+---
+layout: news_item
+title: 'Jekyll 3.0.3 Released'
+date: 2016-02-08 10:39:08 -0800
+author: parkr
+version: 3.0.3
+categories: [release]
+---
+
+[GitHub Pages upgraded to Jekyll 3.0.2][1] last week. With a testbed of
+over a million sites, this really put Jekyll 3 through the wringer. This
+release addresses a handful of bugs that were surfaced as a result. The
+fixes:
+
+* Fix problem where outputting to a folder would have two extensions
+* Handle tildes (`~`) in filenames properly
+* Fix issue when comparing documents without dates
+* Include line numbers in liquid error output
+
+Read more on the [changelog](/docs/history/#v3-0-3) with links to the
+related patches.
+
+Please keep [submitting bugs][2] as you find them! Please do take a look
+[in our various help resources](/help/) before filing a bug and use [our
+forum][3] for asking questions and getting help on a specific problem
+you're having.
+
+Happy Jekylling!
+
+[1]: https://github.com/blog/2100-github-pages-now-faster-and-simpler-with-jekyll-3-0
+[2]: {{ site.repository }}/issues
+[3]: https://talk.jekyllrb.com/
diff --git a/site/_posts/2016-02-19-jekyll-3-1-2-released.markdown b/site/_posts/2016-02-19-jekyll-3-1-2-released.markdown
new file mode 100644
index 0000000..7754451
--- /dev/null
+++ b/site/_posts/2016-02-19-jekyll-3-1-2-released.markdown
@@ -0,0 +1,20 @@
+---
+layout: news_item
+title: 'Jekyll 3.1.2 Released!'
+date: 2016-02-19 15:24:00 -0800
+author: parkr
+version: 3.1.2
+categories: [release]
+---
+
+Happy Friday from sunny California! Today, we're excited to announce the release of Jekyll v3.1.2, which comes with some crucial bug fixes:
+
+* If a syntax error is encountered by Liquid, it will now print the line number.
+* A nasty war between symbols and strings in our configuration hash caused kramdown syntax highlighting to break. That has been resolved; you stand victorious!
+* A tilde at the beginning of a filename will no longer crash Jekyll.
+* The `titleize` filter mistakenly dropped words that were already capitalized. Fixed!
+* Permalinks which end in a slash will now always output as a folder with an `index.html` inside.
+
+Nitty-gritty details, like always, are available in the [history](/docs/history/).
+
+Thanks to those who contributed to this release: Alfred Xing, atomicules, bojanland, Brenton Horne, Carlos Garcés, Cash Costello, Chris, chrisfinazzo, Daniel Schildt, Dean Attali, Florian Thomas, Jordon Bedwell, Juuso Mikkonen, Katya Demidova, lonnen, Manabu Sakai, Michael Lee, Michael Lyons, Mitesh Shah, Nicolas Hoizey, Parker Moore, Pat Hawks, Prayag Verma, Robert Martin, Suriyaa Kudo, and toshi.
diff --git a/site/_sass/_style.scss b/site/_sass/_style.scss
index 5980d24..f06ea77 100644
--- a/site/_sass/_style.scss
+++ b/site/_sass/_style.scss
@@ -643,10 +643,14 @@ p > pre,
 p > code,
 p > nobr > code,
 li > code,
+li> pre,
 h5 > code,
 .note > code {
   background-color: #2b2b2b;
   color: #fff;
+  max-width: 100%;
+  overflow-x: auto;
+  vertical-align: middle;
   @include border-radius(5px);
   @include box-shadow(inset 0 1px 10px rgba(0,0,0,.3),
     0 1px 0 rgba(255,255,255,.1),
diff --git a/site/help/index.md b/site/help/index.md
index 5ce0846..ba15959 100644
--- a/site/help/index.md
+++ b/site/help/index.md
@@ -5,6 +5,11 @@ title: Getting Help
 
 Need help with Jekyll? Try these resources.
 
+### [Upgrading Documentation](/docs/upgrading/)
+
+Did you recently upgrade from Jekyll 1 to 2 or from Jekyll 2 to 3?
+Known breaking changes are listed in the upgrading docs.
+
 ### [Google](https://google.com)
 
 Add **jekyll** to almost any query, and you'll find just what you need.
diff --git a/site/index.html b/site/index.html
index a8bda74..cda453f 100644
--- a/site/index.html
+++ b/site/index.html
@@ -30,7 +30,7 @@ overview: true
       <p>
         Permalinks, categories, pages, posts, and custom layouts are all first-class citizens here.
       </p>
-      <a href="/docs/migrations/">Migrate your blog →</a>
+      <a href="http://import.jekyllrb.com">Migrate your blog →</a>
     </div>
     <div class="clear"></div>
   </div>
@@ -79,7 +79,7 @@ overview: true
           <img src="img/octojekyll.png" width="300" height="251" alt="Free Jekyll hosting on GitHub Pages">
           <div class="pane-content">
             <h2 class="center-on-mobiles"><strong>Free hosting</strong> with GitHub Pages</h2>
-            <p>Sick of dealing with hosting companies? <a href="http://pages.github.com/">GitHub Pages</a> are <em>powered by Jekyll</em>, so you can easily deploy your site using GitHub for free—<a href="https://help.github.com/articles/setting-up-a-custom-domain-with-pages">custom domain name</a> and all.</p>
+            <p>Sick of dealing with hosting companies? <a href="https://pages.github.com/">GitHub Pages</a> are <em>powered by Jekyll</em>, so you can easily deploy your site using GitHub for free—<a href="https://help.github.com/articles/about-supported-custom-domains/">custom domain name</a> and all.</p>
             <a href="http://pages.github.com/">Learn more about GitHub Pages →</a>
           </div>
         </div>
diff --git a/site/latest_version.txt b/site/latest_version.txt
index 4a36342..9cec716 100644
--- a/site/latest_version.txt
+++ b/site/latest_version.txt
@@ -1 +1 @@
-3.0.0
+3.1.6
diff --git a/site/redirects/github.html b/site/redirects/github.html
new file mode 100644
index 0000000..6042d0d
--- /dev/null
+++ b/site/redirects/github.html
@@ -0,0 +1,4 @@
+---
+permalink: /github.html
+redirect_to: https://github.com/jekyll/jekyll
+---
diff --git a/site/redirects/issues.html b/site/redirects/issues.html
new file mode 100644
index 0000000..6776051
--- /dev/null
+++ b/site/redirects/issues.html
@@ -0,0 +1,4 @@
+---
+permalink: /issues.html
+redirect_to: https://github.com/jekyll/jekyll/issues
+---
diff --git a/test/fixtures/empty_permalink.erb b/test/fixtures/empty_permalink.erb
new file mode 100644
index 0000000..6dabf63
--- /dev/null
+++ b/test/fixtures/empty_permalink.erb
@@ -0,0 +1,4 @@
+---
+permalink: ''
+---
+Empty Permalink
diff --git a/test/helper.rb b/test/helper.rb
index dc02176..8bede4a 100644
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -2,23 +2,26 @@ def jruby?
   defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
 end
 
-unless ENV['TRAVIS']
-  require File.expand_path('../simplecov_custom_profile', __FILE__)
-  SimpleCov.start('gem') do
-    add_filter "/vendor/bundle"
+if ENV["CI"]
+  require "codeclimate-test-reporter"
+  CodeClimate::TestReporter.start
+else
+  require File.expand_path("../simplecov_custom_profile", __FILE__)
+  SimpleCov.start "gem" do
     add_filter "/vendor/gem"
+    add_filter "/vendor/bundle"
     add_filter ".bundle"
   end
 end
 
+require "nokogiri"
 require 'rubygems'
 require 'ostruct'
 require 'minitest/autorun'
 require 'minitest/reporters'
 require 'minitest/profile'
 require 'rspec/mocks'
-
-require 'jekyll'
+require_relative "../lib/jekyll.rb"
 
 Jekyll.logger = Logger.new(StringIO.new)
 
@@ -32,9 +35,6 @@ require 'shoulda'
 
 include Jekyll
 
-# FIXME: If we really need this we lost the game.
-# STDERR.reopen(test(?e, '/dev/null') ? '/dev/null' : 'NUL:')
-
 # Report with color.
 Minitest::Reporters.use! [
   Minitest::Reporters::DefaultReporter.new(
@@ -42,8 +42,46 @@ Minitest::Reporters.use! [
   )
 ]
 
+module Minitest::Assertions
+  def assert_exist(filename, msg = nil)
+    msg = message(msg) {
+      "Expected '#{filename}' to exist"
+    }
+    assert File.exist?(filename), msg
+  end
+
+  def refute_exist(filename, msg = nil)
+    msg = message(msg) {
+      "Expected '#{filename}' not to exist"
+    }
+    refute File.exist?(filename), msg
+  end
+end
+
+module DirectoryHelpers
+  def dest_dir(*subdirs)
+    test_dir('dest', *subdirs)
+  end
+
+  def source_dir(*subdirs)
+    test_dir('source', *subdirs)
+  end
+
+  def test_dir(*subdirs)
+    File.join(File.dirname(__FILE__), *subdirs)
+  end
+end
+
 class JekyllUnitTest < Minitest::Test
   include ::RSpec::Mocks::ExampleMethods
+  include DirectoryHelpers
+  extend DirectoryHelpers
+
+  def mu_pp obj
+    s = obj.is_a?(Hash) ? JSON.pretty_generate(obj) : obj.inspect
+    s = s.encode Encoding.default_external if defined? Encoding
+    s
+  end
 
   def mocks_expect(*args)
     RSpec::Mocks::ExampleMethods::ExpectHost.instance_method(:expect).\
@@ -51,24 +89,27 @@ class JekyllUnitTest < Minitest::Test
   end
 
   def before_setup
-    ::RSpec::Mocks.setup
+    RSpec::Mocks.setup
     super
   end
 
   def after_teardown
     super
-    ::RSpec::Mocks.verify
+    RSpec::Mocks.verify
   ensure
-    ::RSpec::Mocks.teardown
+    RSpec::Mocks.teardown
   end
 
   def fixture_site(overrides = {})
     Jekyll::Site.new(site_configuration(overrides))
   end
 
-  def build_configs(overrides, base_hash = Jekyll::Configuration::DEFAULTS)
+  def default_configuration
+    Marshal.load(Marshal.dump(Jekyll::Configuration::DEFAULTS))
+  end
+
+  def build_configs(overrides, base_hash = default_configuration)
     Utils.deep_merge_hashes(base_hash, overrides)
-      .fix_common_issues.backwards_compatibilize.add_default_collections
   end
 
   def site_configuration(overrides = {})
@@ -78,15 +119,10 @@ class JekyllUnitTest < Minitest::Test
     }))
     build_configs({
       "source" => source_dir
-    }, full_overrides)
-  end
-
-  def dest_dir(*subdirs)
-    test_dir('dest', *subdirs)
-  end
-
-  def source_dir(*subdirs)
-    test_dir('source', *subdirs)
+    }, full_overrides).
+      fix_common_issues.
+      backwards_compatibilize.
+      add_default_collections
   end
 
   def clear_dest
@@ -94,10 +130,6 @@ class JekyllUnitTest < Minitest::Test
     FileUtils.rm_rf(source_dir('.jekyll-metadata'))
   end
 
-  def test_dir(*subdirs)
-    File.join(File.dirname(__FILE__), *subdirs)
-  end
-
   def directory_with_contents(path)
     FileUtils.rm_rf(path)
     FileUtils.mkdir(path)
@@ -120,4 +152,10 @@ class JekyllUnitTest < Minitest::Test
   end
   alias_method :capture_stdout, :capture_output
   alias_method :capture_stderr, :capture_output
+
+  def nokogiri_fragment(str)
+    Nokogiri::HTML.fragment(
+      str
+    )
+  end
 end
diff --git a/test/safe_glob_test[/find_me.txt b/test/safe_glob_test[/find_me.txt
new file mode 100644
index 0000000..e69de29
diff --git a/test/source/+/foo.md b/test/source/+/foo.md
index 30f9535..bd2d148 100644
--- a/test/source/+/foo.md
+++ b/test/source/+/foo.md
@@ -1,7 +1,7 @@
 ---
 layout: default
 title : Page inside +
-permalink: /+/plus+in+url
+permalink: /+/plus+in+url.html
 ---
 Line 1
 {{ page.title }}
diff --git a/test/source/_posts/2015-12-27-extra-spaces.markdown b/test/source/_posts/2015-12-27-extra-spaces.markdown
new file mode 100644
index 0000000..595a9cd
--- /dev/null
+++ b/test/source/_posts/2015-12-27-extra-spaces.markdown
@@ -0,0 +1,3 @@
+---  
+extra: spaces
+---
diff --git a/test/source/_slides/example-slide-7.md b/test/source/_slides/example-slide-7.md
new file mode 100644
index 0000000..a17c79f
--- /dev/null
+++ b/test/source/_slides/example-slide-7.md
@@ -0,0 +1,6 @@
+---
+am_i_convertible: yes
+permalink: /slides/example-slide-7.php
+---
+
+Am I convertible? {{ page.am_i_convertible }}
diff --git a/test/source/_thanksgiving/2015-11-26-thanksgiving.md b/test/source/_thanksgiving/2015-11-26-thanksgiving.md
new file mode 100644
index 0000000..48d2dd5
--- /dev/null
+++ b/test/source/_thanksgiving/2015-11-26-thanksgiving.md
@@ -0,0 +1,3 @@
+---
+---
+Happy {{ page.title }} !
diff --git a/test/source/_thanksgiving/black-friday.md b/test/source/_thanksgiving/black-friday.md
new file mode 100644
index 0000000..1d8ea1b
--- /dev/null
+++ b/test/source/_thanksgiving/black-friday.md
@@ -0,0 +1,3 @@
+---
+---
+{{ page.title }}
diff --git a/test/source/_urls_differ_by_case_invalid/page1.html b/test/source/_urls_differ_by_case_invalid/page1.html
new file mode 100644
index 0000000..a6a79f9
--- /dev/null
+++ b/test/source/_urls_differ_by_case_invalid/page1.html
@@ -0,0 +1,6 @@
+---
+title: About
+permalink: /about/
+---
+
+About the site
diff --git a/test/source/_urls_differ_by_case_invalid/page2.html b/test/source/_urls_differ_by_case_invalid/page2.html
new file mode 100644
index 0000000..21f679f
--- /dev/null
+++ b/test/source/_urls_differ_by_case_invalid/page2.html
@@ -0,0 +1,6 @@
+---
+title: About
+permalink: /About/
+---
+
+About the site
diff --git a/test/source/_urls_differ_by_case_valid/page1.html b/test/source/_urls_differ_by_case_valid/page1.html
new file mode 100644
index 0000000..a6a79f9
--- /dev/null
+++ b/test/source/_urls_differ_by_case_valid/page1.html
@@ -0,0 +1,6 @@
+---
+title: About
+permalink: /about/
+---
+
+About the site
diff --git a/test/source/_with.dots/mit.txt b/test/source/_with.dots/mit.txt
new file mode 100644
index 0000000..c366b0d
--- /dev/null
+++ b/test/source/_with.dots/mit.txt
@@ -0,0 +1,4 @@
+---
+---
+
+I should be output to `/with.dots/mit/index.html`.
diff --git a/test/source/_with.dots/permalink.with.slash.tho.md b/test/source/_with.dots/permalink.with.slash.tho.md
new file mode 100644
index 0000000..71b9b2e
--- /dev/null
+++ b/test/source/_with.dots/permalink.with.slash.tho.md
@@ -0,0 +1,5 @@
+---
+permalink: /with.dots/permalink.with.slash.tho/
+---
+
+I'm a file with dots BUT I have a permalink which ends with a slash.
diff --git a/test/source/contacts/humans.txt b/test/source/contacts/humans.txt
new file mode 100644
index 0000000..84e2982
--- /dev/null
+++ b/test/source/contacts/humans.txt
@@ -0,0 +1,5 @@
+---
+permalink: /contacts/humans/
+---
+
+I should be output to `/contacts/humans/index.html`.
diff --git a/test/source/deal.with.dots.html b/test/source/deal.with.dots.html
index 6c87d80..fb3d473 100644
--- a/test/source/deal.with.dots.html
+++ b/test/source/deal.with.dots.html
@@ -1,6 +1,5 @@
 ---
 title: Deal with dots
-permalink: /deal.with.dots
 ---
 
 Let's test if jekyll deals properly with dots.
diff --git a/test/source/dynamic_file.php b/test/source/dynamic_file.php
new file mode 100644
index 0000000..823bb47
--- /dev/null
+++ b/test/source/dynamic_file.php
@@ -0,0 +1,4 @@
+---
+---
+
+I'm a Jekyll file! I should be output as dynamic_file.php, no .html to be found.
diff --git a/test/test_ansi.rb b/test/test_ansi.rb
new file mode 100644
index 0000000..b209e23
--- /dev/null
+++ b/test/test_ansi.rb
@@ -0,0 +1,23 @@
+require "helper"
+
+class TestAnsi < JekyllUnitTest
+  context nil do
+    setup do
+      @subject = Jekyll::Utils::Ansi
+    end
+
+    Jekyll::Utils::Ansi::COLORS.each do |color, val|
+      should "respond_to? #{color}" do
+        assert @subject.respond_to?(color)
+      end
+    end
+
+    should "be able to strip colors" do
+      assert_equal @subject.strip(@subject.yellow(@subject.red("hello"))), "hello"
+    end
+
+    should "be able to detect colors" do
+      assert @subject.has?(@subject.yellow("hello"))
+    end
+  end
+end
diff --git a/test/test_cleaner.rb b/test/test_cleaner.rb
index 819dbf5..43d9950 100644
--- a/test/test_cleaner.rb
+++ b/test/test_cleaner.rb
@@ -21,19 +21,19 @@ class TestCleaner < JekyllUnitTest
     end
 
     should "keep the parent directory" do
-      assert File.exist?(dest_dir('to_keep'))
+      assert_exist dest_dir('to_keep')
     end
 
     should "keep the child directory" do
-      assert File.exist?(dest_dir('to_keep/child_dir'))
+      assert_exist dest_dir('to_keep', 'child_dir')
     end
 
     should "keep the file in the directory in keep_files" do
-      assert File.exist?(File.join(dest_dir('to_keep/child_dir'), 'index.html'))
+      assert_exist dest_dir('to_keep', 'child_dir', 'index.html')
     end
 
     should "delete the file in the directory not in keep_files" do
-      assert !File.exist?(File.join(dest_dir('to_keep'), 'index.html'))
+      refute_exist dest_dir('to_keep', 'index.html')
     end
   end
 
@@ -41,8 +41,8 @@ class TestCleaner < JekyllUnitTest
     setup do
       clear_dest
 
-      FileUtils.mkdir_p(source_dir('no_files_inside/child_dir'))
-      FileUtils.touch(File.join(source_dir('no_files_inside/child_dir'), 'index.html'))
+      FileUtils.mkdir_p(source_dir('no_files_inside', 'child_dir'))
+      FileUtils.touch(source_dir('no_files_inside', 'child_dir', 'index.html'))
 
       @site = fixture_site
       @site.process
@@ -57,15 +57,15 @@ class TestCleaner < JekyllUnitTest
     end
 
     should "keep the parent directory" do
-      assert File.exist?(dest_dir('no_files_inside'))
+      assert_exist dest_dir('no_files_inside')
     end
 
     should "keep the child directory" do
-      assert File.exist?(dest_dir('no_files_inside/child_dir'))
+      assert_exist dest_dir('no_files_inside', 'child_dir')
     end
 
     should "keep the file" do
-      assert File.exist?(File.join(dest_dir('no_files_inside/child_dir'), 'index.html'))
+      assert_exist source_dir('no_files_inside', 'child_dir', 'index.html')
     end
   end
 end
diff --git a/test/test_coffeescript.rb b/test/test_coffeescript.rb
index 68e19a5..09c9b0a 100644
--- a/test/test_coffeescript.rb
+++ b/test/test_coffeescript.rb
@@ -37,7 +37,7 @@ JS
     end
 
     should "write a JS file in place" do
-      assert File.exist?(@test_coffeescript_file), "Can't find the converted CoffeeScript file in the dest_dir."
+      assert_exist @test_coffeescript_file, "Can't find the converted CoffeeScript file in the dest_dir."
     end
 
     should "produce JS" do
diff --git a/test/test_collections.rb b/test/test_collections.rb
index be3a932..d6d7d7d 100644
--- a/test/test_collections.rb
+++ b/test/test_collections.rb
@@ -203,7 +203,7 @@ class TestCollections < JekyllUnitTest
     end
 
     should "contain one document" do
-      assert_equal 2, @collection.docs.size
+      assert_equal 4, @collection.docs.size
     end
 
     should "allow dots in the filename" do
diff --git a/test/test_commands_serve.rb b/test/test_commands_serve.rb
new file mode 100644
index 0000000..8e7a1d6
--- /dev/null
+++ b/test/test_commands_serve.rb
@@ -0,0 +1,115 @@
+require "webrick"
+require "mercenary"
+require "helper"
+
+class TestCommandsServe < JekyllUnitTest
+  def custom_opts(what)
+    @cmd.send(
+      :webrick_opts, what
+    )
+  end
+
+  context "with a program" do
+    setup do
+      @merc, @cmd = nil, Jekyll::Commands::Serve
+      Mercenary.program(:jekyll) do |p|
+        @merc = @cmd.init_with_program(
+          p
+        )
+      end
+    end
+
+    should "label itself" do
+      assert_equal(
+        @merc.name, :serve
+      )
+    end
+
+    should "have aliases" do
+      assert_includes @merc.aliases, :s
+      assert_includes @merc.aliases, :server
+    end
+
+    should "have a description" do
+      refute_nil(
+        @merc.description
+      )
+    end
+
+    should "have an action" do
+      refute_empty(
+        @merc.actions
+      )
+    end
+
+    should "not have an empty options set" do
+      refute_empty(
+        @merc.options
+      )
+    end
+
+    context "with custom options" do
+      should "create a default set of mimetypes" do
+        refute_nil custom_opts({})[
+          :MimeTypes
+        ]
+      end
+
+      should "use user destinations" do
+        assert_equal "foo", custom_opts({ "destination" => "foo" })[
+          :DocumentRoot
+        ]
+      end
+
+      should "use user port" do
+        # WHAT?!?!1 Over 9000? That's impossible.
+        assert_equal 9001, custom_opts( { "port" => 9001 })[
+          :Port
+        ]
+      end
+
+      context "verbose" do
+        should "debug when verbose" do
+          assert_equal custom_opts({ "verbose" => true })[:Logger].level, 5
+        end
+
+        should "warn when not verbose" do
+          assert_equal custom_opts({})[:Logger].level, 3
+        end
+      end
+
+      context "enabling ssl" do
+        should "raise if enabling without key or cert" do
+          assert_raises RuntimeError do
+            custom_opts({
+              "ssl_key" => "foo"
+            })
+          end
+
+          assert_raises RuntimeError do
+            custom_opts({
+              "ssl_key" => "foo"
+            })
+          end
+        end
+
+        should "allow SSL with a key and cert" do
+          expect(OpenSSL::PKey::RSA).to receive(:new).and_return("c2")
+          expect(OpenSSL::X509::Certificate).to receive(:new).and_return("c1")
+          allow(File).to receive(:read).and_return("foo")
+
+          result = custom_opts({
+            "ssl_cert" => "foo",
+            "source" => "bar",
+            "enable_ssl" => true,
+            "ssl_key" => "bar"
+          })
+
+          assert result[:SSLEnable]
+          assert_equal result[:SSLPrivateKey ], "c2"
+          assert_equal result[:SSLCertificate], "c1"
+        end
+      end
+    end
+  end
+end
diff --git a/test/test_configuration.rb b/test/test_configuration.rb
index 553dfda..08cc3bd 100644
--- a/test/test_configuration.rb
+++ b/test/test_configuration.rb
@@ -1,7 +1,62 @@
 require 'helper'
 
 class TestConfiguration < JekyllUnitTest
-  @@defaults = Jekyll::Configuration::DEFAULTS.add_default_collections.freeze
+  @@test_config = {
+    "source" => new(nil).source_dir,
+    "destination" => dest_dir
+  }
+
+  context ".from" do
+    should "create a Configuration object" do
+      assert_instance_of Configuration, Configuration.from({})
+    end
+
+    should "merge input over defaults" do
+      result = Configuration.from({"source" => "blah"})
+      refute_equal result["source"], Configuration::DEFAULTS["source"]
+      assert_equal result["source"], "blah"
+    end
+
+    should "fix common mistakes" do
+      result = Configuration.from({"paginate" => 0})
+      assert_nil result["paginate"], "Expected 'paginate' to be corrected to 'nil', but was #{result["paginate"].inspect}"
+    end
+
+    should "add default collections" do
+      result = Configuration.from({})
+      assert_equal result["collections"], {"posts" => {"output" => true, "permalink" => "/:categories/:year/:month/:day/:title:output_ext"}}
+    end
+
+    should "NOT backwards-compatibilize" do
+      assert Configuration.from("watch" => true)["watch"], "Expected the 'watch' key to not be removed."
+    end
+  end
+
+  context "#add_default_collections" do
+    should "no-op if collections is nil" do
+      result = Configuration[{"collections" => nil}].add_default_collections
+      assert_nil result["collections"]
+    end
+
+    should "turn an array into a hash" do
+      result = Configuration[{"collections" => %w{methods}}].add_default_collections
+      assert_instance_of Hash, result["collections"]
+      assert_equal result["collections"], {"posts" => {"output" => true}, "methods" => {}}
+    end
+
+    should "only assign collections.posts.permalink if a permalink is specified" do
+      result = Configuration[{"permalink" => "pretty", "collections" => {}}].add_default_collections
+      assert_equal result["collections"], {"posts" => {"output" => true, "permalink" => "/:categories/:year/:month/:day/:title/"}}
+
+      result = Configuration[{"permalink" => nil, "collections" => {}}].add_default_collections
+      assert_equal result["collections"], {"posts" => {"output" => true}}
+    end
+
+    should "forces posts to output" do
+      result = Configuration[{"collections" => {"posts" => {"output" => false}}}].add_default_collections
+      assert_equal result["collections"]["posts"]["output"], true
+    end
+  end
 
   context "#stringify_keys" do
     setup do
@@ -59,6 +114,34 @@ class TestConfiguration < JekyllUnitTest
       assert_equal %w[config/site.yml config/deploy.toml configuration.yml], @config.config_files(@multiple_files)
     end
   end
+
+  context "#read_config_file" do
+    setup do
+      @config = Configuration[{"source" => source_dir('empty.yml')}]
+    end
+
+    should "not raise an error on empty files" do
+      allow(SafeYAML).to receive(:load_file).with('empty.yml').and_return(false)
+      Jekyll.logger.log_level = :warn
+      @config.read_config_file('empty.yml')
+      Jekyll.logger.log_level = :info
+    end
+  end
+
+  context "#read_config_files" do
+    setup do
+      @config = Configuration[{"source" => source_dir}]
+    end
+
+    should "continue to read config files if one is empty" do
+      allow(SafeYAML).to receive(:load_file).with('empty.yml').and_return(false)
+      allow(SafeYAML).to receive(:load_file).with('not_empty.yml').and_return({'foo' => 'bar', 'include' => '', 'exclude' => ''})
+      Jekyll.logger.log_level = :warn
+      read_config = @config.read_config_files(['empty.yml', 'not_empty.yml'])
+      Jekyll.logger.log_level = :info
+      assert_equal 'bar', read_config['foo']
+    end
+  end
   context "#backwards_compatibilize" do
     setup do
       @config = Configuration[{
@@ -126,27 +209,27 @@ class TestConfiguration < JekyllUnitTest
   end
   context "loading configuration" do
     setup do
-      @path = File.join(Dir.pwd, '_config.yml')
+      @path = source_dir('_config.yml')
       @user_config = File.join(Dir.pwd, "my_config_file.yml")
     end
 
     should "fire warning with no _config.yml" do
       allow(SafeYAML).to receive(:load_file).with(@path) { raise SystemCallError, "No such file or directory - #{@path}" }
       allow($stderr).to receive(:puts).with("Configuration file: none".yellow)
-      assert_equal @@defaults, Jekyll.configuration({})
+      assert_equal site_configuration, Jekyll.configuration(@@test_config)
     end
 
     should "load configuration as hash" do
       allow(SafeYAML).to receive(:load_file).with(@path).and_return(Hash.new)
       allow($stdout).to receive(:puts).with("Configuration file: #{@path}")
-      assert_equal @@defaults, Jekyll.configuration({})
+      assert_equal site_configuration, Jekyll.configuration(@@test_config)
     end
 
     should "fire warning with bad config" do
       allow(SafeYAML).to receive(:load_file).with(@path).and_return(Array.new)
       allow($stderr).to receive(:puts).and_return(("WARNING: ".rjust(20) + "Error reading configuration. Using defaults (and options).").yellow)
       allow($stderr).to receive(:puts).and_return("Configuration file: (INVALID) #{@path}".yellow)
-      assert_equal @@defaults, Jekyll.configuration({})
+      assert_equal site_configuration, Jekyll.configuration(@@test_config)
     end
 
     should "fire warning when user-specified config file isn't there" do
@@ -165,8 +248,8 @@ class TestConfiguration < JekyllUnitTest
   context "loading config from external file" do
     setup do
       @paths = {
-        :default => File.join(Dir.pwd, '_config.yml'),
-        :other   => File.join(Dir.pwd, '_config.live.yml'),
+        :default => source_dir('_config.yml'),
+        :other   => source_dir('_config.live.yml'),
         :toml    => source_dir('_config.dev.toml'),
         :empty   => ""
       }
@@ -175,24 +258,31 @@ class TestConfiguration < JekyllUnitTest
     should "load default plus posts config if no config_file is set" do
       allow(SafeYAML).to receive(:load_file).with(@paths[:default]).and_return({})
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:default]}")
-      assert_equal @@defaults, Jekyll.configuration({})
+      assert_equal site_configuration, Jekyll.configuration(@@test_config)
     end
 
     should "load different config if specified" do
       allow(SafeYAML).to receive(:load_file).with(@paths[:other]).and_return({"baseurl" => "http://wahoo.dev"})
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:other]}")
-      assert_equal Utils.deep_merge_hashes(@@defaults, { "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => @paths[:other] })
+      Jekyll.configuration({ "config" => @paths[:other] })
+      assert_equal \
+        site_configuration({ "baseurl" => "http://wahoo.dev" }),
+        Jekyll.configuration(@@test_config.merge({ "config" => @paths[:other] }))
     end
 
     should "load default config if path passed is empty" do
       allow(SafeYAML).to receive(:load_file).with(@paths[:default]).and_return({})
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:default]}")
-      assert_equal @@defaults, Jekyll.configuration({ "config" => @paths[:empty] })
+      assert_equal \
+        site_configuration,
+        Jekyll.configuration(@@test_config.merge({ "config" => [@paths[:empty]] }))
     end
 
     should "successfully load a TOML file" do
       Jekyll.logger.log_level = :warn
-      assert_equal @@defaults.clone.merge({ "baseurl" => "/you-beautiful-blog-you", "title" => "My magnificent site, wut" }), Jekyll.configuration({ "config" => [@paths[:toml]] })
+      assert_equal \
+        site_configuration({ "baseurl" => "/you-beautiful-blog-you", "title" => "My magnificent site, wut" }),
+        Jekyll.configuration(@@test_config.merge({ "config" => [@paths[:toml]] }))
       Jekyll.logger.log_level = :info
     end
 
@@ -205,7 +295,9 @@ class TestConfiguration < JekyllUnitTest
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:default]}")
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:other]}")
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:toml]}")
-      assert_equal @@defaults, Jekyll.configuration({ "config" => [@paths[:default], @paths[:other], @paths[:toml]] })
+      assert_equal \
+        site_configuration,
+        Jekyll.configuration(@@test_config.merge({ "config" => [@paths[:default], @paths[:other], @paths[:toml]] }))
     end
 
     should "load multiple config files and last config should win" do
@@ -213,7 +305,63 @@ class TestConfiguration < JekyllUnitTest
       allow(SafeYAML).to receive(:load_file).with(@paths[:other]).and_return({"baseurl" => "http://wahoo.dev"})
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:default]}")
       allow($stdout).to receive(:puts).with("Configuration file: #{@paths[:other]}")
-      assert_equal Utils.deep_merge_hashes(@@defaults, { "baseurl" => "http://wahoo.dev" }), Jekyll.configuration({ "config" => [@paths[:default], @paths[:other]] })
+      assert_equal \
+        site_configuration({ "baseurl" => "http://wahoo.dev" }),
+        Jekyll.configuration(@@test_config.merge({ "config" => [@paths[:default], @paths[:other]] }))
+    end
+  end
+
+  context "#add_default_collections" do
+    should "not do anything if collections is nil" do
+      conf = Configuration[default_configuration].tap {|c| c['collections'] = nil }
+      assert_equal conf.add_default_collections, conf
+      assert_nil conf.add_default_collections['collections']
+    end
+
+    should "converts collections to a hash if an array" do
+      conf = Configuration[default_configuration].tap {|c| c['collections'] = ['docs'] }
+      assert_equal conf.add_default_collections, conf.merge({
+        "collections" => {
+          "docs" => {},
+          "posts" => {
+            "output" => true,
+            "permalink" => "/:categories/:year/:month/:day/:title:output_ext"
+          }}})
+    end
+
+    should "force collections.posts.output = true" do
+      conf = Configuration[default_configuration].tap {|c| c['collections'] = {'posts' => {'output' => false}} }
+      assert_equal conf.add_default_collections, conf.merge({
+        "collections" => {
+          "posts" => {
+            "output" => true,
+            "permalink" => "/:categories/:year/:month/:day/:title:output_ext"
+          }}})
+    end
+
+    should "set collections.posts.permalink if it's not set" do
+      conf = Configuration[default_configuration]
+      assert_equal conf.add_default_collections, conf.merge({
+        "collections" => {
+          "posts" => {
+            "output" => true,
+            "permalink" => "/:categories/:year/:month/:day/:title:output_ext"
+          }}})
+    end
+
+    should "leave collections.posts.permalink alone if it is set" do
+      posts_permalink = "/:year/:title/"
+      conf = Configuration[default_configuration].tap do |c|
+        c['collections'] = {
+          "posts" => { "permalink" => posts_permalink }
+        }
+      end
+      assert_equal conf.add_default_collections, conf.merge({
+        "collections" => {
+          "posts" => {
+            "output" => true,
+            "permalink" => posts_permalink
+          }}})
     end
   end
 end
diff --git a/test/test_convertible.rb b/test/test_convertible.rb
index 09c6973..524ecdf 100644
--- a/test/test_convertible.rb
+++ b/test/test_convertible.rb
@@ -49,5 +49,19 @@ class TestConvertible < JekyllUnitTest
       assert_match(/invalid byte sequence in UTF-8/, out)
       assert_match(/#{File.join(@base, name)}/, out)
     end
+
+    should "parse the front-matter but show an error if permalink is empty" do
+      name = 'empty_permalink.erb'
+      assert_raises(Errors::InvalidPermalinkError) do
+        @convertible.read_yaml(@base, name)
+      end
+    end
+
+    should "parse the front-matter correctly whitout permalink" do
+      out = capture_stderr do
+        @convertible.read_yaml(@base, 'front_matter.erb')
+      end
+      refute_match(/Invalid permalink/, out)
+    end
   end
 end
diff --git a/test/test_doctor_command.rb b/test/test_doctor_command.rb
new file mode 100644
index 0000000..dee50ac
--- /dev/null
+++ b/test/test_doctor_command.rb
@@ -0,0 +1,36 @@
+require 'helper'
+require 'jekyll/commands/doctor'
+
+class TestDoctorCommand < JekyllUnitTest
+  context 'urls only differ by case' do
+    setup do
+      clear_dest
+    end
+
+    should 'return success on a valid site/page' do
+      @site = Site.new(Jekyll.configuration({
+        "source" => File.join(source_dir, '/_urls_differ_by_case_valid'),
+        "destination" => dest_dir
+      }))
+      @site.process
+      output = capture_stderr do
+         ret = Jekyll::Commands::Doctor.urls_only_differ_by_case(@site)
+         assert_equal false, ret
+      end
+      assert_equal "", output
+    end
+
+    should 'return warning for pages only differing by case' do
+      @site = Site.new(Jekyll.configuration({
+        "source" => File.join(source_dir, '/_urls_differ_by_case_invalid'),
+        "destination" => dest_dir
+      }))
+      @site.process
+      output = capture_stderr do
+         ret = Jekyll::Commands::Doctor.urls_only_differ_by_case(@site)
+         assert_equal true, ret
+      end
+      assert_includes output, "Warning: The following URLs only differ by case. On a case-insensitive file system one of the URLs will be overwritten by the other: #{dest_dir}/about/index.html, #{dest_dir}/About/index.html"
+    end
+  end
+end
diff --git a/test/test_document.rb b/test/test_document.rb
index 6689e50..ee80081 100644
--- a/test/test_document.rb
+++ b/test/test_document.rb
@@ -44,12 +44,50 @@ class TestDocument < JekyllUnitTest
       assert_equal "foo.bar", @document.data["whatever"]
     end
 
+    should "be jsonify-able" do
+      page_json = @document.to_liquid.to_json
+      parsed = JSON.parse(page_json)
+
+      assert_equal "Jekyll.configuration", parsed["title"]
+      assert_equal "foo.bar", parsed["whatever"]
+      assert_equal nil, parsed["previous"]
+
+      next_doc = parsed["next"]
+      assert_equal "_methods/escape-+ #%20[].md", next_doc["path"]
+      assert_equal "Jekyll.escape", next_doc["title"]
+
+      next_prev_doc = next_doc["previous"]
+      assert_equal "Jekyll.configuration", next_prev_doc["title"]
+      assert_equal "_methods/configuration.md", next_prev_doc["path"]
+      assert_equal "_methods/escape-+ #%20[].md", next_prev_doc["next"]["path"]
+      assert_nil next_prev_doc["previous"] # nothing before Jekyll.configuration
+      assert_nil next_prev_doc["next"]["next"]
+      assert_nil next_prev_doc["next"]["previous"]
+      assert_nil next_prev_doc["next"]["content"]
+      assert_nil next_prev_doc["next"]["excerpt"]
+      assert_nil next_prev_doc["next"]["output"]
+
+      next_next_doc = next_doc["next"]
+      assert_equal "Jekyll.sanitized_path", next_next_doc["title"]
+      assert_equal "_methods/sanitized_path.md", next_next_doc["path"]
+      assert_equal "_methods/escape-+ #%20[].md", next_next_doc["previous"]["path"]
+      assert_equal "_methods/site/generate.md", next_next_doc["next"]["path"]
+      assert_nil next_next_doc["next"]["next"]
+      assert_nil next_next_doc["next"]["previous"]
+      assert_nil next_next_doc["next"]["content"]
+      assert_nil next_next_doc["next"]["excerpt"]
+      assert_nil next_next_doc["next"]["output"]
+      assert_nil next_next_doc["previous"]["next"]
+      assert_nil next_next_doc["previous"]["previous"]
+      assert_nil next_next_doc["previous"]["content"]
+      assert_nil next_next_doc["previous"]["excerpt"]
+      assert_nil next_next_doc["previous"]["output"]
+    end
+
     context "with YAML ending in three dots" do
 
       setup do
-        @site = fixture_site({
-          "collections" => ["methods"],
-        })
+        @site = fixture_site({"collections" => ["methods"]})
         @site.process
         @document = @site.collections["methods"].docs.last
       end
@@ -124,7 +162,7 @@ class TestDocument < JekyllUnitTest
       @site = fixture_site({
         "collections" => ["slides"],
         "defaults" => [{
-          "scope"=> {"path"=>"slides", "type"=>"slides"},
+          "scope"=> {"path"=>"_slides", "type"=>"slides"},
           "values"=> {
             "nested"=> {
               "key"=>"value123",
@@ -195,6 +233,7 @@ class TestDocument < JekyllUnitTest
             "permalink" => "/slides/test/:name"
           }
         },
+        "permalink" => "pretty"
       })
       @site.process
       @document = @site.collections["slides"].docs[0]
@@ -208,6 +247,10 @@ class TestDocument < JekyllUnitTest
     should "produce the right destination file" do
       assert_equal @dest_file, @document.destination(dest_dir)
     end
+
+    should "honor the output extension of its permalink" do
+      assert_equal ".html", @document.output_ext
+    end
   end
 
   context "a document in a collection with pretty permalink style" do
@@ -245,7 +288,7 @@ class TestDocument < JekyllUnitTest
       })
       @site.permalink_style = :pretty
       @site.process
-      @document = @site.collections["slides"].docs[6]
+      @document = @site.collections["slides"].docs[7]
       @dest_file = dest_dir("slides/example-slide-Upper-Cased/index.html")
     end
 
@@ -254,6 +297,37 @@ class TestDocument < JekyllUnitTest
     end
   end
 
+  context "a document in a collection with cased file name" do
+    setup do
+      @site = fixture_site({
+        "collections" => {
+          "slides" => {
+            "output" => true
+          }
+        }
+      })
+      @site.process
+      @document = @site.collections["slides"].docs[6]
+      @dest_file = dest_dir("slides/example-slide-7.php")
+    end
+
+    should "be written out properly" do
+      assert_exist @dest_file
+    end
+
+    should "produce the permalink as the url" do
+      assert_equal "/slides/example-slide-7.php", @document.url
+    end
+
+    should "be written to the proper directory" do
+      assert_equal @dest_file, @document.destination(dest_dir)
+    end
+
+    should "honor the output extension of its permalink" do
+      assert_equal ".php", @document.output_ext
+    end
+  end
+
   context "documents in a collection with custom title permalinks" do
     setup do
       @site = fixture_site({
@@ -273,6 +347,7 @@ class TestDocument < JekyllUnitTest
     should "produce the right URL if they have a slug" do
       assert_equal "/slides/so-what-is-jekyll-exactly", @document.url
     end
+
     should "produce the right destination file if they have a slug" do
       dest_file = dest_dir("slides/so-what-is-jekyll-exactly.html")
       assert_equal dest_file, @document.destination(dest_dir)
@@ -295,6 +370,29 @@ class TestDocument < JekyllUnitTest
     end
   end
 
+  context "document with a permalink with dots & a trailing slash" do
+    setup do
+      @site = fixture_site({"collections" => {
+        "with.dots" => { "output" => true }
+      }})
+      @site.process
+      @document = @site.collections["with.dots"].docs.last
+      @dest_file = dest_dir("with.dots", "permalink.with.slash.tho", "index.html")
+    end
+
+    should "yield an HTML document" do
+      assert_equal @dest_file, @document.destination(dest_dir)
+    end
+
+    should "be written properly" do
+      assert_exist @dest_file
+    end
+
+    should "get the right output_ext" do
+      assert_equal ".html", @document.output_ext
+    end
+  end
+
   context "documents in a collection" do
     setup do
       @site = fixture_site({
diff --git a/test/test_excerpt.rb b/test/test_excerpt.rb
index 322ba3c..61ffded 100644
--- a/test/test_excerpt.rb
+++ b/test/test_excerpt.rb
@@ -10,8 +10,7 @@ class TestExcerpt < JekyllUnitTest
 
   def do_render(document)
     @site.layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")}
-    payload = {"site" => {"posts" => []}}
-    document.output = Jekyll::Renderer.new(@site, document, payload).run
+    document.output = Jekyll::Renderer.new(@site, document, @site.site_payload).run
   end
 
   context "With extraction disabled" do
diff --git a/test/test_excerpt_drop.rb b/test/test_excerpt_drop.rb
new file mode 100644
index 0000000..769aef0
--- /dev/null
+++ b/test/test_excerpt_drop.rb
@@ -0,0 +1,36 @@
+require 'helper'
+
+class TestExcerptDrop < JekyllUnitTest
+  context "an excerpt drop" do
+    setup do
+      @site = fixture_site
+      @site.read
+      @doc = @site.docs_to_write.find { |d| !d.data['layout'].nil? }
+      @doc_drop = @doc.to_liquid
+      @excerpt = @doc.data['excerpt']
+      @excerpt_drop = @excerpt.to_liquid
+    end
+
+    should "have the right thing" do
+      assert @doc.is_a? Jekyll::Document
+      assert @doc_drop.is_a? Jekyll::Drops::DocumentDrop
+      assert @excerpt.is_a? Jekyll::Excerpt
+      assert @excerpt_drop.is_a? Jekyll::Drops::ExcerptDrop
+    end
+
+    should "not have an excerpt" do
+      assert_nil @excerpt.data['excerpt']
+      assert @excerpt_drop.class.invokable? 'excerpt'
+      assert_nil @excerpt_drop['excerpt']
+    end
+
+    should "inherit the layout for the drop but not the excerpt" do
+      assert_nil @excerpt.data['layout']
+      assert_equal @excerpt_drop['layout'], @doc_drop['layout']
+    end
+
+    should "inherit values from the document" do
+      assert_equal @excerpt_drop.keys.sort, @doc_drop.keys.sort
+    end
+  end
+end
diff --git a/test/test_filters.rb b/test/test_filters.rb
index cf4db89..41dde3d 100644
--- a/test/test_filters.rb
+++ b/test/test_filters.rb
@@ -31,6 +31,34 @@ class TestFilters < JekyllUnitTest
       assert_equal "<p>something <strong>really</strong> simple</p>\n", @filter.markdownify("something **really** simple")
     end
 
+    context "smartify filter" do
+      should "convert quotes and typographic characters" do
+        assert_equal "SmartyPants is *not* Markdown", @filter.smartify("SmartyPants is *not* Markdown")
+        assert_equal "“This filter’s test…”", @filter.smartify(%q{"This filter's test..."})
+      end
+
+      should "escapes special characters when configured to do so" do
+        kramdown = JekyllFilter.new({:kramdown => {:entity_output => :symbolic}})
+        assert_equal "“This filter’s test…”", kramdown.smartify(%q{"This filter's test..."})
+      end
+
+      should "convert HTML entities to unicode characters" do
+        assert_equal "’", @filter.smartify("’")
+        assert_equal "“", @filter.smartify("“")
+      end
+
+      should "allow raw HTML passthrough" do
+        assert_equal "Span HTML is <em>not</em> escaped", @filter.smartify("Span HTML is <em>not</em> escaped")
+        assert_equal "<div>Block HTML is not escaped</div>", @filter.smartify("<div>Block HTML is not escaped</div>")
+      end
+
+      should "escape special characters" do
+        assert_equal "3 < 4", @filter.smartify("3 < 4")
+        assert_equal "5 > 4", @filter.smartify("5 > 4")
+        assert_equal "This & that", @filter.smartify("This & that")
+      end
+    end
+
     should "sassify with simple string" do
       assert_equal "p {\n  color: #123456; }\n", @filter.sassify("$blue:#123456\np\n  color: $blue")
     end
@@ -163,6 +191,48 @@ class TestFilters < JekyllUnitTest
         assert_equal "[{\"name\":\"Jack\"},{\"name\":\"Smith\"}]", @filter.jsonify([{:name => 'Jack'}, {:name => 'Smith'}])
       end
 
+      should "convert drop to json" do
+        @filter.site.read
+        expected = {
+          "path" => "_posts/2008-02-02-published.markdown",
+          "previous" => nil,
+          "output" => nil,
+          "content" => "This should be published.\n",
+          "id" => "/publish_test/2008/02/02/published",
+          "url" => "/publish_test/2008/02/02/published.html",
+          "relative_path" => "_posts/2008-02-02-published.markdown",
+          "collection" => "posts",
+          "excerpt" => "<p>This should be published.</p>\n",
+          "draft" => false,
+          "categories" => [
+            "publish_test"
+          ],
+          "layout" => "default",
+          "title" => "Publish",
+          "category" => "publish_test",
+          "date" => "2008-02-02 00:00:00 +0000",
+          "slug" => "published",
+          "ext" => ".markdown",
+          "tags" => []
+        }
+        actual = JSON.parse(@filter.jsonify(@filter.site.docs_to_write.first.to_liquid))
+
+        next_doc = actual.delete("next")
+        refute_nil next_doc
+        assert next_doc.is_a?(Hash), "doc.next should be an object"
+
+        assert_equal expected, actual
+      end
+
+      should "convert drop with drops to json" do
+        @filter.site.read
+        actual = @filter.jsonify(@filter.site.to_liquid)
+        assert_equal JSON.parse(actual)["jekyll"], {
+          "environment" => "development",
+          "version" => Jekyll::VERSION
+        }
+      end
+
       class M < Struct.new(:message)
         def to_liquid
           [message]
@@ -257,7 +327,7 @@ class TestFilters < JekyllUnitTest
             assert_equal 2, g["items"].size
           when ""
             assert g["items"].is_a?(Array), "The list of grouped items for '' is not an Array."
-            assert_equal 11, g["items"].size
+            assert_equal 13, g["items"].size
           end
         end
       end
@@ -388,5 +458,19 @@ class TestFilters < JekyllUnitTest
       end
     end
 
+    context "sample filter" do
+      should "return a random item from the array" do
+        input = %w(hey there bernie)
+        assert_includes input, @filter.sample(input)
+      end
+
+      should "allow sampling of multiple values (n > 1)" do
+        input = %w(hey there bernie)
+        @filter.sample(input, 2).each do |val|
+          assert_includes input, val
+        end
+      end
+    end
+
   end
 end
diff --git a/test/test_front_matter_defaults.rb b/test/test_front_matter_defaults.rb
index 99efede..067caff 100644
--- a/test/test_front_matter_defaults.rb
+++ b/test/test_front_matter_defaults.rb
@@ -4,9 +4,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with full front matter defaults" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
             "path" => "contacts",
@@ -16,7 +14,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
       @site.process
       @affected = @site.pages.find { |page| page.relative_path == "/contacts/bar.html" }
       @not_affected = @site.pages.find { |page| page.relative_path == "about.html" }
@@ -30,9 +28,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter type pages and an extension" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
             "path" => "index.html"
@@ -41,7 +37,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
 
       @site.process
       @affected = @site.pages.find { |page| page.relative_path == "index.html" }
@@ -56,9 +52,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter defaults with no type" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
             "path" => "win"
@@ -67,7 +61,8 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
+
       @site.process
       @affected = @site.posts.docs.find { |page| page.relative_path =~ /win\// }
       @not_affected = @site.pages.find { |page| page.relative_path == "about.html" }
@@ -81,9 +76,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter defaults with no path and a deprecated type" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
             "type" => "page"
@@ -92,7 +85,8 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
+
       @site.process
       @affected = @site.pages
       @not_affected = @site.posts.docs
@@ -106,9 +100,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter defaults with no path" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
             "type" => "pages"
@@ -117,7 +109,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
       @site.process
       @affected = @site.pages
       @not_affected = @site.posts.docs
@@ -131,9 +123,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter defaults with no path or type" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "scope" => {
           },
@@ -141,7 +131,7 @@ class TestFrontMatterDefaults < JekyllUnitTest
             "key" => "val"
           }
         }]
-      }))
+      })
       @site.process
       @affected = @site.pages
       @not_affected = @site.posts
@@ -155,15 +145,13 @@ class TestFrontMatterDefaults < JekyllUnitTest
 
   context "A site with front matter defaults with no scope" do
     setup do
-      @site = Site.new(Jekyll.configuration({
-        "source"      => source_dir,
-        "destination" => dest_dir,
+      @site = fixture_site({
         "defaults" => [{
           "values" => {
             "key" => "val"
           }
         }]
-      }))
+      })
       @site.process
       @affected = @site.pages
       @not_affected = @site.posts
@@ -175,4 +163,29 @@ class TestFrontMatterDefaults < JekyllUnitTest
     end
   end
 
+  context "A site with front matter defaults with quoted date" do
+    setup do
+      @site = Site.new(Jekyll.configuration({
+        "source"      => source_dir,
+        "destination" => dest_dir,
+        "defaults" => [{
+          "values" => {
+            "date" => "2015-01-01 00:00:01"
+          }
+        }]
+      }))
+    end
+
+    should "not raise error" do
+      @site.process
+    end
+
+    should "parse date" do
+      @site.process
+      date = Time.parse("2015-01-01 00:00:01")
+      assert @site.pages.find { |page| page.data["date"] == date }
+      assert @site.posts.find { |page| page.data["date"] == date }
+    end
+  end
+
 end
diff --git a/test/test_generated_site.rb b/test/test_generated_site.rb
index 88e0fe9..71fc45e 100644
--- a/test/test_generated_site.rb
+++ b/test/test_generated_site.rb
@@ -4,15 +4,14 @@ class TestGeneratedSite < JekyllUnitTest
   context "generated sites" do
     setup do
       clear_dest
-      config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
 
-      @site = fixture_site config
+      @site = fixture_site
       @site.process
       @index = File.read(dest_dir('index.html'))
     end
 
     should "ensure post count is as expected" do
-      assert_equal 48, @site.posts.size
+      assert_equal 49, @site.posts.size
     end
 
     should "insert site.posts into the index" do
@@ -31,16 +30,22 @@ class TestGeneratedSite < JekyllUnitTest
     end
 
     should "hide unpublished page" do
-      assert !File.exist?(dest_dir('/unpublished.html'))
+      refute_exist dest_dir('/unpublished.html')
     end
 
     should "not copy _posts directory" do
-      assert !File.exist?(dest_dir('_posts'))
+      refute_exist dest_dir('_posts')
+    end
+
+    should "process a page with a folder permalink properly" do
+      about = @site.pages.find {|page| page.name == 'about.html' }
+      assert_equal dest_dir('about', 'index.html'), about.destination(dest_dir)
+      assert_exist dest_dir('about', 'index.html')
     end
 
     should "process other static files and generate correct permalinks" do
-      assert File.exist?(dest_dir('/about/index.html'))
-      assert File.exist?(dest_dir('/contacts.html'))
+      assert_exist dest_dir('contacts.html')
+      assert_exist dest_dir('dynamic_file.php')
     end
 
     should "print a nice list of static files" do
@@ -58,8 +63,7 @@ OUTPUT
   context "generating limited posts" do
     setup do
       clear_dest
-      config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 5})
-      @site = fixture_site config
+      @site = fixture_site("limit_posts" => 5)
       @site.process
       @index = File.read(dest_dir('index.html'))
     end
@@ -71,17 +75,13 @@ OUTPUT
     should "ensure limit posts is 0 or more" do
       assert_raises ArgumentError do
         clear_dest
-        config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => -1})
-
-        @site = fixture_site config
+        @site = fixture_site("limit_posts" => -1)
       end
     end
 
     should "acceptable limit post is 0" do
       clear_dest
-      config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir, 'limit_posts' => 0})
-
-      assert Site.new(config), "Couldn't create a site with the given limit_posts."
+      assert fixture_site("limit_posts" => 0), "Couldn't create a site with limit_posts=0."
     end
   end
 end
diff --git a/test/test_kramdown.rb b/test/test_kramdown.rb
index b7f4492..fc18c4c 100644
--- a/test/test_kramdown.rb
+++ b/test/test_kramdown.rb
@@ -8,65 +8,120 @@ class TestKramdown < JekyllUnitTest
       @config = {
         'markdown' => 'kramdown',
         'kramdown' => {
-          'auto_ids'      => false,
-          'footnote_nr'   => 1,
+          'smart_quotes' => 'lsquo,rsquo,ldquo,rdquo',
           'entity_output' => 'as_char',
-          'toc_levels'    => '1..6',
-          'smart_quotes'  => 'lsquo,rsquo,ldquo,rdquo',
-
-          'enable_coderay'   => true,
-          'coderay_bold_every'=> 12,
-          'coderay' => {
-            'coderay_css'        => :style,
-            'coderay_bold_every' => 8
+          'toc_levels' => '1..6',
+          'auto_ids' => false,
+          'footnote_nr' => 1,
+
+          'syntax_highlighter_opts' => {
+            'bold_every' => 8, 'css' => :class
           }
         }
       }
+
       @config = Jekyll.configuration(@config)
-      @markdown = Converters::Markdown.new(@config)
+      @markdown = Converters::Markdown.new(
+        @config
+      )
     end
 
-    # http://kramdown.gettalong.org/converter/html.html#options
-    should "pass kramdown options" do
+    should "run Kramdown" do
       assert_equal "<h1>Some Header</h1>", @markdown.convert('# Some Header #').strip
     end
 
-    should "convert quotes to smart quotes" do
-      assert_match /<p>(“|“)Pit(’|’)hy(”|”)<\/p>/, @markdown.convert(%{"Pit'hy"}).strip
+    context "when asked to convert smart quotes" do
+      should "convert" do
+        assert_match %r!<p>(“|“)Pit(’|’)hy(”|”)<\/p>!, @markdown.convert(%{"Pit'hy"}).strip
+      end
+
+      should "support custom types" do
+        override = {
+          "highlighter" => nil,
+          'kramdown' => {
+            'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo'
+          }
+        }
 
-      override = { 'kramdown' => { 'smart_quotes' => 'lsaquo,rsaquo,laquo,raquo' } }
-      markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override))
-      assert_match /<p>(«|«)Pit(›|›)hy(»|»)<\/p>/, markdown.convert(%{"Pit'hy"}).strip
+        markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override))
+        assert_match %r!<p>(«|«)Pit(›|›)hy(»|»)<\/p>!, \
+          markdown.convert(%{"Pit'hy"}).strip
+      end
     end
 
     should "render fenced code blocks with syntax highlighting" do
-      assert_equal "<div class=\"highlighter-rouge\"><pre class=\"highlight\"><code><span class=\"nb\">puts</span> <span class=\"s2\">\"Hello world\"</span>\n</code></pre>\n</div>", @markdown.convert(
-        <<-EOS
-~~~ruby
-puts "Hello world"
-~~~
-        EOS
-      ).strip
+      result = nokogiri_fragment(@markdown.convert(Utils.strip_heredoc <<-MARKDOWN))
+        ~~~ruby
+        puts "Hello World"
+        ~~~
+      MARKDOWN
+
+      selector = "div.highlighter-rouge>pre.highlight>code"
+      refute result.css(selector).empty?
     end
 
-    context "moving up nested coderay options" do
-      setup do
-        @markdown.convert('some markup')
-        @converter_config = @markdown.instance_variable_get(:@config)['kramdown']
-      end
+    context "when a custom highlighter is chosen" do
+      should "use the chosen highlighter if it's available" do
+        override = {
+          "highlighter" => nil,
+          "markdown" => "kramdown",
+          "kramdown" => {
+            "syntax_highlighter" => :coderay
+          }
+        }
 
-      should "work correctly" do
-        assert_equal :style, @converter_config['coderay_css']
+        markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override))
+        result = nokogiri_fragment(markdown.convert(Utils.strip_heredoc <<-MARKDOWN))
+          ~~~ruby
+          puts "Hello World"
+          ~~~
+        MARKDOWN
+
+        selector = "div.highlighter-coderay>div.CodeRay>div.code>pre"
+        refute result.css(selector).empty?
       end
 
-      should "also work for defaults" do
-        default = Jekyll::Configuration::DEFAULTS['kramdown']['coderay']['coderay_tab_width']
-        assert_equal default, @converter_config['coderay_tab_width']
+      should "support legacy enable_coderay... for now" do
+        override = {
+          "markdown" => "kramdown",
+          "kramdown" => {
+            "enable_coderay" => true,
+          }
+        }
+
+        @config.delete("highlighter")
+        @config["kramdown"].delete("syntax_highlighter")
+        markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, override))
+        result = nokogiri_fragment(markdown.convert(Utils.strip_heredoc <<-MARKDOWN))
+          ~~~ruby
+          puts "Hello World"
+          ~~~
+        MARKDOWN
+
+        selector = "div.highlighter-coderay>div.CodeRay>div.code>pre"
+        refute result.css(selector).empty?, "pre tag should exist"
       end
+    end
 
-      should "not overwrite" do
-        assert_equal 12, @converter_config['coderay_bold_every']
+    should "move coderay to syntax_highlighter_opts" do
+      original = Kramdown::Document.method(:new)
+      markdown = Converters::Markdown.new(Utils.deep_merge_hashes(@config, {
+        "higlighter" => nil,
+        "markdown" => "kramdown",
+        "kramdown" => {
+          "syntax_highlighter" => "coderay",
+          "coderay" => {
+            "hello" => "world"
+          }
+        }
+      }))
+
+      expect(Kramdown::Document).to receive(:new) do |arg1, hash|
+        assert_equal hash["syntax_highlighter_opts"]["hello"], "world"
+        original.call(arg1, hash)
       end
+
+      markdown.convert("hello world")
     end
   end
 end
diff --git a/test/test_layout_reader.rb b/test/test_layout_reader.rb
index 88f3522..11acdb3 100644
--- a/test/test_layout_reader.rb
+++ b/test/test_layout_reader.rb
@@ -4,7 +4,7 @@ class TestLayoutReader < JekyllUnitTest
   context "reading layouts" do
     setup do
       config = Jekyll::Configuration::DEFAULTS.merge({'source' => source_dir, 'destination' => dest_dir})
-      @site = fixture_site config
+      @site = fixture_site(config)
     end
 
     should "read layouts" do
diff --git a/test/test_new_command.rb b/test/test_new_command.rb
index 33bd104..f0d2a38 100644
--- a/test/test_new_command.rb
+++ b/test/test_new_command.rb
@@ -24,9 +24,9 @@ class TestNewCommand < JekyllUnitTest
     end
 
     should 'create a new directory' do
-      assert !File.exist?(@full_path)
+      refute_exist @full_path
       Jekyll::Commands::New.process(@args)
-      assert File.exist?(@full_path)
+      assert_exist @full_path
     end
 
     should 'display a success message' do
@@ -96,9 +96,9 @@ class TestNewCommand < JekyllUnitTest
     end
 
     should 'create a new directory' do
-      assert !File.exist?(@site_name_with_spaces)
+      refute_exist @site_name_with_spaces
       capture_stdout { Jekyll::Commands::New.process(@multiple_args) }
-      assert File.exist?(@site_name_with_spaces)
+      assert_exist @site_name_with_spaces
     end
   end
 
diff --git a/test/test_page.rb b/test/test_page.rb
index 1e4d3da..8930095 100644
--- a/test/test_page.rb
+++ b/test/test_page.rb
@@ -8,8 +8,10 @@ class TestPage < JekyllUnitTest
   end
 
   def do_render(page)
-    layouts = { "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")}
-    page.render(layouts, {"site" => {"posts" => []}})
+    layouts = {
+      "default" => Layout.new(@site, source_dir('_layouts'), "simple.html")
+    }
+    page.render(layouts, @site.site_payload)
   end
 
   context "A Page" do
@@ -55,12 +57,20 @@ class TestPage < JekyllUnitTest
         assert_equal ".html", @page.ext
       end
 
+      should "deal properly with non-html extensions" do
+        @page = setup_page('dynamic_page.php')
+        @dest_file = dest_dir("dynamic_page.php")
+        assert_equal ".php", @page.ext
+        assert_equal "dynamic_page", @page.basename
+        assert_equal "/dynamic_page.php", @page.url
+        assert_equal @dest_file, @page.destination(dest_dir)
+      end
+
       should "deal properly with dots" do
         @page = setup_page('deal.with.dots.html')
         @dest_file = dest_dir("deal.with.dots.html")
 
         assert_equal "deal.with.dots", @page.basename
-        assert_equal "/deal.with.dots", @page.url
         assert_equal @dest_file, @page.destination(dest_dir)
       end
 
@@ -140,6 +150,12 @@ class TestPage < JekyllUnitTest
           assert_equal '/contacts.html', @page.url
           assert_equal @dest_file, @page.destination(dest_dir)
         end
+
+        should "return dir correctly" do
+          assert_equal '/', setup_page('contacts.html').dir
+          assert_equal '/contacts/', setup_page('contacts/bar.html').dir
+          assert_equal '/contacts/', setup_page('contacts/index.html').dir
+        end
       end
 
       context "with custom permalink style with trailing slash" do
@@ -184,8 +200,9 @@ class TestPage < JekyllUnitTest
       context "with any other permalink style" do
         should "return dir correctly" do
           @site.permalink_style = nil
-          @page = setup_page('contacts.html')
-          assert_equal '/', @page.dir
+          assert_equal '/', setup_page('contacts.html').dir
+          assert_equal '/contacts/', setup_page('contacts/index.html').dir
+          assert_equal '/contacts/', setup_page('contacts/bar.html').dir
         end
       end
 
@@ -198,6 +215,11 @@ class TestPage < JekyllUnitTest
         assert_equal "/about/", @page.dir
       end
 
+      should "return nil permalink if no permalink exists" do
+        @page = setup_page('')
+        assert_equal nil, @page.permalink
+      end
+
       should "not be writable outside of destination" do
         unexpected = File.expand_path("../../../baddie.html", dest_dir)
         File.delete unexpected if File.exist?(unexpected)
@@ -205,7 +227,7 @@ class TestPage < JekyllUnitTest
         do_render(page)
         page.write(dest_dir)
 
-        assert !File.exist?(unexpected)
+        refute_exist unexpected
       end
     end
 
@@ -230,7 +252,7 @@ class TestPage < JekyllUnitTest
         page.write(dest_dir)
 
         assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir, 'contacts.html'))
+        assert_exist dest_dir('contacts.html')
       end
 
       should "write even when the folder name is plus and permalink has +" do
@@ -238,8 +260,8 @@ class TestPage < JekyllUnitTest
         do_render(page)
         page.write(dest_dir)
 
-        assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir, '+', 'plus+in+url.html'))
+        assert File.directory?(dest_dir), "#{dest_dir} should be a directory"
+        assert_exist dest_dir('+', 'plus+in+url.html')
       end
 
       should "write even when permalink has '%# +'" do
@@ -248,7 +270,7 @@ class TestPage < JekyllUnitTest
         page.write(dest_dir)
 
         assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir, '+', '%# +.html'))
+        assert_exist dest_dir('+', '%# +.html')
       end
 
       should "write properly without html extension" do
@@ -258,7 +280,27 @@ class TestPage < JekyllUnitTest
         page.write(dest_dir)
 
         assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir, 'contacts', 'index.html'))
+        assert_exist dest_dir('contacts', 'index.html')
+      end
+
+      should "support .htm extension and respects that" do
+        page = setup_page('contacts.htm')
+        page.site.permalink_style = :pretty
+        do_render(page)
+        page.write(dest_dir)
+
+        assert File.directory?(dest_dir)
+        assert_exist dest_dir('contacts', 'index.htm')
+      end
+
+      should "support .xhtml extension and respects that" do
+        page = setup_page('contacts.xhtml')
+        page.site.permalink_style = :pretty
+        do_render(page)
+        page.write(dest_dir)
+
+        assert File.directory?(dest_dir)
+        assert_exist dest_dir('contacts', 'index.xhtml')
       end
 
       should "write properly with extension different from html" do
@@ -267,10 +309,10 @@ class TestPage < JekyllUnitTest
         do_render(page)
         page.write(dest_dir)
 
-        assert_equal("/sitemap.xml", page.url)
-        assert_nil(page.url[/\.html$/])
+        assert_equal "/sitemap.xml", page.url
+        assert_nil page.url[/\.html$/]
         assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir,'sitemap.xml'))
+        assert_exist dest_dir('sitemap.xml')
       end
 
       should "write dotfiles properly" do
@@ -279,7 +321,7 @@ class TestPage < JekyllUnitTest
         page.write(dest_dir)
 
         assert File.directory?(dest_dir)
-        assert File.exist?(File.join(dest_dir, '.htaccess'))
+        assert_exist dest_dir('.htaccess')
       end
 
       context "in a directory hierarchy" do
@@ -289,7 +331,7 @@ class TestPage < JekyllUnitTest
           page.write(dest_dir)
 
           assert File.directory?(dest_dir)
-          assert File.exist?(File.join(dest_dir, 'contacts', 'index.html'))
+          assert_exist dest_dir('contacts', 'index.html')
         end
 
         should "write properly" do
@@ -298,7 +340,7 @@ class TestPage < JekyllUnitTest
           page.write(dest_dir)
 
           assert File.directory?(dest_dir)
-          assert File.exist?(File.join(dest_dir, 'contacts', 'bar.html'))
+          assert_exist dest_dir('contacts', 'bar.html')
         end
 
         should "write properly without html extension" do
@@ -308,7 +350,7 @@ class TestPage < JekyllUnitTest
           page.write(dest_dir)
 
           assert File.directory?(dest_dir)
-          assert File.exist?(File.join(dest_dir, 'contacts', 'bar', 'index.html'))
+          assert_exist dest_dir('contacts', 'bar', 'index.html')
         end
       end
     end
diff --git a/test/test_path_sanitization.rb b/test/test_path_sanitization.rb
index b04a2ba..148103e 100644
--- a/test/test_path_sanitization.rb
+++ b/test/test_path_sanitization.rb
@@ -15,4 +15,13 @@ class TestPathSanitization < JekyllUnitTest
       assert_equal "/tmp/foobar/jail/..c:/..c:/..c:/etc/passwd", Jekyll.sanitized_path("/tmp/foobar/jail", "..c:/..c:/..c:/etc/passwd")
     end
   end
+
+  should "escape tilde" do
+    assert_equal source_dir("~hi.txt"), Jekyll.sanitized_path(source_dir, "~hi.txt")
+    assert_equal source_dir("files", "~hi.txt"), Jekyll.sanitized_path(source_dir, "files/../files/~hi.txt")
+  end
+
+  should "remove path traversals" do
+    assert_equal source_dir("files", "hi.txt"), Jekyll.sanitized_path(source_dir, "f./../../../../../../files/hi.txt")
+  end
 end
diff --git a/test/test_regenerator.rb b/test/test_regenerator.rb
index c9dfb57..1ed2121 100644
--- a/test/test_regenerator.rb
+++ b/test/test_regenerator.rb
@@ -112,7 +112,7 @@ class TestRegenerator < JekyllUnitTest
       assert_equal 1, @regenerator.metadata.size
       path = @regenerator.metadata.keys[0]
 
-      assert File.exist?(@layout_path)
+      assert_exist @layout_path
       @regenerator.add_dependency(path, @layout_path)
 
       File.rename(@layout_path, @layout_path + ".tmp")
diff --git a/test/test_site.rb b/test/test_site.rb
index a638a34..f8f01a2 100644
--- a/test/test_site.rb
+++ b/test/test_site.rb
@@ -3,42 +3,42 @@ require 'helper'
 class TestSite < JekyllUnitTest
   context "configuring sites" do
     should "have an array for plugins by default" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS)
+      site = Site.new default_configuration
       assert_equal [File.join(Dir.pwd, '_plugins')], site.plugins
     end
 
     should "look for plugins under the site directory by default" do
       site = Site.new(site_configuration)
-      assert_equal [File.join(source_dir, '_plugins')], site.plugins
+      assert_equal [source_dir('_plugins')], site.plugins
     end
 
     should "have an array for plugins if passed as a string" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'plugins_dir' => '/tmp/plugins'}))
+      site = Site.new(site_configuration({ 'plugins_dir' => '/tmp/plugins' }))
       assert_equal ['/tmp/plugins'], site.plugins
     end
 
     should "have an array for plugins if passed as an array" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'plugins_dir' => ['/tmp/plugins', '/tmp/otherplugins']}))
+      site = Site.new(site_configuration({ 'plugins_dir' => ['/tmp/plugins', '/tmp/otherplugins'] }))
       assert_equal ['/tmp/plugins', '/tmp/otherplugins'], site.plugins
     end
 
     should "have an empty array for plugins if nothing is passed" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'plugins_dir' => []}))
+      site = Site.new(site_configuration({ 'plugins_dir' => [] }))
       assert_equal [], site.plugins
     end
 
-    should "have an empty array for plugins if nil is passed" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'plugins_dir' => nil}))
-      assert_equal [], site.plugins
+    should "have the default for plugins if nil is passed" do
+      site = Site.new(site_configuration({ 'plugins_dir' => nil }))
+      assert_equal [source_dir('_plugins')], site.plugins
     end
 
     should "expose default baseurl" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS)
+      site = Site.new(default_configuration)
       assert_equal Jekyll::Configuration::DEFAULTS['baseurl'], site.baseurl
     end
 
     should "expose baseurl passed in from config" do
-      site = Site.new(Jekyll::Configuration::DEFAULTS.merge({'baseurl' => '/blog'}))
+      site = Site.new(site_configuration({ 'baseurl' => '/blog' }))
       assert_equal '/blog', site.baseurl
     end
   end
@@ -174,9 +174,11 @@ class TestSite < JekyllUnitTest
         coffeescript.coffee
         contacts.html
         deal.with.dots.html
+        dynamic_file.php
         environment.html
         exploit.md
         foo.md
+        humans.txt
         index.html
         index.html
         main.scss
@@ -274,25 +276,25 @@ class TestSite < JekyllUnitTest
 
       should 'remove orphaned files in destination' do
         @site.process
-        assert !File.exist?(dest_dir('obsolete.html'))
-        assert !File.exist?(dest_dir('qux'))
-        assert !File.exist?(dest_dir('quux'))
-        assert File.exist?(dest_dir('.git'))
-        assert File.exist?(dest_dir('.git/HEAD'))
+        refute_exist dest_dir('obsolete.html')
+        refute_exist dest_dir('qux')
+        refute_exist dest_dir('quux')
+        assert_exist dest_dir('.git')
+        assert_exist dest_dir('.git', 'HEAD')
       end
 
       should 'remove orphaned files in destination - keep_files .svn' do
         config = site_configuration('keep_files' => %w{.svn})
         @site = Site.new(config)
         @site.process
-        assert !File.exist?(dest_dir('.htpasswd'))
-        assert !File.exist?(dest_dir('obsolete.html'))
-        assert !File.exist?(dest_dir('qux'))
-        assert !File.exist?(dest_dir('quux'))
-        assert !File.exist?(dest_dir('.git'))
-        assert !File.exist?(dest_dir('.git/HEAD'))
-        assert File.exist?(dest_dir('.svn'))
-        assert File.exist?(dest_dir('.svn/HEAD'))
+        refute_exist dest_dir('.htpasswd')
+        refute_exist dest_dir('obsolete.html')
+        refute_exist dest_dir('qux')
+        refute_exist dest_dir('quux')
+        refute_exist dest_dir('.git')
+        refute_exist dest_dir('.git', 'HEAD')
+        assert_exist dest_dir('.svn')
+        assert_exist dest_dir('.svn', 'HEAD')
       end
     end
 
@@ -464,6 +466,14 @@ class TestSite < JekyllUnitTest
         @site = Site.new(site_configuration('profile' => true))
       end
 
+      # Suppress output while testing
+      setup do
+        $stdout = StringIO.new
+      end
+      teardown do
+        $stdout = STDOUT
+      end
+
       should "print profile table" do
         expect(@site.liquid_renderer).to receive(:stats_table)
         @site.process
diff --git a/test/test_static_file.rb b/test/test_static_file.rb
index 3af7a1f..85512ab 100644
--- a/test/test_static_file.rb
+++ b/test/test_static_file.rb
@@ -19,12 +19,12 @@ class TestStaticFile < JekyllUnitTest
   end
 
   def setup_static_file_with_collection(base, dir, name, label, metadata)
-    site = fixture_site 'collections' => {label => metadata}
+    site = fixture_site('collections' => {label => metadata})
     StaticFile.new(site, base, dir, name, site.collections[label])
   end
 
   def setup_static_file_with_defaults(base, dir, name, defaults)
-    site = fixture_site 'defaults' => defaults
+    site = fixture_site('defaults' => defaults)
     StaticFile.new(site, base, dir, name)
   end
 
@@ -130,4 +130,3 @@ class TestStaticFile < JekyllUnitTest
     end
   end
 end
-
diff --git a/test/test_tags.rb b/test/test_tags.rb
index 2276b20..f263e9d 100644
--- a/test/test_tags.rb
+++ b/test/test_tags.rb
@@ -65,37 +65,37 @@ CONTENT
   context "highlight tag in unsafe mode" do
     should "set the no options with just a language name" do
       tag = highlight_block_with_opts('ruby ')
-      assert_equal({}, tag.instance_variable_get(:@options))
+      assert_equal({}, tag.instance_variable_get(:@highlight_options))
     end
 
     should "set the linenos option as 'inline' if no linenos value" do
       tag = highlight_block_with_opts('ruby linenos ')
-      assert_equal({ :linenos => 'inline' }, tag.instance_variable_get(:@options))
+      assert_equal({ :linenos => 'inline' }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "set the linenos option to 'table' if the linenos key is given the table value" do
       tag = highlight_block_with_opts('ruby linenos=table ')
-      assert_equal({ :linenos => 'table' }, tag.instance_variable_get(:@options))
+      assert_equal({ :linenos => 'table' }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "recognize nowrap option with linenos set" do
       tag = highlight_block_with_opts('ruby linenos=table nowrap ')
-      assert_equal({ :linenos => 'table', :nowrap => true }, tag.instance_variable_get(:@options))
+      assert_equal({ :linenos => 'table', :nowrap => true }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "recognize the cssclass option" do
       tag = highlight_block_with_opts('ruby linenos=table cssclass=hl ')
-      assert_equal({ :cssclass => 'hl', :linenos => 'table' }, tag.instance_variable_get(:@options))
+      assert_equal({ :cssclass => 'hl', :linenos => 'table' }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "recognize the hl_linenos option and its value" do
       tag = highlight_block_with_opts('ruby linenos=table cssclass=hl hl_linenos=3 ')
-      assert_equal({ :cssclass => 'hl', :linenos => 'table', :hl_linenos => '3' }, tag.instance_variable_get(:@options))
+      assert_equal({ :cssclass => 'hl', :linenos => 'table', :hl_linenos => '3' }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "recognize multiple values of hl_linenos" do
       tag = highlight_block_with_opts('ruby linenos=table cssclass=hl hl_linenos="3 5 6" ')
-      assert_equal({ :cssclass => 'hl', :linenos => 'table', :hl_linenos => ['3', '5', '6'] }, tag.instance_variable_get(:@options))
+      assert_equal({ :cssclass => 'hl', :linenos => 'table', :hl_linenos => ['3', '5', '6'] }, tag.instance_variable_get(:@highlight_options))
     end
 
     should "treat language name as case insensitive" do
diff --git a/test/test_url.rb b/test/test_url.rb
index e4529be..578e896 100644
--- a/test/test_url.rb
+++ b/test/test_url.rb
@@ -54,5 +54,23 @@ class TestURL < JekyllUnitTest
       ).to_s
     end
 
+    should "handle UrlDrop as a placeholder in addition to a hash" do
+      site = fixture_site({
+        "collections" => {
+          "methods" => {
+            "output" => true
+          }
+        },
+      })
+      site.read
+      doc = site.collections["methods"].docs.find do |doc|
+        doc.relative_path == "_methods/escape-+ #%20[].md"
+      end
+      assert_equal '/methods/escape-+-20/escape-20.html', URL.new(
+        :template => '/methods/:title/:name:output_ext',
+        :placeholders => doc.url_placeholders
+      ).to_s
+    end
+
   end
 end
diff --git a/test/test_utils.rb b/test/test_utils.rb
index d1ec2ec..eab0ca1 100644
--- a/test/test_utils.rb
+++ b/test/test_utils.rb
@@ -1,6 +1,31 @@
 require 'helper'
 
 class TestUtils < JekyllUnitTest
+  context "The \`Utils.deep_merge_hashes\` method" do
+    setup do
+      clear_dest
+      @site = fixture_site
+      @site.process
+    end
+
+    should "merge a drop into a hash" do
+      data = {"page" => {}}
+      merged = Utils.deep_merge_hashes(data, @site.site_payload)
+      assert merged.is_a? Hash
+      assert merged["site"].is_a? Drops::SiteDrop
+      assert_equal data["page"], merged["page"]
+    end
+
+    should "merge a hash into a drop" do
+      data = {"page" => {}}
+      assert_nil @site.site_payload["page"]
+      merged = Utils.deep_merge_hashes(@site.site_payload, data)
+      assert merged.is_a? Drops::UnifiedPayloadDrop
+      assert merged["site"].is_a? Drops::SiteDrop
+      assert_equal data["page"], merged["page"]
+    end
+  end
+
   context "hash" do
 
     context "pluralized_array" do
@@ -181,6 +206,14 @@ class TestUtils < JekyllUnitTest
     end
   end
 
+  context "The \`Utils.titleize_slug\` method" do
+    should "capitalize all words and not drop any words" do
+      assert_equal "This Is A Long Title With Mixed Capitalization", Utils.titleize_slug("This-is-a-Long-title-with-Mixed-capitalization")
+      assert_equal "This Is A Title With Just The Initial Word Capitalized", Utils.titleize_slug("This-is-a-title-with-just-the-initial-word-capitalized")
+      assert_equal "This Is A Title With No Capitalization", Utils.titleize_slug("this-is-a-title-with-no-capitalization")
+    end
+  end
+
   context "The \`Utils.add_permalink_suffix\` method" do
     should "handle built-in permalink styles" do
       assert_equal "/:basename/", Utils.add_permalink_suffix("/:basename", :pretty)
@@ -195,4 +228,77 @@ class TestUtils < JekyllUnitTest
       assert_equal "/:basename", Utils.add_permalink_suffix("/:basename", "/:title")
     end
   end
+
+  context "The \`Utils.safe_glob\` method" do
+    should "not apply pattern to the dir" do
+      dir = "test/safe_glob_test["
+      assert_equal [], Dir.glob(dir + "/*")
+      assert_equal ["test/safe_glob_test[/find_me.txt"], Utils.safe_glob(dir, "*")
+    end
+
+    should "return the same data to #glob" do
+      dir = "test"
+      assert_equal Dir.glob(dir + "/*"), Utils.safe_glob(dir, "*")
+      assert_equal Dir.glob(dir + "/**/*"), Utils.safe_glob(dir, "**/*")
+    end
+
+    should "return the same data to #glob if dir is not found" do
+      dir = "dir_not_exist"
+      assert_equal [], Utils.safe_glob(dir, "*")
+      assert_equal Dir.glob(dir + "/*"), Utils.safe_glob(dir, "*")
+    end
+
+    should "return the same data to #glob if pattern is blank" do
+      dir = "test"
+      assert_equal [dir], Utils.safe_glob(dir, "")
+      assert_equal Dir.glob(dir), Utils.safe_glob(dir, "")
+      assert_equal Dir.glob(dir), Utils.safe_glob(dir, nil)
+    end
+
+    should "return the same data to #glob if flag is given" do
+      dir = "test"
+      assert_equal Dir.glob(dir + "/*", File::FNM_DOTMATCH),
+                   Utils.safe_glob(dir, "*", File::FNM_DOTMATCH)
+    end
+
+    should "support pattern as an array to support windows" do
+      dir = "test"
+      assert_equal Dir.glob(dir + "/**/*"), Utils.safe_glob(dir, ["**", "*"])
+    end
+  end
+
+  context "The \`Utils.has_yaml_header?\` method" do
+    should "accept files with yaml front matter" do
+      file = source_dir("_posts", "2008-10-18-foo-bar.markdown")
+      assert_equal "---\n", File.open(file, 'rb') { |f| f.read(4) }
+      assert Utils.has_yaml_header?(file)
+    end
+    should "accept files with extraneous spaces after yaml front matter" do
+      file = source_dir("_posts", "2015-12-27-extra-spaces.markdown")
+      assert_equal "---  \n", File.open(file, 'rb') { |f| f.read(6) }
+      assert Utils.has_yaml_header?(file)
+    end
+    should "reject pgp files and the like which resemble front matter" do
+      file = source_dir("pgp.key")
+      assert_equal "-----B", File.open(file, 'rb') { |f| f.read(6) }
+      refute Utils.has_yaml_header?(file)
+    end
+  end
+
+  context "The \`Utils.merged_file_read_opts\` method" do
+    should "ignore encoding if it's not there" do
+      opts = Utils.merged_file_read_opts(nil, {})
+      assert_nil opts["encoding"]
+    end
+
+    should "add bom to encoding" do
+      opts = Utils.merged_file_read_opts(nil, { "encoding" => "utf-8" })
+      assert_equal "bom|utf-8", opts["encoding"]
+    end
+
+    should "preserve bom in encoding" do
+      opts = Utils.merged_file_read_opts(nil, { "encoding" => "bom|utf-8" })
+      assert_equal "bom|utf-8", opts["encoding"]
+    end
+  end
 end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/jekyll.git



More information about the Pkg-ruby-extras-commits mailing list