[DRE-commits] [asciidoctor] 01/06: New upstream version 1.5.5

Lucas Nussbaum lucas at moszumanska.debian.org
Sun Jul 2 11:12:36 UTC 2017


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

lucas pushed a commit to branch master
in repository asciidoctor.

commit 45672bf538560b450d7fa5a2fb0ac9853c089429
Author: Lucas Nussbaum <lucas at debian.org>
Date:   Sun Jul 2 11:24:27 2017 +0200

    New upstream version 1.5.5
---
 .travis.yml                                        |  17 +-
 CHANGELOG.adoc                                     |  77 +++-
 CONTRIBUTING.adoc                                  |   6 +-
 README-fr.adoc                                     | 191 ++++++---
 README-jp.adoc                                     | 395 +++++++++++++++++
 README-zh_CN.adoc                                  | 414 ++++++++++++++++++
 README.adoc                                        | 206 +++++----
 _settings-README.adoc                              |   7 +-
 asciidoctor.gemspec                                |  38 +-
 benchmark/benchmark.rb                             |   2 +-
 data/locale/attributes.adoc                        | 470 +++++++++++++++++++++
 data/stylesheets/asciidoctor-default.css           |  11 +-
 lib/asciidoctor.rb                                 |  41 +-
 lib/asciidoctor/abstract_block.rb                  |  30 +-
 lib/asciidoctor/abstract_node.rb                   |  17 +-
 lib/asciidoctor/cli/invoker.rb                     |   9 +-
 lib/asciidoctor/cli/options.rb                     |   2 +-
 lib/asciidoctor/converter/docbook5.rb              |   2 +-
 lib/asciidoctor/converter/factory.rb               |   6 +-
 lib/asciidoctor/converter/html5.rb                 |  67 +--
 lib/asciidoctor/converter/manpage.rb               |  23 +-
 lib/asciidoctor/converter/template.rb              |  12 +-
 lib/asciidoctor/core_ext.rb                        |  13 +-
 lib/asciidoctor/core_ext/{ => 1.8.7}/string/chr.rb |   2 +-
 lib/asciidoctor/core_ext/1.8.7/string/limit.rb     |  28 ++
 .../core_ext/{ => 1.8.7}/symbol/length.rb          |   2 +-
 lib/asciidoctor/core_ext/nil_or_empty.rb           |  23 +
 lib/asciidoctor/core_ext/object/nil_or_empty.rb    |  23 -
 lib/asciidoctor/core_ext/string/limit.rb           |  10 +
 lib/asciidoctor/document.rb                        |  59 +--
 lib/asciidoctor/extensions.rb                      |  32 +-
 lib/asciidoctor/helpers.rb                         |   2 +-
 lib/asciidoctor/list.rb                            |   3 +
 lib/asciidoctor/parser.rb                          |  90 ++--
 lib/asciidoctor/path_resolver.rb                   |   4 +-
 lib/asciidoctor/reader.rb                          |  29 +-
 lib/asciidoctor/section.rb                         |   4 +-
 lib/asciidoctor/stylesheets.rb                     |   3 +-
 lib/asciidoctor/substitutors.rb                    |  90 ++--
 lib/asciidoctor/table.rb                           |  79 ++--
 lib/asciidoctor/version.rb                         |   2 +-
 man/asciidoctor.1                                  |  15 +-
 man/asciidoctor.adoc                               |   8 +-
 test/attributes_test.rb                            |  52 +++
 test/blocks_test.rb                                |  16 +-
 test/document_test.rb                              |  14 +-
 test/extensions_test.rb                            |  38 ++
 test/fixtures/circle.svg                           |   3 +-
 test/invoker_test.rb                               |  15 +
 test/lists_test.rb                                 | 131 +++---
 test/manpage_test.rb                               |  15 +
 test/paths_test.rb                                 |   3 +
 test/reader_test.rb                                |   4 +-
 test/sections_test.rb                              |  10 +
 test/substitutions_test.rb                         |  18 +-
 test/tables_test.rb                                |  78 +++-
 56 files changed, 2380 insertions(+), 581 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 536ad5b..6a4f6aa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,17 +3,18 @@ git:
   depth: 1
 language: ruby
 rvm:
-  - 2.3.0
-  - 2.2.4
-  - 2.1.8
+  - 2.3.1
+  - 2.2.5
+  - 2.1.10
   - 2.0.0
   - 1.9.3
   - 1.8.7
-  - jruby-9.0.4.0
-  - jruby-19mode
-  - jruby-18mode
-  - rbx-2
+  - jruby-9.0.5.0
+  - jruby-9.1.2.0
+  - jruby-19mode # based on jruby-1.7.19
+  - jruby-18mode # based on jruby-1.7.19
+  #- rbx-3.60 # NOTE not working currently
 script: bundle exec rake coverage test:all
 notifications:
   email: false
-  irc: 'irc.freenode.org#asciidoctor'
+  #irc: 'irc.freenode.org#asciidoctor'
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index c604982..7891f83 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -1,6 +1,8 @@
 = Asciidoctor Changelog
-:uri-asciidoctor: https://github.com/asciidoctor/asciidoctor
-:uri-asciidoc: http://asciidoctor.org/docs/what-is-asciidoc
+:uri-asciidoctor: http://asciidoctor.org
+:uri-asciidoc: {uri-asciidoctor}/docs/what-is-asciidoc
+:uri-repo: https://github.com/asciidoctor/asciidoctor
+:icons: font
 :star: icon:star[role=red]
 ifndef::icons[]
 :star: ★
@@ -9,9 +11,73 @@ endif::[]
 {uri-asciidoctor}[Asciidoctor] is a _fast_, open source text processor and publishing toolchain for converting {uri-asciidoc}[AsciiDoc] content into HTML5, DocBook 5 (or 4.5) and other formats.
 
 This document provides a high-level view of the changes introduced in Asciidoctor by release.
-For a detailed view of what has changed, refer to the https://github.com/asciidoctor/asciidoctor/commits/master[commit history] on GitHub.
+For a detailed view of what has changed, refer to the {uri-repo}/commits/master[commit history] on GitHub.
 
 // tag::compact[]
+== 1.5.5 (2016-10-05) - @mojavelinux
+
+Enhancements::
+  * Add preference to limit the maximum size of an attribute value (#1861)
+  * Honor SOURCE_DATE_EPOCH environment variable to accomodate reproducible builds (@JojoBoulix) (#1721)
+  * Add reversed attribute to ordered list if reversed option is enabled (#1830)
+  * Add support for additional docinfo locations (e.g., :header)
+  * Configure default stylesheet to break monospace word if exceeds length of line; add roles to prevent breaks (#1814)
+  * Introduce translation file for built-in labels (@ciampix)
+  * Provide translations for built-in labels (@JmyL - kr, @ciampix - it, @ivannov - bg, @maxandersen - da, @radcortez - pt, @eddumelendez - es, @leathersole - jp, @aslakknutsen - no, @shahryareiv - fa, @AlexanderZobkov - ru, @dongwq - zh, @rmpestano - pt_BR, @ncomet - fr, @lgvz - fi, @patoi - hu, @BojanStipic - sr, @fwilhe - de, @rahmanusta - tr, @abelsromero - ca, @aboullaite - ar, @roelvs - nl)
+  * Translate README to Chinese (@diguage)
+  * Translate README to Japanese (@Mizuho32)
+
+Improvements::
+  * Style nested emphasized phrases properly when using default stylesheet (#1691)
+  * Honor explicit table width even when autowidth option is set (#1843)
+  * Only explicit noheader option on table should disable implicit table header (#1849)
+  * Support docbook orient="land" attribute on tables (#1815)
+  * Add alias named list to retrieve parent List of ListItem
+  * Update push_include method to support chaining (#1836)
+  * Enable font smoothing on Firefox on OSX (#1837)
+  * Support combined use of sectanchors and sectlinks in HTML5 output (#1806)
+  * fix API docs for find_by
+  * Upgrade to Font Awesome 4.6.3 (@allenan, @mogztter) (#1723)
+  * README: add install instructions for Alpine Linux
+  * README: Switch yum commands to dnf in README
+  * README: Mention Mint as a Debian distro that packages Asciidoctor
+  * README: Add caution advising against using gem update to update a system-managed gem (@oddhack)
+  * README: sync French version with English version (@flashcode)
+  * Add missing endline after title element when converting open block to HTML
+  * Move list_marker_keyword method from AbstractNode to AbstractBlock
+  * Rename definition list to description list internally
+
+Compliance::
+  * Support 6-digit decimal char refs, 5-digit hexidecimal char refs (#1824)
+  * Compatibility fixes for Opal
+  * Check for number using Integer instead of Fixnum class for compatibility with Ruby 2.4
+
+Bug fixes::
+  * Use method_defined? instead of respond_to? to check if method is already defined when patching (#1838)
+  * Fix invalid conditional in HTML5 converter when handling of SVG
+  * Processor#parse_content helper no longer shares attribute list between blocks (#1651)
+  * Fix infinite loop if unordered list marker is immediately followed by a dot (#1679)
+  * Don't break SVG source when cleaning if svg start tag name is immediately followed by endline (#1676)
+  * Prevent template converter from crashing if .rb file found in template directory (#1827)
+  * Fix crash when generating section ID when both idprefix & idseparator are blank (#1821)
+  * Use stronger CSS rule for general text color in Pygments stylesheet (#1802)
+  * Don't duplicate forward slash for path relative to root (#1822)
+
+Infrastructure::
+  * Build gem properly in the absense of a git workspace, make compatible with JRuby (#1779)
+  * Run tests in CI using latest versions of Ruby, including Ruby 2.3 (@ferdinandrosario)
+
+Distribution Packages::
+
+  * http://rubygems.org/gems/asciidoctor[RubyGem (asciidoctor)]
+  * https://apps.fedoraproject.org/packages/rubygem-asciidoctor[Fedora (rubygem-asciidoctor)]
+  * http://packages.debian.org/sid/asciidoctor[Debian (asciidoctor)]
+  * http://packages.ubuntu.com/saucy/asciidoctor[Ubuntu (asciidoctor)]
+
+https://github.com/asciidoctor/asciidoctor/issues?q=milestone%3Av1.5.5[issues resolved] |
+https://github.com/asciidoctor/asciidoctor/releases/tag/v1.5.5[git tag] |
+https://github.com/asciidoctor/asciidoctor/compare/v1.5.4...v1.5.5[full diff]
+
 == 1.5.4 (2016-01-03) - @mojavelinux
 
 Enhancements::
@@ -100,7 +166,7 @@ Improvements::
   * restore attributes to header attributes after parse (#1255)
   * allow docdate and doctime to be overridden (#1495)
   * add CSS class `.center` for center block alignment (#1456)
-  * recognize U+2022 as alternative marker for unordered lists (@mogztter) (#1177)
+  * recognize U+2022 (bullet) as alternative marker for unordered lists (@mogztter) (#1177)
   * allow videos to work for local files by prepending asset-uri-scheme (Chris) (#1320)
   * always assign playlist param when loop option is enabled for YouTube video
   * parse isolated version in revision line (@bk2204) (#790)
@@ -125,6 +191,7 @@ Improvements::
   * fix `+--help+` output text for `-I` (@bk2204)
   * don't require open-uri-cached if already loaded
   * do not attempt to scan pattern of non-existent directory in template converter
+  * prevent CodeRay from bolding every 10th line number
 
 Compliance::
   * use `<sup>` for footnote reference in text instead of `<span>` (#1523)
@@ -177,6 +244,7 @@ Distribution Packages::
 https://github.com/asciidoctor/asciidoctor/issues?q=milestone%3Av1.5.3[issues resolved] |
 https://github.com/asciidoctor/asciidoctor/releases/tag/v1.5.3[git tag] |
 https://github.com/asciidoctor/asciidoctor/compare/v1.5.2...v1.5.3[full diff]
+// end::compact[]
 
 == 1.5.2 (2014-11-27) - @mojavelinux
 
@@ -231,7 +299,6 @@ Distribution Packages::
 https://github.com/asciidoctor/asciidoctor/issues?q=milestone%3Av1.5.2[issues resolved] |
 https://github.com/asciidoctor/asciidoctor/releases/tag/v1.5.2[git tag] |
 https://github.com/asciidoctor/asciidoctor/compare/v1.5.1...v1.5.2[full diff]
-// end::compact[]
 
 == 1.5.1 (2014-09-29) - @mojavelinux
 
diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc
index d729c53..64e1fe9 100644
--- a/CONTRIBUTING.adoc
+++ b/CONTRIBUTING.adoc
@@ -38,12 +38,12 @@ An ideal bug report would include a pull request with failing specs.
 . {uri-branch-help}[Create a topic branch] (preferably using the pattern `issue-XYZ`, where `XYZ` is the issue number).
 . Add tests for your unimplemented feature or bug fix. (See <<writing-and-executing-tests>>)
 . Run `bundle exec rake` to run the tests.
-If your tests pass, return to step 3.
+If your tests pass, return to step 4.
 . Implement your feature or bug fix.
 . Run `bundle exec rake` to run the tests.
-If your tests fail, return to step 5.
+If your tests fail, return to step 6.
 . Add documentation for your feature or bug fix.
-. If your changes are not 100% documented, go back to step 7.
+. If your changes are not 100% documented, go back to step 8.
 . Add, commit, and push your changes.
 . {uri-pr-help}[Submit a pull request].
 
diff --git a/README-fr.adoc b/README-fr.adoc
index 2594f8c..7440b08 100644
--- a/README-fr.adoc
+++ b/README-fr.adoc
@@ -1,6 +1,5 @@
 = Asciidoctor
 Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>; Ryan Waldron <https://github.com/erebor[@erebor]>
-v1.5.4, 2016-01-03
 // FIXME use build system to expand includes statically so document renders properly on GitHub
 ifeval::[{safe-mode-level} < 20]
 include::_settings-README.adoc[]
@@ -12,14 +11,14 @@ ifeval::[{safe-mode-level} >= 20]
 :idseparator: -
 :source-language: ruby
 :language: {source-language}
-ifdef::env-github[:badges:]
+ifdef::env-github[:status:]
 // URIs:
 :uri-org: https://github.com/asciidoctor
 :uri-repo: {uri-org}/asciidoctor
 :uri-asciidoctorj: {uri-org}/asciidoctorj
 :uri-asciidoctorjs: {uri-org}/asciidoctor.js
 :uri-project: http://asciidoctor.org
-ifdef::awestruct-version[:uri-project: link:]
+ifdef::env-site[:uri-project: link:]
 :uri-docs: {uri-project}/docs
 :uri-news: {uri-project}/news
 :uri-manpage: {uri-project}/man/asciidoctor
@@ -27,7 +26,7 @@ ifdef::awestruct-version[:uri-project: link:]
 :uri-contributors: {uri-repo}/graphs/contributors
 :uri-rel-file-base: link:
 :uri-rel-tree-base: link:
-ifdef::awestruct-version[]
+ifdef::env-site[]
 :uri-rel-file-base: {uri-repo}/blob/master/
 :uri-rel-tree-base: {uri-repo}/tree/master/
 endif::[]
@@ -40,7 +39,8 @@ endif::[]
 :uri-rubygem: https://rubygems.org/gems/asciidoctor
 :uri-what-is-asciidoc: {uri-docs}/what-is-asciidoc
 :uri-user-manual: {uri-docs}/user-manual
-:uri-install-doc: {uri-docs}/install-toolchain
+:uri-install-docker: https://github.com/asciidoctor/docker-asciidoctor
+//:uri-install-doc: {uri-docs}/install-toolchain
 :uri-install-osx-doc: {uri-docs}/install-asciidoctor-macosx
 :uri-render-doc: {uri-docs}/render-documents
 :uri-themes-doc: {uri-docs}/produce-custom-themes-using-asciidoctor-stylesheet-factory
@@ -56,10 +56,17 @@ endif::[]
 
 {uri-project}/[Asciidoctor] est un processeur de texte _rapide_ et une chaîne de publication pour convertir du contenu {uri-what-is-asciidoc}[AsciiDoc] en HTML5, DocBook 5 (ou 4.5) et d'autres formats.
 Asciidoctor est écrit en Ruby, packagé sous forme de RubyGem et publié sur {uri-rubygem}[RubyGems.org].
-La gem est aussi incluse dans plusieurs distributions Linux, dont Fedora, Debian et Ubuntu.
+La gemme est aussi incluse dans plusieurs distributions Linux, dont Fedora, Debian et Ubuntu.
 Asciidoctor est open source, {uri-repo}[hébergé sur GitHub] et distribué sous {uri-license}[licence MIT].
 
-.Documentation clée
+ifndef::env-site[]
+.Ce document est traduit dans les langues suivantes :
+* {uri-rel-file-base}README.adoc[Anglais]
+* {uri-rel-file-base}README-zh_CN.adoc[Chinois]
+* {uri-rel-file-base}README-jp.adoc[Japonais]
+endif::[]
+
+.Documentation clé
 [.compact]
 * {uri-docs}/what-is-asciidoc[Qu'est ce qu'AsciiDoc ?]
 * {uri-docs}/asciidoc-writers-guide[Guide pour Rédacteur AsciiDoc]
@@ -77,7 +84,7 @@ Nous utilisons http://opalrb.org[Opal] pour transcrire le code source Ruby en Ja
 Asciidoctor.js est utilisé pour faire fonctionner les extensions AsciiDoc Preview pour Chrome, Atom, Brackets et autres outils web.
 ****
 
-ifdef::badges[]
+ifdef::status[]
 .*Santé du projet*
 image:https://img.shields.io/travis/asciidoctor/asciidoctor/master.svg[Build Status (Travis CI), link=https://travis-ci.org/asciidoctor/asciidoctor]
 image:https://ci.appveyor.com/api/projects/status/ifplu67oxvgn6ceq/branch/master?svg=true&passingText=green%20bar&failingText=%23fail&pendingText=building%2E%2E%2E[Build Status (AppVeyor), link=https://ci.appveyor.com/project/asciidoctor/asciidoctor]
@@ -99,111 +106,155 @@ Asciidoctor lit et analyse la syntaxe du texte écrit en AsciiDoc afin de créer
 
 Vous avez la possibilité d'écrire votre propre convertisseur ou de fournir des templates supportant {uri-tilt}[Tilt] pour personnaliser le résultat généré ou pour produire des formats alternatifs.
 
-NOTE: Asciidoctor est un remplaçant du processeur AsciiDoc orginal écrit en Python (`asciidoc.py`).
+NOTE: Asciidoctor est un remplaçant du processeur AsciiDoc original écrit en Python (`asciidoc.py`).
 La suite de tests Asciidoctor possède {uri-tests}[> 1,600 tests] pour garantir la compatibilité avec la syntaxe AsciiDoc.
 
-En plus de la syntaxe AsciiDoc standard, Asciidoctor reconnait des balises additionnelles ainsi que des options de formatage, comme les polices d'icônes (e.g., `+icon:fire[]+`) et des éléments d'interface (e.g., `+button:[Enregistrer]+`).
-Asciidoctor offre aussi un thème moderne et responsive basé sur {uri-foundation}[Foundation] pour styliser le document HTML5 généré.
+En plus de la syntaxe AsciiDoc standard, Asciidoctor reconnaît des balises additionnelles ainsi que des options de formatage, comme les polices d'icônes (par exemple `+icon:fire[]+`) et des éléments d'interface (par exemple `+button:[Enregistrer]+`).
+Asciidoctor offre aussi un thème moderne et « responsive » basé sur {uri-foundation}[Foundation] pour styliser le document HTML5 généré.
 
 == Prérequis
 
-Asciidoctor fonctionne sur Linux, OSX (Mac), Windows et requiert une des implémentations suivantes :
+Asciidoctor fonctionne sur Linux, OS X (Mac), Windows et requiert une des implémentations suivantes :
 
-* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1 & 2.2)
-* JRuby 1.7 (Ruby 1.8 and 1.9 modes) & 9000
+* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1, 2.2 & 2.3)
+* JRuby (1.7 dans les modes Ruby 1.8 et 1.9, 9000)
 * Rubinius 2.2.x
 * Opal (JavaScript)
 
 Votre aide est appréciée pour tester Asciidoctor sur l'une de ces plateformes.
-Référez-vous au paragraphe <<{idprefix}contributions,Contributions>> si vous souhaitez vous impliquer dans ce projet.
+Référez-vous au paragraphe <<Contributions>> si vous souhaitez vous impliquer dans ce projet.
+
+[CAUTION]
+====
+Si vous utilisez un environnement Windows dans une autre langue que l'anglais, vous pourriez tomber sur l'erreur `Encoding::UndefinedConversionError` lors du lancement d'Asciidoctor.
+Pour corriger ce problème, nous recommandons de changer la page de code en UTF-8 dans votre console :
+
+ chcp 65001
+
+Après ce changement, tous les maux de tête liés à l'Unicode seront derrière vous.
+Si vous utilisez un environnement de développement comme Eclipse, assurez-vous de définir l'encodage en UTF-8.
+Asciidoctor fonctionne mieux lorsque vous utilisez UTF-8 partout.
+====
 
 == Installation
 
 Asciidoctor peut être installé en utilisant la commande (a) `gem install`, (b) Bundler ou (c) les gestionnaires de paquets pour les distributions Linux populaires.
 
-TIP: L'avantage d'utiliser le gestionnaire de paquets pour installer la gem est que l'installation englobe celle des librairies Ruby et RubyGems si elles ne sont pas déjà installés.
-L'inconvénient est que le paquet n'est pas forcément mis à jour immédiatement après la release de la gem.
+TIP: L'avantage d'utiliser le gestionnaire de paquets pour installer la gemme est que l'installation englobe celle des librairies Ruby et RubyGems si elles ne sont pas déjà installés.
+L'inconvénient est que le paquet n'est pas forcément mis à jour immédiatement après la mise à disposition de la gemme.
 Si vous avez besoin de la dernière version, vous devez passer par la commande `gem`.
 
-=== (a) Installation de la gem
+=== (a) Installation de la gemme
 
-Ouvrir un terminal et taper (en excluant le `$`) :
+Ouvrir un terminal et taper (en excluant le `$`) :
 
  $ gem install asciidoctor
 
-Si vous souhaitez installer une version pre-release (càd, une release candidate), utilisez :
+Si vous souhaitez installer une version pre-release (c'est-à-dire, une « release candidate »), utilisez :
 
  $ gem install asciidoctor --pre
 
 .Mettre à jour votre installation
 [TIP]
 ====
-Si vous avez une précédente version d'Asciidoctor installée, vous pouvez la mettre à jour en utilisant :
+Si vous avez une précédente version d'Asciidoctor installée, vous pouvez la mettre à jour en utilisant :
 
  $ gem update asciidoctor
 
-Si vous installez une nouvelle version de la gem en utilisant `gem install` au lieu de `gem update`, vous aurez plusieurs versions d'installées.
-Si c'est le cas, utilisez la commande gem suivante pour supprimer la vieille version :
+Si vous installez une nouvelle version de la gemme en utilisant `gem install` au lieu de `gem update`, vous aurez plusieurs versions d'installées.
+Si c'est le cas, utilisez la commande gem suivante pour supprimer la vieille version :
 
  $ gem cleanup asciidoctor
 ====
 
 === (b) Bundler
 
-. Créez un fichier Gemfile à la racine de votre projet (ou du répertoire courant),
-. Ajoutez la gem `asciidoctor` dans votre fichier Gemfile comme ci-dessous :
+. Créez un fichier Gemfile à la racine de votre projet (ou du répertoire courant)
+. Ajoutez la gemme `asciidoctor` dans votre fichier Gemfile comme ci-dessous :
 +
 [source]
 ----
 source 'https://rubygems.org'
 gem 'asciidoctor'
 # ou spécifier la version explicitement
-# gem 'asciidoctor', '1.5.3'
+# gem 'asciidoctor', '1.5.4'
 ----
 
-. Sauvegardez le fichier Gemfile,
-. Ouvrez un terminal et installez la gem en utilisant :
+. Sauvegardez le fichier Gemfile
+. Ouvrez un terminal et installez la gemme en utilisant :
 
  $ bundle
 
-Pour mettre à jour la gem, spécifiez la nouvelle version dans le fichier Gemfile et exécutez `bundle` à nouveau.
-Utiliser `bundle update` *n*'est *pas* recommandé car les autres gems seront également mises à jour, ce qui n'est pas forcément le résultat attendu.
+Pour mettre à jour la gemme, spécifiez la nouvelle version dans le fichier Gemfile et exécutez `bundle` à nouveau.
+Utiliser `bundle update` *n*'est *pas* recommandé car les autres gemmes seront également mises à jour, ce qui n'est pas forcément le résultat voulu.
 
 === (c) Gestionnaire de paquets Linux
 
-==== Yum (Fedora 21 ou supérieure)
+==== DNF (Fedora 21 ou supérieure)
 
-Pour installer la gem sur Fedora 21 ou supérieure en utilisant yum, ouvrez un terminal et tapez :
+Pour installer la gemme sur Fedora 21 ou supérieure en utilisant dnf, ouvrez un terminal et tapez :
 
- $ sudo yum install -y asciidoctor
+ $ sudo dnf install -y asciidoctor
 
-Pour mettre à jour la gem, utilisez :
+Pour mettre à jour la gemme, utilisez :
 
- $ sudo yum update -y asciidoctor
+ $ sudo dnf update -y asciidoctor
 
-TIP: Votre système Fedora peut être configuré pour mettre à jour les paquets automatiquement, auquel cas aucune action de votre part ne sera nécessaire pour mettre à jour la gem.
+TIP: Votre système peut être configuré pour mettre à jour automatiquement les paquets rpm, auquel cas aucune action de votre part ne sera nécessaire pour mettre à jour la gemme.
 
-==== apt-get (Debian Sid, Ubuntu Saucy ou supérieure)
+==== apt-get (Debian, Ubuntu, Mint)
 
-Pour installer la gem sur Debian ou Ubuntu, ouvrez un terminal et tapez :
+Pour installer la gemme sur Debian, Ubuntu ou Mint, ouvrez un terminal et tapez :
 
  $ sudo apt-get install -y asciidoctor
 
-Pour mettre à jour la gem, utilisez :
+Pour mettre à jour la gemme, utilisez :
 
  $ sudo apt-get upgrade -y asciidoctor
 
-TIP: Votre système Debian ou Ubuntu peut être configuré pour mettre à jour les paquets automatiquement, auquel cas aucune action de votre part ne sera nécessaire pour mettre à jour la gem.
+TIP: Votre système peut être configuré pour mettre à jour automatiquement les paquets deb, auquel cas aucune action de votre part ne sera nécessaire pour mettre à jour la gemme.
+
+La version d'Asciidoctor installé par le gestionnaire de paquets (apt-get) peut ne pas correspondre à la dernière version d'Asciidoctor.
+Consultez le dépôt de paquets de votre distribution pour trouver quelle version est disponible par version de distribution.
+
+* https://packages.debian.org/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[Paquet asciidoctor par version de Debian]
+* http://packages.ubuntu.com/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[Paquet asciidoctor par version d'Ubuntu]
+* https://community.linuxmint.com/software/view/asciidoctor[Paquet asciidoctor par version de Mint]
+
+[CAUTION]
+====
+Il est déconseillé d'utiliser la commande `gem update` pour mettre à jour la gemme gérée par le gestionnaire de paquets.
+Le faire mettrait la système dans un état incohérent car le gestionnaire de paquets ne pourrait plus gérer les fichiers (qui sont installés dans /usr/local).
+En résumé, les gemmes du système doivent être gérées seulement par le gestionnaire de paquets.
+
+Si vous souhaitez utiliser une version d'Asciidoctor qui est plus récente que celle installée par votre gestionnaire de paquets, vous devriez utiliser http://rvm.io[RVM] pour installer Ruby dans votre répertoire personnel (dans votre espace utilisateur).
+Vous pouvez alors utiliser la commande `gem` pour installer ou mettre à jour la gemme Asciidoctor.
+En utilisant RVM, les gemmes sont installées dans un emplacement isolé du système.
+====
+
+==== apk (Alpine Linux)
+
+Pour installer la gemme sur Alpine Linux, ouvrez un terminal et tapez :
+
+ $ sudo apk add asciidoctor
+
+Pour mettre à jour la gemme, utilisez :
+
+ $ sudo apk add -u asciidoctor
+
+TIP: Votre système peut être configuré pour mettre à jour automatiquement les paquets apk, auquel cas aucune action de votre part ne sera nécessaire pour mettre à jour la gemme.
 
 === Autres options d'installation
 
-* {uri-install-doc}[Installation de l'outillage Asciidoctor]
+* {uri-install-docker}[Installation d'Asciidoctor avec Docker]
 * {uri-install-osx-doc}[Installation d'Asciidoctor sur Mac OS X]
+// pour l'instant, l'entrée suivante est juste une répétition de l'information dans ce README
+//* {uri-install-doc}[Installation de l'outillage Asciidoctor]
 
 == Utilisation
 
-Si la gem Asciidoctor s'est installée correctement, la ligne de commande (CLI) `asciidoctor` sera disponible dans votre PATH.
-Pour vérifier sa disponibilité, exécutez la commande suivante dans votre terminal :
+Si la gemme Asciidoctor s'est installée correctement, la ligne de commande (CLI) `asciidoctor` sera disponible dans votre PATH.
+Pour vérifier sa disponibilité, exécutez la commande suivante dans votre terminal :
 
  $ asciidoctor --version
 
@@ -211,7 +262,7 @@ Vous devriez voir les informations concernant la version d'Asciidoctor et celle
 
 [.output]
 ....
-Asciidoctor 1.5.3 [http://asciidoctor.org]
+Asciidoctor 1.5.4 [http://asciidoctor.org]
 Runtime Environment (ruby 2.2.2p95 [x86_64-linux]) (lc:UTF-8 fs:UTF-8 in:- ex:UTF-8)
 ....
 
@@ -220,22 +271,22 @@ Cette API permet une intégration avec d'autres logiciels Ruby, comme Rails, Sin
 
 === Interface de Ligne de Commande (CLI)
 
-La commande `asciidoctor` vous permet d'invoquer Asciidoctor à partir de la ligne de commande (càd, un terminal).
+La commande `asciidoctor` vous permet d'invoquer Asciidoctor à partir de la ligne de commande (c'est-à-dire, un terminal).
 
-La commande suivante convertit le fichier README.adoc en HTML et sauvegarde le résultat dans le fichier README.html dans le même dossier.
+La commande suivante convertit le fichier README.adoc en HTML et sauvegarde le résultat dans le fichier README.html dans le même répertoire.
 Le nom du fichier HTML généré est tiré de celui du fichier source, l'extension a été changée pour `.html`.
 
  $ asciidoctor README.adoc
 
-Vous pouvez contrôler le processeur Asciidoctor en ajoutant plusieurs paramètres, vous pouvez en apprendre plus sur ces derniers en utilisant la commande :
+Vous pouvez contrôler le processeur Asciidoctor en ajoutant plusieurs paramètres, vous pouvez en apprendre plus sur ces derniers en utilisant la commande :
 
  $ asciidoctor --help
 
-Par exemple, pour écrire le fichier dans un répertoire différent, utilisez :
+Par exemple, pour écrire le fichier dans un répertoire différent, utilisez :
 
  $ asciidoctor -D output README.adoc
 
-Le {uri-manpage}[man page] `asciidoctor` fournit une référence complète sur l'interface de ligne de commande.
+La {uri-manpage}[page man] `asciidoctor` fournit une référence complète sur l'interface de ligne de commande.
 
 Référez-vous aux ressources suivantes pour en apprendre davantage sur la façon d'utiliser la commande `asciidoctor`.
 
@@ -244,21 +295,21 @@ Référez-vous aux ressources suivantes pour en apprendre davantage sur la faço
 
 === API Ruby
 
-Pour utiliser Asciidoctor dans votre application, vous avez tout d'abord besoin de faire un require sur la gem :
+Pour utiliser Asciidoctor dans votre application, vous avez tout d'abord besoin de faire un « require » sur la gemme :
 
 [source]
 require 'asciidoctor'
 
-Vous pouvez ensuite convertir un fichier AsciiDoc en fichier HTML en utilisant :
+Vous pouvez ensuite convertir un fichier AsciiDoc en fichier HTML en utilisant :
 
 [source]
 Asciidoctor.convert_file 'README.adoc', to_file: true, safe: :safe
 
 WARNING: Quand vous utilisez Asciidoctor via l'API, le mode de sûreté par défaut est `:secure`.
-Dans le mode secure, plusieurs fonctionnalités centrales sont désactivées, comme la directive `include`.
-Si vous souhaitez activer ces fonctionnalités, vous aurez besoin de définir explicitement le mode de sûreté avec une la valeur `:server` ou `:safe`.
+Dans le mode « secure », plusieurs fonctionnalités centrales sont désactivées, comme la directive `include`.
+Si vous souhaitez activer ces fonctionnalités, vous aurez besoin de définir explicitement le mode de sûreté avec une la valeur `:server` (recommandée) ou `:safe`.
 
-Vous pouvez aussi convertir une chaîne de texte en fragment HTML (pour une insertion dans une page HTML) en utilisant :
+Vous pouvez aussi convertir une chaîne de texte en fragment HTML (pour une insertion dans une page HTML) en utilisant :
 
 [source]
 ----
@@ -266,7 +317,7 @@ content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
 Asciidoctor.convert content, safe: :safe
 ----
 
-Si vous voulez le document HTML complet, activez l'option `header_footer` comme ci-dessous :
+Si vous voulez le document HTML complet, activez l'option `header_footer` comme ci-dessous :
 
 [source]
 ----
@@ -274,7 +325,7 @@ content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
 html = Asciidoctor.convert content, header_footer: true, safe: :safe
 ----
 
-Si vous avez besoin d'accèder au document analysé, vous pouvez séparer la conversion en deux étapes distinctes :
+Si vous avez besoin d'accéder au document analysé, vous pouvez séparer la conversion en deux étapes distinctes :
 
 [source]
 ----
@@ -284,10 +335,10 @@ puts document.doctitle
 html = document.convert
 ----
 
-Gardez en tête que si vous n'aimez pas le contenu généré par Asciidoctor, _vous pouvez le changer !_
-Asciidoctor supporte des convertisseurs personnalisés qui peuvent prendre en charge la conversion du document analysé vers un contenu généré.
+Gardez en tête que si vous n'aimez pas le contenu généré par Asciidoctor, _vous pouvez le changer !_
+Asciidoctor supporte des convertisseurs personnalisés qui peuvent prendre en charge la conversion depuis le document analysé jusqu'au contenu généré.
 
-Une façon simple de personnaliser les morceaux de contenu généré est d'utiliser le convertisseur de template.
+Une façon simple de personnaliser les morceaux de contenu générés est d'utiliser le convertisseur de template.
 Le convertisseur de template vous permet, en utilisant un template supporté par {uri-tilt}[Tilt], de prendre en charge la conversion de n'importe quel élément dans le document.
 
 Vous l'aurez compris, vous _pouvez_ complètement prendre le contrôle sur le contenu généré.
@@ -296,10 +347,10 @@ Pour plus d'informations sur comment utiliser l'API ou personnaliser le contenu
 == Contributions
 
 Dans l'esprit du {uri-freesoftware}[logiciel libre], _tout le monde_ est encouragé à aider en vue d'améliorer le projet.
-Si vous découvrez des erreurs ou des oublis dans le code source, la documentation, ou le contenu du site web, s'il vous plaît n'hésitez pas à ouvrir un ticket ou une pull request avec un correctif.
-Les contributeurs et contributrices sont toujours les bienvenus !
+Si vous découvrez des erreurs ou des oublis dans le code source, la documentation, ou le contenu du site web, s'il vous plaît n'hésitez pas à ouvrir un ticket ou une « pull request » avec un correctif.
+Les contributeurs et contributrices sont toujours les bienvenus !
 
-Voici quelques façons de contribuer :
+Voici quelques façons de contribuer :
 
 * en utilisant les versions prerelease (alpha, beta ou preview),
 * en rapportant des anomalies,
@@ -310,7 +361,7 @@ Voici quelques façons de contribuer :
 ** corriger une coquille,
 ** ajouter des commentaires,
 ** nettoyer des espaces inutiles,
-** écrire des tests !
+** écrire des tests !
 * en refactorant le code,
 * en corrigeant des {uri-issues}[anomalies],
 * en effectuant des relectures des patches.
@@ -320,30 +371,32 @@ Le guide du {uri-contribute}[parfait Contributeur] fournit des informations sur
 == Être aidé
 
 Le projet Asciidoctor est développé pour vous aider à écrire et publier du contenu.
-Mais nous ne pouvons pas le faire sans avoir vos avis !
-Nous vous encourageons à poser vos questions et discuter de n'importe quels aspects du projet sur la liste de discussion, Twitter ou IRC.
+Mais nous ne pouvons pas le faire sans avoir vos avis !
+Nous vous encourageons à poser vos questions et discuter de n'importe quels aspects du projet sur la liste de discussion, Twitter ou dans le salon de discussion.
 
 Mailing list:: {uri-discuss}
-Twitter (Chat):: hashtag #asciidoctor
+Twitter (Chat):: hashtag #asciidoctor ou la mention @asciidoctor
 Gitter (Chat):: image:https://badges.gitter.im/Join%20In.svg[Gitter, link=https://gitter.im/asciidoctor/asciidoctor]
+////
 IRC (Chat):: {uri-irc}[#asciidoctor] sur FreeNode IRC
+////
 
 ifdef::env-github[]
-De plus amples informations et documentation sur Asciidoctor peuvent être trouvé sur le site web du projet.
+De plus amples informations et documentations sur Asciidoctor peuvent être trouvées sur le site web du projet.
 
 {uri-project}/[Home] | {uri-news}[News] | {uri-docs}[Docs]
 endif::[]
 
 L'organisation Asciidoctor sur GitHub héberge le code source du projet, le gestionnaire de tickets ainsi que des sous-projets.
 
-Repository des sources (git):: {uri-repo}
+Dépôt des sources (git):: {uri-repo}
 Gestionnaire de tickets:: {uri-issues}
 L'organisation Asciidoctor sur GitHub:: {uri-org}
 
 == Copyright et licence
 
 Copyright (C) 2012-2016 Dan Allen, Ryan Waldron et le projet Asciidoctor.
-Une utilisation libre de ce logiciel est autorisé sous les termes de la licence MIT.
+Une utilisation libre de ce logiciel est autorisée sous les termes de la licence MIT.
 
 Consultez le fichier {uri-license}[LICENSE] pour plus de détails.
 
diff --git a/README-jp.adoc b/README-jp.adoc
new file mode 100644
index 0000000..b698626
--- /dev/null
+++ b/README-jp.adoc
@@ -0,0 +1,395 @@
+= Asciidoctor
+Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>; Ryan Waldron <https://github.com/erebor[@erebor]>
+// settings:
+:page-layout: base
+:idprefix:
+:idseparator: -
+:source-language: ruby
+:language: {source-language}
+ifdef::env-github[:status:]
+// URIs:
+:uri-org: https://github.com/asciidoctor
+:uri-repo: {uri-org}/asciidoctor
+:uri-asciidoctorj: {uri-org}/asciidoctorj
+:uri-asciidoctorjs: {uri-org}/asciidoctor.js
+:uri-project: http://asciidoctor.org
+ifdef::env-site[:uri-project: link:]
+:uri-docs: {uri-project}/docs
+:uri-news: {uri-project}/news
+:uri-manpage: {uri-project}/man/asciidoctor
+:uri-issues: {uri-repo}/issues
+:uri-contributors: {uri-repo}/graphs/contributors
+:uri-rel-file-base: link:
+:uri-rel-tree-base: link:
+ifdef::env-site[]
+:uri-rel-file-base: {uri-repo}/blob/master/
+:uri-rel-tree-base: {uri-repo}/tree/master/
+endif::[]
+:uri-changelog: {uri-rel-file-base}CHANGELOG.adoc
+:uri-contribute: {uri-rel-file-base}CONTRIBUTING.adoc
+:uri-license: {uri-rel-file-base}LICENSE.adoc
+:uri-tests: {uri-rel-tree-base}test
+:uri-discuss: http://discuss.asciidoctor.org
+:uri-irc: irc://irc.freenode.org/#asciidoctor
+:uri-rubygem: https://rubygems.org/gems/asciidoctor
+:uri-what-is-asciidoc: {uri-docs}/what-is-asciidoc
+:uri-user-manual: {uri-docs}/user-manual
+:uri-install-docker: https://github.com/asciidoctor/docker-asciidoctor
+//:uri-install-doc: {uri-docs}/install-toolchain
+:uri-install-osx-doc: {uri-docs}/install-asciidoctor-macosx
+:uri-render-doc: {uri-docs}/render-documents
+:uri-themes-doc: {uri-docs}/produce-custom-themes-using-asciidoctor-stylesheet-factory
+:uri-gitscm-repo: https://github.com/git/git-scm.com
+:uri-prototype: {uri-gitscm-repo}/commits/master/lib/asciidoc.rb
+:uri-freesoftware: https://www.gnu.org/philosophy/free-sw.html
+:uri-foundation: http://foundation.zurb.com
+:uri-tilt: https://github.com/rtomayko/tilt
+:uri-ruby: https://ruby-lang.org
+// images:
+:image-uri-screenshot: https://raw.githubusercontent.com/asciidoctor/asciidoctor/master/screenshot.png
+
+{uri-project}/[Asciidoctor]は _高速な_ テキストプロセッサで {uri-what-is-asciidoc}[Asciidoc] をHTML5, DocBook 5(4.5)や他のフォーマットに変換するツールチェインを配布しています.
+AsciidoctorはRubyで書かれており, RubyGemとしてパッケージされ,  {uri-rubygem}[RubyGems.org] で配布されています.
+gemはいくつかのLinuxディストリビューション, Fedora, Debian, Ubuntuにも含まれています.
+Asciidoctorはオープンソース {uri-repo}[hosted on Github] で {uri-license}[the MIT licence]のもとに配布されます.
+
+ifndef::env-site[]
+.Translations of the document are available in the following languages:
+* {uri-rel-file-base}README-zh_CN.adoc[汉语]
+* {uri-rel-file-base}README.adoc[English]
+* {uri-rel-file-base}README-fr.adoc[Français]
+endif::[]
+
+.Key documentation
+[.compact]
+* {uri-docs}/what-is-asciidoc[What is Asciidoc?]
+* {uri-docs}/asciidoc-writers-guide[AsciiDoc Writer's Guide]
+* {uri-docs}/asciidoc-syntax-quick-reference[AsciiDoc Syntax Reference]
+* {uri-docs}/user-manual[Asciidoctor User Manual]
+
+.Rubyの行く先, Asciidoctorの追うところ
+****
+AsciidoctorはJRubyを用いてJVM上でも実行できます.
+Javaや他のJVM言語からAsciidoctor APIを直接呼び出すには,  {uri-asciidoctorj}[AsciidoctorJ] を使ってください.
+AsciidoctorJに基づいた, AsciidoctorプロセッサをApache Maven, GradleやJavadocに統合するプラグインがあります.
+
+AsciidoctorはJavaScriptでも実行可能です.
+{uri-asciidoctorjs}[Asciidoctor.js], WebブラウザやNode.jsのようなJavaScript環境で動くAsciidoctorの完全機能版, を生成するために, RubyのソースをJavaScriptにトランスパイルするのに http://opalrb.org[Opal]を使います.
+Asciidoctor.jsはChrome, Atom, Brackets や他のウェブベースのツールの拡張機能としてAsciiDocのプレビューのために使われます.
+****
+
+ifdef::status[]
+.*Project health*
+image:https://img.shields.io/travis/asciidoctor/asciidoctor/master.svg[Build Status (Travis CI), link=https://travis-ci.org/asciidoctor/asciidoctor]
+image:https://ci.appveyor.com/api/projects/status/ifplu67oxvgn6ceq/branch/master?svg=true&passingText=green%20bar&failingText=%23fail&pendingText=building%2E%2E%2E[Build Status (AppVeyor), link=https://ci.appveyor.com/project/asciidoctor/asciidoctor]
+//image:https://img.shields.io/coveralls/asciidoctor/asciidoctor/master.svg[Coverage Status, link=https://coveralls.io/r/asciidoctor/asciidoctor]
+image:https://codeclimate.com/github/asciidoctor/asciidoctor/badges/gpa.svg[Code Climate, link="https://codeclimate.com/github/asciidoctor/asciidoctor"]
+image:https://inch-ci.org/github/asciidoctor/asciidoctor.svg?branch=master[Inline docs, link="https://inch-ci.org/github/asciidoctor/asciidoctor"]
+endif::[]
+
+== The Big Picture
+
+Asciidoctorは下図の左側のパネルに示されるように, 平文で書かれた内容を読み, 右のパネルに描かれるようにHTML5に変換します.
+Asciidoctorは枠にとらわれない快適なエクスペリエンスのためにデフォルトスタイルシートをHTML5時メントに適用します.
+
+image::{image-uri-screenshot}[Preview of AsciiDoc source and corresponding rendered HTML]
+
+== AsciiDoc Processing
+AsciidoctorはAsciiDoc文法で書かれたテキストを読み込み解釈し, それからHTML5, DocBook5(4.5)やman(ual)を出力するために内蔵コンバータセットにパースツリーを渡します.
+生成された出力をカスタマイズ, あるいは追加のフォーマットをつくるためにあなた自身のコンバータを使うことや {uri-tilt}[Tilt]-supported テンプレートを読み込むオプションがあります.
+
+NOTE: AsciidoctorはオリジナルのAsciiDoc Pythonプロセッサ(`asciidoc.py`)の完全互換です.
+Asciidoctorテストスイートは {uri-tests}[> 1,600 tests] をAsciiDoc文法との互換性を保証するために有しています.
+
+クラシックなAsciiDoc文法に加えて, Asciidoctorは追加のマークアップとフォントベースのicons(例えば, `+icon:fire[]+`)などのフォーマッティングオプションとUIエレメント(`+button:[Save]+`)を  受け付けます.
+AsciidoctorはHTML5出力をスタイルするため, モダンで,  {uri-foundation}[Foundation] に基づいたレスポンシブテーマをも提供します.
+
+== Requirements
+
+AsciidoctorはLinux, OS X (Mac)とWindowsで動き, 下記の {uri-ruby}[Ruby]実装の一つを必要とします.
+
+* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1, 2.2 & 2.3)
+* JRuby (1.7 in Ruby 1.8 and 1.9 modes, 9000)
+* Rubinius 2.2.x
+* Opal (JavaScript)
+
+[CAUTION]
+====
+もし非英語環境のWindowsを使っているなら, Asciidoctorを起動した時に`Encoding::UndefinedConversionError`に遭遇するでしょう.
+これを解決するには使っているコンソールの有効なコードページをUTF-8:
+
+ chcp 65001
+
+に変更することを推奨します.
+一度この変更をすると, Unicode関連の頭痛の種は消えるでしょう.
+もしEclipseのようなIDEを使っているなら, 同様にエンコーディングをUTF-8にするのを忘れないでください.
+AsciidoctorはUTF-8が使われているところで最高の働きを見せます.
+====
+
+== Installation
+
+Asciidoctorは (a) `gem install` コマンド,  (b) Bundler あるいは (c) 有名Linuxディストリビューションのパッケージマネージャ を用いてインストールされます.
+
+TIP: Linuxパッケージマネージャを用いてインストールすることの利点は, もしRubyやRubyGemsライブラリがまだインストールされていなかったら, それらを処理してくれることです.
+欠点はgemのリリース直後にはすぐには有効にならないことです.
+もし最新バージョンを使いたければ, 必ず `gem` コマンドを使いましょう.
+
+=== (a) gem install
+
+ターミナルを開, 入力しましょう (先頭の`$`は除く):
+
+ $ gem install asciidoctor
+
+もし, 先行リリースバージョン(例えばリリース候補版)をインストールしたければ
+
+ $ gem install asciidoctor --pre
+
+.アップグレード
+[TIP]
+====
+もしAsciidoctorの以前のバージョンあインストール済みであれば, 以下によってアップデートできます:
+ 
+ $ gem update asciidoctor
+
+もし gem update の代わりに `gem install` を使ってgemを新バージョンにした場合, 複数バージョンばインストールされるでしょう.
+そのときは, 以下のgemコマンドで古いバージョンを削除しましょう:
+
+ $ gem cleanup asciidoctor
+====
+
+=== (b) Bundler
+
+. プロジェクトフォルダーのルート(かカレントディレクトリ)にGemfileを作成
+. `asciidoctor` gemをGemfileに以下のように追加:
++
+[source]
+----
+source 'https://rubygems.org'
+gem 'asciidoctor'
+# or specify the version explicitly
+# gem 'asciidoctor', '1.5.4'
+----
+
+. Gemfileを保存
+. ターミナルを開き, gemをインストール:
+
+ $ bundle
+
+gemをアップグレードするには, Gemfileで新バージョンを指定し, `bundle` を再び実行してください.
+`bundle update` は他のgemもアップデートするため推奨されて *いない* ので, 思わぬ結果になるかも知れません.
+
+=== (c) Linux package managers
+
+==== DNF (Fedora 21 or greater)
+
+dnfを使いFedora21かそれ以上にインストールするには, ターミナルを開き, 以下を入力してください:
+
+ $ sudo dnf install -y asciidoctor
+
+gemをアップグレードするには:
+
+ $ sudo dnf update -y asciidoctor
+
+TIP: お使いのシステムは自動的にrpmパッケージをアップデートするよう設定されているかも知れません.その場合, gemのアップデートのためにあなたがすべきことはありません.
+
+==== apt-get (Debian, Ubuntu, Mint)
+
+Debian, UbuntuまたはMintにインストールするには, ターミナルを開き, 以下を入力してください:
+
+ $ sudo apt-get install -y asciidoctor
+
+gemをアップグレードするには:
+ 
+ $ sudo apt-get upgrade -y asciidoctor
+
+TIP: お使いのシステムは自動的にdebパッケージをアップデートするよう設定されているかも知れません.その場合, gemのアップデートのためにあなたがすべきことはありません.
+
+パッケージマネージャ(apt-get)によってインストールされたバージョンのAsciidoctorは最新リリースのAsciidoctorではないかもしれません.
+ディストリビューションのリリース毎に, どのバージョンがパッケージされているかはパッケージリポジトリを調べてください.
+
+* https://packages.debian.org/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[asciidoctor package by Debian release]
+* http://packages.ubuntu.com/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[asciidoctor package by Ubuntu release]
+* https://community.linuxmint.com/software/view/asciidoctor[asciidoctor package by Mint release]
+
+[CAUTION]
+====
+パッケージマネージャによって管理されているgemをアップデートするのに `gem udpate` コマンドを使うなといわれるでしょう.
+そのようなことをするのは, パッケージマネージャがファイル(/usr/local下にインストールされた)を追跡できなくなるためにシステムが不安定な状態にするためです.
+単純に, システムgemはパッケージマネージャによってのみ管理されるべきです.
+
+もし, パッケージマネージャによってインストールされたのより新しいバージョンのAsciidoctorを使いたければ,  http://rvm.io[RVM] や https://github.com/rbenv/rbenv[rbenv]を使ってRubyをホームディレクトリ(すなわち, ユーザースペース)にインストールするべきです.
+それから, 安心して `gem` コマンドをAsciidoctorのアップデート, インストールのために使うことができます.
+RVMやrbenvを使っているなら, gemはシステムからは孤立した場所にインストールされます.
+====
+
+==== apk (Alpine Linux)
+
+Alpine Linuxにgemをインストールするには, ターミナルを開き, 以下を入力してください:
+
+ $ sudo apk add asciidoctor
+
+gemをアップグレードするには:
+
+ $ sudo apk add -u asciidoctor
+
+TIP: お使いのシステムは自動的にapkパッケージをアップデートするよう設定されているかも知れません.その場合, gemのアップデートのためにあなたがすべきことはありません.
+
+=== Other installation options
+
+* {uri-install-docker}[Installing Asciidoctor using Docker]
+* {uri-install-osx-doc}[Installing Asciidoctor on Mac OS X]
+// at the moment, the following entry is just a reiteration of the information in this README
+//* {uri-install-doc}[Installing the Asciidoctor toolchain]
+
+== Usage
+
+Asciidoctorのインストールに成功すれば,  `asciidoctor` コマンドラインインターフェース(CLI)がPATH中で有効になります.
+確認のために, 以下をターミナルで実行しましょう:
+
+ $ asciidoctor --version
+
+AsciidoctorのバージョンとRuby環境についての情報がターミナルに出力されたのを見ることができるはずです.
+
+[.output]
+....
+Asciidoctor 1.5.4 [http://asciidoctor.org]
+Runtime Environment (ruby 2.2.2p95 [x86_64-linux]) (lc:UTF-8 fs:UTF-8 in:- ex:UTF-8)
+....
+
+AsciidoctorはAPIを提供します.
+APIは他のRubyソフトウェア, Rails, SinatraとGitHub, そして他の言語, Java (via {uri-asciidoctorj}[AsciidoctorJ] )とJavaScript (via {uri-asciidoctorjs}[Asciidoctor.js])との統合を意図しています.
+
+=== Command line interface (CLI)
+
+`asciidoctorjs` コマンドはAsciidoctorをコマンドライン(つまりターミナル)から起動することを可能にします.
+
+次のコマンドはファイルREADME.adocをHTMLに変換し, 結果を同じディレクトリのREADME.htmlに保存します.
+生成されたHTMLファイルの名前はソースファイル依存し, その拡張子を `.html` に変えます.
+
+ $ asciidoctor README.adoc
+
+Asciidoctorプロセッサに様々なフラグやスイッチを与えることで制御できます.それは以下を用いて調べることができます:
+
+ $ asciidoctor --help
+
+例えば, ファイルを異なるディレクトリに書き出すには:
+
+ $ asciidoctor -D output README.adoc
+
+`asciidoctor` {uri-manpage}[man page] はコマンドライン・インタフェースの完全なリファレンスを提供します.
+
+`asciidoctor` コマンドの使い方についてもっと学ぶには以下を参照してください.
+
+* {uri-render-doc}[How do I convert a document?]
+* {uri-themes-doc}[How do I use the Asciidoctor stylesheet factory to produce custom themes?]
+
+=== Ruby API
+
+Asciidoctorをアプリケーションの中で使うには, まずgemをrequireする必要があります:
+
+[source]
+require 'asciidoctor'
+
+それから, AsciiDocソースファイルをHTMLファイルに変換できます:
+
+[source]
+Asciidoctor.convert_file 'README.adoc', to_file: true, safe: :safe
+
+WARNING: AsciidoctorをAPI経由で使っている時, デフォルトのセーフモードは `:secure` です.
+セキュアモードでは,  `include` ディレクティブを含むいくつかのコア機能は無効化されています.
+もしこれらの機能を有効化したい場合, 明示的にセーフモードを `:server` (推奨)か `:safe` にする必要があります.
+
+AsciiDoc文字列を埋め込みHTML(HTMLページヘの挿入)へ変換することもできます:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+Asciidoctor.convert content, safe: :safe
+----
+
+もし完全なHTMLドキュメントを求めるのであれば,  `header_footer` オプションを以下の通り有効にしてください:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+html = Asciidoctor.convert content, header_footer: true, safe: :safe
+----
+
+パースされたドキュメントにアクセスしたいのなら, 変換を個々のステップに分割することが出来ます:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+document = Asciidoctor.load content, header_footer: true, safe: :safe
+puts document.doctitle
+html = document.convert
+----
+
+Asciidoctorの生成する出力が気に入らないのであれば,  _あなたはそれを変更できる_ ことを忘れないでください!
+Asciidoctorはパースされたドキュメントを生成された出力に変換する処理を扱うカスタムコンバーターをサポートしています.
+
+断片的な出力をカスタマイズする簡単な方法の一つはテンプレートコンバーターを使うことです.
+テンプレートコンバーターによって, ドキュメント中のあらゆるノードの変換を扱うために {uri-tilt}[Tilt]-supportedテンプレートファイルを使うことができます.
+
+そのようにすれば, 出力を100%制御することが _できます_ .
+APIの使い方や出力のカスタマイズ方法についてのより詳しい情報は {uri-user-manual}[user manual] を参照してください.
+
+== Contributing
+
+{uri-freesoftware}[free software] の精神においては,  _everyone_ がこのプロジェクトを改良するのをたすけることが勧められている.
+もしエラーや手抜かりをソースコード, ドキュメント, あるいはウェブサイトに見つけたのなら, 恥じることなく修正と共にpull requestの開設やissueの送信をしてください.
+New contributors are always welcome!
+
+*あなた*  にもできることがあります:
+
+* 先行バージョン(alpha, beta or preview)の使用
+* バグレポート
+* 新機能提案
+* ドキュメントの執筆
+* 仕様の執筆
+* コーディング -- _パッチでも, 足りなすぎるなんてことはありません_
+** typoの修正
+** コメントの追加
+** 一貫性のないホワイトスペースの除去
+** テストの記述!
+* リファクタリング
+*  {uri-issues}[issues] の修正
+* パッチの批評
+
+{uri-contribute}[Contributing] ガイドはどうやってスタイルをつくるか, issueを送るか, 機能リクエスト, コーディング, ドキュメンテーションをAsciidoctor Projectにするかの情報を提供しています.
+
+== Getting Help
+
+Asciidoctorプロジェクトはあなたが簡単に著作を書いて, 配布するのをたすけるため開発されています.
+しかしあなたのフィードバックなしにはできません!
+ディスカッションリストで, Twitterで, チャットルームで, 質問し, プロジェクトのあらゆる側面について話し合うようお勧めします.
+
+Discussion list (Nabble):: {uri-discuss}
+Twitter:: #asciidoctor hashtag or @asciidoctor mention
+Chat (Gitter):: image:https://badges.gitter.im/Join%20In.svg[Gitter, link=https://gitter.im/asciidoctor/asciidoctor]
+
+ifdef::env-github[]
+Further information and documentation about Asciidoctor can be found on the project's website.
+
+{uri-project}/[Home] | {uri-news}[News] | {uri-docs}[Docs]
+endif::[]
+
+GitHub上のAsciidoctorはプロジェクトのソースコード, イシュートラッカー, サブプロジェクトを管理しています.
+
+Source repository (git):: {uri-repo}
+Issue tracker:: {uri-issues}
+Asciidoctor organization on GitHub:: {uri-org}
+
+== Copyright and Licensing
+
+Copyright (C) 2012-2016 Dan Allen, Ryan Waldron and the Asciidoctor Project.
+Free use of this software is granted under the terms of the MIT License.
+
+See the {uri-license}[LICENSE] file for details.
+
+== Authors
+
+*Asciidoctor* is led by https://github.com/mojavelinux[Dan Allen] and https://github.com/graphitefriction[Sarah White] and has received contributions from {uri-contributors}[many other individuals] in Asciidoctor's awesome community.
+The project was initiated in 2012 by https://github.com/erebor[Ryan Waldron] and based on {uri-prototype}[a prototype] written by https://github.com/nickh[Nick Hengeveld].
+
+*AsciiDoc* was started by Stuart Rackham and has received contributions from many other individuals in the AsciiDoc community.
diff --git a/README-zh_CN.adoc b/README-zh_CN.adoc
new file mode 100644
index 0000000..75f287d
--- /dev/null
+++ b/README-zh_CN.adoc
@@ -0,0 +1,414 @@
+= Asciidoctor
+Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>; Ryan Waldron <https://github.com/erebor[@erebor]>
+// settings:
+:page-layout: base
+:idprefix:
+:idseparator: -
+:source-language: ruby
+:language: {source-language}
+ifdef::env-github[:status:]
+// URIs:
+:uri-org: https://github.com/asciidoctor
+:uri-repo: {uri-org}/asciidoctor
+:uri-asciidoctorj: {uri-org}/asciidoctorj
+:uri-asciidoctorjs: {uri-org}/asciidoctor.js
+:uri-project: http://asciidoctor.org
+ifdef::env-site[:uri-project: link:]
+:uri-docs: {uri-project}/docs
+:uri-news: {uri-project}/news
+:uri-manpage: {uri-project}/man/asciidoctor
+:uri-issues: {uri-repo}/issues
+:uri-contributors: {uri-repo}/graphs/contributors
+:uri-rel-file-base: link:
+:uri-rel-tree-base: link:
+ifdef::env-site[]
+:uri-rel-file-base: {uri-repo}/blob/master/
+:uri-rel-tree-base: {uri-repo}/tree/master/
+endif::[]
+:uri-changelog: {uri-rel-file-base}CHANGELOG.adoc
+:uri-contribute: {uri-rel-file-base}CONTRIBUTING.adoc
+:uri-license: {uri-rel-file-base}LICENSE.adoc
+:uri-tests: {uri-rel-tree-base}test
+:uri-discuss: http://discuss.asciidoctor.org
+:uri-irc: irc://irc.freenode.org/#asciidoctor
+:uri-rubygem: https://rubygems.org/gems/asciidoctor
+:uri-what-is-asciidoc: {uri-docs}/what-is-asciidoc
+:uri-user-manual: {uri-docs}/user-manual
+:uri-install-docker: https://github.com/asciidoctor/docker-asciidoctor
+//:uri-install-doc: {uri-docs}/install-toolchain
+:uri-install-osx-doc: {uri-docs}/install-asciidoctor-macosx
+:uri-render-doc: {uri-docs}/render-documents
+:uri-themes-doc: {uri-docs}/produce-custom-themes-using-asciidoctor-stylesheet-factory
+:uri-gitscm-repo: https://github.com/git/git-scm.com
+:uri-prototype: {uri-gitscm-repo}/commits/master/lib/asciidoc.rb
+:uri-freesoftware: https://www.gnu.org/philosophy/free-sw.html
+:uri-foundation: http://foundation.zurb.com
+:uri-tilt: https://github.com/rtomayko/tilt
+:uri-ruby: https://ruby-lang.org
+// images:
+:image-uri-screenshot: https://raw.githubusercontent.com/asciidoctor/asciidoctor/master/screenshot.png
+
+{uri-project}/[Asciidoctor] 是一个 _快速_ 文本处理器和发布工具链,它可以将 {uri-what-is-asciidoc}[AsciiDoc] 文档转化成 HTML5、 DocBook 5 (或 4.5) 以及其他格式。
+Asciidoctor 由 Ruby 编写,打包成 RubyGem,然后发布到 {uri-rubygem}[RubyGems.org] 上。
+这个 gem 还被包含道几个 Linux 发行版中,其中包括 Fedora、Debian 和 Ubuntu。
+Asciidoctor 是开源的,{uri-repo}[代码托管在 GitHub],并且是以 {uri-license}[MIT 协议]授权。
+
+.该文档有如下语言的翻译版:
+* {uri-rel-file-base}README.adoc[English]
+* {uri-rel-file-base}README-fr.adoc[Français]
+
+.关键文档
+[.compact]
+* {uri-docs}/what-is-asciidoc[什么是 Asciidoctor?]
+* {uri-docs}/asciidoc-writers-guide[AsciiDoc 作家指南]
+* {uri-docs}/asciidoc-syntax-quick-reference[AsciiDoc 语法快速参考]
+* {uri-docs}/user-manual[Asciidoctor 用户手册]
+
+.Ruby 所至, Asciidoctor 相随
+****
+使用 JRuby 可以让 Asciidoctor 运行在 Java 虚拟机上。
+使用 {uri-asciidoctorj}[AsciidoctorJ] 就可以让 Java 或者其他 Java 虚拟机语言直接调用 Asciidoctor API。
+基于 AsciidoctorJ 有好多好多插件可用,这些插件可以将 Asciidoctor 整合到 Apache Maven,Gradle 或 Javadoc 构建中。
+
+Asciidoctor 也可以运行在 JavaScript 上。
+我们可以使用 http://opalrb.org[Opal] 将 Ruby 源码编译成 JavaScript 并生成 {uri-asciidoctorjs}[Asciidoctor.js],这是一个全功能版的 Asciidoctor,可以运行在任意的 JavaScript 环境中,比如 Web 浏览器 或 Node.js。
+Asciidoctor.js 被用于 AsciiDoc 预览,支持 Chrome 扩展,Atom,Brackets 或其他基于 Web 的工具。
+****
+
+ifdef::badges[]
+.*Project health*
+image:https://img.shields.io/travis/asciidoctor/asciidoctor/master.svg[Build Status (Travis CI), link=https://travis-ci.org/asciidoctor/asciidoctor]
+image:https://ci.appveyor.com/api/projects/status/ifplu67oxvgn6ceq/branch/master?svg=true&passingText=green%20bar&failingText=%23fail&pendingText=building%2E%2E%2E[Build Status (AppVeyor), link=https://ci.appveyor.com/project/asciidoctor/asciidoctor]
+//image:https://img.shields.io/coveralls/asciidoctor/asciidoctor/master.svg[Coverage Status, link=https://coveralls.io/r/asciidoctor/asciidoctor]
+image:https://codeclimate.com/github/asciidoctor/asciidoctor/badges/gpa.svg[Code Climate, link="https://codeclimate.com/github/asciidoctor/asciidoctor"]
+image:https://inch-ci.org/github/asciidoctor/asciidoctor.svg?branch=master[Inline docs, link="https://inch-ci.org/github/asciidoctor/asciidoctor"]
+endif::[]
+
+[#the-big-picture]
+== 全局概况
+
+Asciidoctor 以纯文本格式读取内容,见下图左边的面板,将它转换成 HTML5 呈现在右侧面板中。
+Asciidoctor 将默认的样式表应用到 HTML5 文档上,提供一个愉快的开箱即用的体验。
+
+image::{image-uri-screenshot}[AsciiDoc 源文预览和相应的 HTML 渲染]
+
+[#asciidoc-processing]
+== AsciiDoc Processing
+
+Asciidoctor 读取并处理以 AsciiDoc 语法写作的文件,然后然后将解析出来的解析树交给内置的转化器生成 HTML5,DocBook 5 (或 4.5) 或帮助手册页面输出。
+你可以选择使用你自己的转化器或者加载 {uri-tilt}[Tilt] - 支持通过模板来自定义输出或产生附加的格式。
+
+NOTE: Asciidoctor是为了直接替换原 AsciiDoc Python 处理器(`asciidoc.py`)。
+Asciidoctor 测试套件含有 {uri-tests}[> 1,600 测试用例] 来确保和 AsciiDoc 语法的兼容性。
+
+除了经典的 AsciiDoc 语法,Asciidoctor 还添加额外的标记和格式设置选项,例如 font-based 图标(例如: `+icon:fire[]+`)和 UI 元素(例如: `+button:[Save]+`)。
+Asciidoctor 还提供了一个基于 {uri-foundation}[Foundation] 的现代的、响应式主题来美化 HTML5 输出。
+
+[#requirements]
+== 要求
+
+Asciidoctor 可以在 Linux,OSX (Mac) 和 Windows,并且需要下面其中一个 {uri-ruby}[Ruby] 实现:
+
+* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1, 2.2 & 2.3)
+* JRuby (1.7 in Ruby 1.8 and 1.9 modes, 9000)
+* Rubinius 2.2.x
+* Opal (JavaScript)
+
+我们欢迎你来帮助在这些以及其他平台测试 Asciidoctor。
+参考 <<{idprefix}contributing,Contributing>> 来学习如何参与进来。
+
+[CAUTION]
+====
+如果你使用一个非英语的 Windows 环境,当调用 Asciidoctor 时,可能会碰到 `Encoding::UndefinedConversionError` 错误。
+为了解决这个问题,我们建议将控制台的编码更改为 UTF-8:
+
+ chcp 65001
+
+一旦你做了这个改变,所有的编码问题,都将迎刃而解。
+只要你在任何地方都是 UTF-8,Asciidoctor 总会工作地很好。
+====
+
+[#installation]
+== 安装
+
+Asciidoctor 可以通过三种方式安装:(a) 使用 `gem install` 命令;(b) 使用 Bundler;(c) 流行的 Linux 发行版的包管理器
+
+TIP: 使用 Linux 包管理器安装的好处是如果 Ruby 和 RubyGems 库没有在你的机器上安装,它会一并安装上去。
+不利的是在 gem 发布之后,这类安装包并不是立即可用。
+如果你需要最新版,你应该总是优先使用 `gem` 命令安装。
+
+[#a-gem-install]
+=== (a) gem 安装
+
+打开一个终端输入如下命令(不含开头的 `$`):
+
+ $ gem install asciidoctor
+
+如果想安装一个预览版(比如:候选发布版),请使用:
+
+ $ gem install asciidoctor --pre
+
+.升级
+[TIP]
+====
+如果你安装有一个旧版本的 Asciidoctor,你可以使用下面的命令来升级:
+
+ $ gem update asciidoctor
+
+如果使用 `gem install` 命令来安装一个新版本的 gem 来代替升级,则会安装多个版本。
+如果是这种情况,使用下面的 gem 命令来移除旧版本:
+
+ $ gem cleanup asciidoctor
+====
+
+[#b-bundler]
+=== (b) Bundler
+
+. 在项目的根目录(或者当前路径),创建一个 `Gemfile` 文件;
+. 在这个文件中添加 `asciidoctor` gem 如下:
++
+[source]
+----
+source 'https://rubygems.org'
+gem 'asciidoctor'
+# 或者明确指明版本
+# gem 'asciidoctor', '1.5.4'
+----
+
+. 保存 `Gemfile` 文件
+. 打开终端,使用如下命令安装 gem:
+
+ $ bundle
+
+要升级 gem 的话,在 `Gemfile` 文件中,指明新版本,然后再次运行 `bundle` 即可。
+*不推荐* 直接使用 `bundle update` 命令,因为它还会升级其他 gem,也许会造成不可预料的结果。
+
+[#c-linux-package-managers]
+=== (c) Linux 包管理
+
+[#dnf-fedora-21-or-greater]
+==== DNF (Fedora 21 或更高版本)
+
+在 Fedora 21 或更高版本中安装这个 gem,可以使用 dnf。打开终端并输入如下命令:
+
+ $ sudo dnf install -y asciidoctor
+
+升级则使用:
+
+ $ sudo dnf update -y asciidoctor
+
+TIP: 如果你的 Fedora 系统配置的是自动升级包,在这种情况下,不需要你亲自动手升级。
+
+[#apt-get-debian-ubuntu-mint]
+==== apt-get (Debian, Ubuntu, Mint)
+
+在 Debian,Ubuntu 或 Mint 中安装这个 gem,请打开终端并输入如下命令:
+
+ $ sudo apt-get install -y asciidoctor
+
+升级则使用:
+
+ $ sudo apt-get upgrade -y asciidoctor
+
+TIP: 如果你的 Debian 或 Ubuntu 系统配置的是自动升级包,在这种情况下,不需要你亲自动手升级。
+
+使用包管理器( apt-get )安装的 Asciidoctor 的版本也许不是最新发布版。
+请查看发行版的包库,来确定每个发行版是打包的哪个版本。
+
+* https://packages.debian.org/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[Debian 发行版中的 asciidoctor]
+* http://packages.ubuntu.com/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[Ubuntu 发行版中的 asciidoctor]
+* https://community.linuxmint.com/software/view/asciidoctor[Mint 发行版中的 asciidoctor]
+
+[CAUTION]
+====
+我们建议不要使用 `gem update` 来升级包管理的 gem。
+这样做会使系统进入不一致的状态,包管理工具将不再跟踪相关文件(通常安装在 /usr/local 下。)
+简单地说,系统的 gem 只能由包管理器进行管理。
+
+如果你想使用一个比包管理器安装的更新版本的 Asciidoctor,你应该使用 http://rvm.io[RVM] 在你的用户家目录(比如:用户空间)下安装 Ruby。
+然后,你就可以放心地使用 `gem` 命令来安装或者更新 Asciidoctor gem。
+当使用 RVM 时,gem 将被安装到与系统隔离的位置。
+====
+
+[#apk-alpine-linux]
+==== apk (Alpine Linux)
+
+在 Alpine Linux 中安装这个 gem,请打开终端并输入如下命令:
+
+ $ sudo apk add asciidoctor
+
+升级则使用:
+
+ $ sudo apk add -u asciidoctor
+
+TIP: 如果你的 Alpine Linux 系统配置的是自动升级包,在这种情况下,不需要你亲自动手升级。
+
+[#other-installation-options]
+=== 其他安装选项
+
+* {uri-install-docker}[使用 Docker 安装 Asciidoctor ]
+* {uri-install-osx-doc}[在 Mac OS X 安装 Asciidoctor ]
+
+[#usage]
+== 使用
+
+如果成功安装 Asciidoctor,则在可执行程序路径中,`asciidoctor` 就可用了。
+为了验证它的可用性,你可以在终端中执行如下命令:
+
+ $ asciidoctor --version
+
+你应该看到关于 Asciidoctor 和 Ruby 环境信息将打印到你的终端上。
+
+[.output]
+....
+Asciidoctor 1.5.4 [http://asciidoctor.org]
+Runtime Environment (ruby 2.2.2p95 [x86_64-linux]) (lc:UTF-8 fs:UTF-8 in:- ex:UTF-8)
+....
+
+Asciidoctor 还提供了一套 API。
+这套 API 是为了整合其他的 Ruby 软件,例如 Rails、Sinatra、Github,甚至其他语言,比如 Java (通过 {uri-asciidoctorj}[AsciidoctorJ]) 和 JavaScript (通过 {uri-asciidoctorjs}[Asciidoctor.js])。
+
+[#command-line-interface-cli]
+=== 命令行(CLI)
+
+`asciidoctor` 命令可以让你通过命令行(比如:终端)来调用 Asciidoctor。
+
+下面的命令将 README.adoc 文件转化为 HTML,并且保存到同一目录下的 README.html 文件中。
+生成的 HTML 文件名源自源文件名,只是将其扩展名改为了 `.html`。
+
+ $ asciidoctor README.adoc
+
+您可以通过添加各种标志和开关控制 Asciidoctor 处理器,通过下面的命令你可以学习它的更多用法:
+
+ $ asciidoctor --help
+
+比如,将文件写入到不同路径里,使用如下命令:
+
+ $ asciidoctor -D output README.adoc
+
+`asciidoctor` {uri-manpage}[帮助页面] 提供了这个命令的完整参考。
+
+点击下面的资源,学习更多关于 `asciidoctor` 命令的用法。
+
+* {uri-render-doc}[如何转化文档?]
+* {uri-themes-doc}[如何使用 Asciidoctor 样式工厂来创建自定义主题?]
+
+[#ruby-api]
+=== Ruby API
+
+为了在你应用中使用 Asciidoctor,首先需要引入这个 gem:
+
+[source]
+require 'asciidoctor'
+
+然后,你可以通过下面的代码将 AsciiDoc 源文件转化成一个 HTML 文件:
+
+[source]
+Asciidoctor.convert_file 'README.adoc', to_file: true, safe: :safe
+
+WARNING: 当你通过 API 使用 Asciidoctor 时,默认的安全模式是 `:secure`。
+在 secure 模式下,很多核心特性将不可用,包括 `include` 特性。
+如果你想启用这些特性,你需要明确设置安全模式为 `:server` (推荐)或 `:safe`。
+
+你也可以将 AsciiDoc 字符串转化我内嵌的 HTML (为了插入到一个 HTML 页面),用法如下:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+Asciidoctor.convert content, safe: :safe
+----
+
+如果你想得到完整的 HTML 文档,只需要启用 `header_footer` 选项即可。如下:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+html = Asciidoctor.convert content, header_footer: true, safe: :safe
+----
+
+如果你想访问已经处理过的文档,可以将转化过程拆分成离散的几步:
+
+[source]
+----
+content = '_Zen_ in the art of writing http://asciidoctor.org[AsciiDoc].'
+document = Asciidoctor.load content, header_footer: true, safe: :safe
+puts document.doctitle
+html = document.convert
+----
+
+请注意:如果你不喜欢 Asciidoctor 输出结果,_你完全可以改变它。_
+Asciidoctor 支持自定义转化器,它可以操作从待处理文件到生成文档整个环节。
+
+一个简单的、细微地自定义输出的方式是使用模板转化器。
+模板转化器运行你提供一个 {uri-tilt}[Tilt] 模板,这样通过模板文件来操作转化出的文档的每个节点。
+
+这样,你就 _可以_ 百分之百地控制你的输出。
+关于更多关于 API 或自定义输出信息,请参考 {uri-user-manual}[用户帮助手册]。
+
+[#contributing]
+== 贡献
+
+自由软件的精神鼓励 _每个人_ 来帮助改善这个项目。
+如果你在源码、文档或网站内容中发现错误或漏洞,请不要犹豫,提交一个议题或者推送一个修复请求。
+随时欢迎新的贡献者!
+
+这里有几种 *你* 可以做出贡献的方式:
+
+* 使用预发布版本(alpha, beta 或 preview)
+* 报告 Bug
+* 提议新功能
+* 编写文档
+* 编写规范
+* 编写 -- _任何补丁都不小。_
+** 修正错别字
+** 添加评论
+** 清理多余空白
+** 编写测试!
+* 重构代码
+* 修复 {uri-issues}[议题]
+* 审查补丁
+
+{uri-contribute}[贡献] 指南提供了如何提供贡献,包括如何创建、修饰和提交问题、特性、需求、代码和文档给 Asciidoctor 项目。
+
+[#getting-help]
+== 获得帮助
+
+开发 Asciidoctor 项目是未来了帮助你更容易地书写和发布你的内容。
+但是,如果没有反馈,我们将寸步难行。
+我们鼓励你在讨论组、Twitter或聊天室里,提问为题,讨论项目的方方面面,
+
+讨论组 (Nabble):: {uri-discuss}
+Twitter:: #asciidoctor 井号或 @asciidoctor 提醒
+聊天 (Gitter):: image:https://badges.gitter.im/Join%20In.svg[Gitter, link=https://gitter.im/asciidoctor/asciidoctor]
+
+ifdef::env-github[]
+Further information and documentation about Asciidoctor can be found on the project's website.
+
+{uri-project}/[Home] | {uri-news}[News] | {uri-docs}[Docs]
+endif::[]
+
+Asciidoctor 组织在 Github 托管代码、议案跟踪和相关子项目。
+
+代码库 (git):: {uri-repo}
+议案跟踪:: {uri-issues}
+在 GitHub 的 Asciidoctor 组织:: {uri-org}
+
+[#copyright-and-licensing]
+== 版权和协议
+
+Copyright (C) 2012-2016 Dan Allen, Ryan Waldron and the Asciidoctor Project.
+这个软件的免费使用是在MIT许可条款授予的。
+
+请看 {uri-license}[版权声明] 文件来获取更多详细信息。
+
+[#authors]
+== 作者
+
+*Asciidoctor* 由 https://github.com/mojavelinux[Dan Allen] 和 https://github.com/graphitefriction[Sarah White] 领导,并从 Asciidoctor 社区的 {uri-contributors}[很多其他独立开发者] 上收到了很多贡献。
+项目最初由 https://github.com/erebor[Ryan Waldron] 于 2012年基于 https://github.com/nickh[Nick Hengeveld] 的 {uri-prototype}[原型] 创建。
+
+*AsciiDoc* 由 Stuart Rackham 启动,并从 AsciiDoc 社区的其他独立开发者上收到很多贡献。
+
+== Changelog
+
+请看 {uri-changelog}[CHANGELOG]。
diff --git a/README.adoc b/README.adoc
index d081400..e1d265d 100644
--- a/README.adoc
+++ b/README.adoc
@@ -1,20 +1,20 @@
 = Asciidoctor
 Dan Allen <https://github.com/mojavelinux[@mojavelinux]>; Sarah White <https://github.com/graphitefriction[@graphitefriction]>; Ryan Waldron <https://github.com/erebor[@erebor]>
-v1.5.4, 2016-01-05
+v1.5.5, 2016-10-05
 // settings:
 :page-layout: base
 :idprefix:
 :idseparator: -
 :source-language: ruby
 :language: {source-language}
-ifdef::env-github[:badges:]
+ifdef::env-github[:status:]
 // URIs:
 :uri-org: https://github.com/asciidoctor
 :uri-repo: {uri-org}/asciidoctor
 :uri-asciidoctorj: {uri-org}/asciidoctorj
 :uri-asciidoctorjs: {uri-org}/asciidoctor.js
 :uri-project: http://asciidoctor.org
-ifdef::awestruct-version[:uri-project: link:]
+ifdef::env-site[:uri-project: link:]
 :uri-docs: {uri-project}/docs
 :uri-news: {uri-project}/news
 :uri-manpage: {uri-project}/man/asciidoctor
@@ -22,7 +22,7 @@ ifdef::awestruct-version[:uri-project: link:]
 :uri-contributors: {uri-repo}/graphs/contributors
 :uri-rel-file-base: link:
 :uri-rel-tree-base: link:
-ifdef::awestruct-version[]
+ifdef::env-site[]
 :uri-rel-file-base: {uri-repo}/blob/master/
 :uri-rel-tree-base: {uri-repo}/tree/master/
 endif::[]
@@ -54,6 +54,13 @@ Asciidoctor is written in Ruby, packaged as a RubyGem and published to {uri-ruby
 The gem is also included in several Linux distributions, including Fedora, Debian and Ubuntu.
 Asciidoctor is open source, {uri-repo}[hosted on GitHub] and released under {uri-license}[the MIT license].
 
+ifndef::env-site[]
+.Translations of this document are available in the following languages:
+* {uri-rel-file-base}README-zh_CN.adoc[汉语]
+* {uri-rel-file-base}README-fr.adoc[Français]
+* {uri-rel-file-base}README-jp.adoc[日本語]
+endif::[]
+
 .Key documentation
 [.compact]
 * {uri-docs}/what-is-asciidoc[What is Asciidoc?]
@@ -72,10 +79,10 @@ We use http://opalrb.org[Opal] to transcompile the Ruby source to JavaScript to
 Asciidoctor.js is used to power the AsciiDoc preview extensions for Chrome, Atom, Brackets and other web-based tooling.
 ****
 
-ifdef::badges[]
+ifdef::status[]
 .*Project health*
-image:https://img.shields.io/travis/asciidoctor/asciidoctor/master.svg[Build Status (Travis CI), link=https://travis-ci.org/asciidoctor/asciidoctor] 
-image:https://ci.appveyor.com/api/projects/status/ifplu67oxvgn6ceq/branch/master?svg=true&passingText=green%20bar&failingText=%23fail&pendingText=building%2E%2E%2E[Build Status (AppVeyor), link=https://ci.appveyor.com/project/asciidoctor/asciidoctor] 
+image:https://img.shields.io/travis/asciidoctor/asciidoctor/master.svg[Build Status (Travis CI), link=https://travis-ci.org/asciidoctor/asciidoctor]
+image:https://ci.appveyor.com/api/projects/status/ifplu67oxvgn6ceq/branch/master?svg=true&passingText=green%20bar&failingText=%23fail&pendingText=building%2E%2E%2E[Build Status (AppVeyor), link=https://ci.appveyor.com/project/asciidoctor/asciidoctor]
 //image:https://img.shields.io/coveralls/asciidoctor/asciidoctor/master.svg[Coverage Status, link=https://coveralls.io/r/asciidoctor/asciidoctor]
 image:https://codeclimate.com/github/asciidoctor/asciidoctor/badges/gpa.svg[Code Climate, link="https://codeclimate.com/github/asciidoctor/asciidoctor"]
 image:https://inch-ci.org/github/asciidoctor/asciidoctor.svg?branch=master[Inline docs, link="https://inch-ci.org/github/asciidoctor/asciidoctor"]
@@ -101,15 +108,27 @@ Asciidoctor also offers a modern, responsive theme based on {uri-foundation}[Fou
 
 == Requirements
 
-Asciidoctor works on Linux, OSX (Mac) and Windows and requires one of the following implementations of {uri-ruby}[Ruby]:
+Asciidoctor works on Linux, OS X (Mac) and Windows and requires one of the following implementations of {uri-ruby}[Ruby]:
 
-* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1 & 2.2)
-* JRuby 1.7 (Ruby 1.8 and 1.9 modes) & 9000
+* MRI (Ruby 1.8.7, 1.9.3, 2.0, 2.1, 2.2 & 2.3)
+* JRuby (1.7 in Ruby 1.8 and 1.9 modes, 9000)
 * Rubinius 2.2.x
 * Opal (JavaScript)
 
 We welcome your help testing Asciidoctor on these and other platforms.
-Refer to <<{idprefix}contributing,Contributing>> to learn how to get involved.
+Refer to the <<Contributing>> section to learn how to get involved.
+
+[CAUTION]
+====
+If you're using a non-English Windows environment, you may bump into an `Encoding::UndefinedConversionError` when invoking Asciidoctor.
+To solve this issue, we recommend changing the active code page in your console to UTF-8:
+
+ chcp 65001
+
+Once you make this change, all your Unicode headaches will be behind you.
+If you're using an IDE like Eclipse, make sure you set the encoding to UTF-8 there as well.
+Asciidoctor works best when you use UTF-8 everywhere.
+====
 
 == Installation
 
@@ -152,7 +171,7 @@ If that's the case, use the following gem command to remove the old versions:
 source 'https://rubygems.org'
 gem 'asciidoctor'
 # or specify the version explicitly
-# gem 'asciidoctor', '1.5.3'
+# gem 'asciidoctor', '1.5.5'
 ----
 
 . Save the Gemfile
@@ -165,21 +184,21 @@ Using `bundle update` is *not* recommended as it will also update other gems, wh
 
 === (c) Linux package managers
 
-==== Yum (Fedora 21 or greater)
+==== DNF (Fedora 21 or greater)
 
-To install the gem on Fedora 21 or greater using yum, open a terminal and type:
+To install the gem on Fedora 21 or greater using dnf, open a terminal and type:
 
- $ sudo yum install -y asciidoctor
+ $ sudo dnf install -y asciidoctor
 
 To upgrade the gem, use:
 
- $ sudo yum update -y asciidoctor
+ $ sudo dnf update -y asciidoctor
 
-TIP: Your Fedora system may be configured to automatically update packages, in which case no action is required by you to update the gem.
+TIP: Your system may be configured to automatically update rpm packages, in which case no action is required by you to update the gem.
 
-==== apt-get (Debian Sid, Ubuntu Saucy or greater)
+==== apt-get (Debian, Ubuntu, Mint)
 
-To install the gem on Debian or Ubuntu, open a terminal and type:
+To install the gem on Debian, Ubuntu or Mint, open a terminal and type:
 
  $ sudo apt-get install -y asciidoctor
 
@@ -187,7 +206,37 @@ To upgrade the gem, use:
 
  $ sudo apt-get upgrade -y asciidoctor
 
-TIP: Your Debian or Ubuntu system may be configured to automatically update packages, in which case no action is required by you to update the gem.
+TIP: Your system may be configured to automatically update deb packages, in which case no action is required by you to update the gem.
+
+The version of Asciidoctor installed by the package manager (apt-get) may not match the latest release of Asciidoctor.
+Consult the package repository for your distribution to find out which version is packaged per distribution release.
+
+* https://packages.debian.org/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[asciidoctor package by Debian release]
+* http://packages.ubuntu.com/search?keywords=asciidoctor&searchon=names&exact=1&suite=all&section=all[asciidoctor package by Ubuntu release]
+* https://community.linuxmint.com/software/view/asciidoctor[asciidoctor package by Mint release]
+
+[CAUTION]
+====
+You're advised against using the `gem update` command to update a gem managed by the package manager.
+Doing so puts the system into an inconsistent state as the package manager can no longer track the files (which get installed under /usr/local).
+Simply put, system gems should only be managed by the package manager.
+
+If you want to use a version of Asciidoctor that is newer than what is installed by the package manager, you should use http://rvm.io[RVM] to install Ruby in your home directory (i.e., user space).
+Then, you can safely use the `gem` command to install or update the Asciidoctor gem.
+When using RVM, gems are installed in a location isolated from the system.
+====
+
+==== apk (Alpine Linux)
+
+To install the gem on Alpine Linux, open a terminal and type:
+
+ $ sudo apk add asciidoctor
+
+To upgrade the gem, use:
+
+ $ sudo apk add -u asciidoctor
+
+TIP: Your system may be configured to automatically update apk packages, in which case no action is required by you to update the gem.
 
 === Other installation options
 
@@ -207,7 +256,7 @@ You should see information about the Asciidoctor version and your Ruby environme
 
 [.output]
 ....
-Asciidoctor 1.5.3 [http://asciidoctor.org]
+Asciidoctor 1.5.5 [http://asciidoctor.org]
 Runtime Environment (ruby 2.2.2p95 [x86_64-linux]) (lc:UTF-8 fs:UTF-8 in:- ex:UTF-8)
 ....
 
@@ -284,7 +333,7 @@ Keep in mind that if you don't like the output Asciidoctor produces, _you can ch
 Asciidoctor supports custom converters that can handle converting from the parsed document to the generated output.
 
 One easy way to customize the output piecemeal is by using the template converter.
-The template converter allows you uses supply a {uri-tilt}[Tilt]-supported template file to handle converting any node in the document.
+The template converter allows you to supply a {uri-tilt}[Tilt]-supported template file to handle converting any node in the document.
 
 However you go about it, you _can_ have 100% control over the output.
 For more information about how to use the API or to customize the output, refer to the {uri-user-manual}[user manual].
@@ -316,13 +365,15 @@ The {uri-contribute}[Contributing] guide provides information on how to create,
 == Getting Help
 
 The Asciidoctor project is developed to help you easily write and publish your content.
-But we can't do that without your feedback!
-We encourage you to ask questions and discuss any aspects of the project on the discussion list, Twitter or IRC.
+But we can't do it without your feedback!
+We encourage you to ask questions and discuss any aspects of the project on the discussion list, on Twitter or in the chat room.
 
-Mailing list:: {uri-discuss}
-Twitter (Chat):: #asciidoctor hashtag
-Gitter (Chat):: image:https://badges.gitter.im/Join%20In.svg[Gitter, link=https://gitter.im/asciidoctor/asciidoctor]
-IRC (Chat):: {uri-irc}[#asciidoctor] on FreeNode IRC
+Discussion list (Nabble):: {uri-discuss}
+Twitter:: #asciidoctor hashtag or @asciidoctor mention
+Chat (Gitter):: image:https://badges.gitter.im/Join%20In.svg[Gitter, link=https://gitter.im/asciidoctor/asciidoctor]
+////
+Chat (IRC):: {uri-irc}[#asciidoctor] on FreeNode IRC
+////
 
 ifdef::env-github[]
 Further information and documentation about Asciidoctor can be found on the project's website.
@@ -352,6 +403,59 @@ The project was initiated in 2012 by https://github.com/erebor[Ryan Waldron] and
 
 == Changelog
 
+== 1.5.5 (2016-10-05) - @mojavelinux
+
+Enhancements::
+  * Add preference to limit the maximum size of an attribute value (#1861)
+  * Honor SOURCE_DATE_EPOCH environment variable to accomodate reproducible builds (@JojoBoulix) (#1721)
+  * Add reversed attribute to ordered list if reversed option is enabled (#1830)
+  * Add support for additional docinfo locations (e.g., :header)
+  * Configure default stylesheet to break monospace word if exceeds length of line; add roles to prevent breaks (#1814)
+  * Introduce translation file for built-in labels (@ciampix)
+  * Provide translations for built-in labels (@JmyL - kr, @ciampix - it, @ivannov - bg, @maxandersen - da, @radcortez - pt, @eddumelendez - es, @leathersole - jp, @aslakknutsen - no, @shahryareiv - fa, @AlexanderZobkov - ru, @dongwq - zh, @rmpestano - pt_BR, @ncomet - fr, @lgvz - fi, @patoi - hu, @BojanStipic - sr, @fwilhe - de, @rahmanusta - tr, @abelsromero - ca, @aboullaite - ar, @roelvs - nl)
+  * Translate README to Chinese (@diguage)
+  * Translate README to Japanese (@Mizuho32)
+
+Improvements::
+  * Style nested emphasized phrases properly when using default stylesheet (#1691)
+  * Honor explicit table width even when autowidth option is set (#1843)
+  * Only explicit noheader option on table should disable implicit table header (#1849)
+  * Support docbook orient="land" attribute on tables (#1815)
+  * Add alias named list to retrieve parent List of ListItem
+  * Update push_include method to support chaining (#1836)
+  * Enable font smoothing on Firefox on OSX (#1837)
+  * Support combined use of sectanchors and sectlinks in HTML5 output (#1806)
+  * fix API docs for find_by
+  * Upgrade to Font Awesome 4.6.3 (@allenan, @mogztter) (#1723)
+  * README: add install instructions for Alpine Linux
+  * README: Switch yum commands to dnf in README
+  * README: Mention Mint as a Debian distro that packages Asciidoctor
+  * README: Add caution advising against using gem update to update a system-managed gem (@oddhack)
+  * README: sync French version with English version (@flashcode)
+  * Add missing endline after title element when converting open block to HTML
+  * Move list_marker_keyword method from AbstractNode to AbstractBlock
+  * Rename definition list to description list internally
+
+Compliance::
+  * Support 6-digit decimal char refs, 5-digit hexidecimal char refs (#1824)
+  * Compatibility fixes for Opal
+  * Check for number using Integer instead of Fixnum class for compatibility with Ruby 2.4
+
+Bug fixes::
+  * Use method_defined? instead of respond_to? to check if method is already defined when patching (#1838)
+  * Fix invalid conditional in HTML5 converter when handling of SVG
+  * Processor#parse_content helper no longer shares attribute list between blocks (#1651)
+  * Fix infinite loop if unordered list marker is immediately followed by a dot (#1679)
+  * Don't break SVG source when cleaning if svg start tag name is immediately followed by endline (#1676)
+  * Prevent template converter from crashing if .rb file found in template directory (#1827)
+  * Fix crash when generating section ID when both idprefix & idseparator are blank (#1821)
+  * Use stronger CSS rule for general text color in Pygments stylesheet (#1802)
+  * Don't duplicate forward slash for path relative to root (#1822)
+
+Infrastructure::
+  * Build gem properly in the absense of a git workspace, make compatible with JRuby (#1779)
+  * Run tests in CI using latest versions of Ruby, including Ruby 2.3 (@ferdinandrosario)
+
 == 1.5.4 (2016-01-03) - @mojavelinux
 
 Enhancements::
@@ -429,7 +533,7 @@ Improvements::
   * restore attributes to header attributes after parse (#1255)
   * allow docdate and doctime to be overridden (#1495)
   * add CSS class `.center` for center block alignment (#1456)
-  * recognize U+2022 as alternative marker for unordered lists (@mogztter) (#1177)
+  * recognize U+2022 (bullet) as alternative marker for unordered lists (@mogztter) (#1177)
   * allow videos to work for local files by prepending asset-uri-scheme (Chris) (#1320)
   * always assign playlist param when loop option is enabled for YouTube video
   * parse isolated version in revision line (@bk2204) (#790)
@@ -454,6 +558,7 @@ Improvements::
   * fix `+--help+` output text for `-I` (@bk2204)
   * don't require open-uri-cached if already loaded
   * do not attempt to scan pattern of non-existent directory in template converter
+  * prevent CodeRay from bolding every 10th line number
 
 Compliance::
   * use `<sup>` for footnote reference in text instead of `<span>` (#1523)
@@ -496,47 +601,4 @@ Infrastructure::
   * add config to run CI build on AppVeyor
   * exclude benchmark folder from gem (#1522)
 
-== 1.5.2 (2014-11-27) - @mojavelinux
-
-Enhancements::
-
-  * add docinfo extension (@mogztter) (#1162)
-  * allow docinfo to be in separate directory from content, specified by `docinfodir` attribute (@mogztter) (#511)
-  * enable TeX equation auto-numbering if `eqnums` attribute is set (@jxxcarlson) (#1110)
-
-Improvements::
-
-  * recognize `+--+` as valid line comment for callout numbers; make line comment configurable (#1068)
-  * upgrade highlight.js to version 8.4 (#1216)
-  * upgrade Font Awesome to version 4.2.0 (@clojens) (#1201)
-  * define JAVASCRIPT_PLATFORM constant to simplify conditional logic in the JavaScript environment (#897)
-  * provide access to destination directory, outfile and outdir via Document object (#1203)
-  * print encoding information in version report produced by `asciidoctor -v` (#1210)
-  * add intrinsic attribute named `cpp` with value `pass:[C++]` (#1208)
-  * preserve URI targets passed to `stylesheet` and related attributes (#1192)
-  * allow numeric characters in block attribute name (#1103)
-  * support custom YouTube playlists (#1105)
-  * make start number for unique id generation configurable (#1148)
-  * normalize and force UTF-8 encoding of docinfo content (#831)
-  * allow subs and default_subs to be specified in Block constructor (#749)
-  * enhance error message when reading binary input files (@mogztter) (#1158)
-  * add `append` method as alias to `<<` method on AbstractBlock (#1085)
-  * assign value of `preface-title` as title of preface node (#1090)
-  * fix spacing around checkbox in checklist (#1138)
-  * automatically load Slim's include plugin when using slim templates (@jirutka) (#1151)
-  * mixin Slim helpers into execution scope of slim templates (@jirutka) (#1143)
-  * improve DocBook output for manpage doctype (@bk2204) (#1134, #1142)
-
-Compliance::
-
-  * substitute attribute entry value in attributes defined outside of header (#1130)
-  * allow empty cell to appear at end of table row (#1106)
-  * only produce one row for table in CSV or DSV format with a single cell (#1180)
-
-Bug fixes::
-
-  * add explicit to_s call to generate delimiter settings for MathJax config (#1198)
-  * fix includes that reference absolute Windows paths (#1144)
-  * apply DSL to extension block in a way compatible with Opal
-
 Refer to the {uri-changelog}[CHANGELOG] for a complete list of changes in older releases.
diff --git a/_settings-README.adoc b/_settings-README.adoc
index c8b2928..8e88bdf 100644
--- a/_settings-README.adoc
+++ b/_settings-README.adoc
@@ -11,7 +11,7 @@ ifdef::env-github[:badges:]
 :uri-asciidoctorj: {uri-org}/asciidoctorj
 :uri-asciidoctorjs: {uri-org}/asciidoctor.js
 :uri-project: http://asciidoctor.org
-ifdef::awestruct-version[:uri-project: link:]
+ifdef::env-site[:uri-project: link:]
 :uri-docs: {uri-project}/docs
 :uri-news: {uri-project}/news
 :uri-manpage: {uri-project}/man/asciidoctor
@@ -19,7 +19,7 @@ ifdef::awestruct-version[:uri-project: link:]
 :uri-contributors: {uri-repo}/graphs/contributors
 :uri-rel-file-base: link:
 :uri-rel-tree-base: link:
-ifdef::awestruct-version[]
+ifdef::env-site[]
 :uri-rel-file-base: {uri-repo}/blob/master/
 :uri-rel-tree-base: {uri-repo}/tree/master/
 endif::[]
@@ -32,7 +32,8 @@ endif::[]
 :uri-rubygem: https://rubygems.org/gems/asciidoctor
 :uri-what-is-asciidoc: {uri-docs}/what-is-asciidoc
 :uri-user-manual: {uri-docs}/user-manual
-:uri-install-doc: {uri-docs}/install-toolchain
+:uri-install-docker: https://github.com/asciidoctor/docker-asciidoctor
+//:uri-install-doc: {uri-docs}/install-toolchain
 :uri-install-osx-doc: {uri-docs}/install-asciidoctor-macosx
 :uri-render-doc: {uri-docs}/render-documents
 :uri-themes-doc: {uri-docs}/produce-custom-themes-using-asciidoctor-stylesheet-factory
diff --git a/asciidoctor.gemspec b/asciidoctor.gemspec
index d9e79b2..942d392 100644
--- a/asciidoctor.gemspec
+++ b/asciidoctor.gemspec
@@ -1,29 +1,29 @@
 # -*- encoding: utf-8 -*-
 require File.expand_path '../lib/asciidoctor/version', __FILE__
+require 'open3' unless defined? Open3
 
 Gem::Specification.new do |s|
-  s.name              = 'asciidoctor'
-  s.version           = Asciidoctor::VERSION
-  s.summary           = 'An implementation of the AsciiDoc text processor and publishing toolchain in Ruby'
-  s.description       = <<-EOS
-A fast, open source text processor and publishing toolchain, written in Ruby, for converting AsciiDoc content to HTML5, DocBook 5 (or 4.5) and other formats.
-  EOS
-  s.authors           = ['Dan Allen', 'Sarah White', 'Ryan Waldron', 'Jason Porter', 'Nick Hengeveld', 'Jeremy McAnally']
-  s.email             = ['dan.j.allen at gmail.com']
-  s.homepage          = 'http://asciidoctor.org'
-  s.license           = 'MIT'
+  s.name = 'asciidoctor'
+  s.version = Asciidoctor::VERSION
+  s.summary = 'An implementation of the AsciiDoc text processor and publishing toolchain in Ruby'
+  s.description = 'A fast, open source text processor and publishing toolchain, written in Ruby, for converting AsciiDoc content to HTML5, DocBook 5 (or 4.5) and other formats.'
+  s.authors = ['Dan Allen', 'Sarah White', 'Ryan Waldron', 'Jason Porter', 'Nick Hengeveld', 'Jeremy McAnally']
+  s.email = ['dan.j.allen at gmail.com']
+  s.homepage = 'http://asciidoctor.org'
+  s.license = 'MIT'
 
-  begin
-    s.files           = `git ls-files -z -- {bin,data,features,lib,man,test}/* {CHANGELOG,CONTRIBUTING,LICENSE,README}.adoc Rakefile`.split "\0"
+  files = begin
+    (result = Open3.popen3('git ls-files -z') {|_, out| out.read }.split %(\0)).empty? ? Dir['**/*'] : result
   rescue
-    s.files           = Dir['**/*']
+    Dir['**/*']
   end
-  s.executables       = ['asciidoctor', 'asciidoctor-safe']
-  s.test_files        = s.files.grep(/^(?:test\/.*_test\.rb|features\/.*\.(?:feature|rb))$/)
-  s.require_paths     = ['lib']
-  s.has_rdoc          = true
-  s.rdoc_options      = ['--charset=UTF-8']
-  s.extra_rdoc_files  = ['CHANGELOG.adoc', 'CONTRIBUTING.adoc', 'LICENSE.adoc']
+  s.files = files.grep(/^(?:(?:data|lib|man)\/.+|Gemfile|Rakefile|(?:CHANGELOG|CONTRIBUTING|LICENSE|README(?:-\w+)?)\.adoc|#{s.name}\.gemspec)$/)
+  s.executables = files.grep(/^bin\//).map {|f| File.basename f }
+  s.test_files = files.grep(/^(?:test\/.*_test\.rb|features\/.*\.(?:feature|rb))$/)
+  s.require_paths = ['lib']
+  s.has_rdoc = true
+  s.rdoc_options = ['--charset=UTF-8']
+  s.extra_rdoc_files = ['CHANGELOG.adoc', 'CONTRIBUTING.adoc', 'LICENSE.adoc']
 
   # asciimath is needed for testing AsciiMath in DocBook backend
   s.add_development_dependency 'asciimath', '~> 1.0.2'
diff --git a/benchmark/benchmark.rb b/benchmark/benchmark.rb
index 9acb3ac..c65d80d 100755
--- a/benchmark/benchmark.rb
+++ b/benchmark/benchmark.rb
@@ -110,7 +110,7 @@ when 'userguide-loop'
 when 'mdbasics-loop'
   require '../lib/asciidoctor.rb'
   GC.start
-  sample_file = ENV['BENCH_TEST_FILE'] || 'sample-data/userguide.adoc'
+  sample_file = ENV['BENCH_TEST_FILE'] || 'sample-data/mdbasics.adoc'
   backend = ENV['BENCH_BACKEND'] || 'html5'
 
   best = nil
diff --git a/data/locale/attributes.adoc b/data/locale/attributes.adoc
new file mode 100644
index 0000000..2a7e50c
--- /dev/null
+++ b/data/locale/attributes.adoc
@@ -0,0 +1,470 @@
+// This file provides translations for all built-in attributes in Asciidoctor that output localized content.
+// See http://asciidoctor.org/docs/user-manual/#customizing-built-in-labels to learn how to use it.
+//
+// NOTE: Please use a line comment in front of the listing-caption and preface-title entries.
+// These attributes are optional and not set by default.
+//
+// IMPORTANT: Do not add any blank lines.
+//
+// Arabic translation, courtesy of Aboullaite Mohammed <aboullaite.mohammed at gmail.com>
+ifeval::["{lang}" == "ar"]
+:appendix-caption: ملحق
+:caution-caption: تنبيه
+:example-caption: مثال
+:figure-caption: الشكل
+:important-caption: مهم
+:last-update-label: اخر تحديث
+//:listing-caption: قائمة
+:manname-title: اسم
+:note-caption: ملاحظة
+//:preface-title: تمهيد
+:table-caption: جدول
+:tip-caption: تلميح
+:toc-title: فهرس
+:untitled-label: بدون عنوان
+:version-label: نسخة
+:warning-caption: تحذير
+endif::[]
+//
+// Bulgarian translation, courtesy of Ivan St. Ivanov <ivan.st.ivanov at gmail.com>
+ifeval::["{lang}" == "bg"]
+:appendix-caption: Приложение
+:caution-caption: Внимание
+:example-caption: Пример
+:figure-caption: Фигура
+:important-caption: Важно
+:last-update-label: Последно обновен
+//:listing-caption: Листинг
+:manname-title: ИМЕ
+:note-caption: Забележка
+//:preface-title: Предговор
+:table-caption: Таблица
+:tip-caption: Подсказка
+:toc-title: Съдържание
+:untitled-label: Без заглавие
+:version-label: Версия
+:warning-caption: Внимание
+endif::[]
+//
+// Catalan translation, courtesy of Abel Salgado Romero <abelromero at gmail.com> and Alex Soto
+ifeval::["{lang}" == "ca"]
+:appendix-caption: Apendix
+:caution-caption: Atenció
+:example-caption: Exemple
+:figure-caption: Figura
+:important-caption: Important
+:last-update-label: Última actualització
+//:listing-caption: Llista
+:manname-title: NOM
+:note-caption: Nota
+//:preface-title: Prefaci
+:table-caption: Taula
+:tip-caption: Suggeriment
+:toc-title: Índex
+:untitled-label: Sense títol
+:version-label: Versió
+:warning-caption: Advertència
+endif::[]
+//
+// Danish translation, courtesy of Max Rydahl Andersen <manderse at redhat.com>
+ifeval::["{lang}" == "da"]
+:appendix-caption: Appendix
+:caution-caption: Forsigtig
+:example-caption: Eksempel
+:figure-caption: Figur
+:important-caption: Vigtig
+:last-update-label: Sidst opdateret
+:listing-caption: List
+:manname-title: NAVN
+:note-caption: Notat
+//:preface-title:
+:table-caption: Tabel
+:tip-caption: Tips
+:toc-title: Indholdsfortegnelse
+:untitled-label: Unavngivet
+:version-label: Version
+:warning-caption: Advarsel
+endif::[]
+//
+// German translation, courtesy of Florian Wilhelm
+ifeval::["{lang}" == "de"]
+:appendix-caption: Anhang
+:caution-caption: Achtung
+:example-caption: Beispiel
+:figure-caption: Abbildung
+:important-caption: Wichtig
+:last-update-label: Zuletzt aktualisiert
+//:listing-caption: Listing
+:manname-title: BEZEICHNUNG
+:note-caption: Anmerkung
+//:preface-title: Vorwort
+:table-caption: Tabelle
+:tip-caption: Hinweis
+:toc-title: Inhalt
+:untitled-label: Ohne Titel
+:version-label: Version
+:warning-caption: Warnung
+endif::[]
+//
+// Spanish translation, courtesy of Eddú Meléndez <eddu.melendez at gmail.com>
+ifeval::["{lang}" == "es"]
+:appendix-caption: Apéndice
+:caution-caption: Precaución
+:example-caption: Ejemplo
+:figure-caption: Figura
+:important-caption: Importante
+:last-update-label: Ultima actualización
+//:listing-caption: Lista
+:manname-title: NOMBRE
+:note-caption: Nota
+//:preface-title: Prefacio
+:table-caption: Tabla
+:tip-caption: Sugerencia
+:toc-title: Tabla de Contenido
+:untitled-label: Sin título
+:version-label: Versión
+:warning-caption: Aviso
+endif::[]
+//
+// Persian (Farsi) translation, courtesy of Shahryar Eivazzadeh <shahryareiv at gmail.com>
+ifeval::["{lang}" == "fa"]
+:appendix-caption: پیوست
+:caution-caption: گوشزد
+:example-caption: نمونه
+:figure-caption: نمودار
+:important-caption: مهم
+:last-update-label: آخرین به روز رسانی
+//:listing-caption: فهرست
+:manname-title: نام
+:note-caption: یادداشت
+//:preface-title: پیشگفتار
+:table-caption: جدول
+:tip-caption: نکته
+:toc-title: فهرست مطالب
+:untitled-label: بی‌نام
+:version-label: نگارش
+:warning-caption: هشدار
+endif::[]
+//
+// Finnish translation by Tero Hänninen
+ifeval::["{lang}" == "fi"]
+:appendix-caption: Liitteet
+:caution-caption: Huom
+:example-caption: Esimerkki
+:figure-caption: Kuvio
+:important-caption: Tärkeää
+:last-update-label: Viimeksi päivitetty
+//:listing-caption: Listaus
+:manname-title: NIMI
+:note-caption: Huomio
+//:preface-title: Esipuhe
+:table-caption: Taulukko
+:tip-caption: Vinkki
+:toc-title: Sisällysluettelo
+:untitled-label: Nimetön
+:version-label: Versio
+:warning-caption: Varoitus
+endif::[]
+//
+// French translation, courtesy of Nicolas Comet <nicolas.comet at gmail.com>
+ifeval::["{lang}" == "fr"]
+:appendix-caption: Appendice
+:caution-caption: Avertissement
+:example-caption: Exemple
+:figure-caption: Figure
+:important-caption: Important
+:last-update-label: Dernière mise à jour
+//:listing-caption: Liste
+:manname-title: NOM
+:note-caption: Note
+//:preface-title: Préface
+:table-caption: Tableau
+:tip-caption: Astuce
+:toc-title: Table des matières
+:untitled-label: Sans titre
+:version-label: Version
+:warning-caption: Attention
+endif::[]
+//
+// Hungarian translation, courtesy of István Pató <istvan.pato at gmail.com>
+ifeval::["{lang}" == "hu"]
+:appendix-caption: függelék
+:caution-caption: Figyelmeztetés
+:example-caption: Példa
+:figure-caption: Ábra
+:important-caption: Fontos
+:last-update-label: Utolsó frissítés
+//:listing-caption: Lista
+:manname-title: NÉV
+:note-caption: Megjegyzés
+//:preface-title: Előszó
+:table-caption: Táblázat
+:tip-caption: Tipp
+:toc-title: Tartalomjegyzék
+:untitled-label: Névtelen
+:version-label: Verzió
+:warning-caption: Figyelem
+endif::[]
+//
+// Italian translation, courtesy of Marco Ciampa <ciampix at libero.it>
+ifeval::["{lang}" == "it"]
+:appendix-caption: Appendice
+:caution-caption: Attenzione
+:chapter-label: Capitolo
+:example-caption: Esempio
+:figure-caption: Figura
+:important-caption: Importante
+:last-update-label: Ultimo aggiornamento
+//:listing-caption: Elenco
+:manname-title: NOME
+:note-caption: Nota
+//:preface-title: Prefazione
+:table-caption: Tabella
+:tip-caption: Suggerimento
+:toc-title: Indice
+:untitled-label: Senza titolo
+:version-label: Versione
+:warning-caption: Attenzione
+endif::[]
+//
+// Japanese translation, courtesy of Takayuki Konishi <seannos.takayuki at gmail.com>
+ifeval::["{lang}" == "ja"]
+:appendix-caption: 付録
+:caution-caption: 注意
+:example-caption: 例
+:figure-caption: 図
+:important-caption: 重要
+:last-update-label: 最終更新
+//:listing-caption: リスト
+:manname-title: 名前
+:note-caption: 注記
+//:preface-title: まえがき
+:table-caption: 表
+:tip-caption: ヒント
+:toc-title: 目次
+:untitled-label: 無題
+:version-label: バージョン
+:warning-caption: 警告
+endif::[]
+//
+// Korean translation, courtesy of Sungsik Nam <jmyl at me.com>
+ifeval::["{lang}" == "kr"]
+:appendix-caption: 부록
+:caution-caption: 주의
+:example-caption: 예시
+:figure-caption: 그림
+:important-caption: 중요
+:last-update-label: 마지막 업데이트
+//:listing-caption: 목록
+:manname-title: 이름
+:note-caption: 노트
+//:preface-title: 머리말
+:table-caption: 표
+:tip-caption: 힌트
+:toc-title: 차례
+:untitled-label: 익명
+:version-label: 버전
+:warning-caption: 경고
+endif::[]
+//
+// Dutch translation, courtesy of Roel Van Steenberghe <roel.vansteenberghe at gmail.com>
+ifeval::["{lang}" == "nl"]
+:appendix-caption: Bijlage
+:caution-caption: Opgelet
+:example-caption: Voorbeeld
+:figure-caption: Figuur
+:important-caption: Belangrijk
+:last-update-label: Laatste aanpassing
+//:listing-caption: Lijst
+:manname-title: NAAM
+:note-caption: Noot
+//:preface-title: Inleiding
+:table-caption: Tabel
+:tip-caption: Tip
+:toc-title: Ínhoudsopgave
+:untitled-label: Naamloos
+:version-label: Versie
+:warning-caption: Waarschuwing
+endif::[]
+//
+// Norwegian, courtesy of Aslak Knutsen <aslak at 4fs.no>
+ifeval::["{lang}" == "no"]
+:appendix-caption: Vedlegg
+:caution-caption: Forsiktig
+:example-caption: Eksempel
+:figure-caption: Figur
+:important-caption: Viktig
+:last-update-label: Sist oppdatert
+//:listing-caption:
+:manname-title: NAVN
+:note-caption: Notat
+//:preface-title:
+:table-caption: Tabell
+:tip-caption: Tips
+:toc-title: Innholdsfortegnelse
+:untitled-label: Navnløs
+:version-label: Versjon
+:warning-caption: Advarsel
+endif::[]
+//
+// Portuguese translation, courtesy of Roberto Cortez <radcortez at yahoo.com>
+ifeval::["{lang}" == "pt"]
+:appendix-caption: Apêndice
+:caution-caption: Atenção
+:example-caption: Exemplo
+:figure-caption: Figura
+:important-caption: Importante
+:last-update-label: Última actualização
+//:listing-caption: Listagem
+:manname-title: NOME
+:note-caption: Nota
+//:preface-title: Prefácio
+:table-caption: Tabela
+:tip-caption: Sugestão
+:toc-title: Índice
+:untitled-label: Sem título
+:version-label: Versão
+:warning-caption: Aviso
+endif::[]
+//
+// Brazilian Portuguese translation, courtesy of Rafael Pestano <rmpestano at gmail.com>
+ifeval::["{lang}" == "pt_BR"]
+:appendix-caption: Apêndice
+:caution-caption: Cuidado
+:example-caption: Exemplo
+:figure-caption: Figura
+:important-caption: Importante
+:last-update-label: Última atualização
+//:listing-caption: Listagem
+:manname-title: NOME
+:note-caption: Nota
+//:preface-title: Prefácio
+:table-caption: Tabela
+:tip-caption: Dica
+:toc-title: Índice
+:untitled-label: Sem título
+:version-label: Versão
+:warning-caption: Aviso
+endif::[]
+//
+// Russian translation, courtesy of Alexander Zobkov <alexander.zobkov at gmail.com>
+ifeval::["{lang}" == "ru"]
+:appendix-caption: Приложение
+:caution-caption: Внимание
+:example-caption: Пример
+:figure-caption: Рисунок
+:important-caption: Важно
+:last-update-label: Последний раз обновлено
+//:listing-caption: Листинг
+:manname-title: НАЗВАНИЕ
+:note-caption: Примечание
+//:preface-title: Предисловие
+:table-caption: Таблица
+:tip-caption: Подсказка
+:toc-title: Содержание
+:untitled-label: Без названия
+:version-label: Версия
+:warning-caption: Предупреждение
+endif::[]
+//
+// Serbian Cyrillic translation, courtesy of Bojan Stipic <bojan-7 at live.com>
+ifeval::["{lang}" == "sr"]
+:appendix-caption: Додатак
+:caution-caption: Опрез
+//:chapter-label: Поглавље
+:example-caption: Пример
+:figure-caption: Слика
+:important-caption: Важно
+:last-update-label: Последње ажурирано
+//:listing-caption: Списак
+:manname-title: НАЗИВ
+:note-caption: Белешка
+//:preface-title: Предговор
+:table-caption: Табела
+:tip-caption: Савет
+:toc-title: Садржај
+:untitled-label: Без назива
+:version-label: Верзија
+:warning-caption: Упозорење
+endif::[]
+//
+// Serbian Latin translation, courtesy of Bojan Stipic <bojan-7 at live.com>
+ifeval::["{lang}" == "sr_Latn"]
+:appendix-caption: Dodatak
+:caution-caption: Oprez
+//:chapter-label: Poglavlje
+:example-caption: Primer
+:figure-caption: Slika
+:important-caption: Važno
+:last-update-label: Poslednje ažurirano
+//:listing-caption: Spisak
+:manname-title: NAZIV
+:note-caption: Beleška
+//:preface-title: Predgovor
+:table-caption: Tabela
+:tip-caption: Savet
+:toc-title: Sadržaj
+:untitled-label: Bez naziva
+:version-label: Verzija
+:warning-caption: Upozorenje
+endif::[]
+//
+// Turkish translation, courtesy of Rahman Usta <rahman.usta.88 at gmail.com>
+ifeval::["{lang}" == "tr"]
+:appendix-caption: Ek bölüm
+:caution-caption: Dikkat
+:example-caption: Örnek
+:figure-caption: Görsel
+:important-caption: Önemli
+:last-update-label: Son güncelleme
+//:listing-caption: Listeleme
+:manname-title: İSİM
+:note-caption: Not
+//:preface-title: Ön söz
+:table-caption: Tablo
+:tip-caption: İpucu
+:toc-title: İçindekiler
+:untitled-label: İsimsiz
+:version-label: Versiyon
+:warning-caption: Uyarı
+endif::[]
+//
+// Simplified Chinese translation, courtesy of John Dong <dongwqs at gmail.com>
+ifeval::["{lang}" == "zh_CN"]
+:appendix-caption: 附录
+:caution-caption: 注意
+:example-caption: 示例
+:figure-caption: 图表
+:important-caption: 重要
+:last-update-label: 最后更新
+//:listing-caption: 列表
+:manname-title: 名称
+:note-caption: 笔记
+//:preface-title: 序言
+:table-caption: 表格
+:tip-caption: 提示
+:toc-title: 目录
+:untitled-label: 暂无标题
+:version-label: 版本
+:warning-caption: 警告
+endif::[]
+//
+// Traditional Chinese translation, courtesy of John Dong <dongwqs at gmail.com>
+ifeval::["{lang}" == "zh_TW"]
+:appendix-caption: 附錄
+:caution-caption: 注意
+:example-caption: 示例
+:figure-caption: 圖表
+:important-caption: 重要
+:last-update-label: 最後更新
+//:listing-caption: 列表
+:manname-title: 名稱
+:note-caption: 筆記
+//:preface-title: 序言
+:table-caption: 表格
+:tip-caption: 提示
+:toc-title: 目錄
+:untitled-label: 暫無標題
+:version-label: 版本
+:warning-caption: 警告
+endif::[]
diff --git a/data/stylesheets/asciidoctor-default.css b/data/stylesheets/asciidoctor-default.css
index 36590bf..27ac53b 100644
--- a/data/stylesheets/asciidoctor-default.css
+++ b/data/stylesheets/asciidoctor-default.css
@@ -7,7 +7,6 @@ audio:not([controls]){display:none;height:0}
 [hidden],template{display:none}
 script{display:none!important}
 html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
-body{margin:0}
 a{background:transparent}
 a:focus{outline:thin dotted}
 a:active,a:hover{outline:0}
@@ -42,7 +41,7 @@ textarea{overflow:auto;vertical-align:top}
 table{border-collapse:collapse;border-spacing:0}
 *,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
 html,body{font-size:100%}
-body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto}
+body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
 a:hover{cursor:pointer}
 img,object,embed{max-width:100%;height:auto}
 object,embed{height:100%}
@@ -54,7 +53,6 @@ img{-ms-interpolation-mode:bicubic}
 .text-center{text-align:center!important}
 .text-justify{text-align:justify!important}
 .hide{display:none}
-body{-webkit-font-smoothing:antialiased}
 img,object,svg{display:inline-block;vertical-align:middle}
 textarea{height:auto;min-height:50px}
 select{width:100%}
@@ -109,13 +107,16 @@ table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:
 table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
 table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
 table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
-body{tab-size:4}
 h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
 h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
 .clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
 .clearfix:after,.float-group:after{clear:both}
-*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
+*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
+*:not(pre)>code.nobreak{word-wrap:normal}
+*:not(pre)>code.nowrap{white-space:nowrap}
 pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
+em em{font-style:normal}
+strong strong{font-weight:400}
 .keyseq{color:rgba(51,51,51,.8)}
 kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
 .keyseq kbd:first-child{margin-left:0}
diff --git a/lib/asciidoctor.rb b/lib/asciidoctor.rb
index 1a6398d..a34192a 100644
--- a/lib/asciidoctor.rb
+++ b/lib/asciidoctor.rb
@@ -13,7 +13,6 @@ if RUBY_ENGINE == 'opal'
   require 'asciidoctor/opal_ext'
 else
   autoload :Base64, 'base64'
-  autoload :FileUtils, 'fileutils'
   autoload :OpenURI, 'open-uri'
   autoload :StringScanner, 'strscan'
 end
@@ -632,7 +631,7 @@ module Asciidoctor
     InlineSectionAnchorRx = /^(.*?)#{CG_BLANK}+(\\)?\[\[([#{CC_ALPHA}:_][#{CC_WORD}:.-]*)(?:,#{CG_BLANK}*(\S.*?))?\]\]$/
 
     # Matches invalid characters in a section id.
-    InvalidSectionIdCharsRx = /&(?:[a-zA-Z]{2,}|#\d{2,5}|#x[a-fA-F0-9]{2,4});|[^#{CC_WORD}]+?/
+    InvalidSectionIdCharsRx = /&(?:[a-zA-Z]{2,}|#\d{2,6}|#x[a-fA-F0-9]{2,5});|[^#{CC_WORD}]+?/
 
     # Matches the block style used to designate a section title as a floating title.
     #
@@ -646,7 +645,9 @@ module Asciidoctor
     ## Lists
 
     # Detects the start of any list item.
-    AnyListRx = /^(?:<?\d+>#{CG_BLANK}+#{CG_GRAPH}|#{CG_BLANK}*(?:-|(?:\*|\.|\u2022){1,5}|\d+\.|[a-zA-Z]\.|[IVXivx]+\))#{CG_BLANK}+#{CG_GRAPH}|#{CG_BLANK}*.*?(?::{2,4}|;;)(?:#{CG_BLANK}+#{CG_GRAPH}|$))/
+    #
+    # NOTE we only have to check as far as the blank character because we know it means non-whitespace follows.
+    AnyListRx = /^(?:#{CG_BLANK}*(?:-|([*.\u2022])\1{0,4}|\d+\.|[a-zA-Z]\.|[IVXivx]+\))#{CG_BLANK}|#{CG_BLANK}*.*?(?::{2,4}|;;)(?:$|#{CG_BLANK})|<?\d+>#{CG_BLANK})/
 
     # Matches an unordered list item (one level for hyphens, up to 5 levels for asterisks).
     #
@@ -656,6 +657,7 @@ module Asciidoctor
     #   - Foo
     #
     # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
+    # NOTE I want to use (-|([*\u2022])\2{0,4}) but breaks the parser since it relies on fixed match positions
     UnorderedListRx = /^#{CG_BLANK}*(-|\*{1,5}|\u2022{1,5})#{CG_BLANK}+(.*)$/
 
     # Matches an ordered list item (explicit numbering or up to 5 consecutive dots).
@@ -684,7 +686,7 @@ module Asciidoctor
       #:lowergreek => /[a-z]\]/
     }
 
-    # Matches a definition list item.
+    # Matches a description list entry.
     #
     # Examples
     #
@@ -693,26 +695,26 @@ module Asciidoctor
     #   foo::::
     #   foo;;
     #
-    #   # should be followed by a definition, on the same line...
+    #   # the term can be followed by a description on the same line...
     #
     #   foo:: That which precedes 'bar' (see also, <<bar>>)
     #
-    #   # ...or on a separate line
+    #   # ...or on a separate line (optionally indented)
     #
     #   foo::
     #     That which precedes 'bar' (see also, <<bar>>)
     #
-    #   # the term may be an attribute reference
+    #   # the term or description may be an attribute reference
     #
     #   {foo_term}:: {foo_def}
     #
     # NOTE negative match for comment line is intentional since that isn't handled when looking for next list item
-    # QUESTION should we check for line comment in regex or when scanning the lines?
+    # TODO check for line comment when scanning lines instead of in regex
     #
-    DefinitionListRx = /^(?!\/\/)#{CG_BLANK}*(.*?)(:{2,4}|;;)(?:#{CG_BLANK}+(.*))?$/
+    DescriptionListRx = /^(?!\/\/)#{CG_BLANK}*(.*?)(:{2,4}|;;)(?:#{CG_BLANK}+(.*))?$/
 
-    # Matches a sibling definition list item (which does not include the keyed type).
-    DefinitionListSiblingRx = {
+    # Matches a sibling description list item (which does not include the type in the key).
+    DescriptionListSiblingRx = {
       # (?:.*?[^:])? - a non-capturing group which grabs longest sequence of characters that doesn't end w/ colon
       '::' => /^(?!\/\/)#{CG_BLANK}*((?:.*[^:])?)(::)(?:#{CG_BLANK}+(.*))?$/,
       ':::' => /^(?!\/\/)#{CG_BLANK}*((?:.*[^:])?)(:::)(?:#{CG_BLANK}+(.*))?$/,
@@ -727,7 +729,7 @@ module Asciidoctor
     #   <1> Foo
     #
     # NOTE we know trailing (.*) will match at least one character because we strip trailing spaces
-    CalloutListRx = /^<?(\d+)>#{CG_BLANK}+(.*)/
+    CalloutListRx = /^<?(\d+)>#{CG_BLANK}+(.*)$/
 
     # Matches a callout reference inside literal text.
     #
@@ -749,7 +751,7 @@ module Asciidoctor
     ListRxMap = {
       :ulist => UnorderedListRx,
       :olist => OrderedListRx,
-      :dlist => DefinitionListRx,
+      :dlist => DescriptionListRx,
       :colist => CalloutListRx
     }
 
@@ -965,12 +967,12 @@ module Asciidoctor
     ## Layout
 
     # Matches a trailing + preceded by at least one space character,
-    # which forces a hard line break (<br> tag in HTML outputs).
+    # which forces a hard line break (<br> tag in HTML output).
     #
     # Examples
     #
-    #    +
-    #   Foo +
+    #   Humpty Dumpty sat on a wall, +
+    #   Humpty Dumpty had a great fall.
     #
     if RUBY_ENGINE == 'opal'
       # NOTE JavaScript only treats ^ and $ as line boundaries in multiline regexp; . won't match newlines
@@ -1249,7 +1251,7 @@ module Asciidoctor
     # left double arrow <=
     [/\\?<=/, '⇐', :none],
     # restore entities
-    [/\\?(&)amp;((?:[a-zA-Z]+|#\d{2,5}|#x[a-fA-F0-9]{2,4});)/, '', :bounding]
+    [/\\?(&)amp;((?:[a-zA-Z]{2,}|#\d{2,6}|#x[a-fA-F0-9]{2,5});)/, '', :bounding]
   ]
 
   class << self
@@ -1308,7 +1310,8 @@ module Asciidoctor
     if ::File === input
       # TODO cli checks if input path can be read and is file, but might want to add check to API
       input_path = ::File.expand_path input.path
-      input_mtime = input.mtime
+      # See https://reproducible-builds.org/specs/source-date-epoch/
+      input_mtime = ::ENV['SOURCE_DATE_EPOCH'] ? (::Time.at ::ENV['SOURCE_DATE_EPOCH'].to_i).utc : input.mtime
       lines = input.readlines
       # hold off on setting infile and indir until we get a better sense of their purpose
       attributes['docfile'] = input_path
@@ -1487,7 +1490,7 @@ module Asciidoctor
 
       unless ::File.directory? outdir
         if mkdirs
-          ::FileUtils.mkdir_p outdir
+          Helpers.mkdir_p outdir
         else
           # NOTE we intentionally refer to the directory as it was passed to the API
           raise ::IOError, %(target directory does not exist: #{to_dir})
diff --git a/lib/asciidoctor/abstract_block.rb b/lib/asciidoctor/abstract_block.rb
index 5e8259b..4f44d8a 100644
--- a/lib/asciidoctor/abstract_block.rb
+++ b/lib/asciidoctor/abstract_block.rb
@@ -244,11 +244,10 @@ class AbstractBlock < AbstractNode
   end
 =end
 
-  # Public: Query for all descendant block nodes in the document tree that
-  # match the specified Symbol filter_context and, optionally, the style and/or
-  # role specified in the options Hash. If a block is provided, it's used as an
-  # additional filter. If no filters are specified, all block nodes in the tree
-  # are returned.
+  # Public: Query for all descendant block-level nodes in the document tree
+  # that match the specified selector (context, style, id, and/or role). If a
+  # Ruby block is given, it's used as an additional filter. If no selector or
+  # Ruby block is supplied, all block-level nodes in the tree are returned.
   #
   # Examples
   #
@@ -262,7 +261,7 @@ class AbstractBlock < AbstractNode
   #   doc.find_by context: :listing, style: 'source'
   #   #=> Asciidoctor::Block at 13136720 { context: :listing, content_model: :verbatim, style: "source", lines: 1 }
   #
-  # Returns An Array of block nodes that match the given selector or an empty Array if no matches are found
+  # Returns An Array of block-level nodes that match the filter or an empty Array if no matches are found
   #--
   # TODO support jQuery-style selector (e.g., image.thumb)
   def find_by selector = {}, &block
@@ -290,8 +289,8 @@ class AbstractBlock < AbstractNode
       result.concat(@header.find_by selector, &block)
     end
 
-    # yuck, dlist is a special case
     unless context_selector == :document # optimization
+      # yuck, dlist is a special case
       if @context == :dlist
         if any_context || context_selector != :section # optimization
           @blocks.flatten.each do |li|
@@ -356,6 +355,17 @@ class AbstractBlock < AbstractNode
     nil
   end
 
+  # Public: Retrieve the list marker keyword for the specified list type.
+  #
+  # For use in the HTML type attribute.
+  #
+  # list_type - the type of list; default to the @style if not specified
+  #
+  # Returns the single-character [String] keyword that represents the marker for the specified list type
+  def list_marker_keyword list_type = nil
+    ORDERED_LIST_KEYWORDS[list_type || @style]
+  end
+
   # Internal: Assign the next index (0-based) to this section
   #
   # Assign the next index of this section within the parent
@@ -369,10 +379,10 @@ class AbstractBlock < AbstractNode
     if section.sectname == 'appendix'
       appendix_number = @document.counter 'appendix-number', 'A'
       section.number = appendix_number if section.numbered
-      if (caption = @document.attr 'appendix-caption', '') != ''
-        section.caption = %(#{caption} #{appendix_number}: )
-      else
+      if (caption = @document.attr 'appendix-caption', '').empty?
         section.caption = %(#{appendix_number}. )
+      else
+        section.caption = %(#{caption} #{appendix_number}: )
       end
     elsif section.numbered
       # chapters in a book doctype should be sequential even when divided into parts
diff --git a/lib/asciidoctor/abstract_node.rb b/lib/asciidoctor/abstract_node.rb
index 2b97871..b336a39 100644
--- a/lib/asciidoctor/abstract_node.rb
+++ b/lib/asciidoctor/abstract_node.rb
@@ -548,9 +548,9 @@ class AbstractNode
   end
 
   # Public: Calculate the relative path to this absolute filename from the Document#base_dir
-  def relative_path(filename)
-    (@path_resolver ||= PathResolver.new).relative_path filename, @document.base_dir
-  end
+  #def relative_path(filename)
+  #  (@path_resolver ||= PathResolver.new).relative_path filename, @document.base_dir
+  #end
 
   # Public: Check whether the specified String is a URI by
   # matching it against the Asciidoctor::UriSniffRx regex.
@@ -559,16 +559,5 @@ class AbstractNode
   def is_uri? str
     Helpers.uriish? str
   end
-
-  # Public: Retrieve the list marker keyword for the specified list type.
-  #
-  # For use in the HTML type attribute.
-  #
-  # list_type - the type of list; default to the @style if not specified
-  #
-  # Returns the single-character [String] keyword that represents the marker for the specified list type
-  def list_marker_keyword(list_type = nil)
-    ORDERED_LIST_KEYWORDS[list_type || @style]
-  end
 end
 end
diff --git a/lib/asciidoctor/cli/invoker.rb b/lib/asciidoctor/cli/invoker.rb
index 08a687d..5055e24 100644
--- a/lib/asciidoctor/cli/invoker.rb
+++ b/lib/asciidoctor/cli/invoker.rb
@@ -13,12 +13,13 @@ module Asciidoctor
         @err = nil
         @code = 0
         options = options.flatten
-        if (first_option = options[0]).is_a?(Cli::Options)
+        case (first_option = options[0])
+        when Options
           @options = first_option
-        elsif first_option.is_a?(::Hash)
-          @options = Cli::Options.new(options)
+        when ::Hash
+          @options = Options.new options
         else
-          if (result = Cli::Options.parse! options).is_a? ::Integer
+          if ::Integer === (result = Options.parse! options)
             @code = result
             @options = nil
           else
diff --git a/lib/asciidoctor/cli/options.rb b/lib/asciidoctor/cli/options.rb
index 82db4e5..2932158 100644
--- a/lib/asciidoctor/cli/options.rb
+++ b/lib/asciidoctor/cli/options.rb
@@ -243,7 +243,7 @@ Example: asciidoctor -b html5 source.asciidoc
         os.puts %(Asciidoctor #{::Asciidoctor::VERSION} [http://asciidoctor.org])
         if RUBY_VERSION >= '1.9.3'
           encoding_info = {'lc' => 'locale', 'fs' => 'filesystem', 'in' => 'internal', 'ex' => 'external'}.map do |k,v|
-            %(#{k}:#{Encoding.find(v) || '-'})
+            %(#{k}:#{::Encoding.find(v) || '-'})
           end
           os.puts %(Runtime Environment (#{RUBY_DESCRIPTION}) (#{encoding_info * ' '}))
         else
diff --git a/lib/asciidoctor/converter/docbook5.rb b/lib/asciidoctor/converter/docbook5.rb
index b176a06..060c429 100644
--- a/lib/asciidoctor/converter/docbook5.rb
+++ b/lib/asciidoctor/converter/docbook5.rb
@@ -388,7 +388,7 @@ module Asciidoctor
       has_body = false
       result = []
       pgwide_attribute = (node.option? 'pgwide') ? ' pgwide="1"' : nil
-      result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{node.attr 'frame', 'all'}" rowsep="#{['none', 'cols'].include?(node.attr 'grid') ? 0 : 1}" colsep="#{['none', 'rows'].include?(node.attr 'grid') ? 0 : 1}">)
+      result << %(<#{tag_name = node.title? ? 'table' : 'informaltable'}#{common_attributes node.id, node.role, node.reftext}#{pgwide_attribute} frame="#{node.attr 'frame', 'all'}" rowsep="#{['none', 'cols'].include?(node.attr 'grid') ? 0 : 1}" colsep="#{['none', 'rows'].include?(node.attr 'grid') ? 0 : 1}"#{(node.attr? 'orientation', 'landscape', nil) ? ' orient="land"' : nil}>)
       if (node.option? 'unbreakable')
         result << '<?dbfo keep-together="always"?>'
       elsif (node.option? 'breakable')
diff --git a/lib/asciidoctor/converter/factory.rb b/lib/asciidoctor/converter/factory.rb
index c6d84d1..c74616f 100644
--- a/lib/asciidoctor/converter/factory.rb
+++ b/lib/asciidoctor/converter/factory.rb
@@ -184,11 +184,7 @@ module Asciidoctor
       # Returns the [Converter] object
       def create backend, opts = {}
         if (converter = resolve backend)
-          if converter.is_a? ::Class
-            return converter.new backend, opts
-          else
-            return converter
-          end
+          return ::Class === converter ? (converter.new backend, opts) : converter
         end
 
         base_converter = case backend
diff --git a/lib/asciidoctor/converter/html5.rb b/lib/asciidoctor/converter/html5.rb
index 2aeebcc..42116b9 100644
--- a/lib/asciidoctor/converter/html5.rb
+++ b/lib/asciidoctor/converter/html5.rb
@@ -19,7 +19,7 @@ module Asciidoctor
       #:latexmath   => INLINE_MATH_DELIMITERS[:latexmath] + [false]
     }).default = [nil, nil, nil]
 
-    SvgPreambleRx = /\A.*?(?=<svg[ >])/m
+    SvgPreambleRx = /\A.*?(?=<svg\b)/m
     SvgStartTagRx = /\A<svg[^>]*>/
     DimensionAttributeRx = /\s(?:width|height|style)=(["']).*?\1/
 
@@ -74,7 +74,7 @@ module Asciidoctor
 
       if node.attr? 'icons', 'font'
         if node.attr? 'iconfont-remote'
-          result << %(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base}/font-awesome/4.5.0/css/font-awesome.min.css]}"#{slash}>)
+          result << %(<link rel="stylesheet" href="#{node.attr 'iconfont-cdn', %[#{cdn_base}/font-awesome/4.6.3/css/font-awesome.min.css]}"#{slash}>)
         else
           iconfont_stylesheet = %(#{node.attr 'iconfont-name', 'font-awesome'}.css)
           result << %(<link rel="stylesheet" href="#{node.normalize_web_path iconfont_stylesheet, (node.attr 'stylesdir', ''), false}"#{slash}>)
@@ -220,7 +220,7 @@ module Asciidoctor
 
       if node.attr? 'stem'
         eqnums_val = node.attr 'eqnums', 'none'
-        eqnums_val = 'AMS' if eqnums_val == ''
+        eqnums_val = 'AMS' if eqnums_val.empty?
         eqnums_opt = %( equationNumbers: { autoNumber: "#{eqnums_val}" } )
         # IMPORTANT inspect calls on delimiter arrays are intentional for JavaScript compat (emulates JSON.stringify)
         result << %(<script type="text/x-mathjax-config">
@@ -321,15 +321,18 @@ MathJax.Hub.Config({
       htag = %(h#{slevel + 1})
       id_attr = anchor = link_start = link_end = nil
       if node.id
-        id_attr = %( id="#{node.id}")
-        if node.document.attr? 'sectanchors'
-          anchor = %(<a class="anchor" href="##{node.id}"></a>)
+        id_attr = %( id="#{id = node.id}")
+        if (doc = node.document).attr? 'sectanchors'
+          anchor = %(<a class="anchor" href="##{id}"></a>)
           # possible idea - anchor icons GitHub-style
-          #if node.document.attr? 'icons', 'font'
-          #  anchor = %(<a class="anchor" href="##{node.id}"><i class="fa fa-anchor"></i></a>)
+          #if doc.attr? 'icons', 'font'
+          #  anchor = %(<a class="anchor" href="##{id}"><i class="fa fa-anchor"></i></a>)
           #else
-        elsif node.document.attr? 'sectlinks'
-          link_start = %(<a class="link" href="##{node.id}">)
+          #  anchor = %(<a class="anchor" href="##{id}"></a>)
+          #end
+        end
+        if doc.attr? 'sectlinks'
+          link_start = %(<a class="link" href="##{id}">)
           link_end = '</a>'
         end
       end
@@ -377,9 +380,9 @@ MathJax.Hub.Config({
     end
 
     def audio node
-      xml = node.document.attr? 'htmlsyntax', 'xml'
+      xml = @xml_mode
       id_attribute = node.id ? %( id="#{node.id}") : nil
-      classes = ['audioblock', node.style, node.role].compact
+      classes = ['audioblock', node.role].compact
       class_attribute = %( class="#{classes * ' '}")
       title_element = node.title? ? %(<div class="title">#{node.captioned_title}</div>\n) : nil
       %(<div#{id_attribute}#{class_attribute}>
@@ -537,7 +540,7 @@ Your browser does not support the audio tag.
       target = node.attr 'target'
       width_attr = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil
       height_attr = (node.attr? 'height') ? %( height="#{node.attr 'height'}") : nil
-      if ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE
+      if ((node.attr? 'format', 'svg', false) || (target.include? '.svg')) && node.document.safe < SafeMode::SECURE &&
           ((svg = (node.option? 'inline')) || (obj = (node.option? 'interactive')))
         if svg
           img = (read_svg_contents node, target) || %(<span class="alt">#{node.attr 'alt'}</span>)
@@ -551,7 +554,7 @@ Your browser does not support the audio tag.
         img = %(<a class="image" href="#{link}">#{img}</a>)
       end
       id_attr = node.id ? %( id="#{node.id}") : nil
-      classes = ['imageblock', node.style, node.role].compact
+      classes = ['imageblock', node.role].compact
       class_attr = %( class="#{classes * ' '}")
       styles = []
       styles << %(text-align: #{node.attr 'align'}) if node.attr? 'align'
@@ -645,7 +648,8 @@ Your browser does not support the audio tag.
 
       type_attribute = (keyword = node.list_marker_keyword) ? %( type="#{keyword}") : nil
       start_attribute = (node.attr? 'start') ? %( start="#{node.attr 'start'}") : nil
-      result << %(<ol class="#{node.style}"#{type_attribute}#{start_attribute}>)
+      reversed_attribute = (node.option? 'reversed') ? (append_boolean_attribute 'reversed', @xml_mode) : nil
+      result << %(<ol class="#{node.style}"#{type_attribute}#{start_attribute}#{reversed_attribute}>)
 
       node.items.each do |item|
         result << '<li>'
@@ -666,19 +670,19 @@ Your browser does not support the audio tag.
           ''
         else
           id_attr = node.id ? %( id="#{node.id}") : nil
-          title_el = node.title? ? %(<div class="title">#{node.title}</div>) : nil
+          title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
           %(<div#{id_attr} class="quoteblock abstract#{(role = node.role) && " #{role}"}">
 #{title_el}<blockquote>
 #{node.content}
 </blockquote>
 </div>)
         end
-      elsif style == 'partintro' && (node.level != 0 || node.parent.context != :section || node.document.doctype != 'book')
+      elsif style == 'partintro' && (node.level > 0 || node.parent.context != :section || node.document.doctype != 'book')
         warn 'asciidoctor: ERROR: partintro block can only be used when doctype is book and it\'s a child of a book part. Excluding block content.'
         ''
       else
           id_attr = node.id ? %( id="#{node.id}") : nil
-          title_el = node.title? ? %(<div class="title">#{node.title}</div>) : nil
+          title_el = node.title? ? %(<div class="title">#{node.title}</div>\n) : nil
         %(<div#{id_attr} class="openblock#{style && style != 'open' ? " #{style}" : ''}#{(role = node.role) && " #{role}"}">
 #{title_el}<div class="content">
 #{node.content}
@@ -766,11 +770,11 @@ Your browser does not support the audio tag.
       id_attribute = node.id ? %( id="#{node.id}") : nil
       classes = ['tableblock', %(frame-#{node.attr 'frame', 'all'}), %(grid-#{node.attr 'grid', 'all'})]
       styles = []
-      unless node.option? 'autowidth'
-        if (tablepcwidth = node.attr 'tablepcwidth') == 100
+      unless (node.option? 'autowidth') && !(node.attr? 'width', nil, false)
+        if node.attr? 'tablepcwidth', 100
           classes << 'spread'
         else
-          styles << %(width: #{tablepcwidth}%;)
+          styles << %(width: #{node.attr 'tablepcwidth'}%;)
         end
       end
       if (role = node.role)
@@ -867,7 +871,7 @@ Your browser does not support the audio tag.
         div_classes.insert 1, 'checklist'
         ul_class_attribute = ' class="checklist"'
         if node.option? 'interactive'
-          if node.document.attr? 'htmlsyntax', 'xml'
+          if @xml_mode
             marker_checked = '<input type="checkbox" data-item-complete="1" checked="checked"/> '
             marker_unchecked = '<input type="checkbox" data-item-complete="0"/> '
           else
@@ -927,9 +931,9 @@ Your browser does not support the audio tag.
     end
 
     def video node
-      xml = node.document.attr? 'htmlsyntax', 'xml'
+      xml = @xml_mode
       id_attribute = node.id ? %( id="#{node.id}") : nil
-      classes = ['videoblock', node.style, node.role].compact
+      classes = ['videoblock', node.role].compact
       class_attribute = %( class="#{classes * ' '}")
       title_element = node.title? ? %(\n<div class="title">#{node.captioned_title}</div>) : nil
       width_attribute = (node.attr? 'width') ? %( width="#{node.attr 'width'}") : nil
@@ -1070,7 +1074,7 @@ Your browser does not support the video tag.
     def inline_image node
       if (type = node.type) == 'icon' && (node.document.attr? 'icons', 'font')
         class_attr_val = %(fa fa-#{node.target})
-        {'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-'}.each do |(key, prefix)|
+        {'size' => 'fa-', 'rotate' => 'fa-rotate-', 'flip' => 'fa-flip-'}.each do |key, prefix|
           class_attr_val = %(#{class_attr_val} #{prefix}#{node.attr key}) if node.attr? key
         end
         title_attr = (node.attr? 'title') ? %( title="#{node.attr 'title'}") : nil
@@ -1146,16 +1150,17 @@ Your browser does not support the video tag.
 
     def read_svg_contents node, target
       if (svg = node.read_contents target, :start => (node.document.attr 'imagesdir'), :normalize => true, :label => 'SVG')
-        svg = svg.sub SvgPreambleRx, ''
-        start_tag = nil
+        svg = svg.sub SvgPreambleRx, '' unless svg.start_with? '<svg'
+        old_start_tag = new_start_tag = nil
+        # NOTE width, height and style attributes are removed if either width or height is specified
         ['width', 'height'].each do |dim|
           if node.attr? dim
-            # NOTE width, height and style attributes are removed if either width or height is specified
-            start_tag ||= (svg.match SvgStartTagRx)[0].gsub DimensionAttributeRx, ''
-            start_tag = %(#{start_tag.chop} #{dim}="#{node.attr dim}px">)
+            new_start_tag = (old_start_tag = (svg.match SvgStartTagRx)[0]).gsub DimensionAttributeRx, '' unless new_start_tag
+            # QUESTION should we add px since it's already the default?
+            new_start_tag = %(#{new_start_tag.chop} #{dim}="#{node.attr dim}px">)
           end
         end
-        svg = svg.sub SvgStartTagRx, start_tag if start_tag
+        svg = %(#{new_start_tag}#{svg[old_start_tag.length..-1]}) if new_start_tag
       end
       svg
     end
diff --git a/lib/asciidoctor/converter/manpage.rb b/lib/asciidoctor/converter/manpage.rb
index d745f8b..238f7d9 100644
--- a/lib/asciidoctor/converter/manpage.rb
+++ b/lib/asciidoctor/converter/manpage.rb
@@ -14,6 +14,13 @@ module Asciidoctor
     ESC_BS = %(#{ESC}\\) # escaped backslash (indicates troff formatting sequence)
     ESC_FS = %(#{ESC}.)  # escaped full stop (indicates troff macro)
 
+    LiteralBackslashRx = /(?:\A|[^#{ESC}])\\/
+    LeadingPeriodRx = /^\./
+    EscapedMacroRx = /^(?:#{ESC}\\c\n)?#{ESC}\.((?:URL|MTO) ".*?" ".*?" )( |[^\s]*)(.*?)(?: *#{ESC}\\c)?$/
+    MockBoundaryRx = /<\/?BOUNDARY>/
+    EmDashCharRefRx = /&#8212(?:;​)?/
+    EllipsisCharRefRx = /…(?:​)?/
+
     # Converts HTML entity references back to their original form, escapes
     # special man characters and strips trailing whitespace.
     #
@@ -26,12 +33,10 @@ module Asciidoctor
     #        * :append_newline a Boolean that indicates whether to append an endline to the result (default: false)
     def manify str, opts = {}
       str = ((opts.fetch :preserve_space, true) ? (str.gsub TAB, ET) : (str.tr_s WHITESPACE, ' ')).
-        gsub(/(?:\A|[^#{ESC}])\\/, '\&(rs'). # literal backslash (not a troff escape sequence)
-        gsub(/^\./, '\\\&.').     # leading . is used in troff for macro call or other formatting; replace with \&.
+        gsub(LiteralBackslashRx, '\&(rs'). # literal backslash (not a troff escape sequence)
+        gsub(LeadingPeriodRx, '\\\&.'). # leading . is used in troff for macro call or other formatting; replace with \&.
         # drop orphaned \c escape lines, unescape troff macro, quote adjacent character, isolate macro line
-        gsub(/^(?:#{ESC}\\c\n)?#{ESC}\.((?:URL|MTO) ".*?" ".*?" )( |[^\s]*)(.*?)(?: *#{ESC}\\c)?$/) {
-          (rest = $3.lstrip).empty? ? %(.#$1"#$2") : %(.#$1"#$2"#{LF}#{rest})
-        }.
+        gsub(EscapedMacroRx) { (rest = $3.lstrip).empty? ? %(.#$1"#$2") : %(.#$1"#$2"#{LF}#{rest}) }.
         gsub('-', '\-').
         gsub('<', '<').
         gsub('>', '>').
@@ -41,20 +46,20 @@ module Asciidoctor
         gsub('™', '\(tm').  # trademark sign
         gsub(' ', ' ').     # thin space
         gsub('–', '\(en').  # en dash
-        gsub(/&#8212(?:;​)?/, '\(em'). # em dash
+        gsub(EmDashCharRefRx, '\(em'). # em dash
         gsub('‘', '\(oq').  # left single quotation mark
         gsub('’', '\(cq').  # right single quotation mark
         gsub('“', '\(lq').  # left double quotation mark
         gsub('”', '\(rq').  # right double quotation mark
-        gsub(/…(?:​)?/, '...'). # horizontal ellipsis
+        gsub(EllipsisCharRefRx, '...'). # horizontal ellipsis
         gsub('←', '\(<-').  # leftwards arrow
         gsub('→', '\(->').  # rightwards arrow
         gsub('⇐', '\(lA').  # leftwards double arrow
         gsub('⇒', '\(rA').  # rightwards double arrow
         gsub('​', '\:').    # zero width space
         gsub('\'', '\(aq').       # apostrophe-quote
-        gsub(/<\/?BOUNDARY>/, '').# artificial boundary
-        gsub(ESC_BS, '\\').       # unescape troff backslash (NOTE update if more escaped are added)
+        gsub(MockBoundaryRx, ''). # mock boundary
+        gsub(ESC_BS, '\\').       # unescape troff backslash (NOTE update if more escapes are added)
         rstrip                    # strip trailing space
       opts[:append_newline] ? %(#{str}#{LF}) : str
     end
diff --git a/lib/asciidoctor/converter/template.rb b/lib/asciidoctor/converter/template.rb
index b9e108a..4308dfd 100644
--- a/lib/asciidoctor/converter/template.rb
+++ b/lib/asciidoctor/converter/template.rb
@@ -246,20 +246,24 @@ module Asciidoctor
         elsif name.start_with? 'block_'
           name = name[6..-1]
         end
-        ext_name = path_segments[-1]
+        
         template_class = ::Tilt
         extra_engine_options = {}
-        if ext_name == 'slim'
+        case (ext_name = path_segments[-1])
+        when 'slim'
           # slim doesn't get loaded by Tilt, so we have to load it explicitly
           Helpers.require_library 'slim' unless defined? ::Slim
           # align safe mode of AsciiDoc embedded in Slim template with safe mode of current document
           (@engine_options[:slim][:asciidoc] ||= {})[:safe] ||= @safe if @safe && ::Slim::VERSION >= '3.0'
           # load include plugin when using Slim >= 2.1
           require 'slim/include' unless (defined? ::Slim::Include) || ::Slim::VERSION < '2.1'
-        elsif ext_name == 'erb'
+        when 'erb'
           template_class, extra_engine_options = (eruby_loaded ||= load_eruby(@eruby))
+        when 'rb'
+          next
+        else
+          next unless ::Tilt.registered? ext_name
         end
-        next unless ::Tilt.registered? ext_name
         unless template_cache && (template = template_cache[file])
           template = template_class.new file, 1, (@engine_options[ext_name.to_sym] || {}).merge(extra_engine_options)
         end
diff --git a/lib/asciidoctor/core_ext.rb b/lib/asciidoctor/core_ext.rb
index 5f2fdbc..a3e2b73 100644
--- a/lib/asciidoctor/core_ext.rb
+++ b/lib/asciidoctor/core_ext.rb
@@ -1,7 +1,8 @@
-require 'asciidoctor/core_ext/object/nil_or_empty'
-unless RUBY_ENGINE == 'opal'
-  unless RUBY_MIN_VERSION_1_9
-    require 'asciidoctor/core_ext/string/chr'
-    require 'asciidoctor/core_ext/symbol/length'
-  end
+require 'asciidoctor/core_ext/nil_or_empty'
+if RUBY_MIN_VERSION_1_9
+  require 'asciidoctor/core_ext/string/limit'
+elsif RUBY_ENGINE != 'opal'
+  require 'asciidoctor/core_ext/1.8.7/string/chr'
+  require 'asciidoctor/core_ext/1.8.7/string/limit'
+  require 'asciidoctor/core_ext/1.8.7/symbol/length'
 end
diff --git a/lib/asciidoctor/core_ext/string/chr.rb b/lib/asciidoctor/core_ext/1.8.7/string/chr.rb
similarity index 73%
rename from lib/asciidoctor/core_ext/string/chr.rb
rename to lib/asciidoctor/core_ext/1.8.7/string/chr.rb
index 8592ee6..b9b9c92 100644
--- a/lib/asciidoctor/core_ext/string/chr.rb
+++ b/lib/asciidoctor/core_ext/1.8.7/string/chr.rb
@@ -2,5 +2,5 @@
 class String
   def chr
     self[0..0]
-  end unless respond_to? :chr
+  end unless method_defined? :chr
 end
diff --git a/lib/asciidoctor/core_ext/1.8.7/string/limit.rb b/lib/asciidoctor/core_ext/1.8.7/string/limit.rb
new file mode 100644
index 0000000..c778bae
--- /dev/null
+++ b/lib/asciidoctor/core_ext/1.8.7/string/limit.rb
@@ -0,0 +1,28 @@
+if RUBY_ENGINE_JRUBY
+  class String
+    # Safely truncate the string to the specified number of bytes.
+    # If a multibyte char gets split, the dangling fragment is removed.
+    def limit size
+      return self unless size < bytesize
+      result = (unpack %(a#{size}))[0]
+      begin
+        result.unpack 'U*'
+      rescue ArgumentError
+        result.chop!
+        retry
+      end
+      result
+    end unless method_defined? :limit
+  end
+else
+  class String
+    # Safely truncate the string to the specified number of bytes.
+    # If a multibyte char gets split, the dangling fragment is removed.
+    def limit size
+      return self unless size < bytesize
+      result = (unpack %(a#{size}))[0]
+      result.chop! until result.empty? || /.$/u =~ result
+      result
+    end unless method_defined? :limit
+  end
+end
diff --git a/lib/asciidoctor/core_ext/symbol/length.rb b/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb
similarity index 72%
rename from lib/asciidoctor/core_ext/symbol/length.rb
rename to lib/asciidoctor/core_ext/1.8.7/symbol/length.rb
index 7e35bfd..c51de6f 100644
--- a/lib/asciidoctor/core_ext/symbol/length.rb
+++ b/lib/asciidoctor/core_ext/1.8.7/symbol/length.rb
@@ -2,5 +2,5 @@
 class Symbol
   def length
     to_s.length
-  end unless respond_to? :length
+  end unless method_defined? :length
 end
diff --git a/lib/asciidoctor/core_ext/nil_or_empty.rb b/lib/asciidoctor/core_ext/nil_or_empty.rb
new file mode 100644
index 0000000..7e3f79a
--- /dev/null
+++ b/lib/asciidoctor/core_ext/nil_or_empty.rb
@@ -0,0 +1,23 @@
+# A core library extension that defines the method nil_or_empty? as an alias to
+# optimize checks for nil? or empty? on common object types such as NilClass,
+# String, Array, Hash, and Numeric.
+
+class NilClass
+  alias :nil_or_empty? :nil? unless method_defined? :nil_or_empty?
+end
+
+class String
+  alias :nil_or_empty? :empty? unless method_defined? :nil_or_empty?
+end
+
+class Array
+  alias :nil_or_empty? :empty? unless method_defined? :nil_or_empty?
+end
+
+class Hash
+  alias :nil_or_empty? :empty? unless method_defined? :nil_or_empty?
+end
+
+class Numeric
+  alias :nil_or_empty? :nil? unless method_defined? :nil_or_empty?
+end
diff --git a/lib/asciidoctor/core_ext/object/nil_or_empty.rb b/lib/asciidoctor/core_ext/object/nil_or_empty.rb
deleted file mode 100644
index 029ac61..0000000
--- a/lib/asciidoctor/core_ext/object/nil_or_empty.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# A core library extension that defines the method nil_or_empty? as an alias to
-# optimize checks for nil? or empty? on common object types such as NilClass,
-# String, Array and Hash.
-
-class NilClass
-  alias :nil_or_empty? :nil? unless respond_to? :nil_or_empty?
-end
-
-class String
-  alias :nil_or_empty? :empty? unless respond_to? :nil_or_empty?
-end
-
-class Array
-  alias :nil_or_empty? :empty? unless respond_to? :nil_or_empty?
-end
-
-class Hash
-  alias :nil_or_empty? :empty? unless respond_to? :nil_or_empty?
-end
-
-class Numeric
-  alias :nil_or_empty? :nil? unless respond_to? :nil_or_empty?
-end
diff --git a/lib/asciidoctor/core_ext/string/limit.rb b/lib/asciidoctor/core_ext/string/limit.rb
new file mode 100644
index 0000000..8a20d54
--- /dev/null
+++ b/lib/asciidoctor/core_ext/string/limit.rb
@@ -0,0 +1,10 @@
+class String
+  # Safely truncate the string to the specified number of bytes.
+  # If a multibyte char gets split, the dangling fragment is removed.
+  def limit size
+    return self unless size < bytesize
+    # NOTE JRuby 1.7 & Rubinius fail to detect invalid encoding unless encoding is forced; impact is marginal.
+    size -= 1 until ((result = byteslice 0, size).force_encoding ::Encoding::UTF_8).valid_encoding?
+    result
+  end unless method_defined? :limit
+end
diff --git a/lib/asciidoctor/document.rb b/lib/asciidoctor/document.rb
index 65d4e50..4004891 100644
--- a/lib/asciidoctor/document.rb
+++ b/lib/asciidoctor/document.rb
@@ -225,7 +225,7 @@ class Document < AbstractBlock
       # safely resolve the safe mode from const, int or string
       if !(safe_mode = options[:safe])
         @safe = SafeMode::SECURE
-      elsif ::Fixnum === safe_mode
+      elsif ::Integer === safe_mode
         # be permissive in case API user wants to define new levels
         @safe = safe_mode
       else
@@ -236,8 +236,8 @@ class Document < AbstractBlock
           @safe = SafeMode::SECURE
         end
       end
+      @compat_mode = attr_overrides.key? 'compat-mode'
       @sourcemap = options[:sourcemap]
-      @compat_mode = false
       @converter = nil
       initialize_extensions = defined? ::Asciidoctor::Extensions
       @extensions = nil # initialize furthur down
@@ -287,7 +287,7 @@ class Document < AbstractBlock
     attr_overrides['asciidoctor'] = ''
     attr_overrides['asciidoctor-version'] = VERSION
 
-    safe_mode_name = SafeMode.constants.detect {|l| SafeMode.const_get(l) == @safe }.to_s.downcase
+    safe_mode_name = SafeMode.constants.find {|l| SafeMode.const_get(l) == @safe }.to_s.downcase
     attr_overrides['safe-mode-name'] = safe_mode_name
     attr_overrides["safe-mode-#{safe_mode_name}"] = ''
     attr_overrides['safe-mode-level'] = @safe
@@ -295,14 +295,11 @@ class Document < AbstractBlock
     # sync the embedded attribute w/ the value of options...do not allow override
     attr_overrides['embedded'] = header_footer ? nil : ''
 
-    # the only way to set the max-include-depth attribute is via the document options
-    # 64 is the AsciiDoc default
+    # the only way to set the max-include-depth attribute is via the API; default to 64 like AsciiDoc Python
     attr_overrides['max-include-depth'] ||= 64
 
-    # the only way to enable uri reads is via the document options, disabled by default
-    unless !attr_overrides['allow-uri-read'].nil?
-      attr_overrides['allow-uri-read'] = nil
-    end
+    # the only way to set the allow-uri-read attribute is via the API; disabled by default
+    attr_overrides['allow-uri-read'] ||= nil
 
     attr_overrides['user-home'] = USER_HOME
 
@@ -344,6 +341,7 @@ class Document < AbstractBlock
       attr_overrides['docdir'] = ''
       attr_overrides['user-home'] = '.'
       if @safe >= SafeMode::SECURE
+        attr_overrides['max-attribute-value-size'] = 4096 unless attr_overrides.key? 'max-attribute-value-size'
         # assign linkcss (preventing css embedding) unless explicitly disabled from the commandline or API
         # effectively the same has "has key 'linkcss' and value == nil"
         unless attr_overrides.fetch('linkcss', '').nil?
@@ -354,6 +352,9 @@ class Document < AbstractBlock
       end
     end
 
+    # the only way to set the max-attribute-value-size attribute is via the API; disabled by default
+    @max_attribute_value_size = (val = (attr_overrides['max-attribute-value-size'] ||= nil)) ? val.to_i.abs : nil
+
     attr_overrides.delete_if do |key, val|
       verdict = false
       # a nil value undefines the attribute
@@ -371,8 +372,6 @@ class Document < AbstractBlock
       verdict
     end
 
-    @compat_mode = true if attrs.key? 'compat-mode'
-
     if parent_doc
       # setup default doctype (backend is fixed)
       attrs['doctype'] ||= DEFAULT_DOCTYPE
@@ -401,13 +400,15 @@ class Document < AbstractBlock
       #attrs['infile'] = attrs['docfile']
 
       # dynamic intrinstic attribute values
-      now = ::Time.now
+
+      # See https://reproducible-builds.org/specs/source-date-epoch/
+      now = ::ENV['SOURCE_DATE_EPOCH'] ? (::Time.at ::ENV['SOURCE_DATE_EPOCH'].to_i).utc : ::Time.now
       localdate = (attrs['localdate'] ||= now.strftime('%Y-%m-%d'))
       unless (localtime = attrs['localtime'])
         begin
           localtime = attrs['localtime'] = now.strftime('%H:%M:%S %Z')
-        rescue
-          localtime = attrs['localtime'] = now.strftime('%H:%M:%S')
+        rescue # Asciidoctor.js fails if timezone string has characters outside basic Latin (see asciidoctor.js#23)
+          localtime = attrs['localtime'] = now.strftime('%H:%M:%S %z')
         end
       end
       attrs['localdatetime'] ||= %(#{localdate} #{localtime})
@@ -679,7 +680,7 @@ class Document < AbstractBlock
 
   # QUESTION move to AbstractBlock?
   def first_section
-    has_header? ? @header : (@blocks || []).detect{|e| e.context == :section }
+    has_header? ? @header : (@blocks || []).find {|e| e.context == :section }
   end
 
   def has_header?
@@ -835,13 +836,18 @@ class Document < AbstractBlock
     if attribute_locked?(name)
       false
     else
+      if @max_attribute_value_size
+        resolved_value = (apply_attribute_value_subs value).limit @max_attribute_value_size
+      else
+        resolved_value = apply_attribute_value_subs value
+      end
       case name
       when 'backend'
-        update_backend_attributes apply_attribute_value_subs(value), !!@attributes_modified.delete?('htmlsyntax')
+        update_backend_attributes resolved_value, !!@attributes_modified.delete?('htmlsyntax')
       when 'doctype'
-        update_doctype_attributes apply_attribute_value_subs(value)
+        update_doctype_attributes resolved_value
       else
-        @attributes[name] = apply_attribute_value_subs(value)
+        @attributes[name] = resolved_value
       end
       @attributes_modified << name
       true
@@ -1110,17 +1116,18 @@ class Document < AbstractBlock
   # attribute is set, read the doc-name.docinfo.ext file. If the docinfo2
   # attribute is set, read both files in that order.
   #
-  # location - The Symbol location of the docinfo, either :header or :footer. (default: :header)
-  # ext      - The extension of the docinfo file(s). If not set, the extension
-  #            will be determined based on the basebackend. (default: nil)
+  # location - The Symbol location of the docinfo (e.g., :head, :footer, etc). (default: :head)
+  # suffix   - The suffix of the docinfo file(s). If not set, the extension
+  #            will be set to the outfilesuffix. (default: nil)
   #
-  # returns The contents of the docinfo file(s)
-  def docinfo(location = :head, ext = nil)
+  # returns The contents of the docinfo file(s) or empty string if no files are
+  # found or the safe mode is secure or greater.
+  def docinfo location = :head, suffix = nil
     if safe >= SafeMode::SECURE
       ''
     else
-      qualifier = (location == :footer ? '-footer' : nil)
-      ext = @outfilesuffix unless ext
+      qualifier = location == :head ? nil : %(-#{location})
+      suffix = @outfilesuffix unless suffix
       docinfodir = @attributes['docinfodir']
 
       content = nil
@@ -1138,7 +1145,7 @@ class Document < AbstractBlock
       end
 
       if docinfo
-        docinfo_filename = %(docinfo#{qualifier}#{ext})
+        docinfo_filename = %(docinfo#{qualifier}#{suffix})
         unless (docinfo & ['shared', %(shared-#{location})]).empty?
           docinfo_path = normalize_system_path(docinfo_filename, docinfodir)
           # NOTE normalizing the lines is essential if we're performing substitutions
diff --git a/lib/asciidoctor/extensions.rb b/lib/asciidoctor/extensions.rb
index 752e158..7e86d5a 100644
--- a/lib/asciidoctor/extensions.rb
+++ b/lib/asciidoctor/extensions.rb
@@ -106,16 +106,16 @@ module Extensions
 
     # Public: Parses blocks in the content and attaches the block to the parent.
     #
-    # Returns nothing
+    # Returns The parent node into which the blocks are parsed.
     #--
     # QUESTION is parse_content the right method name? should we wrap in open block automatically?
-    def parse_content parent, content, attributes = {}
-      reader = (content.is_a? Reader) ? content : (Reader.new content)
+    def parse_content parent, content, attributes = nil
+      reader = Reader === content ? content : (Reader.new content)
       while reader.has_more_lines?
-        block = Parser.next_block reader, parent, attributes
+        block = Parser.next_block reader, parent, (attributes ? attributes.dup : {})
         parent << block if block
       end
-      nil
+      parent
     end
 
     # TODO fill out remaining methods
@@ -145,7 +145,7 @@ module Extensions
     def process *args, &block
       # need to check for both block/proc and lambda
       # TODO need test for this!
-      #if block_given? || (args.size == 1 && ((block = args[0]).is_a? ::Proc))
+      #if block_given? || (args.size == 1 && ::Proc === (block = args[0]))
       if block_given?
         @process_block = block
       elsif @process_block
@@ -326,7 +326,7 @@ module Extensions
 
     # FIXME this isn't the prettiest thing
     def named value
-      if self.is_a? Processor
+      if Processor === self
         @name = value
       else
         option :name, value
@@ -379,7 +379,7 @@ module Extensions
     # QUESTION perhaps include a SyntaxDsl?
 
     def named value
-      if self.is_a? Processor
+      if Processor === self
         @name = value
       else
         option :name, value
@@ -803,7 +803,7 @@ module Extensions
     def docinfo_processors? location = nil
       if @docinfo_processor_extensions
         if location
-          @docinfo_processor_extensions.find {|ext| ext.config[:location] == location }
+          @docinfo_processor_extensions.any? {|ext| ext.config[:location] == location }
         else
           true
         end
@@ -1133,7 +1133,7 @@ module Extensions
       else
         processor, config = resolve_args args, 2
         # style 2: specified as class or class name
-        if (processor.is_a? ::Class) || ((processor.is_a? ::String) && (processor = Extensions.class_for_name processor))
+        if ::Class === processor || (::String === processor && (processor = Extensions.class_for_name processor))
           unless processor < kind_class || (kind_java_class && processor < kind_java_class)
             raise ::ArgumentError.new %(Invalid type for #{kind_name} extension: #{processor})
           end
@@ -1141,7 +1141,7 @@ module Extensions
           processor_instance.freeze
           ProcessorExtension.new kind, processor_instance
         # style 3: specified as instance
-        elsif (processor.is_a? kind_class) || (kind_java_class && (processor.is_a? kind_java_class))
+        elsif kind_class === processor || (kind_java_class && kind_java_class === processor)
           processor.update_config config
           processor.freeze
           ProcessorExtension.new kind, processor
@@ -1190,7 +1190,7 @@ module Extensions
       else
         processor, name, config = resolve_args args, 3
         # style 2: specified as class or class name
-        if (processor.is_a? ::Class) || ((processor.is_a? ::String) && (processor = Extensions.class_for_name processor))
+        if ::Class === processor || (::String === processor && (processor = Extensions.class_for_name processor))
           unless processor < kind_class || (kind_java_class && processor < kind_java_class)
             raise ::ArgumentError.new %(Class specified for #{kind_name} extension does not inherit from #{kind_class}: #{processor})
           end
@@ -1201,7 +1201,7 @@ module Extensions
           processor.freeze
           kind_store[name] = ProcessorExtension.new kind, processor_instance
         # style 3: specified as instance
-        elsif (processor.is_a? kind_class) || (kind_java_class && (processor.is_a? kind_java_class))
+        elsif kind_class === processor || (kind_java_class && kind_java_class === processor)
           processor.update_config config
           # TODO need a test for this override!
           unless (name = name ? (processor.name = as_symbol name) : (as_symbol processor.name))
@@ -1216,7 +1216,7 @@ module Extensions
     end
 
     def resolve_args args, expect
-      opts = (args[-1].is_a? ::Hash) ? args.pop : {}
+      opts = ::Hash === args[-1] ? args.pop : {}
       return opts if expect == 1
       num_args = args.size
       if (missing = expect - 1 - num_args) > 0
@@ -1229,7 +1229,7 @@ module Extensions
     end
 
     def as_symbol name
-      name ? ((name.is_a? ::Symbol) ? name : name.to_sym) : nil
+      name ? name.to_sym : nil
     end
   end
 
@@ -1323,7 +1323,7 @@ module Extensions
 
     # unused atm, but tested
     def resolve_class object
-      (object.is_a? ::Class) ? object : (class_for_name object.to_s)
+      ::Class === object ? object : (class_for_name object.to_s)
     end
 
     # Public: Resolves the Class object for the qualified name.
diff --git a/lib/asciidoctor/helpers.rb b/lib/asciidoctor/helpers.rb
index 3b24067..c588c80 100644
--- a/lib/asciidoctor/helpers.rb
+++ b/lib/asciidoctor/helpers.rb
@@ -189,7 +189,7 @@ module Helpers
   # Returns the String filename with leading directories removed and, if specified, the extension removed
   def self.basename(file_name, drop_extname = false)
     if drop_extname
-      ::File.basename file_name, ((::File.extname file_name) || '')
+      ::File.basename file_name, (::File.extname file_name)
     else
       ::File.basename file_name
     end
diff --git a/lib/asciidoctor/list.rb b/lib/asciidoctor/list.rb
index f14fcb6..d8143da 100644
--- a/lib/asciidoctor/list.rb
+++ b/lib/asciidoctor/list.rb
@@ -43,6 +43,9 @@ end
 # Public: Methods for managing items for AsciiDoc olists, ulist, and dlists.
 class ListItem < AbstractBlock
 
+  # A contextual alias for the list parent node; counterpart to the items alias on List
+  alias :list :parent
+
   # Public: Get/Set the String used to mark this list item
   attr_accessor :marker
 
diff --git a/lib/asciidoctor/parser.rb b/lib/asciidoctor/parser.rb
index df97104..b73b6f2 100644
--- a/lib/asciidoctor/parser.rb
+++ b/lib/asciidoctor/parser.rb
@@ -437,7 +437,7 @@ class Parser
     else
       block_extensions = block_macro_extensions = false
     end
-    #parent_context = parent.is_a?(Block) ? parent.context : nil
+    #parent_context = Block === parent ? parent.context : nil
     in_list = ListItem === parent
     block = nil
     style = nil
@@ -523,9 +523,11 @@ class Parser
                 posattrs = []
               end
 
-              unless !style || explicit_style
+              # QUESTION why did we make exception for explicit style?
+              #if style && !explicit_style
+              if style
                 attributes['alt'] = style if blk_ctx == :image
-                attributes.delete('style')
+                attributes.delete 'style'
                 style = nil
               end
 
@@ -633,7 +635,7 @@ class Parser
           elsif (match = OrderedListRx.match(this_line))
             reader.unshift_line this_line
             block = next_outline_list(reader, :olist, parent)
-            # QUESTION move this logic to next_outline_list?
+            # TODO move this logic into next_outline_list
             if !attributes['style'] && !block.attributes['style']
               marker = block.items[0].marker
               if marker.start_with? '.'
@@ -641,13 +643,13 @@ class Parser
                 #attributes['style'] = (ORDERED_LIST_STYLES[block.level - 1] || ORDERED_LIST_STYLES[0]).to_s
                 attributes['style'] = (ORDERED_LIST_STYLES[marker.length - 1] || ORDERED_LIST_STYLES[0]).to_s
               else
-                style = ORDERED_LIST_STYLES.detect{|s| OrderedListMarkerRxMap[s] =~ marker }
+                style = ORDERED_LIST_STYLES.find {|s| OrderedListMarkerRxMap[s] =~ marker }
                 attributes['style'] = (style || ORDERED_LIST_STYLES[0]).to_s
               end
             end
             break
 
-          elsif (match = DefinitionListRx.match(this_line))
+          elsif (match = DescriptionListRx.match(this_line))
             reader.unshift_line this_line
             block = next_labeled_list(reader, match, parent)
             break
@@ -710,7 +712,7 @@ class Parser
             adjust_indentation! lines
 
             block = Block.new(parent, :literal, :content_model => :verbatim, :source => lines, :attributes => attributes)
-            # a literal gets special meaning inside of a definition list
+            # a literal gets special meaning inside of a description list
             # TODO this feels hacky, better way to distinguish from explicit literal block?
             block.set_option('listparagraph') if in_list
 
@@ -901,7 +903,7 @@ class Parser
     if block
       block.source_location = source_location if source_location
       # REVIEW seems like there is a better way to organize this wrap-up
-      block.title     = attributes['title'] unless block.title?
+      block.title = attributes['title'] unless block.title?
       # FIXME HACK don't hardcode logic for alt, caption and scaledwidth on images down here
       if block.context == :image
         resolved_target = attributes['target']
@@ -1034,7 +1036,7 @@ class Parser
     end
   end
 
-  # whether a block supports complex content should be a config setting
+  # whether a block supports compound content should be a config setting
   # if terminator is false, that means the all the lines in the reader should be parsed
   # NOTE could invoke filter in here, before and after parsing
   def self.build_block(block_context, content_model, terminator, parent, reader, attributes, options = {})
@@ -1237,7 +1239,7 @@ class Parser
     nil
   end
 
-  # Internal: Parse and construct a labeled (e.g., definition) list Block from the current position of the Reader
+  # Internal: Parse and construct a description list Block from the current position of the Reader
   #
   # reader    - The Reader from which to retrieve the labeled list
   # match     - The Regexp match for the head of the list
@@ -1249,7 +1251,7 @@ class Parser
     previous_pair = nil
     # allows us to capture until we find a labeled item
     # that uses the same delimiter (::, :::, :::: or ;;)
-    sibling_pattern = DefinitionListSiblingRx[match[2]]
+    sibling_pattern = DescriptionListSiblingRx[match[2]]
 
     # NOTE skip the match on the first time through as we've already done it (emulates begin...while)
     while match || (reader.has_more_lines? && (match = sibling_pattern.match(reader.peek_line)))
@@ -1270,12 +1272,12 @@ class Parser
 
   # Internal: Parse and construct the next ListItem for the current bulleted
   # (unordered or ordered) list Block, callout lists included, or the next
-  # term ListItem and definition ListItem pair for the labeled list Block.
+  # term ListItem and description ListItem pair for the labeled list Block.
   #
   # First collect and process all the lines that constitute the next list
   # item for the parent list (according to its type). Next, parse those lines
   # into blocks and associate them with the ListItem (in the case of a
-  # labeled list, the definition ListItem). Finally, fold the first block
+  # labeled list, the description ListItem). Finally, fold the first block
   # into the item's text attribute according to rules described in ListItem.
   #
   # reader        - The Reader from which to retrieve the next list item
@@ -1370,7 +1372,7 @@ class Parser
   # through all the rules that determine what comprises a list item.
   #
   # Grab lines until a sibling list item is found, or the block is broken by a
-  # terminator (such as a line comment). Definition lists are more greedy if
+  # terminator (such as a line comment). Description lists are more greedy if
   # they don't have optional inline item text...they want that text
   #
   # reader          - The Reader from which to retrieve the lines.
@@ -1464,7 +1466,7 @@ class Parser
           elsif BlockTitleRx =~ this_line || BlockAttributeLineRx =~ this_line || AttributeEntryRx =~ this_line
             buffer << this_line
           else
-            if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).detect {|ctx| ListRxMap[ctx] =~ this_line }
+            if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
               within_nested_list = true
               if nested_list_type == :dlist && $~[3].nil_or_empty?
                 # get greedy again
@@ -1494,7 +1496,7 @@ class Parser
               # TODO any way to combine this with the check after skipping blank lines?
               if is_sibling_list_item?(this_line, list_type, sibling_trait)
                 break
-              elsif nested_list_type = NESTABLE_LIST_CONTEXTS.detect {|ctx| ListRxMap[ctx] =~ this_line }
+              elsif nested_list_type = NESTABLE_LIST_CONTEXTS.find {|ctx| ListRxMap[ctx] =~ this_line }
                 buffer << this_line
                 within_nested_list = true
                 if nested_list_type == :dlist && $~[3].nil_or_empty?
@@ -1525,7 +1527,7 @@ class Parser
           end
         else
           has_text = true if !this_line.empty?
-          if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).detect {|ctx| ListRxMap[ctx] =~ this_line }
+          if nested_list_type = (within_nested_list ? [:dlist] : NESTABLE_LIST_CONTEXTS).find {|ctx| ListRxMap[ctx] =~ this_line }
             within_nested_list = true
             if nested_list_type == :dlist && $~[3].nil_or_empty?
               # get greedy again
@@ -1818,7 +1820,7 @@ class Parser
           # apply header subs and assign to document
           author_metadata.each do |key, val|
             unless document.attributes.has_key? key
-              document.attributes[key] = ((val.is_a? ::String) ? document.apply_header_subs(val) : val)
+              document.attributes[key] = ::String === val ? (document.apply_header_subs val) : val
             end
           end
 
@@ -1838,7 +1840,7 @@ class Parser
         rev_line = reader.read_line
         if (match = RevisionInfoLineRx.match(rev_line))
           rev_metadata['revnumber'] = match[1].rstrip if match[1]
-          unless (component = match[2].strip) == ''
+          unless (component = match[2].strip).empty?
             # version must begin with 'v' if date is absent
             if !match[1] && (component.start_with? 'v')
               rev_metadata['revnumber'] = component[1..-1]
@@ -1928,7 +1930,7 @@ class Parser
     author_entries.each_with_index do |author_entry, idx|
       next if author_entry.empty?
       key_map = {}
-      if idx.zero?
+      if idx == 0
         keys.each do |key|
           key_map[key.to_sym] = key
         end
@@ -1977,7 +1979,7 @@ class Parser
           author_metadata[%(#{key}_1)] = author_metadata[key] if author_metadata.has_key? key
         end
       end
-      if idx.zero?
+      if idx == 0
         author_metadata['authors'] = author_metadata[key_map[:author]]
       else
         author_metadata['authors'] = %(#{author_metadata['authors']}, #{author_metadata[key_map[:author]]})
@@ -2193,7 +2195,7 @@ class Parser
   #
   # Returns the String of the first marker in this number series
   def self.resolve_ordered_list_marker(marker, ordinal = 0, validate = false, reader = nil)
-    number_style = ORDERED_LIST_STYLES.detect {|s| OrderedListMarkerRxMap[s] =~ marker }
+    number_style = ORDERED_LIST_STYLES.find {|s| OrderedListMarkerRxMap[s] =~ marker }
     expected = actual = nil
     case number_style
       when :arabic
@@ -2247,7 +2249,7 @@ class Parser
   # Returns a Boolean indicating whether this line is a sibling list item given
   # the criteria provided
   def self.is_sibling_list_item?(line, list_type, sibling_trait)
-    if sibling_trait.is_a? ::Regexp
+    if ::Regexp === sibling_trait
       matcher = sibling_trait
       expected_marker = false
     else
@@ -2280,25 +2282,27 @@ class Parser
       table.assign_caption attributes.delete('caption')
     end
 
-    if (attributes.key? 'cols') && !(col_specs = parse_col_specs attributes['cols']).empty?
-      table.create_columns col_specs
-      explicit_col_specs = true
+    if (attributes.key? 'cols') && !(colspecs = parse_colspecs attributes['cols']).empty?
+      table.create_columns colspecs
+      explicit_colspecs = true
     else
-      explicit_col_specs = false
+      explicit_colspecs = false
     end
 
     skipped = table_reader.skip_blank_lines
 
     parser_ctx = Table::ParserContext.new(table_reader, table, attributes)
+    skip_implicit_header = (attributes.key? 'header-option') || (attributes.key? 'noheader-option')
     loop_idx = -1
     while table_reader.has_more_lines?
       loop_idx += 1
       line = table_reader.read_line
 
-      if skipped == 0 && loop_idx.zero? && !attributes.has_key?('options') &&
+      if !skip_implicit_header && skipped == 0 && loop_idx == 0 &&
           !(next_line = table_reader.peek_line).nil? && next_line.empty?
         table.has_header_option = true
-        table.set_option 'header'
+        attributes['header-option'] = ''
+        attributes['options'] = (attributes.key? 'options') ? %(#{attributes['options']},header) : 'header'
       end
 
       if parser_ctx.format == 'psv'
@@ -2307,10 +2311,10 @@ class Parser
           # push an empty cell spec if boundary at start of line
           parser_ctx.close_open_cell
         else
-          next_cell_spec, line = parse_cell_spec(line, :start, parser_ctx.delimiter)
+          next_cellspec, line = parse_cellspec(line, :start, parser_ctx.delimiter)
           # if the cell spec is not null, then we're at a cell boundary
-          if !next_cell_spec.nil?
-            parser_ctx.close_open_cell next_cell_spec
+          if !next_cellspec.nil?
+            parser_ctx.close_open_cell next_cellspec
           else
             # QUESTION do we not advance to next line? if so, when will we if we came into this block?
           end
@@ -2341,14 +2345,14 @@ class Parser
           end
 
           if parser_ctx.format == 'psv'
-            next_cell_spec, cell_text = parse_cell_spec(m.pre_match, :end)
-            parser_ctx.push_cell_spec next_cell_spec
+            next_cellspec, cell_text = parse_cellspec(m.pre_match, :end)
+            parser_ctx.push_cellspec next_cellspec
             parser_ctx.buffer = %(#{parser_ctx.buffer}#{cell_text})
           else
             parser_ctx.buffer = %(#{parser_ctx.buffer}#{m.pre_match})
           end
 
-          if (line = m.post_match) == ''
+          if (line = m.post_match).empty?
             # hack to prevent dropping empty cell found at end of line (see issue #1106)
             seen = false
           end
@@ -2380,8 +2384,8 @@ class Parser
       end
     end
 
-    unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_col_specs
-      table.assign_col_widths
+    unless (table.attributes['colcount'] ||= table.columns.size) == 0 || explicit_colspecs
+      table.assign_column_widths
     end
 
     table.partition_header_footer attributes
@@ -2400,7 +2404,7 @@ class Parser
   #
   # returns a Hash of attributes that specify how to format
   # and layout the cells in the table.
-  def self.parse_col_specs records
+  def self.parse_colspecs records
     records = records.tr ' ', '' if records.include? ' '
     # check for deprecated syntax: single number, equal column spread
     if records == records.to_i.to_s
@@ -2410,7 +2414,7 @@ class Parser
     specs = []
     # NOTE -1 argument ensures we don't drop empty records
     records.split(',', -1).each {|record|
-      if record == ''
+      if record.empty?
         specs << { 'width' => 1 }
       # TODO might want to use scan rather than this mega-regexp
       elsif (m = ColumnSpecRx.match(record))
@@ -2458,7 +2462,7 @@ class Parser
   #
   # returns the Hash of attributes that indicate how to layout
   # and style this cell in the table.
-  def self.parse_cell_spec(line, pos = :start, delimiter = nil)
+  def self.parse_cellspec(line, pos = :start, delimiter = nil)
     m = nil
     rest = ''
 
@@ -2665,13 +2669,13 @@ class Parser
       lines.map! do |line|
         next line if line.empty?
 
-        if line.start_with? TAB
-          line.sub!(TabIndentRx) {|tabs| full_tab_space * tabs.length }
-        end
+        # NOTE Opal has to patch this use of sub!
+        line.sub!(TabIndentRx) {|tabs| full_tab_space * tabs.length } if line.start_with? TAB
 
         if line.include? TAB
           # keeps track of how many spaces were added to adjust offset in match data
           spaces_added = 0
+          # NOTE Opal has to patch this use of gsub!
           line.gsub!(TabRx) {
             # calculate how many spaces this tab represents, then replace tab with spaces
             if (offset = ($~.begin 0) + spaces_added) % tab_size == 0
diff --git a/lib/asciidoctor/path_resolver.rb b/lib/asciidoctor/path_resolver.rb
index 32061e1..f047c39 100644
--- a/lib/asciidoctor/path_resolver.rb
+++ b/lib/asciidoctor/path_resolver.rb
@@ -417,7 +417,7 @@ class PathResolver
     uri_prefix = nil
 
     unless start.nil_or_empty? || (is_web_root? target)
-      target = %(#{start}#{SLASH}#{target})
+      target = %(#{start.chomp '/'}#{SLASH}#{target})
       if (uri_prefix = Helpers.uri_prefix target)
         target = target[uri_prefix.length..-1]
       end
@@ -448,6 +448,8 @@ class PathResolver
         end
       else
         resolved_segments << segment
+        # checking for empty would eliminate repeating forward slashes
+        #resolved_segments << segment unless segment.empty?
       end
     end
 
diff --git a/lib/asciidoctor/reader.rb b/lib/asciidoctor/reader.rb
index 993e51f..6113551 100644
--- a/lib/asciidoctor/reader.rb
+++ b/lib/asciidoctor/reader.rb
@@ -41,7 +41,7 @@ class Reader
       @file = @dir = nil
       @path = '<stdin>'
       @lineno = 1 # IMPORTANT lineno assignment must proceed prepare_lines call!
-    elsif cursor.is_a? ::String
+    elsif ::String === cursor
       @file = cursor
       @dir, @path = ::File.split @file
       @lineno = 1 # IMPORTANT lineno assignment must proceed prepare_lines call!
@@ -84,7 +84,7 @@ class Reader
   #
   # Returns The String lines extracted from the data
   def prepare_lines data, opts = {}
-    if data.is_a? ::String
+    if ::String === data
       if opts[:normalize]
         Helpers.normalize_lines_from_string data
       else
@@ -732,10 +732,10 @@ class PreprocessorReader < Reader
           skip = !@document.attributes.has_key?(target)
         when ','
           # if any attribute is defined, then don't skip
-          skip = !target.split(',').detect {|name| @document.attributes.has_key? name }
+          skip = target.split(',').none? {|name| @document.attributes.has_key? name }
         when '+'
           # if any attribute is undefined, then skip
-          skip = target.split('+').detect {|name| !@document.attributes.has_key? name }
+          skip = target.split('+').any? {|name| !@document.attributes.has_key? name }
         end
       when 'ifndef'
         case delimiter
@@ -744,10 +744,10 @@ class PreprocessorReader < Reader
           skip = @document.attributes.has_key?(target)
         when ','
           # if any attribute is undefined, then don't skip
-          skip = !target.split(',').detect {|name| !@document.attributes.has_key? name }
+          skip = target.split(',').none? {|name| !@document.attributes.has_key? name }
         when '+'
           # if any attribute is defined, then skip
-          skip = target.split('+').detect {|name| @document.attributes.has_key? name }
+          skip = target.split('+').any? {|name| @document.attributes.has_key? name }
         end
       when 'ifeval'
         # the text in brackets must match an expression
@@ -830,10 +830,11 @@ class PreprocessorReader < Reader
       # FIXME we don't want to use a link macro if we are in a verbatim context
       replace_next_line %(link:#{target}[])
       true
-    elsif (abs_maxdepth = @maxdepth[:abs]) > 0 && @include_stack.size >= abs_maxdepth
-      warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
-      false
-    elsif abs_maxdepth > 0
+    elsif (abs_maxdepth = @maxdepth[:abs]) > 0
+      if @include_stack.size >= abs_maxdepth
+        warn %(asciidoctor: ERROR: #{line_info}: maximum include depth of #{@maxdepth[:rel]} exceeded)
+        return false
+      end
       if ::RUBY_ENGINE_OPAL
         # NOTE resolves uri relative to currently loaded document
         # NOTE we defer checking if file exists and catch the 404 error if it does not
@@ -883,7 +884,7 @@ class PreprocessorReader < Reader
           inc_lines = []
           attributes['lines'].split(DataDelimiterRx).each do |linedef|
             if linedef.include?('..')
-              from, to = linedef.split('..').map(&:to_i)
+              from, to = linedef.split('..', 2).map(&:to_i)
               if to == -1
                 inc_lines << from
                 inc_lines << 1.0/0.0
@@ -911,7 +912,7 @@ class PreprocessorReader < Reader
               f.each_line do |l|
                 inc_lineno += 1
                 take = inc_lines[0]
-                if take.is_a?(::Float) && take.infinite?
+                if ::Float === take && take.infinite?
                   selected.push l
                   inc_line_offset = inc_lineno if inc_line_offset == 0
                 else
@@ -1010,7 +1011,7 @@ class PreprocessorReader < Reader
   #    data = IO.read file
   #    reader.push_include data, file, path
   #
-  # Returns nothing.
+  # Returns this Reader object.
   def push_include data, file = nil, path = nil, lineno = 1, attributes = {}
     @include_stack << [@lines, @file, @dir, @path, @lineno, @maxdepth, @process_lines]
     if file
@@ -1064,7 +1065,7 @@ class PreprocessorReader < Reader
       @eof = false
       @look_ahead = 0
     end
-    nil
+    self
   end
 
   def pop_include
diff --git a/lib/asciidoctor/section.rb b/lib/asciidoctor/section.rb
index 10bb817..651fc85 100644
--- a/lib/asciidoctor/section.rb
+++ b/lib/asciidoctor/section.rb
@@ -87,8 +87,8 @@ class Section < AbstractBlock
       sep = @document.attributes['idseparator'] || '_'
       pre = @document.attributes['idprefix'] || '_'
       base_id = %(#{pre}#{title.downcase.gsub(InvalidSectionIdCharsRx, sep).tr_s(sep, sep).chomp(sep)})
-      # ensure id doesn't begin with idprefix if requested it doesn't
-      if pre.empty? && base_id.start_with?(sep)
+      # ensure id doesn't begin with idseparator if idprefix is empty and idseparator is not empty
+      if pre.empty? && !sep.empty? && base_id.start_with?(sep)
         base_id = base_id[1..-1]
         base_id = base_id[1..-1] while base_id.start_with?(sep)
       end
diff --git a/lib/asciidoctor/stylesheets.rb b/lib/asciidoctor/stylesheets.rb
index 0d6f1dd..d55369f 100644
--- a/lib/asciidoctor/stylesheets.rb
+++ b/lib/asciidoctor/stylesheets.rb
@@ -71,7 +71,8 @@ class Stylesheets
   def pygments_stylesheet_data style = nil
     if load_pygments
       (@pygments_stylesheet_data ||= {})[style || DEFAULT_PYGMENTS_STYLE] ||=
-          ::Pygments.css '.listingblock .pygments', :classprefix => 'tok-', :style => (style || DEFAULT_PYGMENTS_STYLE)
+          (::Pygments.css '.listingblock .pygments', :classprefix => 'tok-', :style => (style || DEFAULT_PYGMENTS_STYLE)).
+          sub('.listingblock .pygments  {', '.listingblock .pygments, .listingblock .pygments code {')
     else
       '/* Pygments styles disabled. Pygments is not available. */'
     end
diff --git a/lib/asciidoctor/substitutors.rb b/lib/asciidoctor/substitutors.rb
index 006dd56..ec52c24 100644
--- a/lib/asciidoctor/substitutors.rb
+++ b/lib/asciidoctor/substitutors.rb
@@ -363,54 +363,50 @@ module Substitutors
   end
   alias :sub_specialcharacters :sub_specialchars
 
-  # Public: Substitute quoted text (includes emphasis, strong, monospaced, etc)
-  #
-  # text - The String text to process
-  #
-  # returns The converted String text
-  def sub_quotes(text)
-    if ::RUBY_ENGINE_OPAL
-      result = text
-      QUOTE_SUBS[@document.compat_mode].each {|type, scope, pattern|
-        result = result.gsub(pattern) { convert_quoted_text $~, type, scope }
-      }
-    else
+  if RUBY_ENGINE == 'opal'
+    def sub_quotes text
+      QUOTE_SUBS[@document.compat_mode].each do |type, scope, pattern|
+        text = text.gsub(pattern) { convert_quoted_text $~, type, scope }
+      end
+      text
+    end
+
+    def sub_replacements text
+      REPLACEMENTS.each do |pattern, replacement, restore|
+        text = text.gsub(pattern) { do_replacement $~, replacement, restore }
+      end
+      text
+    end
+  else
+    # Public: Substitute quoted text (includes emphasis, strong, monospaced, etc)
+    #
+    # text - The String text to process
+    #
+    # returns The converted String text
+    def sub_quotes text
       # NOTE interpolation is faster than String#dup
-      result = %(#{text})
+      text = %(#{text})
       # NOTE using gsub! here as an MRI Ruby optimization
-      QUOTE_SUBS[@document.compat_mode].each {|type, scope, pattern|
-        result.gsub!(pattern) { convert_quoted_text $~, type, scope }
-      }
+      QUOTE_SUBS[@document.compat_mode].each do |type, scope, pattern|
+        text.gsub!(pattern) { convert_quoted_text $~, type, scope }
+      end
+      text
     end
 
-    result
-  end
-
-  # Public: Substitute replacement characters (e.g., copyright, trademark, etc)
-  #
-  # text - The String text to process
-  #
-  # returns The String text with the replacement characters substituted
-  def sub_replacements(text)
-    if ::RUBY_ENGINE_OPAL
-      result = text
-      REPLACEMENTS.each {|pattern, replacement, restore|
-        result = result.gsub(pattern) {
-          do_replacement $~, replacement, restore
-        }
-      }
-    else
+    # Public: Substitute replacement characters (e.g., copyright, trademark, etc)
+    #
+    # text - The String text to process
+    #
+    # returns The String text with the replacement characters substituted
+    def sub_replacements text
       # NOTE interpolation is faster than String#dup
-      result = %(#{text})
+      text = %(#{text})
       # NOTE Using gsub! as optimization
-      REPLACEMENTS.each {|pattern, replacement, restore|
-        result.gsub!(pattern) {
-          do_replacement $~, replacement, restore
-        }
-      }
+      REPLACEMENTS.each do |pattern, replacement, restore|
+        text.gsub!(pattern) { do_replacement $~, replacement, restore }
+      end
+      text
     end
-
-    result
   end
 
   # Internal: Substitute replacement text for matched location
@@ -642,6 +638,8 @@ module Substitutors
 
           target = m[1]
           attributes = if extension.config[:format] == :short
+            # TODO if content_model is :attributes, set target to nil and parse attributes
+            # maybe if content_model is :text, we should put content into text attribute
             {}
           else
             if extension.config[:content_model] == :attributes
@@ -1403,7 +1401,7 @@ module Substitutors
       unless (highlighter_loaded = defined? ::CodeRay) || @document.attributes['coderay-unavailable']
         if (Helpers.require_library 'coderay', true, :warn).nil?
           # prevent further attempts to load CodeRay
-          @document.set_attr 'coderay-unavailable', true
+          @document.set_attr 'coderay-unavailable', ''
         else
           highlighter_loaded = true
         end
@@ -1412,7 +1410,7 @@ module Substitutors
       unless (highlighter_loaded = defined? ::Pygments) || @document.attributes['pygments-unavailable']
         if (Helpers.require_library 'pygments', 'pygments.rb', :warn).nil?
           # prevent further attempts to load Pygments
-          @document.set_attr 'pygments-unavailable', true
+          @document.set_attr 'pygments-unavailable', ''
         else
           highlighter_loaded = true
         end
@@ -1460,7 +1458,7 @@ module Substitutors
     when 'coderay'
       if (linenums_mode = (attr? 'linenums') ? (@document.attributes['coderay-linenums-mode'] || :table).to_sym : nil)
         if attr? 'highlight', nil, false
-          highlight_lines = resolve_lines_to_highlight(attr 'highlight', nil, false)
+          highlight_lines = resolve_highlight_lines(attr 'highlight', nil, false)
         end
       end
       result = ::CodeRay::Duo[attr('language', :text, false).to_sym, :html, {
@@ -1477,7 +1475,7 @@ module Substitutors
         opts[:style] = (@document.attributes['pygments-style'] || Stylesheets::DEFAULT_PYGMENTS_STYLE)
       end
       if attr? 'highlight', nil, false
-        unless (highlight_lines = resolve_lines_to_highlight(attr 'highlight', nil, false)).empty?
+        unless (highlight_lines = resolve_highlight_lines(attr 'highlight', nil, false)).empty?
           opts[:hl_lines] = highlight_lines * ' '
         end
       end
@@ -1545,7 +1543,7 @@ module Substitutors
   end
 
   # e.g., highlight="1-5, !2, 10" or highlight=1-5;!2,10
-  def resolve_lines_to_highlight spec
+  def resolve_highlight_lines spec
     lines = []
     spec.delete(' ').split(DataDelimiterRx).map do |entry|
       negate = false
diff --git a/lib/asciidoctor/table.rb b/lib/asciidoctor/table.rb
index 9587388..832be8c 100644
--- a/lib/asciidoctor/table.rb
+++ b/lib/asciidoctor/table.rb
@@ -77,9 +77,11 @@ class Table < AbstractBlock
 
     # smell like we need a utility method here
     # to resolve an integer width from potential bogus input
-    pcwidth = attributes['width']
-    pcwidth_intval = pcwidth.to_i.abs
-    if pcwidth_intval == 0 && pcwidth != '0' || pcwidth_intval > 100
+    if (pcwidth = attributes['width'])
+      if (pcwidth_intval = pcwidth.to_i) > 100 || pcwidth_intval < 1
+        pcwidth_intval = 100 unless pcwidth_intval == 0 && (pcwidth == '0' || pcwidth == '0%')
+      end
+    else
       pcwidth_intval = 100
     end
     @attributes['tablepcwidth'] = pcwidth_intval
@@ -88,6 +90,8 @@ class Table < AbstractBlock
       @attributes['tableabswidth'] ||=
           ((@attributes['tablepcwidth'].to_f / 100) * @document.attributes['pagewidth']).round
     end
+
+    attributes['orientation'] = 'landscape' if attributes.key? 'rotate-option'
   end
 
   # Internal: Returns whether the current row being processed is
@@ -99,16 +103,16 @@ class Table < AbstractBlock
   # Internal: Creates the Column objects from the column spec
   #
   # returns nothing
-  def create_columns col_specs
+  def create_columns colspecs
     cols = []
     width_base = 0
-    col_specs.each do |col_spec|
-      width_base += col_spec['width']
-      cols << (Column.new self, cols.size, col_spec)
+    colspecs.each do |colspec|
+      width_base += colspec['width']
+      cols << (Column.new self, cols.size, colspec)
     end
     unless (@columns = cols).empty?
       @attributes['colcount'] = cols.size
-      assign_col_widths(width_base == 0 ? nil : width_base)
+      assign_column_widths(width_base == 0 ? nil : width_base)
     end
     nil
   end
@@ -123,7 +127,7 @@ class Table < AbstractBlock
   # width_base - the total of the relative column values used for calculating percentage widths (default: nil)
   #
   # returns nothing
-  def assign_col_widths width_base = nil
+  def assign_column_widths width_base = nil
     pf = 10.0 ** 4 # precision factor (multipler / divisor) for managing precision of calculated result
     total_width = col_pcwidth = 0
 
@@ -301,10 +305,10 @@ class Table::ParserContext
 
   # Public: Get the expected column count for a row
   #
-  # col_count is the number of columns to pull into a row
+  # colcount is the number of columns to pull into a row
   # A value of -1 means we use the number of columns found
-  # in the first line as the col_count
-  attr_reader :col_count
+  # in the first line as the colcount
+  attr_reader :colcount
 
   # Public: The String buffer of the currently open cell
   attr_accessor :buffer
@@ -334,12 +338,12 @@ class Table::ParserContext
       attributes['separator'] || Table::DEFAULT_DELIMITERS[@format]
     end
     @delimiter_re = /#{Regexp.escape @delimiter}/
-    @col_count = table.columns.empty? ? -1 : table.columns.size
+    @colcount = table.columns.empty? ? -1 : table.columns.size
     @buffer = ''
-    @cell_specs = []
+    @cellspecs = []
     @cell_open = false
     @active_rowspans = [0]
-    @col_visits = 0
+    @column_visits = 0
     @current_row = []
     @linenum = -1
   end
@@ -392,17 +396,17 @@ class Table::ParserContext
   # when the cell is being closed.
   #
   # returns The cell spec Hash captured from parsing the previous cell
-  def take_cell_spec()
-    @cell_specs.shift
+  def take_cellspec
+    @cellspecs.shift
   end
 
   # Public: Puts a cell spec onto the stack. Cell specs precede the delimiter, so a
   # stack is used to carry over the spec to the next cell.
   #
   # returns nothing
-  def push_cell_spec(cell_spec = {})
+  def push_cellspec(cellspec = {})
     # this shouldn't be nil, but we check anyway
-    @cell_specs << (cell_spec || {})
+    @cellspecs << (cellspec || {})
     nil
   end
 
@@ -443,8 +447,8 @@ class Table::ParserContext
   # by the next cell.
   #
   # returns nothing
-  def close_open_cell(next_cell_spec = {})
-    push_cell_spec next_cell_spec
+  def close_open_cell(next_cellspec = {})
+    push_cellspec next_cellspec
     close_cell(true) if cell_open?
     advance
     nil
@@ -459,17 +463,16 @@ class Table::ParserContext
     cell_text = @buffer.strip
     @buffer = ''
     if @format == 'psv'
-      cell_spec = take_cell_spec
-      if cell_spec
-        repeat = cell_spec.fetch('repeatcol', 1)
-        cell_spec.delete('repeatcol')
+      cellspec = take_cellspec
+      if cellspec
+        repeat = cellspec.delete('repeatcol') || 1
       else
         warn %(asciidoctor: ERROR: #{@last_cursor.line_info}: table missing leading separator, recovering automatically)
-        cell_spec = {}
+        cellspec = {}
         repeat = 1
       end
     else
-      cell_spec = nil
+      cellspec = nil
       repeat = 1
       if @format == 'csv'
         if !cell_text.empty? && cell_text.include?('"')
@@ -487,9 +490,9 @@ class Table::ParserContext
 
     1.upto(repeat) do |i|
       # TODO make column resolving an operation
-      if @col_count == -1
+      if @colcount == -1
         @table.columns << (column = Table::Column.new(@table, @table.columns.size + i - 1))
-        if cell_spec && (cell_spec.key? 'colspan') && (extra_cols = cell_spec['colspan'].to_i - 1) > 0
+        if cellspec && (cellspec.key? 'colspan') && (extra_cols = cellspec['colspan'].to_i - 1) > 0
           offset = @table.columns.size
           extra_cols.times do |j|
             @table.columns << Table::Column.new(@table, offset + j)
@@ -503,16 +506,16 @@ class Table::ParserContext
         end
       end
 
-      cell = Table::Cell.new(column, cell_text, cell_spec, @last_cursor)
+      cell = Table::Cell.new(column, cell_text, cellspec, @last_cursor)
       @last_cursor = @reader.cursor
       unless !cell.rowspan || cell.rowspan == 1
         activate_rowspan(cell.rowspan, (cell.colspan || 1))
       end
-      @col_visits += (cell.colspan || 1)
+      @column_visits += (cell.colspan || 1)
       @current_row << cell
       # don't close the row if we're on the first line and the column count has not been set explicitly
-      # TODO perhaps the col_count/linenum logic should be in end_of_row? (or a should_end_row? method)
-      close_row if end_of_row? && (@col_count != -1 || @linenum > 0 || (eol && i == repeat))
+      # TODO perhaps the colcount/linenum logic should be in end_of_row? (or a should_end_row? method)
+      close_row if end_of_row? && (@colcount != -1 || @linenum > 0 || (eol && i == repeat))
     end
     @cell_open = false
     nil
@@ -526,8 +529,8 @@ class Table::ParserContext
     @table.rows.body << @current_row
     # don't have to account for active rowspans here
     # since we know this is first row
-    @col_count = @col_visits if @col_count == -1
-    @col_visits = 0
+    @colcount = @column_visits if @colcount == -1
+    @column_visits = 0
     @current_row = []
     @active_rowspans.shift
     @active_rowspans[0] ||= 0
@@ -548,13 +551,13 @@ class Table::ParserContext
 
   # Public: Check whether we've met the number of effective columns for the current row.
   def end_of_row?
-    @col_count == -1 || effective_col_visits == @col_count
+    @colcount == -1 || effective_column_visits == @colcount
   end
 
   # Public: Calculate the effective column visits, which consists of the number of
   # cells plus any active rowspans.
-  def effective_col_visits
-    @col_visits + @active_rowspans[0]
+  def effective_column_visits
+    @column_visits + @active_rowspans[0]
   end
 
   # Internal: Advance to the next line (which may come after the parser begins processing
diff --git a/lib/asciidoctor/version.rb b/lib/asciidoctor/version.rb
index be5825c..ac83829 100644
--- a/lib/asciidoctor/version.rb
+++ b/lib/asciidoctor/version.rb
@@ -1,3 +1,3 @@
 module Asciidoctor
-  VERSION = '1.5.4'
+  VERSION = '1.5.5'
 end
diff --git a/man/asciidoctor.1 b/man/asciidoctor.1
index 36bb476..46ed1d1 100644
--- a/man/asciidoctor.1
+++ b/man/asciidoctor.1
@@ -1,13 +1,13 @@
 '\" t
 .\"     Title: asciidoctor
 .\"    Author: Dan Allen, Sarah White, Ryan Waldron
-.\" Generator: Asciidoctor 1.5.4
-.\"      Date: 2016-01-05
+.\" Generator: Asciidoctor 1.5.5
+.\"      Date: 2016-10-05
 .\"    Manual: Asciidoctor Manual
-.\"    Source: Asciidoctor 1.5.4
+.\"    Source: Asciidoctor 1.5.5
 .\"  Language: English
 .\"
-.TH "ASCIIDOCTOR" "1" "2016-01-05" "Asciidoctor 1.5.4" "Asciidoctor Manual"
+.TH "ASCIIDOCTOR" "1" "2016-10-05" "Asciidoctor 1.5.5" "Asciidoctor Manual"
 .ie \n(.g .ds Aq \(aq
 .el       .ds Aq '
 .ss \n[.ss] 0
@@ -191,6 +191,13 @@ Print program version number.
 .sp
 \f[CR]\-v\fP can also be used if no other flags or arguments are present.
 .RE
+.SH "ENVIRONMENT"
+.sp
+\fBAsciidoctor\fP honors the SOURCE_DATE_EPOCH environment variable.
+If this variable is assigned an integer value, that value is used as the epoch of all input documents and as the local date and time.
+See \c
+.URL "https://reproducible\-builds.org/specs/source\-date\-epoch/" "" " "
+for more information about this environment variable.
 .SH "EXIT STATUS"
 .sp
 \fB0\fP
diff --git a/man/asciidoctor.adoc b/man/asciidoctor.adoc
index b9a1873..d8d518e 100644
--- a/man/asciidoctor.adoc
+++ b/man/asciidoctor.adoc
@@ -2,7 +2,7 @@
 Dan Allen; Sarah White; Ryan Waldron
 :doctype: manpage
 :man manual: Asciidoctor Manual
-:man source: Asciidoctor 1.5.4
+:man source: Asciidoctor 1.5.5
 :page-layout: base
 
 == NAME
@@ -144,6 +144,12 @@ Matching templates found in subsequent directories override ones previously disc
 +
 `-v` can also be used if no other flags or arguments are present.
 
+== ENVIRONMENT
+
+*Asciidoctor* honors the SOURCE_DATE_EPOCH environment variable.
+If this variable is assigned an integer value, that value is used as the epoch of all input documents and as the local date and time.
+See https://reproducible-builds.org/specs/source-date-epoch/ for more information about this environment variable.
+
 == EXIT STATUS
 
 *0*::
diff --git a/test/attributes_test.rb b/test/attributes_test.rb
index 2b10181..00b4d57 100644
--- a/test/attributes_test.rb
+++ b/test/attributes_test.rb
@@ -124,6 +124,58 @@ content
       assert result.include? '<em>big</em>foot'
     end
 
+    test 'should limit maximum size of attribute value if safe mode is SECURE' do
+      expected = 'a' * 4096
+      input = <<-EOS
+:name: #{'a' * 5000}
+
+{name}
+      EOS
+
+      result = render_embedded_string input, :doctype => :inline
+      assert_equal expected, result
+      assert_equal 4096, result.bytesize
+    end
+
+    test 'should handle multibyte characters when limiting attribute value size' do
+      expected = '日本'
+      input = <<-EOS
+:name: 日本語
+
+{name}
+      EOS
+
+      result = render_embedded_string input, :doctype => :inline, :attributes => { 'max-attribute-value-size' => 6 }
+      assert_equal expected, result
+      assert_equal 6, result.bytesize
+    end
+
+    test 'should not mangle multibyte characters when limiting attribute value size' do
+      expected = '日本'
+      input = <<-EOS
+:name: 日本語
+
+{name}
+      EOS
+
+      result = render_embedded_string input, :doctype => :inline, :attributes => { 'max-attribute-value-size' => 8 }
+      assert_equal expected, result
+      assert_equal 6, result.bytesize
+    end
+
+    test 'should allow maximize size of attribute value to be disabled' do
+      expected = 'a' * 5000
+      input = <<-EOS
+:name: #{'a' * 5000}
+
+{name}
+      EOS
+
+      result = render_embedded_string input, :doctype => :inline, :attributes => { 'max-attribute-value-size' => nil }
+      assert_equal expected, result
+      assert_equal 5000, result.bytesize
+    end
+
     test 'resolves user-home attribute if safe mode is less than SERVER' do
       input = <<-EOS
 :imagesdir: {user-home}/etc/images
diff --git a/test/blocks_test.rb b/test/blocks_test.rb
index f541229..62c9d36 100644
--- a/test/blocks_test.rb
+++ b/test/blocks_test.rb
@@ -1523,10 +1523,10 @@ image::circle.svg[Tiger,100]
       EOS
 
       output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'docdir' => ::File.dirname(__FILE__) }
-      assert_match(/<svg [^>]*width="100px"[^>]*>/, output, 1)
-      refute_match(/<svg [^>]*width="500px"[^>]*>/, output)
-      refute_match(/<svg [^>]*height="500px"[^>]*>/, output)
-      refute_match(/<svg [^>]*style="width:500px;height:500px"[^>]*>/, output)
+      assert_match(/<svg\s[^>]*width="100px"[^>]*>/, output, 1)
+      refute_match(/<svg\s[^>]*width="500px"[^>]*>/, output)
+      refute_match(/<svg\s[^>]*height="500px"[^>]*>/, output)
+      refute_match(/<svg\s[^>]*style="width:500px;height:500px"[^>]*>/, output)
     end
 
     test 'renders inline SVG image using svg element even when data-uri is set' do
@@ -1539,7 +1539,7 @@ image::circle.svg[Tiger,100]
       EOS
 
       output = render_embedded_string input, :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'docdir' => ::File.dirname(__FILE__) }
-      assert_match(/<svg [^>]*width="100px">/, output, 1)
+      assert_match(/<svg\s[^>]*width="100px">/, output, 1)
     end
 
     test 'renders alt text for inline svg element if svg cannot be read' do
@@ -2162,7 +2162,7 @@ You can use icons for admonitions by setting the 'icons' attribute.
       EOS
 
       output = render_string input, :safe => Asciidoctor::SafeMode::SERVER
-      assert_css 'html > head > link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css"]', output, 1
+      assert_css 'html > head > link[rel="stylesheet"][href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"]', output, 1
       assert_xpath '//*[@class="admonitionblock tip"]//*[@class="icon"]/i[@class="fa icon-tip"]', output, 1
     end
 
@@ -2193,7 +2193,7 @@ puts "AsciiDoc, FTW!"
       EOS
 
       output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
-      assert_css 'html > head > link[rel="stylesheet"][href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css"]', output, 1
+      assert_css 'html > head > link[rel="stylesheet"][href="http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"]', output, 1
       assert_css 'html > body > script[src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"]', output, 1
     end
 
@@ -2210,7 +2210,7 @@ puts "AsciiDoc, FTW!"
       EOS
 
       output = render_string input, :safe => Asciidoctor::SafeMode::SAFE
-      assert_css 'html > head > link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.min.css"]', output, 1
+      assert_css 'html > head > link[rel="stylesheet"][href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.6.3/css/font-awesome.min.css"]', output, 1
       assert_css 'html > body > script[src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.9.1/highlight.min.js"]', output, 1
     end
   end
diff --git a/test/document_test.rb b/test/document_test.rb
index 40c4680..3c876ec 100644
--- a/test/document_test.rb
+++ b/test/document_test.rb
@@ -520,6 +520,18 @@ term without description::
       assert_xpath '/html/body/*[@id="header"]/h1[text() = "Document Title"]', output, 1
     end
 
+    test 'lines in output should be separated by line feed' do
+      sample_input_path = fixture_path('sample.asciidoc')
+
+      output = Asciidoctor.convert_file sample_input_path, :header_footer => true, :to_file => false
+      assert !output.empty?
+      lines = output.split("\n")
+      assert lines.size == output.split(/\r\n|\r|\n/).size
+      raw_lengths = lines.map(&:length)
+      trimmed_lengths = lines.map {|line| line.rstrip.length }
+      assert raw_lengths == trimmed_lengths
+    end
+
     test 'should accept attributes as array' do
       sample_input_path = fixture_path('sample.asciidoc')
       output = Asciidoctor.convert_file sample_input_path, :attributes => %w(sectnums idprefix idseparator=-), :to_file => false
@@ -1674,7 +1686,7 @@ image::tiger.png[]
 |===
 
 [horizontal, labelwidth="25%", itemwidth="75%"]
-term:: definition
+term:: description
 
 NOTE: note
 
diff --git a/test/extensions_test.rb b/test/extensions_test.rb
index 0fa87cb..69808bc 100644
--- a/test/extensions_test.rb
+++ b/test/extensions_test.rb
@@ -665,6 +665,44 @@ content
       end
     end
 
+    test 'parse_content should not share attributes between parsed blocks' do
+      begin
+        Asciidoctor::Extensions.register do
+          block do
+            named :wrap
+            on_context :open
+            process do |parent, reader, attrs|
+              wrap = create_open_block parent, nil, attrs
+              parse_content wrap, reader.read_lines
+            end
+          end
+        end
+        input = <<-EOS
+[wrap]
+--
+[foo=bar]
+====
+content
+====
+
+[baz=qux]
+====
+content
+====
+--
+        EOS
+        doc = document_from_string input
+        assert_equal 1, doc.blocks.size
+        wrap = doc.blocks[0]
+        assert_equal 2, wrap.blocks.size
+        assert_equal 2, wrap.blocks[0].attributes.size
+        assert_equal 2, wrap.blocks[1].attributes.size
+        assert_nil wrap.blocks[1].attributes['foo']
+      ensure
+        Asciidoctor::Extensions.unregister_all
+      end
+    end
+
     test 'should add docinfo to document' do
       input = <<-EOS
 = Document Title
diff --git a/test/fixtures/circle.svg b/test/fixtures/circle.svg
index 7e05910..6396975 100644
--- a/test/fixtures/circle.svg
+++ b/test/fixtures/circle.svg
@@ -1,7 +1,8 @@
 <?xml version="1.0"?>
 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
 <!-- An SVG of a black circle -->
-<svg viewBox="0 0 120 120" version="1.1"
+<svg
+viewBox="0 0 120 120" version="1.1"
 xmlns="http://www.w3.org/2000/svg" style="width:500px;height:500px"
 width="500px" height="500px">
   <circle cx="60" cy="60" r="50"/>
diff --git a/test/invoker_test.rb b/test/invoker_test.rb
index 6e03ef1..0d05831 100644
--- a/test/invoker_test.rb
+++ b/test/invoker_test.rb
@@ -550,4 +550,19 @@ context 'Invoker' do
     assert_match(/Total time/, error)
   end
 
+  test 'should use SOURCE_DATE_EPOCH as modified time of input file and local time' do
+    old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
+    begin
+      ENV['SOURCE_DATE_EPOCH'] = '1234123412'
+      sample_filepath = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'sample.asciidoc'))
+      invoker = invoke_cli_to_buffer %w(-o /dev/null), sample_filepath
+      doc = invoker.document
+      assert_equal '2009-02-08', (doc.attr 'docdate')
+      assert_match(/2009-02-08 20:03:32 (GMT|UTC)/, (doc.attr 'docdatetime'))
+      assert_equal '2009-02-08', (doc.attr 'localdate')
+      assert_match(/2009-02-08 20:03:32 (GMT|UTC)/, (doc.attr 'localdatetime'))
+    ensure
+      ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch if old_source_date_epoch
+    end
+  end
 end
diff --git a/test/lists_test.rb b/test/lists_test.rb
index eb00070..8545388 100644
--- a/test/lists_test.rb
+++ b/test/lists_test.rb
@@ -258,6 +258,18 @@ second wrapped line
       assert !output.include?('* Foo')
     end
 
+    test 'a list item that starts with a sequence of list markers characters should not match a nested list' do
+      input = <<-EOS
+ * first item
+ *. normal text
+      EOS
+
+      output = render_embedded_string input
+      assert_css 'ul', output, 1
+      assert_css 'ul li', output, 1
+      assert_xpath "//ul/li/p[text()='first item\n*. normal text']", output, 1
+    end
+
     test 'a list item for a different list terminates indented paragraph for text of list item' do
       input = <<-EOS
 == Example 1
@@ -1472,11 +1484,11 @@ attached paragraph
       input = <<-EOS
 * item 1
 
-  term a:: definition a
+  term a:: description a
 +
 attached paragraph
 
-  term b:: definition b
+  term b:: description b
 +
 attached paragraph
 
@@ -1595,6 +1607,19 @@ List
       assert_css '.olist ol.loweralpha', output, 1
     end
 
+    test 'should set reversed attribute on list if reversed option is set' do
+      input = <<-EOS
+[%reversed, start=3]
+. three
+. two
+. one
+. blast off!
+      EOS
+
+      output = render_embedded_string input
+      assert_css 'ol[reversed][start="3"]', output, 1
+    end
+
     test 'should represent implicit role attribute as style class' do
       input = <<-EOS
 [.dry]
@@ -1952,7 +1977,7 @@ def2
       input = <<-EOS
 term::
 alt term::
-definition
+description
 
 last::
       EOS
@@ -2111,7 +2136,7 @@ anotherterm:: def
 term::
 +
 --
-Open block as definition of term.
+Open block as description of term.
 
 And some more detail...
 --
@@ -2201,7 +2226,7 @@ term2:: def
       assert_xpath '((//dl/dd)[1]//ul)[1]//ul', output, 1
     end
 
-    test "should only grab one line following last item if item has no inline definition" do
+    test "should only grab one line following last item if item has no inline description" do
       input = <<-EOS
 term1::
 
@@ -2225,7 +2250,7 @@ Another new paragraph
       assert_xpath '(//*[@class="dlist"]/following-sibling::*[@class="paragraph"])[2]/p[text() = "Another new paragraph"]', output, 1
     end
 
-    test "should only grab one literal line following last item if item has no inline definition" do
+    test "should only grab one literal line following last item if item has no inline description" do
       input = <<-EOS
 term1::
 
@@ -2509,7 +2534,7 @@ term 2:: def 2
 [glossary]
 term::
 alt term::
-definition
+description
 
 last::
       EOS
@@ -2524,11 +2549,11 @@ last::
     test 'should render horizontal list with proper markup' do
       input = <<-EOS
 [horizontal]
-first term:: definition
+first term:: description
 +
 more detail
 
-second term:: definition
+second term:: description
       EOS
       output = render_embedded_string input
       assert_css '.hdlist', output, 1
@@ -2541,11 +2566,11 @@ second term:: definition
       assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist2"]/p', output, 1
       assert_xpath '/*[@class="hdlist"]/table/tr[1]/td[@class="hdlist2"]/p/following-sibling::*[@class="paragraph"]', output, 1
       assert_xpath '((//tr)[1]/td)[1][normalize-space(text())="first term"]', output, 1
-      assert_xpath '((//tr)[1]/td)[2]/p[normalize-space(text())="definition"]', output, 1
+      assert_xpath '((//tr)[1]/td)[2]/p[normalize-space(text())="description"]', output, 1
 
       assert_xpath '/*[@class="hdlist"]/table/tr[2]/td', output, 2
       assert_xpath '((//tr)[2]/td)[1][normalize-space(text())="second term"]', output, 1
-      assert_xpath '((//tr)[2]/td)[2]/p[normalize-space(text())="definition"]', output, 1
+      assert_xpath '((//tr)[2]/td)[2]/p[normalize-space(text())="description"]', output, 1
     end
 
     test 'should set col widths of item and label if specified' do
@@ -2594,7 +2619,7 @@ term:: def
 [horizontal]
 term::
 alt term::
-definition
+description
 
 last::
       EOS
@@ -2612,7 +2637,7 @@ last::
 [horizontal]
 term::
 alt term::
-definition
+description
 
 last::
       EOS
@@ -2628,11 +2653,11 @@ last::
       input = <<-EOS
 .Terms
 [horizontal]
-first term:: definition
+first term:: description
 +
 more detail
 
-second term:: definition
+second term:: description
       EOS
       output = render_embedded_string input, :backend => 'docbook'
       assert_xpath '/table', output, 1
@@ -3010,7 +3035,7 @@ term1::
       assert_xpath '//*[@class="dlist"]//dd/p/following-sibling::*[@class="literalblock"]//pre[text()="literal"]', output, 2
     end
 
-    test 'folds text of subsequent line and appends following literal line offset by blank line as block if term has no inline definition' do
+    test 'folds text of subsequent line and appends following literal line offset by blank line as block if term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3030,7 +3055,7 @@ term2:: def2
       assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="literalblock"]//pre[text()="literal"]', output, 1
     end
 
-    test 'appends literal line attached by continuation as block if item has no inline definition' do
+    test 'appends literal line attached by continuation as block if item has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3047,7 +3072,7 @@ term1::
       assert_xpath '//*[@class="dlist"]//dd/*[@class="literalblock"]//pre[text()="literal"]', output, 1
     end
 
-    test 'appends literal line attached by continuation as block if item has no inline definition followed by ruler' do
+    test 'appends literal line attached by continuation as block if item has no inline description followed by ruler' do
       input = <<-EOS
 == Lists
 
@@ -3067,7 +3092,7 @@ term1::
       assert_xpath '//*[@class="dlist"]/following-sibling::hr', output, 1
     end
 
-    test 'appends line attached by continuation as block if item has no inline definition followed by ruler' do
+    test 'appends line attached by continuation as block if item has no inline description followed by ruler' do
       input = <<-EOS
 == Lists
 
@@ -3087,7 +3112,7 @@ para
       assert_xpath '//*[@class="dlist"]/following-sibling::hr', output, 1
     end
 
-    test 'appends line attached by continuation as block if item has no inline definition followed by block' do
+    test 'appends line attached by continuation as block if item has no inline description followed by block' do
       input = <<-EOS
 == Lists
 
@@ -3134,7 +3159,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="literalblock"]//pre[text()="detached"]', output, 1
     end
 
-    test 'appends list if item has no inline definition' do
+    test 'appends list if item has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3177,13 +3202,13 @@ term2:: def2
 == Lists
 
 label 1::
-  definition 1
+  description 1
 
   * one
   * two
   * three
 label 2::
-  definition 2
+  description 2
 
 paragraph
       EOS
@@ -3193,8 +3218,8 @@ paragraph
       assert_xpath '(//*[@class="dlist"]//dt)[1][normalize-space(text())="label 1"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dt)[2][normalize-space(text())="label 2"]', output, 1
       assert_css '.dlist dd', output, 2
-      assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="definition 1"]', output, 1
-      assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="definition 2"]', output, 1
+      assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="description 1"]', output, 1
+      assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="description 2"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]//li', output, 3
       assert_css '.dlist + .paragraph', output, 1
@@ -3205,13 +3230,13 @@ paragraph
 == Lists
 
 label 1::
-  definition 1
+  description 1
 +
   * one
   * two
   * three
 label 2::
-  definition 2
+  description 2
 
 paragraph
       EOS
@@ -3221,8 +3246,8 @@ paragraph
       assert_xpath '(//*[@class="dlist"]//dt)[1][normalize-space(text())="label 1"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dt)[2][normalize-space(text())="label 2"]', output, 1
       assert_css '.dlist dd', output, 2
-      assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="definition 1"]', output, 1
-      assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="definition 2"]', output, 1
+      assert_xpath '(//*[@class="dlist"]//dd)[1]/p[text()="description 1"]', output, 1
+      assert_xpath '(//*[@class="dlist"]//dd)[2]/p[text()="description 2"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]', output, 1
       assert_xpath '(//*[@class="dlist"]//dd)[1]/p/following-sibling::*[@class="ulist"]//li', output, 3
       assert_css '.dlist + .paragraph', output, 1
@@ -3297,7 +3322,7 @@ notnestedterm:::
       assert_xpath %(//*[@class="dlist"]//dd/*[@class="literalblock"]//pre[text()="  literal\nnotnestedterm:::"]), output, 2
     end
 
-    test 'line attached by continuation is appended as paragraph if term has no inline definition' do
+    test 'line attached by continuation is appended as paragraph if term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3318,7 +3343,7 @@ para
       input = <<-EOS
 term1:: def
 +
-more definition
+more description
 not a term::: def
       EOS
 
@@ -3335,7 +3360,7 @@ not a term::: def
       input = <<-EOS
 term1:: def
 +
-more definition
+more description
 not a term:: def
       EOS
 
@@ -3352,7 +3377,7 @@ not a term:: def
 term1:: def
 +
 [quote]
-more definition
+more description
 not a term::: def
       EOS
 
@@ -3363,7 +3388,7 @@ not a term::: def
       assert output.include?('not a term::: def')
     end
 
-    test 'appends line as paragraph if attached by continuation following blank line and line comment when term has no inline definition' do
+    test 'appends line as paragraph if attached by continuation following blank line and line comment when term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3382,7 +3407,7 @@ para
       assert_xpath '//*[@class="dlist"]//dd/*[@class="paragraph"]/p[text()="para"]', output, 1
     end
 
-    test 'line attached by continuation offset by blank line is appended as paragraph if term has no inline definition' do
+    test 'line attached by continuation offset by blank line is appended as paragraph if term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3400,7 +3425,7 @@ para
       assert_xpath '//*[@class="dlist"]//dd/*[@class="paragraph"]/p[text()="para"]', output, 1
     end
 
-    test 'delimited block breaks list even when term has no inline definition' do
+    test 'delimited block breaks list even when term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3417,7 +3442,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="exampleblock"]//p[text()="detached"]', output, 1
     end
 
-    test 'attribute line breaks list even when term has no inline definition' do
+    test 'attribute line breaks list even when term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3433,7 +3458,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="verseblock"]/pre[text()="detached"]', output, 1
     end
 
-    test 'id line breaks list even when term has no inline definition' do
+    test 'id line breaks list even when term has no inline description' do
       input = <<-EOS
 == Lists
 
@@ -3452,7 +3477,7 @@ detached
 
   context 'Item with text inline' do
 
-    test 'folds text from inline definition and subsequent line' do
+    test 'folds text from inline description and subsequent line' do
       input = <<-EOS
 == Lists
 
@@ -3466,7 +3491,7 @@ continued
       assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued"]), output, 1
     end
 
-    test 'folds text from inline definition and subsequent lines' do
+    test 'folds text from inline description and subsequent lines' do
       input = <<-EOS
 == Lists
 
@@ -3481,7 +3506,7 @@ continued
       assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued\ncontinued"]), output, 1
     end
 
-    test 'folds text from inline definition and line following comment line' do
+    test 'folds text from inline description and line following comment line' do
       input = <<-EOS
 == Lists
 
@@ -3496,7 +3521,7 @@ continued
       assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued"]), output, 1
     end
 
-    test 'folds text from inline definition and subsequent indented line' do
+    test 'folds text from inline description and subsequent indented line' do
       input = <<-EOS
 == Lists
 
@@ -3510,7 +3535,7 @@ term1:: def1
       assert_xpath %(//*[@class="dlist"]//dd/p[text()="def1\ncontinued"]), output, 1
     end
 
-    test 'appends literal line offset by blank line as block if item has inline definition' do
+    test 'appends literal line offset by blank line as block if item has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3527,7 +3552,7 @@ term1:: def1
       assert_xpath '//*[@class="dlist"]//dd/p/following-sibling::*[@class="literalblock"]//pre[text()="literal"]', output, 1
     end
 
-    test 'appends literal line offset by blank line as block and appends line after continuation as block if item has inline definition' do
+    test 'appends literal line offset by blank line as block and appends line after continuation as block if item has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3548,7 +3573,7 @@ para
       assert_xpath '//*[@class="dlist"]//dd/*[@class="literalblock"]/following-sibling::*[@class="paragraph"]/p[text()="para"]', output, 1
     end
 
-    test 'appends line after continuation as block and literal line offset by blank line as block if item has inline definition' do
+    test 'appends line after continuation as block and literal line offset by blank line as block if item has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3569,7 +3594,7 @@ para
       assert_xpath '//*[@class="dlist"]//dd/*[@class="paragraph"]/following-sibling::*[@class="literalblock"]//pre[text()="literal"]', output, 1
     end
 
-    test 'appends list if item has inline definition' do
+    test 'appends list if item has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3587,7 +3612,7 @@ term1:: def1
       assert_xpath '//*[@class="dlist"]//dd/p/following-sibling::*[@class="ulist"]/ul/li', output, 3
     end
 
-    test 'appends literal line attached by continuation as block if item has inline definition followed by ruler' do
+    test 'appends literal line attached by continuation as block if item has inline description followed by ruler' do
       input = <<-EOS
 == Lists
 
@@ -3607,7 +3632,7 @@ term1:: def1
       assert_xpath '//*[@class="dlist"]/following-sibling::hr', output, 1
     end
 
-    test 'line offset by blank line breaks list if term has inline definition' do
+    test 'line offset by blank line breaks list if term has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3624,7 +3649,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="paragraph"]/p[text()="detached"]', output, 1
     end
 
-    test 'nested term with definition does not consume following heading' do
+    test 'nested term with description does not consume following heading' do
       input = <<-EOS
 == Lists
 
@@ -3649,7 +3674,7 @@ Detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="sect2"]/h3[text()="Detached"]', output, 1
     end
 
-    test 'line attached by continuation is appended as paragraph if term has inline definition followed by detached paragraph' do
+    test 'line attached by continuation is appended as paragraph if term has inline description followed by detached paragraph' do
       input = <<-EOS
 == Lists
 
@@ -3670,7 +3695,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="paragraph"]/p[text()="detached"]', output, 1
     end
 
-    test 'line attached by continuation is appended as paragraph if term has inline definition followed by detached block' do
+    test 'line attached by continuation is appended as paragraph if term has inline description followed by detached block' do
       input = <<-EOS
 == Lists
 
@@ -3693,7 +3718,7 @@ detached
       assert_xpath '//*[@class="dlist"]/following-sibling::*[@class="sidebarblock"]//p[text()="detached"]', output, 1
     end
 
-    test 'line attached by continuation offset by line comment is appended as paragraph if term has inline definition' do
+    test 'line attached by continuation offset by line comment is appended as paragraph if term has inline description' do
       input = <<-EOS
 == Lists
 
@@ -3711,7 +3736,7 @@ para
       assert_xpath '//*[@class="dlist"]//dd/p/following-sibling::*[@class="paragraph"]/p[text()="para"]', output, 1
     end
 
-    test 'line attached by continuation offset by blank line is appended as paragraph if term has inline definition' do
+    test 'line attached by continuation offset by blank line is appended as paragraph if term has inline description' do
       input = <<-EOS
 == Lists
 
diff --git a/test/manpage_test.rb b/test/manpage_test.rb
index bac232b..101b9b2 100644
--- a/test/manpage_test.rb
+++ b/test/manpage_test.rb
@@ -200,4 +200,19 @@ T}
 .TE'
     end
   end
+
+  context 'Environment' do
+    test 'should use SOURCE_DATE_EPOCH as modified time of input file and local time' do
+      old_source_date_epoch = ENV.delete 'SOURCE_DATE_EPOCH'
+      begin
+        ENV['SOURCE_DATE_EPOCH'] = '1234123412'
+        output = Asciidoctor.convert SAMPLE_MANPAGE_HEADER, :backend => :manpage, :header_footer => true
+        assert_match(/Date: 2009-02-08/, output)
+        assert_match(/^\.TH "COMMAND" "1" "2009-02-08" "Command 1.2.3" "Command Manual"$/, output)
+      ensure
+        ENV['SOURCE_DATE_EPOCH'] = old_source_date_epoch if old_source_date_epoch
+      end
+    end
+  end
+
 end
diff --git a/test/paths_test.rb b/test/paths_test.rb
index d47b951..bf9f73b 100644
--- a/test/paths_test.rb
+++ b/test/paths_test.rb
@@ -43,7 +43,10 @@ context 'Path Resolver' do
     test 'target with relative path appended to start path' do
       assert_equal 'assets/images', @resolver.web_path('images', 'assets')
       assert_equal '/assets/images', @resolver.web_path('images', '/assets')
+      #assert_equal '/assets/images/tiger.png', @resolver.web_path('tiger.png', '/assets//images')
       assert_equal './assets/images', @resolver.web_path('images', './assets')
+      assert_equal '/theme.css', @resolver.web_path('theme.css', '/')
+      assert_equal '/css/theme.css', @resolver.web_path('theme.css', '/css/')
     end
 
     test 'target with path relative to current directory appended to start path' do
diff --git a/test/reader_test.rb b/test/reader_test.rb
index 281d7f0..b70908a 100644
--- a/test/reader_test.rb
+++ b/test/reader_test.rb
@@ -455,11 +455,11 @@ preamble
     end
 
     context 'Include Stack' do
-      test 'PreprocessorReader#push_include method should return nil' do
+      test 'PreprocessorReader#push_include method should return reader' do
         reader = empty_document.reader
         append_lines = %w(one two three)
         result = reader.push_include append_lines, '<stdin>', '<stdin>'
-        assert_nil result
+        assert_equal reader, result
       end
 
       test 'PreprocessorReader#push_include method should put lines on top of stack' do
diff --git a/test/sections_test.rb b/test/sections_test.rb
index 344efd4..2568abb 100644
--- a/test/sections_test.rb
+++ b/test/sections_test.rb
@@ -51,6 +51,16 @@ context 'Sections' do
       assert_equal '_sectionone', sec.id
     end
 
+    test 'synthetic id separator can be set to blank when idprefix is blank' do
+      sec = block_from_string(":idprefix:\n:idseparator:\n\n== Section One")
+      assert_equal 'sectionone', sec.id
+    end
+
+    test 'synthetic id separator is removed from beginning of id when idprefix is blank' do
+      sec = block_from_string(":idprefix:\n:idseparator: _\n\n== +Section One")
+      assert_equal 'section_one', sec.id
+    end
+
     test 'synthetic ids can be disabled' do
       sec = block_from_string(":sectids!:\n\n== Section One\n")
       assert sec.id.nil?
diff --git a/test/substitutions_test.rb b/test/substitutions_test.rb
index d3a08ca..d44a5e0 100644
--- a/test/substitutions_test.rb
+++ b/test/substitutions_test.rb
@@ -655,15 +655,15 @@ context 'Substitutions' do
     test 'an image macro with an inline SVG image should be converted to an svg element' do
       para = block_from_string('image:circle.svg[Tiger,100,opts=inline]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'imagesdir' => 'fixtures', 'docdir' => ::File.dirname(__FILE__) })
       result = para.sub_macros(para.source).gsub(/>\s+</, '><')
-      assert_match(/<svg [^>]*width="100px"[^>]*>/, result)
-      refute_match(/<svg [^>]*width="500px"[^>]*>/, result)
-      refute_match(/<svg [^>]*height="500px"[^>]*>/, result)
-      refute_match(/<svg [^>]*style="width:500px;height:500px"[^>]*>/, result)
+      assert_match(/<svg\s[^>]*width="100px"[^>]*>/, result)
+      refute_match(/<svg\s[^>]*width="500px"[^>]*>/, result)
+      refute_match(/<svg\s[^>]*height="500px"[^>]*>/, result)
+      refute_match(/<svg\s[^>]*style="width:500px;height:500px"[^>]*>/, result)
     end
 
     test 'an image macro with an inline SVG image should be converted to an svg element even when data-uri is set' do
       para = block_from_string('image:circle.svg[Tiger,100,opts=inline]', :safe => Asciidoctor::SafeMode::SERVER, :attributes => { 'data-uri' => '', 'imagesdir' => 'fixtures', 'docdir' => ::File.dirname(__FILE__) })
-      assert_match(/<svg [^>]*width="100px">/, para.sub_macros(para.source).gsub(/>\s+</, '><'))
+      assert_match(/<svg\s[^>]*width="100px">/, para.sub_macros(para.source).gsub(/>\s+</, '><'))
     end
 
     test 'an image macro with an SVG image should not use an object element when safe mode is secure' do
@@ -1500,11 +1500,17 @@ foo — '
     end
 
     test 'preserves entity references' do
-      input = '& © ✔ &#x2022;'
+      input = '& © ✔ 😀 &#x2022; &#x1f600;'
       result = render_embedded_string input, :doctype => :inline
       assert_equal input, result
     end
 
+    test 'only preserves named entities with two or more letters' do
+      input = '& &a; >'
+      result = render_embedded_string input, :doctype => :inline
+      assert_equal '& &a; >', result
+    end
+
     test 'replaces punctuation' do
       para = block_from_string %(John's Hideout is the Whites`' place... foo\\'bar)
       assert_equal "John’s Hideout is the Whites’ place…​ foo'bar", para.sub_replacements(para.source)
diff --git a/test/tables_test.rb b/test/tables_test.rb
index 4c4d320..5b01bea 100644
--- a/test/tables_test.rb
+++ b/test/tables_test.rb
@@ -191,6 +191,22 @@ A | here| a | there
       assert_css 'table colgroup col[width]', output, 0
     end
 
+    test 'explicit table width is used even when autowidth option is specified' do
+      input = <<-EOS
+[%autowidth,width=75%]
+|=======
+|A |B |C
+|a |b |c
+|1 |2 |3
+|=======
+      EOS
+      output = render_embedded_string input
+      assert_css 'table', output, 1
+      assert_css 'table[style*="width"]', output, 1
+      assert_css 'table colgroup col', output, 3
+      assert_css 'table colgroup col[width]', output, 0
+    end
+
     test 'first row sets number of columns when not specified' do
       input = <<-EOS
 |====
@@ -362,6 +378,21 @@ A | here| a | there
       assert_css 'table > tgroup > tbody > row', output, 3
     end
 
+    test 'table with landscape orientation in DocBook' do
+      ['orientation=landscape', '%rotate'].each do |attrs|
+        input = <<-EOS
+[#{attrs}]
+|===
+|Column A | Column B | Column C
+|===
+        EOS
+
+        output = render_embedded_string input, :backend => 'docbook'
+        assert_css 'informaltable', output, 1
+        assert_css 'informaltable[orient="land"]', output, 1
+      end
+    end
+
     test 'table with implicit header row' do
       input = <<-EOS
 |===
@@ -384,6 +415,27 @@ A | here| a | there
       assert_css 'table > tbody > tr', output, 2
     end
 
+    test 'table with implicit header row when other options set' do
+      input = <<-EOS
+[%autowidth]
+|===
+|Column 1 |Column 2
+
+|Data A1
+|Data B1
+|===
+      EOS
+      output = render_embedded_string input
+      assert_css 'table', output, 1
+      assert_css 'table[style*="width"]', output, 0
+      assert_css 'table > colgroup > col', output, 2
+      assert_css 'table > thead', output, 1
+      assert_css 'table > thead > tr', output, 1
+      assert_css 'table > thead > tr > th', output, 2
+      assert_css 'table > tbody', output, 1
+      assert_css 'table > tbody > tr', output, 1
+    end
+
     test 'no implicit header row if second line not blank' do
       input = <<-EOS
 |===
@@ -425,9 +477,9 @@ A | here| a | there
       assert_css 'table > tbody > tr', output, 3
     end
 
-    test 'no implicit header row if options is specified' do
+    test 'no implicit header row if noheader option is specified' do
       input = <<-EOS
-[options=""]
+[%noheader]
 |===
 |Column 1 |Column 2
 
@@ -671,6 +723,28 @@ d|9 2+>|10
       assert_xpath '(//row)[2]/entry[@nameend]', output, 0
     end
 
+    test 'assigns unique column names for table with implicit column count and colspans in first row' do
+      input = <<-EOS
+|====
+|                 2+| Node 0          2+| Node 1
+
+| Host processes    | Core 0 | Core 1   | Core 4 | Core 5
+| Guest processes   | Core 2 | Core 3   | Core 6 | Core 7
+|====
+      EOS
+
+      output = render_embedded_string input, :backend => 'docbook'
+      assert_xpath '//colspec', output, 5
+      (1..5).each do |n|
+        assert_xpath %((//colspec)[#{n}][@colname="col_#{n}"]), output, 1
+      end
+      assert_xpath '(//row)[1]/entry', output, 3
+      assert_xpath '((//row)[1]/entry)[1][@namest]', output, 0
+      assert_xpath '((//row)[1]/entry)[1][@namend]', output, 0
+      assert_xpath '((//row)[1]/entry)[2][@namest="col_2"][@nameend="col_3"]', output, 1
+      assert_xpath '((//row)[1]/entry)[3][@namest="col_4"][@nameend="col_5"]', output, 1
+    end
+
     test 'ignores cell with colspan that exceeds colspec' do
       input = <<-EOS
 [cols="1,1"]

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



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