summaryrefslogtreecommitdiffstats
path: root/nikola
diff options
context:
space:
mode:
Diffstat (limited to 'nikola')
-rw-r--r--nikola/__init__.py2
-rw-r--r--nikola/__main__.py9
-rw-r--r--nikola/conf.py.in241
-rw-r--r--nikola/data/samplesite/images/frontispiece.jpgbin0 -> 80761 bytes
-rw-r--r--nikola/data/samplesite/images/illus_001.jpgbin0 -> 156895 bytes
-rw-r--r--nikola/data/samplesite/posts/1.rst6
-rw-r--r--nikola/data/samplesite/stories/1.rst2
-rw-r--r--nikola/data/samplesite/stories/a-study-in-scarlet.txt5139
-rw-r--r--nikola/data/samplesite/stories/dr-nikolas-vendetta.rst468
l---------nikola/data/samplesite/stories/path_handlers.txt1
-rw-r--r--nikola/data/samplesite/stories/quickref.rst85
-rw-r--r--nikola/data/samplesite/templates/book.tmpl117
-rw-r--r--nikola/data/symlinked.txt2
-rw-r--r--nikola/data/themes/base-jinja/templates/author.tmpl43
-rw-r--r--nikola/data/themes/base-jinja/templates/authorindex.tmpl13
-rw-r--r--nikola/data/themes/base-jinja/templates/authors.tmpl17
-rw-r--r--nikola/data/themes/base-jinja/templates/base_header.tmpl6
-rw-r--r--nikola/data/themes/base-jinja/templates/base_helper.tmpl5
-rw-r--r--nikola/data/themes/base-jinja/templates/gallery.tmpl6
-rw-r--r--nikola/data/themes/base-jinja/templates/index.tmpl10
-rw-r--r--nikola/data/themes/base-jinja/templates/index_helper.tmpl15
-rw-r--r--nikola/data/themes/base-jinja/templates/list.tmpl9
-rw-r--r--nikola/data/themes/base-jinja/templates/list_post.tmpl4
-rw-r--r--nikola/data/themes/base-jinja/templates/listing.tmpl4
-rw-r--r--nikola/data/themes/base-jinja/templates/post.tmpl4
-rw-r--r--nikola/data/themes/base-jinja/templates/post_header.tmpl14
-rw-r--r--nikola/data/themes/base-jinja/templates/post_helper.tmpl21
-rw-r--r--nikola/data/themes/base-jinja/templates/post_list_directive.tmpl2
-rw-r--r--nikola/data/themes/base-jinja/templates/sectionindex.tmpl21
-rw-r--r--nikola/data/themes/base-jinja/templates/tag.tmpl8
-rw-r--r--nikola/data/themes/base-jinja/templates/tagindex.tmpl6
-rw-r--r--nikola/data/themes/base-jinja/templates/tags.tmpl4
-rw-r--r--nikola/data/themes/base/assets/css/ipython.min.css9
-rw-r--r--nikola/data/themes/base/assets/css/ipython.min.css.map1
-rw-r--r--nikola/data/themes/base/assets/js/jquery.min.map1
-rw-r--r--nikola/data/themes/base/assets/js/mathjax.js11
l---------nikola/data/themes/base/assets/js/moment-with-locales.min.js1
-rw-r--r--nikola/data/themes/base/messages/messages_ar.py4
-rw-r--r--nikola/data/themes/base/messages/messages_az.py4
-rw-r--r--nikola/data/themes/base/messages/messages_bg.py4
-rw-r--r--nikola/data/themes/base/messages/messages_bs.py16
-rw-r--r--nikola/data/themes/base/messages/messages_ca.py4
-rw-r--r--nikola/data/themes/base/messages/messages_cs.py4
-rw-r--r--nikola/data/themes/base/messages/messages_da.py4
-rw-r--r--nikola/data/themes/base/messages/messages_de.py10
-rw-r--r--nikola/data/themes/base/messages/messages_el.py4
-rw-r--r--nikola/data/themes/base/messages/messages_en.py4
-rw-r--r--nikola/data/themes/base/messages/messages_eo.py46
-rw-r--r--nikola/data/themes/base/messages/messages_es.py12
-rw-r--r--nikola/data/themes/base/messages/messages_et.py4
-rw-r--r--nikola/data/themes/base/messages/messages_eu.py4
-rw-r--r--nikola/data/themes/base/messages/messages_fa.py4
-rw-r--r--nikola/data/themes/base/messages/messages_fi.py4
-rw-r--r--nikola/data/themes/base/messages/messages_fil.py4
-rw-r--r--nikola/data/themes/base/messages/messages_fr.py14
-rw-r--r--nikola/data/themes/base/messages/messages_gl.py4
-rw-r--r--nikola/data/themes/base/messages/messages_hi.py4
-rw-r--r--nikola/data/themes/base/messages/messages_hr.py4
-rw-r--r--nikola/data/themes/base/messages/messages_hu.py43
-rw-r--r--nikola/data/themes/base/messages/messages_id.py4
-rw-r--r--nikola/data/themes/base/messages/messages_it.py4
-rw-r--r--nikola/data/themes/base/messages/messages_ja.py60
-rw-r--r--nikola/data/themes/base/messages/messages_ko.py4
-rw-r--r--nikola/data/themes/base/messages/messages_nb.py4
-rw-r--r--nikola/data/themes/base/messages/messages_nl.py8
-rw-r--r--nikola/data/themes/base/messages/messages_pa.py4
-rw-r--r--nikola/data/themes/base/messages/messages_pl.py4
-rw-r--r--nikola/data/themes/base/messages/messages_pt.py4
-rw-r--r--nikola/data/themes/base/messages/messages_pt_br.py4
-rw-r--r--nikola/data/themes/base/messages/messages_ru.py14
-rw-r--r--nikola/data/themes/base/messages/messages_si_lk.py4
-rw-r--r--nikola/data/themes/base/messages/messages_sk.py4
-rw-r--r--nikola/data/themes/base/messages/messages_sl.py4
-rw-r--r--nikola/data/themes/base/messages/messages_sr.py4
-rw-r--r--nikola/data/themes/base/messages/messages_sr_latin.py (renamed from nikola/data/themes/base/messages/messages_sr@latin.py)4
-rw-r--r--nikola/data/themes/base/messages/messages_sv.py4
-rw-r--r--nikola/data/themes/base/messages/messages_tl.py4
-rw-r--r--nikola/data/themes/base/messages/messages_tr.py4
-rw-r--r--nikola/data/themes/base/messages/messages_uk.py14
-rw-r--r--nikola/data/themes/base/messages/messages_ur.py6
-rw-r--r--nikola/data/themes/base/messages/messages_zh_cn.py4
-rw-r--r--nikola/data/themes/base/messages/messages_zh_tw.py4
-rw-r--r--nikola/data/themes/base/templates/author.tmpl43
-rw-r--r--nikola/data/themes/base/templates/authorindex.tmpl13
-rw-r--r--nikola/data/themes/base/templates/authors.tmpl17
-rw-r--r--nikola/data/themes/base/templates/base_header.tmpl6
-rw-r--r--nikola/data/themes/base/templates/base_helper.tmpl5
-rw-r--r--nikola/data/themes/base/templates/gallery.tmpl6
-rw-r--r--nikola/data/themes/base/templates/index.tmpl10
-rw-r--r--nikola/data/themes/base/templates/index_helper.tmpl15
-rw-r--r--nikola/data/themes/base/templates/list.tmpl9
-rw-r--r--nikola/data/themes/base/templates/list_post.tmpl4
-rw-r--r--nikola/data/themes/base/templates/listing.tmpl4
-rw-r--r--nikola/data/themes/base/templates/post.tmpl4
-rw-r--r--nikola/data/themes/base/templates/post_header.tmpl14
-rw-r--r--nikola/data/themes/base/templates/post_helper.tmpl23
-rw-r--r--nikola/data/themes/base/templates/post_list_directive.tmpl2
-rw-r--r--nikola/data/themes/base/templates/sectionindex.tmpl21
-rw-r--r--nikola/data/themes/base/templates/tag.tmpl8
-rw-r--r--nikola/data/themes/base/templates/tagindex.tmpl6
-rw-r--r--nikola/data/themes/base/templates/tags.tmpl4
l---------nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css1
l---------nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.min.css1
l---------nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css1
l---------nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.min.css1
l---------nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.js1
l---------nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.min.js1
-rw-r--r--nikola/data/themes/bootstrap3-jinja/assets/js/flowr.plugin.js530
l---------nikola/data/themes/bootstrap3-jinja/assets/js/jquery.colorbox-min.js1
l---------nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.js1
l---------nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.map1
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/authors.tmpl17
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/base.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/base_helper.tmpl5
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/gallery.tmpl6
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/listing.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/post.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3-jinja/templates/tags.tmpl8
l---------nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css1
l---------nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.min.css1
l---------nikola/data/themes/bootstrap3/assets/css/bootstrap.css1
l---------nikola/data/themes/bootstrap3/assets/css/bootstrap.min.css1
l---------nikola/data/themes/bootstrap3/assets/js/bootstrap.js1
l---------nikola/data/themes/bootstrap3/assets/js/bootstrap.min.js1
-rw-r--r--nikola/data/themes/bootstrap3/assets/js/flowr.plugin.js530
l---------nikola/data/themes/bootstrap3/assets/js/jquery.colorbox-min.js1
l---------nikola/data/themes/bootstrap3/assets/js/jquery.min.js1
l---------nikola/data/themes/bootstrap3/assets/js/jquery.min.map1
-rw-r--r--nikola/data/themes/bootstrap3/templates/authors.tmpl17
-rw-r--r--nikola/data/themes/bootstrap3/templates/base.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3/templates/base_helper.tmpl5
-rw-r--r--nikola/data/themes/bootstrap3/templates/gallery.tmpl6
-rw-r--r--nikola/data/themes/bootstrap3/templates/listing.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3/templates/post.tmpl4
-rw-r--r--nikola/data/themes/bootstrap3/templates/tags.tmpl8
-rw-r--r--nikola/filters.py64
-rw-r--r--nikola/image_processing.py54
-rw-r--r--nikola/nikola.py273
-rw-r--r--nikola/plugin_categories.py15
-rw-r--r--nikola/plugins/basic_import.py1
-rw-r--r--nikola/plugins/command/auto.plugin2
-rw-r--r--nikola/plugins/command/auto/__init__.py23
-rw-r--r--nikola/plugins/command/bootswatch_theme.plugin2
-rw-r--r--nikola/plugins/command/bootswatch_theme.py9
-rw-r--r--nikola/plugins/command/check.plugin2
-rw-r--r--nikola/plugins/command/check.py112
-rw-r--r--nikola/plugins/command/console.plugin2
-rw-r--r--nikola/plugins/command/console.py1
-rw-r--r--nikola/plugins/command/deploy.plugin2
-rw-r--r--nikola/plugins/command/deploy.py1
-rw-r--r--nikola/plugins/command/github_deploy.plugin2
-rw-r--r--nikola/plugins/command/github_deploy.py1
-rw-r--r--nikola/plugins/command/import_wordpress.plugin2
-rw-r--r--nikola/plugins/command/import_wordpress.py60
-rw-r--r--nikola/plugins/command/init.plugin2
-rw-r--r--nikola/plugins/command/init.py11
-rw-r--r--nikola/plugins/command/install_theme.plugin2
-rw-r--r--nikola/plugins/command/install_theme.py1
-rw-r--r--nikola/plugins/command/new_page.plugin2
-rw-r--r--nikola/plugins/command/new_page.py1
-rw-r--r--nikola/plugins/command/new_post.plugin2
-rw-r--r--nikola/plugins/command/new_post.py1
-rw-r--r--nikola/plugins/command/orphans.plugin2
-rw-r--r--nikola/plugins/command/orphans.py1
-rw-r--r--nikola/plugins/command/plugin.plugin2
-rw-r--r--nikola/plugins/command/plugin.py1
-rw-r--r--nikola/plugins/command/rst2html.plugin2
-rw-r--r--nikola/plugins/command/rst2html/__init__.py3
-rw-r--r--nikola/plugins/command/serve.plugin2
-rw-r--r--nikola/plugins/command/serve.py14
-rw-r--r--nikola/plugins/command/status.py1
-rw-r--r--nikola/plugins/command/version.plugin2
-rw-r--r--nikola/plugins/command/version.py1
-rw-r--r--nikola/plugins/compile/html.plugin2
-rw-r--r--nikola/plugins/compile/html.py1
-rw-r--r--nikola/plugins/compile/ipynb.py1
-rw-r--r--nikola/plugins/compile/markdown.plugin2
-rw-r--r--nikola/plugins/compile/markdown/__init__.py1
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_gist.py5
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_nikola.py27
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.plugin2
-rw-r--r--nikola/plugins/compile/markdown/mdx_podcast.py6
-rw-r--r--nikola/plugins/compile/pandoc.plugin2
-rw-r--r--nikola/plugins/compile/pandoc.py1
-rw-r--r--nikola/plugins/compile/php.plugin2
-rw-r--r--nikola/plugins/compile/php.py1
-rw-r--r--nikola/plugins/compile/rest.plugin2
-rw-r--r--nikola/plugins/compile/rest/__init__.py4
-rw-r--r--nikola/plugins/compile/rest/chart.plugin2
-rw-r--r--nikola/plugins/compile/rest/chart.py14
-rw-r--r--nikola/plugins/compile/rest/doc.plugin2
-rw-r--r--nikola/plugins/compile/rest/doc.py1
-rw-r--r--nikola/plugins/compile/rest/gist.plugin2
-rw-r--r--nikola/plugins/compile/rest/gist.py2
-rw-r--r--nikola/plugins/compile/rest/listing.plugin2
-rw-r--r--nikola/plugins/compile/rest/listing.py11
-rw-r--r--nikola/plugins/compile/rest/media.plugin2
-rw-r--r--nikola/plugins/compile/rest/media.py2
-rw-r--r--nikola/plugins/compile/rest/post_list.plugin2
-rw-r--r--nikola/plugins/compile/rest/post_list.py6
-rw-r--r--nikola/plugins/compile/rest/slides.plugin2
-rw-r--r--nikola/plugins/compile/rest/slides.py2
-rw-r--r--nikola/plugins/compile/rest/soundcloud.plugin2
-rw-r--r--nikola/plugins/compile/rest/soundcloud.py3
-rw-r--r--nikola/plugins/compile/rest/thumbnail.plugin2
-rw-r--r--nikola/plugins/compile/rest/thumbnail.py8
-rw-r--r--nikola/plugins/compile/rest/vimeo.py2
-rw-r--r--nikola/plugins/compile/rest/youtube.py2
-rw-r--r--nikola/plugins/misc/scan_posts.plugin2
-rw-r--r--nikola/plugins/misc/scan_posts.py1
-rw-r--r--nikola/plugins/task/archive.plugin2
-rw-r--r--nikola/plugins/task/archive.py23
-rw-r--r--nikola/plugins/task/authors.plugin10
-rw-r--r--nikola/plugins/task/authors.py316
-rw-r--r--nikola/plugins/task/bundles.plugin2
-rw-r--r--nikola/plugins/task/bundles.py8
-rw-r--r--nikola/plugins/task/copy_assets.plugin2
-rw-r--r--nikola/plugins/task/copy_assets.py10
-rw-r--r--nikola/plugins/task/copy_files.plugin2
-rw-r--r--nikola/plugins/task/copy_files.py1
-rw-r--r--nikola/plugins/task/galleries.plugin2
-rw-r--r--nikola/plugins/task/galleries.py43
-rw-r--r--nikola/plugins/task/gzip.plugin2
-rw-r--r--nikola/plugins/task/gzip.py1
-rw-r--r--nikola/plugins/task/indexes.plugin2
-rw-r--r--nikola/plugins/task/indexes.py158
-rw-r--r--nikola/plugins/task/listings.plugin2
-rw-r--r--nikola/plugins/task/listings.py21
-rw-r--r--nikola/plugins/task/pages.plugin2
-rw-r--r--nikola/plugins/task/pages.py1
-rw-r--r--nikola/plugins/task/posts.plugin2
-rw-r--r--nikola/plugins/task/posts.py5
-rw-r--r--nikola/plugins/task/py3_switch.plugin13
-rw-r--r--nikola/plugins/task/py3_switch.py103
-rw-r--r--nikola/plugins/task/redirect.plugin2
-rw-r--r--nikola/plugins/task/redirect.py1
-rw-r--r--nikola/plugins/task/robots.plugin2
-rw-r--r--nikola/plugins/task/robots.py8
-rw-r--r--nikola/plugins/task/rss.plugin2
-rw-r--r--nikola/plugins/task/rss.py21
-rw-r--r--nikola/plugins/task/scale_images.plugin2
-rw-r--r--nikola/plugins/task/scale_images.py1
-rw-r--r--nikola/plugins/task/sitemap.plugin2
-rw-r--r--nikola/plugins/task/sitemap/__init__.py27
-rw-r--r--nikola/plugins/task/sources.plugin2
-rw-r--r--nikola/plugins/task/sources.py1
-rw-r--r--nikola/plugins/task/tags.plugin2
-rw-r--r--nikola/plugins/task/tags.py136
-rw-r--r--nikola/plugins/template/jinja.plugin2
-rw-r--r--nikola/plugins/template/jinja.py1
-rw-r--r--nikola/plugins/template/mako.plugin2
-rw-r--r--nikola/plugins/template/mako.py1
-rw-r--r--nikola/post.py155
-rw-r--r--nikola/utils.py276
256 files changed, 3838 insertions, 6433 deletions
diff --git a/nikola/__init__.py b/nikola/__init__.py
index 4ab6e34..03d83da 100644
--- a/nikola/__init__.py
+++ b/nikola/__init__.py
@@ -29,7 +29,7 @@
from __future__ import absolute_import
import os
-__version__ = "7.6.4"
+__version__ = "7.7.3"
DEBUG = bool(os.getenv('NIKOLA_DEBUG'))
from .nikola import Nikola # NOQA
diff --git a/nikola/__main__.py b/nikola/__main__.py
index 2aa63f4..a4bd989 100644
--- a/nikola/__main__.py
+++ b/nikola/__main__.py
@@ -44,6 +44,7 @@ from doit.doit_cmd import DoitMain
from doit.cmd_help import Help as DoitHelp
from doit.cmd_run import Run as DoitRun
from doit.cmd_clean import Clean as DoitClean
+from doit.cmd_completion import TabCompletion
from doit.cmd_auto import Auto as DoitAuto
from logbook import NullHandler
from blinker import signal
@@ -175,7 +176,6 @@ def main(args=None):
class Help(DoitHelp):
-
"""Show Nikola usage."""
@staticmethod
@@ -199,7 +199,6 @@ class Help(DoitHelp):
class Build(DoitRun):
-
"""Expose "run" command as "build" for backwards compatibility."""
def __init__(self, *args, **kw):
@@ -238,7 +237,6 @@ class Build(DoitRun):
class Clean(DoitClean):
-
"""Clean site, including the cache directory."""
def clean_tasks(self, tasks, dryrun):
@@ -255,7 +253,6 @@ DoitAuto.name = 'doit_auto'
class NikolaTaskLoader(TaskLoader):
-
"""Nikola-specific task loader."""
def __init__(self, nikola, quiet=False):
@@ -288,7 +285,6 @@ class NikolaTaskLoader(TaskLoader):
class DoitNikola(DoitMain):
-
"""Nikola-specific implementation of DoitMain."""
# overwite help command
@@ -359,7 +355,7 @@ class DoitNikola(DoitMain):
LOGGER.info('Did you mean "{}" or "{}"?'.format('", "'.join(best_sugg[:-1]), best_sugg[-1]))
return 3
- if sub_cmds[args[0]] is not Help and not isinstance(sub_cmds[args[0]], Command): # Is a doit command
+ if not sub_cmds[args[0]] in (Help, TabCompletion) and not isinstance(sub_cmds[args[0]], Command):
if not self.nikola.configured:
LOGGER.error("This command needs to run inside an "
"existing Nikola site.")
@@ -399,5 +395,6 @@ def levenshtein(s1, s2):
return previous_row[-1]
+
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
diff --git a/nikola/conf.py.in b/nikola/conf.py.in
index b7a88f7..7ef6927 100644
--- a/nikola/conf.py.in
+++ b/nikola/conf.py.in
@@ -68,8 +68,8 @@ TRANSLATIONS_PATTERN = ${TRANSLATIONS_PATTERN}
# For submenus:
# (
# (
-# ('http://apple.com/', 'Apple'),
-# ('http://orange.com/', 'Orange'),
+# ('https://apple.com/', 'Apple'),
+# ('https://orange.com/', 'Orange'),
# ),
# 'Fruits'
# )
@@ -89,6 +89,39 @@ NAVIGATION_LINKS = ${NAVIGATION_LINKS}
# Name of the theme to use.
THEME = ${THEME}
+# Primary color of your theme. This will be used to customize your theme and
+# auto-generate related colors in POSTS_SECTION_COLORS. Must be a HEX value.
+THEME_COLOR = '#5670d4'
+
+# POSTS and PAGES contains (wildcard, destination, template) tuples.
+#
+# The wildcard is used to generate a list of reSt source files
+# (whatever/thing.txt).
+#
+# That fragment could have an associated metadata file (whatever/thing.meta),
+# and optionally translated files (example for Spanish, with code "es"):
+# whatever/thing.es.txt and whatever/thing.es.meta
+#
+# This assumes you use the default TRANSLATIONS_PATTERN.
+#
+# From those files, a set of HTML fragment files will be generated:
+# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es)
+#
+# These files are combined with the template to produce rendered
+# pages, which will be placed at
+# output / TRANSLATIONS[lang] / destination / pagename.html
+#
+# where "pagename" is the "slug" specified in the metadata file.
+#
+# The difference between POSTS and PAGES is that POSTS are added
+# to feeds and are considered part of a blog, while PAGES are
+# just independent HTML pages.
+#
+
+POSTS = ${POSTS}
+PAGES = ${PAGES}
+
+
##############################################
# Below this point, everything is optional
##############################################
@@ -96,7 +129,7 @@ THEME = ${THEME}
# Post's dates are considered in UTC by default, if you want to use
# another time zone, please set TIMEZONE to match. Check the available
# list from Wikipedia:
-# http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+# https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
# (e.g. 'Europe/Zurich')
# Also, if you want to use a different time zone in some of your posts,
# you can use the ISO 8601/RFC 3339 format (ex. 2012-03-30T23:00:00+02:00)
@@ -107,11 +140,11 @@ TIMEZONE = ${TIMEZONE}
# Note that this does not affect DATE_FORMAT.
# FORCE_ISO8601 = False
-# Date format used to display post dates.
+# Date format used to display post dates. (translatable)
# (str used by datetime.datetime.strftime)
# DATE_FORMAT = '%Y-%m-%d %H:%M'
-# Date format used to display post dates, if local dates are used.
+# Date format used to display post dates, if local dates are used. (translatable)
# (str used by moment.js)
# JS_DATE_FORMAT = 'YYYY-MM-DD HH:mm'
@@ -135,34 +168,6 @@ TIMEZONE = ${TIMEZONE}
# LOCALE_DEFAULT = locale to use for languages not mentioned in LOCALES; if
# not set the default Nikola mapping is used.
-# POSTS and PAGES contains (wildcard, destination, template) tuples.
-#
-# The wildcard is used to generate a list of reSt source files
-# (whatever/thing.txt).
-#
-# That fragment could have an associated metadata file (whatever/thing.meta),
-# and optionally translated files (example for Spanish, with code "es"):
-# whatever/thing.es.txt and whatever/thing.es.meta
-#
-# This assumes you use the default TRANSLATIONS_PATTERN.
-#
-# From those files, a set of HTML fragment files will be generated:
-# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es)
-#
-# These files are combined with the template to produce rendered
-# pages, which will be placed at
-# output / TRANSLATIONS[lang] / destination / pagename.html
-#
-# where "pagename" is the "slug" specified in the metadata file.
-#
-# The difference between POSTS and PAGES is that POSTS are added
-# to feeds and are considered part of a blog, while PAGES are
-# just independent HTML pages.
-#
-
-POSTS = ${POSTS}
-PAGES = ${PAGES}
-
# One or more folders containing files to be copied as-is into the output.
# The format is a dictionary of {source: relative destination}.
# Default is:
@@ -208,6 +213,57 @@ COMPILERS = ${COMPILERS}
# Warning: this option will change its default value to False in v8!
WRITE_TAG_CLOUD = True
+# Generate pages for each section. The site must have at least two sections
+# for this option to take effect. It wouldn't build for just one section.
+POSTS_SECTIONS = True
+
+# Setting this to False generates a list page instead of an index. Indexes
+# are the default and will apply GENERATE_ATOM if set.
+# POSTS_SECTIONS_ARE_INDEXES = True
+
+# Each post and section page will have an associated color that can be used
+# to style them with a recognizable color detail across your site. A color
+# is assigned to each section based on shifting the hue of your THEME_COLOR
+# at least 7.5 % while leaving the lightness and saturation untouched in the
+# HUSL colorspace. You can overwrite colors by assigning them colors in HEX.
+# POSTS_SECTION_COLORS = {
+# DEFAULT_LANG: {
+# 'posts': '#49b11bf',
+# 'reviews': '#ffe200',
+# },
+# }
+
+# Associate a description with a section. For use in meta description on
+# section index pages or elsewhere in themes.
+# POSTS_SECTION_DESCRIPTIONS = {
+# DEFAULT_LANG: {
+# 'how-to': 'Learn how-to things properly with these amazing tutorials.',
+# },
+# }
+
+# Sections are determined by their output directory as set in POSTS by default,
+# but can alternatively be determined from file metadata instead.
+# POSTS_SECTION_FROM_META = False
+
+# Names are determined from the output directory name automatically or the
+# metadata label. Unless overwritten below, names will use title cased and
+# hyphens replaced by spaces.
+# POSTS_SECTION_NAME = {
+# DEFAULT_LANG: {
+# 'posts': 'Blog Posts',
+# 'uncategorized': 'Odds and Ends',
+# },
+# }
+
+# Titles for per-section index pages. Can be either one string where "{name}"
+# is substituted or the POSTS_SECTION_NAME, or a dict of sections. Note
+# that the INDEX_PAGES option is also applied to section page titles.
+# POSTS_SECTION_TITLE = {
+# DEFAULT_LANG: {
+# 'how-to': 'How-to and Tutorials',
+# },
+# }
+
# Paths for different autogenerated bits. These are combined with the
# translation paths.
@@ -215,8 +271,14 @@ WRITE_TAG_CLOUD = True
# output / TRANSLATION[lang] / TAG_PATH / index.html (list of tags)
# output / TRANSLATION[lang] / TAG_PATH / tag.html (list of posts for a tag)
# output / TRANSLATION[lang] / TAG_PATH / tag.xml (RSS feed for a tag)
+ # (translatable)
# TAG_PATH = "categories"
+# See TAG_PATH's "list of tags" for the default setting value. Can be overwritten
+# here any path relative to the output directory.
+ # (translatable)
+# TAGS_INDEX_PATH = "tags.html"
+
# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain
# the posts themselves. If set to False, it will be just a list of links.
# TAG_PAGES_ARE_INDEXES = False
@@ -231,6 +293,13 @@ WRITE_TAG_CLOUD = True
# },
# }
+# Set special titles for tag pages. The default is "Posts about TAG".
+# TAG_PAGES_TITLES = {
+# DEFAULT_LANG: {
+# "blogging": "Meta-posts about blogging",
+# "open source": "Posts about open source software"
+# },
+# }
# If you do not want to display a tag publicly, you can mark it as hidden.
# The tag will not be displayed on the tag list page, the tag cloud and posts.
@@ -247,6 +316,7 @@ HIDDEN_TAGS = ['mathjax']
# output / TRANSLATION[lang] / CATEGORY_PATH / index.html (list of categories)
# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.html (list of posts for a category)
# output / TRANSLATION[lang] / CATEGORY_PATH / CATEGORY_PREFIX category.xml (RSS feed for a category)
+# (translatable)
# CATEGORY_PATH = "categories"
# CATEGORY_PREFIX = "cat_"
@@ -274,11 +344,49 @@ CATEGORY_OUTPUT_FLAT_HIERARCHY = ${CATEGORY_OUTPUT_FLAT_HIERARCHY}
# },
# }
+# Set special titles for category pages. The default is "Posts about CATEGORY".
+# CATEGORY_PAGES_TITLES = {
+# DEFAULT_LANG: {
+# "blogging": "Meta-posts about blogging",
+# "open source": "Posts about open source software"
+# },
+# }
+
# If you do not want to display a category publicly, you can mark it as hidden.
# The category will not be displayed on the category list page.
# Category pages will still be generated.
HIDDEN_CATEGORIES = []
+# If ENABLE_AUTHOR_PAGES is set to True and there is more than one
+# author, author pages are generated.
+# ENABLE_AUTHOR_PAGES = True
+
+# Final locations are:
+# output / TRANSLATION[lang] / AUTHOR_PATH / index.html (list of tags)
+# output / TRANSLATION[lang] / AUTHOR_PATH / author.html (list of posts for a tag)
+# output / TRANSLATION[lang] / AUTHOR_PATH / author.xml (RSS feed for a tag)
+# AUTHOR_PATH = "authors"
+
+# If AUTHOR_PAGES_ARE_INDEXES is set to True, each author's page will contain
+# the posts themselves. If set to False, it will be just a list of links.
+# AUTHOR_PAGES_ARE_INDEXES = False
+
+# Set descriptions for author pages to make them more interesting. The
+# default is no description. The value is used in the meta description
+# and displayed underneath the author list or index page’s title.
+# AUTHOR_PAGES_DESCRIPTIONS = {
+# DEFAULT_LANG: {
+# "Juanjo Conti": "Python coder and writer.",
+# "Roberto Alsina": "Nikola father."
+# },
+# }
+
+
+# If you do not want to display an author publicly, you can mark it as hidden.
+# The author will not be displayed on the author list page and posts.
+# Tag pages will still be generated.
+HIDDEN_AUTHORS = ['Guest']
+
# Final location for the main blog page and sibling paginated pages is
# output / TRANSLATION[lang] / INDEX_PATH / index-*.html
# INDEX_PATH = ""
@@ -311,17 +419,25 @@ HIDDEN_CATEGORIES = []
# absolute: a complete URL (that includes the SITE_URL)
# URL_TYPE = 'rel_path'
+# If USE_BASE_TAG is True, then all HTML files will include
+# something like <base href=http://foo.var.com/baz/bat> to help
+# the browser resolve relative links.
+# In some rare cases, this will be a problem, and you can
+# disable it by setting USE_BASE_TAG to False.
+# USE_BASE_TAG = True
+
# Final location for the blog main RSS feed is:
# output / TRANSLATION[lang] / RSS_PATH / rss.xml
# RSS_PATH = ""
-# Number of posts in RSS feeds
-# FEED_LENGTH = 10
-
-# Slug the Tag URL easier for users to type, special characters are
+# Slug the Tag URL. Easier for users to type, special characters are
# often removed or replaced as well.
# SLUG_TAG_PATH = True
+# Slug the Author URL. Easier for users to type, special characters are
+# often removed or replaced as well.
+# SLUG_AUTHOR_PATH = True
+
# A list of redirection tuples, [("foo/from.html", "/bar/to.html")].
#
# A HTML file will be created in output/foo/from.html that redirects
@@ -563,10 +679,10 @@ IMAGE_FOLDERS = {'images': 'images'}
# 'Read more...' for the index page, if INDEX_TEASERS is True (translatable)
INDEX_READ_MORE_LINK = ${INDEX_READ_MORE_LINK}
-# 'Read more...' for the RSS_FEED, if RSS_TEASERS is True (translatable)
-RSS_READ_MORE_LINK = ${RSS_READ_MORE_LINK}
+# 'Read more...' for the feeds, if FEED_TEASERS is True (translatable)
+FEED_READ_MORE_LINK = ${FEED_READ_MORE_LINK}
-# Append a URL query to the RSS_READ_MORE_LINK in Atom and RSS feeds. Advanced
+# Append a URL query to the FEED_READ_MORE_LINK in Atom and RSS feeds. Advanced
# option used for traffic source tracking.
# Minimum example for use with Piwik: "pk_campaign=feed"
# The following tags exist and are replaced for you:
@@ -574,18 +690,18 @@ RSS_READ_MORE_LINK = ${RSS_READ_MORE_LINK}
# {feedFormat} The name of the syndication format.
# Example using replacement for use with Google Analytics:
# "utm_source={feedRelUri}&utm_medium=nikola_feed&utm_campaign={feedFormat}_feed"
-RSS_LINKS_APPEND_QUERY = False
+FEED_LINKS_APPEND_QUERY = False
# A HTML fragment describing the license, for the sidebar.
# (translatable)
LICENSE = ""
# I recommend using the Creative Commons' wizard:
-# http://creativecommons.org/choose/
+# https://creativecommons.org/choose/
# LICENSE = """
-# <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">
+# <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
# <img alt="Creative Commons License BY-NC-SA"
# style="border-width:0; margin-bottom:12px;"
-# src="http://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"></a>"""
+# src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"></a>"""
# A small copyright notice for the page footer (in HTML).
# (translatable)
@@ -715,6 +831,13 @@ PRETTY_URLS = ${PRETTY_URLS}
# </script>
# """
+# Want to use KaTeX instead of MathJax? While KaTeX is less featureful,
+# it's faster and the output looks better.
+# If you set USE_KATEX to True, you also need to add an extra CSS file
+# like this:
+# EXTRA_HEAD_DATA = """<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.css">"""
+# USE_KATEX = False
+
# Do you want to customize the nbconversion of your IPython notebook?
# IPYNB_CONFIG = {}
# With the following example configuration you can use a custom jinja template
@@ -771,24 +894,34 @@ MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite', 'extra']
# them. Generate Atom for tags by setting TAG_PAGES_ARE_INDEXES to True.
# Atom feeds are built based on INDEX_DISPLAY_POST_COUNT and not FEED_LENGTH
# Switch between plain-text summaries and full HTML content using the
-# RSS_TEASER option. RSS_LINKS_APPEND_QUERY is also respected. Atom feeds
+# FEED_TEASER option. FEED_LINKS_APPEND_QUERY is also respected. Atom feeds
# are generated even for old indexes and have pagination link relations
# between each other. Old Atom feeds with no changes are marked as archived.
# GENERATE_ATOM = False
+# Only inlclude teasers in Atom and RSS feeds. Disabling include the full
+# content. Defaults to True.
+# FEED_TEASERS = True
+
+# Strip HTML from Atom annd RSS feed summaries and content. Defaults to False.
+# FEED_PLAIN = False
+
+# Number of posts in Atom and RSS feeds.
+# FEED_LENGTH = 10
+
+# Include preview image as a <figure><img></figure> at the top of the entry.
+# Requires FEED_PLAIN = False. If the preview image is found in the content,
+# it will not be included again. Image will be included as-is, aim to optmize
+# the image source for Feedly, Apple News, Flipboard, and other popular clients.
+# FEED_PREVIEWIMAGE = True
+
# RSS_LINK is a HTML fragment to link the RSS or Atom feeds. If set to None,
# the base.tmpl will use the feed Nikola generates. However, you may want to
# change it for a FeedBurner feed or something else.
# RSS_LINK = None
-# Show teasers (instead of full posts) in feeds? Defaults to True.
-# RSS_TEASERS = True
-
-# Strip HTML in the RSS feed? Default to False
-# RSS_PLAIN = False
-
# A search form to search this site, for the sidebar. You can use a Google
-# custom search (http://www.google.com/cse/)
+# custom search (https://www.google.com/cse/)
# Or a DuckDuckGo search: https://duckduckgo.com/search_box.html
# Default is no search form.
# (translatable)
@@ -815,7 +948,7 @@ MARKDOWN_EXTENSIONS = ['fenced_code', 'codehilite', 'extra']
# If you prefer a Google search form, here's an example that should just work:
# SEARCH_FORM = """
# <!-- Google custom search -->
-# <form method="get" action="http://www.google.com/search" class="navbar-form navbar-right" role="search">
+# <form method="get" action="https://www.google.com/search" class="navbar-form navbar-right" role="search">
# <div class="form-group">
# <input type="text" name="q" class="form-control" placeholder="Search">
# </div>
@@ -914,6 +1047,8 @@ UNSLUGIFY_TITLES = True
# LINK_CHECK_WHITELIST = []
# If set to True, enable optional hyphenation in your posts (requires pyphen)
+# Enabling hyphenation has been shown to break math support in some cases,
+# use with caution.
# HYPHENATE = False
# The <hN> tags in HTML generated by certain compilers (reST/Markdown)
diff --git a/nikola/data/samplesite/images/frontispiece.jpg b/nikola/data/samplesite/images/frontispiece.jpg
new file mode 100644
index 0000000..0baf371
--- /dev/null
+++ b/nikola/data/samplesite/images/frontispiece.jpg
Binary files differ
diff --git a/nikola/data/samplesite/images/illus_001.jpg b/nikola/data/samplesite/images/illus_001.jpg
new file mode 100644
index 0000000..c8acdcf
--- /dev/null
+++ b/nikola/data/samplesite/images/illus_001.jpg
Binary files differ
diff --git a/nikola/data/samplesite/posts/1.rst b/nikola/data/samplesite/posts/1.rst
index 88263a7..386251b 100644
--- a/nikola/data/samplesite/posts/1.rst
+++ b/nikola/data/samplesite/posts/1.rst
@@ -7,8 +7,8 @@
.. description:
.. category: nikola
-.. figure:: http://farm1.staticflickr.com/138/352972944_4f9d568680.jpg
- :target: http://farm1.staticflickr.com/138/352972944_4f9d568680_z.jpg?zz=1
+.. figure:: https://farm1.staticflickr.com/138/352972944_4f9d568680.jpg
+ :target: https://farm1.staticflickr.com/138/352972944_4f9d568680_z.jpg?zz=1
:class: thumbnail
:alt: Nikola Tesla Corner by nicwest, on Flickr
@@ -22,6 +22,6 @@ Next steps:
* `See a demo photo gallery <link://gallery/demo>`__
* :doc:`See a demo listing <listings-demo>`
* :doc:`See a demo slideshow <slides-demo>`
-* :doc:`See a demo of the Bootstrap theme <bootstrap-demo>`
+* :doc:`See a demo of a longer text <dr-nikolas-vendetta>`
Send feedback to info@getnikola.com!
diff --git a/nikola/data/samplesite/stories/1.rst b/nikola/data/samplesite/stories/1.rst
index abe1d0b..2e70345 100644
--- a/nikola/data/samplesite/stories/1.rst
+++ b/nikola/data/samplesite/stories/1.rst
@@ -8,4 +8,4 @@
Hope you enjoy this software!
* Home page at https://getnikola.com/
-* Author's blog (and reason why Nikola exists): http://ralsina.me/
+* Author's blog (and reason why Nikola exists): https://ralsina.me/
diff --git a/nikola/data/samplesite/stories/a-study-in-scarlet.txt b/nikola/data/samplesite/stories/a-study-in-scarlet.txt
deleted file mode 100644
index 2dfee52..0000000
--- a/nikola/data/samplesite/stories/a-study-in-scarlet.txt
+++ /dev/null
@@ -1,5139 +0,0 @@
-.. link:
-.. description:
-.. tags:
-.. date: 2013-08-27 18:20:55 UTC-03:00
-.. title: A STUDY IN SCARLET.
-.. slug: a-study-in-scarlet
-
-===================
-A STUDY IN SCARLET.
-===================
-
-By A. Conan Doyle [1]_
-======================
-
-
-:Title: A Study In Scarlet
-:Author: Arthur Conan Doyle
-:Posting Date: July 12, 2008 [EBook #244]
-:Release Date: April, 1995 [Last updated: February 17, 2013]
-:Language: English
-:Produced by: Roger Squires
-
-.. class:: alert alert-info pull-right
-
-.. contents::
-
-------------------
-
-.. class:: pull-right
-
-.. note:: The Project Gutenberg EBook of A Study In Scarlet, by Arthur Conan Doyle
-
-
- This eBook is for the use of anyone anywhere at no cost and with
- almost no restrictions whatsoever. You may copy it, give it away or
- re-use it under the terms of the Project Gutenberg License included
- with this eBook or online at www.gutenberg.org
-
-
- Original Transcriber's Note: This etext is prepared directly
- from an 1887 edition, and care has been taken to duplicate the
- original exactly, including typographical and punctuation
- vagaries.
-
- Additions to the text include adding the underscore character to
- indicate italics, and textual end-notes in square braces.
-
- Project Gutenberg Editor's Note: In reproofing and moving old PG
- files such as this to the present PG directory system it is the
- policy to reformat the text to conform to present PG Standards.
- In this case however, in consideration of the note above of the
- original transcriber describing his care to try to duplicate the
- original 1887 edition as to typography and punctuation vagaries,
- no changes have been made in this ascii text file. However, in
- the Latin-1 file and this html file, present standards are
- followed and the several French and Spanish words have been
- given their proper accents.
-
- Part II, The Country of the Saints, deals much with the Mormon Church.
-
-
-PART I.
--------
-
-(Being a reprint from the reminiscences of JOHN H. WATSON, M.D., late of the Army Medical Department.) [2]_
-
-
-CHAPTER I. MR. SHERLOCK HOLMES.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-IN the year 1878 I took my degree of Doctor of Medicine of the
-University of London, and proceeded to Netley to go through the course
-prescribed for surgeons in the army. Having completed my studies there,
-I was duly attached to the Fifth Northumberland Fusiliers as Assistant
-Surgeon. The regiment was stationed in India at the time, and before
-I could join it, the second Afghan war had broken out. On landing at
-Bombay, I learned that my corps had advanced through the passes, and
-was already deep in the enemy's country. I followed, however, with many
-other officers who were in the same situation as myself, and succeeded
-in reaching Candahar in safety, where I found my regiment, and at once
-entered upon my new duties.
-
-The campaign brought honours and promotion to many, but for me it had
-nothing but misfortune and disaster. I was removed from my brigade and
-attached to the Berkshires, with whom I served at the fatal battle of
-Maiwand. There I was struck on the shoulder by a Jezail bullet, which
-shattered the bone and grazed the subclavian artery. I should have
-fallen into the hands of the murderous Ghazis had it not been for the
-devotion and courage shown by Murray, my orderly, who threw me across a
-pack-horse, and succeeded in bringing me safely to the British lines.
-
-Worn with pain, and weak from the prolonged hardships which I had
-undergone, I was removed, with a great train of wounded sufferers, to
-the base hospital at Peshawar. Here I rallied, and had already improved
-so far as to be able to walk about the wards, and even to bask a little
-upon the verandah, when I was struck down by enteric fever, that curse
-of our Indian possessions. For months my life was despaired of, and
-when at last I came to myself and became convalescent, I was so weak and
-emaciated that a medical board determined that not a day should be lost
-in sending me back to England. I was dispatched, accordingly, in the
-troopship "Orontes," and landed a month later on Portsmouth jetty, with
-my health irretrievably ruined, but with permission from a paternal
-government to spend the next nine months in attempting to improve it.
-
-I had neither kith nor kin in England, and was therefore as free as
-air--or as free as an income of eleven shillings and sixpence a day will
-permit a man to be. Under such circumstances, I naturally gravitated to
-London, that great cesspool into which all the loungers and idlers of
-the Empire are irresistibly drained. There I stayed for some time at
-a private hotel in the Strand, leading a comfortless, meaningless
-existence, and spending such money as I had, considerably more freely
-than I ought. So alarming did the state of my finances become, that
-I soon realized that I must either leave the metropolis and rusticate
-somewhere in the country, or that I must make a complete alteration in
-my style of living. Choosing the latter alternative, I began by making
-up my mind to leave the hotel, and to take up my quarters in some less
-pretentious and less expensive domicile.
-
-On the very day that I had come to this conclusion, I was standing at
-the Criterion Bar, when some one tapped me on the shoulder, and turning
-round I recognized young Stamford, who had been a dresser under me at
-Barts. The sight of a friendly face in the great wilderness of London is
-a pleasant thing indeed to a lonely man. In old days Stamford had never
-been a particular crony of mine, but now I hailed him with enthusiasm,
-and he, in his turn, appeared to be delighted to see me. In the
-exuberance of my joy, I asked him to lunch with me at the Holborn, and
-we started off together in a hansom.
-
-"Whatever have you been doing with yourself, Watson?" he asked in
-undisguised wonder, as we rattled through the crowded London streets.
-"You are as thin as a lath and as brown as a nut."
-
-I gave him a short sketch of my adventures, and had hardly concluded it
-by the time that we reached our destination.
-
-"Poor devil!" he said, commiseratingly, after he had listened to my
-misfortunes. "What are you up to now?"
-
-"Looking for lodgings." [3]_ I answered. "Trying to solve the problem
-as to whether it is possible to get comfortable rooms at a reasonable
-price."
-
-"That's a strange thing," remarked my companion; "you are the second man
-to-day that has used that expression to me."
-
-"And who was the first?" I asked.
-
-"A fellow who is working at the chemical laboratory up at the hospital.
-He was bemoaning himself this morning because he could not get someone
-to go halves with him in some nice rooms which he had found, and which
-were too much for his purse."
-
-"By Jove!" I cried, "if he really wants someone to share the rooms and
-the expense, I am the very man for him. I should prefer having a partner
-to being alone."
-
-Young Stamford looked rather strangely at me over his wine-glass. "You
-don't know Sherlock Holmes yet," he said; "perhaps you would not care
-for him as a constant companion."
-
-"Why, what is there against him?"
-
-"Oh, I didn't say there was anything against him. He is a little queer
-in his ideas--an enthusiast in some branches of science. As far as I
-know he is a decent fellow enough."
-
-"A medical student, I suppose?" said I.
-
-"No--I have no idea what he intends to go in for. I believe he is well
-up in anatomy, and he is a first-class chemist; but, as far as I know,
-he has never taken out any systematic medical classes. His studies are
-very desultory and eccentric, but he has amassed a lot of out-of-the way
-knowledge which would astonish his professors."
-
-"Did you never ask him what he was going in for?" I asked.
-
-"No; he is not a man that it is easy to draw out, though he can be
-communicative enough when the fancy seizes him."
-
-"I should like to meet him," I said. "If I am to lodge with anyone, I
-should prefer a man of studious and quiet habits. I am not strong
-enough yet to stand much noise or excitement. I had enough of both in
-Afghanistan to last me for the remainder of my natural existence. How
-could I meet this friend of yours?"
-
-"He is sure to be at the laboratory," returned my companion. "He either
-avoids the place for weeks, or else he works there from morning to
-night. If you like, we shall drive round together after luncheon."
-
-"Certainly," I answered, and the conversation drifted away into other
-channels.
-
-As we made our way to the hospital after leaving the Holborn, Stamford
-gave me a few more particulars about the gentleman whom I proposed to
-take as a fellow-lodger.
-
-"You mustn't blame me if you don't get on with him," he said; "I know
-nothing more of him than I have learned from meeting him occasionally in
-the laboratory. You proposed this arrangement, so you must not hold me
-responsible."
-
-"If we don't get on it will be easy to part company," I answered. "It
-seems to me, Stamford," I added, looking hard at my companion, "that you
-have some reason for washing your hands of the matter. Is this fellow's
-temper so formidable, or what is it? Don't be mealy-mouthed about it."
-
-"It is not easy to express the inexpressible," he answered with a laugh.
-"Holmes is a little too scientific for my tastes--it approaches to
-cold-bloodedness. I could imagine his giving a friend a little pinch of
-the latest vegetable alkaloid, not out of malevolence, you understand,
-but simply out of a spirit of inquiry in order to have an accurate idea
-of the effects. To do him justice, I think that he would take it himself
-with the same readiness. He appears to have a passion for definite and
-exact knowledge."
-
-"Very right too."
-
-"Yes, but it may be pushed to excess. When it comes to beating the
-subjects in the dissecting-rooms with a stick, it is certainly taking
-rather a bizarre shape."
-
-"Beating the subjects!"
-
-"Yes, to verify how far bruises may be produced after death. I saw him
-at it with my own eyes."
-
-"And yet you say he is not a medical student?"
-
-"No. Heaven knows what the objects of his studies are. But here we
-are, and you must form your own impressions about him." As he spoke, we
-turned down a narrow lane and passed through a small side-door, which
-opened into a wing of the great hospital. It was familiar ground to me,
-and I needed no guiding as we ascended the bleak stone staircase and
-made our way down the long corridor with its vista of whitewashed
-wall and dun-coloured doors. Near the further end a low arched passage
-branched away from it and led to the chemical laboratory.
-
-This was a lofty chamber, lined and littered with countless bottles.
-Broad, low tables were scattered about, which bristled with retorts,
-test-tubes, and little Bunsen lamps, with their blue flickering flames.
-There was only one student in the room, who was bending over a distant
-table absorbed in his work. At the sound of our steps he glanced round
-and sprang to his feet with a cry of pleasure. "I've found it! I've
-found it," he shouted to my companion, running towards us with a
-test-tube in his hand. "I have found a re-agent which is precipitated
-by hoemoglobin, [4]_ and by nothing else." Had he discovered a gold mine,
-greater delight could not have shone upon his features.
-
-"Dr. Watson, Mr. Sherlock Holmes," said Stamford, introducing us.
-
-"How are you?" he said cordially, gripping my hand with a strength
-for which I should hardly have given him credit. "You have been in
-Afghanistan, I perceive."
-
-"How on earth did you know that?" I asked in astonishment.
-
-"Never mind," said he, chuckling to himself. "The question now is about
-hoemoglobin. No doubt you see the significance of this discovery of
-mine?"
-
-"It is interesting, chemically, no doubt," I answered, "but
-practically----"
-
-"Why, man, it is the most practical medico-legal discovery for years.
-Don't you see that it gives us an infallible test for blood stains. Come
-over here now!" He seized me by the coat-sleeve in his eagerness, and
-drew me over to the table at which he had been working. "Let us have
-some fresh blood," he said, digging a long bodkin into his finger, and
-drawing off the resulting drop of blood in a chemical pipette. "Now, I
-add this small quantity of blood to a litre of water. You perceive that
-the resulting mixture has the appearance of pure water. The proportion
-of blood cannot be more than one in a million. I have no doubt, however,
-that we shall be able to obtain the characteristic reaction." As he
-spoke, he threw into the vessel a few white crystals, and then added
-some drops of a transparent fluid. In an instant the contents assumed a
-dull mahogany colour, and a brownish dust was precipitated to the bottom
-of the glass jar.
-
-"Ha! ha!" he cried, clapping his hands, and looking as delighted as a
-child with a new toy. "What do you think of that?"
-
-"It seems to be a very delicate test," I remarked.
-
-"Beautiful! beautiful! The old Guiacum test was very clumsy and
-uncertain. So is the microscopic examination for blood corpuscles. The
-latter is valueless if the stains are a few hours old. Now, this appears
-to act as well whether the blood is old or new. Had this test been
-invented, there are hundreds of men now walking the earth who would long
-ago have paid the penalty of their crimes."
-
-"Indeed!" I murmured.
-
-"Criminal cases are continually hinging upon that one point. A man is
-suspected of a crime months perhaps after it has been committed. His
-linen or clothes are examined, and brownish stains discovered upon them.
-Are they blood stains, or mud stains, or rust stains, or fruit stains,
-or what are they? That is a question which has puzzled many an expert,
-and why? Because there was no reliable test. Now we have the Sherlock
-Holmes' test, and there will no longer be any difficulty."
-
-His eyes fairly glittered as he spoke, and he put his hand over his
-heart and bowed as if to some applauding crowd conjured up by his
-imagination.
-
-"You are to be congratulated," I remarked, considerably surprised at his
-enthusiasm.
-
-"There was the case of Von Bischoff at Frankfort last year. He would
-certainly have been hung had this test been in existence. Then there was
-Mason of Bradford, and the notorious Muller, and Lefevre of Montpellier,
-and Samson of New Orleans. I could name a score of cases in which it
-would have been decisive."
-
-"You seem to be a walking calendar of crime," said Stamford with a
-laugh. "You might start a paper on those lines. Call it the 'Police News
-of the Past.'"
-
-"Very interesting reading it might be made, too," remarked Sherlock
-Holmes, sticking a small piece of plaster over the prick on his finger.
-"I have to be careful," he continued, turning to me with a smile, "for I
-dabble with poisons a good deal." He held out his hand as he spoke, and
-I noticed that it was all mottled over with similar pieces of plaster,
-and discoloured with strong acids.
-
-"We came here on business," said Stamford, sitting down on a high
-three-legged stool, and pushing another one in my direction with
-his foot. "My friend here wants to take diggings, and as you were
-complaining that you could get no one to go halves with you, I thought
-that I had better bring you together."
-
-Sherlock Holmes seemed delighted at the idea of sharing his rooms with
-me. "I have my eye on a suite in Baker Street," he said, "which would
-suit us down to the ground. You don't mind the smell of strong tobacco,
-I hope?"
-
-"I always smoke 'ship's' myself," I answered.
-
-"That's good enough. I generally have chemicals about, and occasionally
-do experiments. Would that annoy you?"
-
-"By no means."
-
-"Let me see--what are my other shortcomings. I get in the dumps at
-times, and don't open my mouth for days on end. You must not think I am
-sulky when I do that. Just let me alone, and I'll soon be right. What
-have you to confess now? It's just as well for two fellows to know the
-worst of one another before they begin to live together."
-
-I laughed at this cross-examination. "I keep a bull pup," I said, "and
-I object to rows because my nerves are shaken, and I get up at all sorts
-of ungodly hours, and I am extremely lazy. I have another set of vices
-when I'm well, but those are the principal ones at present."
-
-"Do you include violin-playing in your category of rows?" he asked,
-anxiously.
-
-"It depends on the player," I answered. "A well-played violin is a treat
-for the gods--a badly-played one----"
-
-"Oh, that's all right," he cried, with a merry laugh. "I think we may
-consider the thing as settled--that is, if the rooms are agreeable to
-you."
-
-"When shall we see them?"
-
-"Call for me here at noon to-morrow, and we'll go together and settle
-everything," he answered.
-
-"All right--noon exactly," said I, shaking his hand.
-
-We left him working among his chemicals, and we walked together towards
-my hotel.
-
-"By the way," I asked suddenly, stopping and turning upon Stamford, "how
-the deuce did he know that I had come from Afghanistan?"
-
-My companion smiled an enigmatical smile. "That's just his little
-peculiarity," he said. "A good many people have wanted to know how he
-finds things out."
-
-"Oh! a mystery is it?" I cried, rubbing my hands. "This is very piquant.
-I am much obliged to you for bringing us together. 'The proper study of
-mankind is man,' you know."
-
-"You must study him, then," Stamford said, as he bade me good-bye.
-"You'll find him a knotty problem, though. I'll wager he learns more
-about you than you about him. Good-bye."
-
-"Good-bye," I answered, and strolled on to my hotel, considerably
-interested in my new acquaintance.
-
-
-
-
-CHAPTER II. THE SCIENCE OF DEDUCTION.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-WE met next day as he had arranged, and inspected the rooms at No. 221B,
-[5]_ Baker Street, of which he had spoken at our meeting. They
-consisted of a couple of comfortable bed-rooms and a single large
-airy sitting-room, cheerfully furnished, and illuminated by two broad
-windows. So desirable in every way were the apartments, and so moderate
-did the terms seem when divided between us, that the bargain was
-concluded upon the spot, and we at once entered into possession.
-That very evening I moved my things round from the hotel, and on the
-following morning Sherlock Holmes followed me with several boxes and
-portmanteaus. For a day or two we were busily employed in unpacking and
-laying out our property to the best advantage. That done, we
-gradually began to settle down and to accommodate ourselves to our new
-surroundings.
-
-Holmes was certainly not a difficult man to live with. He was quiet
-in his ways, and his habits were regular. It was rare for him to be
-up after ten at night, and he had invariably breakfasted and gone out
-before I rose in the morning. Sometimes he spent his day at the chemical
-laboratory, sometimes in the dissecting-rooms, and occasionally in long
-walks, which appeared to take him into the lowest portions of the City.
-Nothing could exceed his energy when the working fit was upon him; but
-now and again a reaction would seize him, and for days on end he would
-lie upon the sofa in the sitting-room, hardly uttering a word or moving
-a muscle from morning to night. On these occasions I have noticed such
-a dreamy, vacant expression in his eyes, that I might have suspected him
-of being addicted to the use of some narcotic, had not the temperance
-and cleanliness of his whole life forbidden such a notion.
-
-As the weeks went by, my interest in him and my curiosity as to his
-aims in life, gradually deepened and increased. His very person and
-appearance were such as to strike the attention of the most casual
-observer. In height he was rather over six feet, and so excessively
-lean that he seemed to be considerably taller. His eyes were sharp and
-piercing, save during those intervals of torpor to which I have alluded;
-and his thin, hawk-like nose gave his whole expression an air of
-alertness and decision. His chin, too, had the prominence and squareness
-which mark the man of determination. His hands were invariably
-blotted with ink and stained with chemicals, yet he was possessed of
-extraordinary delicacy of touch, as I frequently had occasion to observe
-when I watched him manipulating his fragile philosophical instruments.
-
-The reader may set me down as a hopeless busybody, when I confess how
-much this man stimulated my curiosity, and how often I endeavoured
-to break through the reticence which he showed on all that concerned
-himself. Before pronouncing judgment, however, be it remembered, how
-objectless was my life, and how little there was to engage my attention.
-My health forbade me from venturing out unless the weather was
-exceptionally genial, and I had no friends who would call upon me and
-break the monotony of my daily existence. Under these circumstances, I
-eagerly hailed the little mystery which hung around my companion, and
-spent much of my time in endeavouring to unravel it.
-
-He was not studying medicine. He had himself, in reply to a question,
-confirmed Stamford's opinion upon that point. Neither did he appear to
-have pursued any course of reading which might fit him for a degree in
-science or any other recognized portal which would give him an entrance
-into the learned world. Yet his zeal for certain studies was remarkable,
-and within eccentric limits his knowledge was so extraordinarily ample
-and minute that his observations have fairly astounded me. Surely no man
-would work so hard or attain such precise information unless he had some
-definite end in view. Desultory readers are seldom remarkable for the
-exactness of their learning. No man burdens his mind with small matters
-unless he has some very good reason for doing so.
-
-His ignorance was as remarkable as his knowledge. Of contemporary
-literature, philosophy and politics he appeared to know next to nothing.
-Upon my quoting Thomas Carlyle, he inquired in the naivest way who he
-might be and what he had done. My surprise reached a climax, however,
-when I found incidentally that he was ignorant of the Copernican Theory
-and of the composition of the Solar System. That any civilized human
-being in this nineteenth century should not be aware that the earth
-travelled round the sun appeared to be to me such an extraordinary fact
-that I could hardly realize it.
-
-"You appear to be astonished," he said, smiling at my expression of
-surprise. "Now that I do know it I shall do my best to forget it."
-
-"To forget it!"
-
-"You see," he explained, "I consider that a man's brain originally is
-like a little empty attic, and you have to stock it with such furniture
-as you choose. A fool takes in all the lumber of every sort that he
-comes across, so that the knowledge which might be useful to him gets
-crowded out, or at best is jumbled up with a lot of other things so that
-he has a difficulty in laying his hands upon it. Now the skilful workman
-is very careful indeed as to what he takes into his brain-attic. He will
-have nothing but the tools which may help him in doing his work, but of
-these he has a large assortment, and all in the most perfect order. It
-is a mistake to think that that little room has elastic walls and can
-distend to any extent. Depend upon it there comes a time when for every
-addition of knowledge you forget something that you knew before. It is
-of the highest importance, therefore, not to have useless facts elbowing
-out the useful ones."
-
-"But the Solar System!" I protested.
-
-"What the deuce is it to me?" he interrupted impatiently; "you say
-that we go round the sun. If we went round the moon it would not make a
-pennyworth of difference to me or to my work."
-
-I was on the point of asking him what that work might be, but something
-in his manner showed me that the question would be an unwelcome one. I
-pondered over our short conversation, however, and endeavoured to draw
-my deductions from it. He said that he would acquire no knowledge which
-did not bear upon his object. Therefore all the knowledge which he
-possessed was such as would be useful to him. I enumerated in my own
-mind all the various points upon which he had shown me that he was
-exceptionally well-informed. I even took a pencil and jotted them down.
-I could not help smiling at the document when I had completed it. It ran
-in this way--
-
-
-SHERLOCK HOLMES--his limits.
-
-1. Knowledge of Literature.--Nil.
-2. Philosophy.--Nil.
-3. Astronomy.--Nil.
-4. Politics.--Feeble.
-5. Botany.--Variable.
- Well up in belladonna,
- opium, and poisons generally.
- Knows nothing of practical gardening.
-6. Geology.--Practical, but limited.
- Tells at a glance different soils
- from each other. After walks has
- shown me splashes upon his trousers,
- and told me by their colour and
- consistence in what part of London
- he had received them.
-7. Chemistry.--Profound.
-8. Anatomy.--Accurate, but unsystematic.
-9. Sensational Literature.--Immense. He appears to know every detail of every horror perpetrated in the century.
-10. Plays the violin well.
-11. Is an expert singlestick player, boxer, and swordsman.
-12. Has a good practical knowledge of British law.
-
-
-When I had got so far in my list I threw it into the fire in despair.
-"If I can only find what the fellow is driving at by reconciling all
-these accomplishments, and discovering a calling which needs them all,"
-I said to myself, "I may as well give up the attempt at once."
-
-I see that I have alluded above to his powers upon the violin. These
-were very remarkable, but as eccentric as all his other accomplishments.
-That he could play pieces, and difficult pieces, I knew well, because
-at my request he has played me some of Mendelssohn's Lieder, and other
-favourites. When left to himself, however, he would seldom produce any
-music or attempt any recognized air. Leaning back in his arm-chair of
-an evening, he would close his eyes and scrape carelessly at the fiddle
-which was thrown across his knee. Sometimes the chords were sonorous and
-melancholy. Occasionally they were fantastic and cheerful. Clearly they
-reflected the thoughts which possessed him, but whether the music aided
-those thoughts, or whether the playing was simply the result of a whim
-or fancy was more than I could determine. I might have rebelled against
-these exasperating solos had it not been that he usually terminated them
-by playing in quick succession a whole series of my favourite airs as a
-slight compensation for the trial upon my patience.
-
-During the first week or so we had no callers, and I had begun to think
-that my companion was as friendless a man as I was myself. Presently,
-however, I found that he had many acquaintances, and those in the most
-different classes of society. There was one little sallow rat-faced,
-dark-eyed fellow who was introduced to me as Mr. Lestrade, and who came
-three or four times in a single week. One morning a young girl called,
-fashionably dressed, and stayed for half an hour or more. The same
-afternoon brought a grey-headed, seedy visitor, looking like a Jew
-pedlar, who appeared to me to be much excited, and who was closely
-followed by a slip-shod elderly woman. On another occasion an old
-white-haired gentleman had an interview with my companion; and on
-another a railway porter in his velveteen uniform. When any of these
-nondescript individuals put in an appearance, Sherlock Holmes used to
-beg for the use of the sitting-room, and I would retire to my bed-room.
-He always apologized to me for putting me to this inconvenience. "I have
-to use this room as a place of business," he said, "and these people
-are my clients." Again I had an opportunity of asking him a point blank
-question, and again my delicacy prevented me from forcing another man to
-confide in me. I imagined at the time that he had some strong reason for
-not alluding to it, but he soon dispelled the idea by coming round to
-the subject of his own accord.
-
-It was upon the 4th of March, as I have good reason to remember, that I
-rose somewhat earlier than usual, and found that Sherlock Holmes had not
-yet finished his breakfast. The landlady had become so accustomed to my
-late habits that my place had not been laid nor my coffee prepared. With
-the unreasonable petulance of mankind I rang the bell and gave a curt
-intimation that I was ready. Then I picked up a magazine from the table
-and attempted to while away the time with it, while my companion munched
-silently at his toast. One of the articles had a pencil mark at the
-heading, and I naturally began to run my eye through it.
-
-Its somewhat ambitious title was "The Book of Life," and it attempted to
-show how much an observant man might learn by an accurate and systematic
-examination of all that came in his way. It struck me as being a
-remarkable mixture of shrewdness and of absurdity. The reasoning was
-close and intense, but the deductions appeared to me to be far-fetched
-and exaggerated. The writer claimed by a momentary expression, a twitch
-of a muscle or a glance of an eye, to fathom a man's inmost thoughts.
-Deceit, according to him, was an impossibility in the case of one
-trained to observation and analysis. His conclusions were as infallible
-as so many propositions of Euclid. So startling would his results appear
-to the uninitiated that until they learned the processes by which he had
-arrived at them they might well consider him as a necromancer.
-
-"From a drop of water," said the writer, "a logician could infer the
-possibility of an Atlantic or a Niagara without having seen or heard of
-one or the other. So all life is a great chain, the nature of which is
-known whenever we are shown a single link of it. Like all other arts,
-the Science of Deduction and Analysis is one which can only be acquired
-by long and patient study nor is life long enough to allow any mortal
-to attain the highest possible perfection in it. Before turning to
-those moral and mental aspects of the matter which present the greatest
-difficulties, let the enquirer begin by mastering more elementary
-problems. Let him, on meeting a fellow-mortal, learn at a glance to
-distinguish the history of the man, and the trade or profession to
-which he belongs. Puerile as such an exercise may seem, it sharpens the
-faculties of observation, and teaches one where to look and what to look
-for. By a man's finger nails, by his coat-sleeve, by his boot, by his
-trouser knees, by the callosities of his forefinger and thumb, by his
-expression, by his shirt cuffs--by each of these things a man's calling
-is plainly revealed. That all united should fail to enlighten the
-competent enquirer in any case is almost inconceivable."
-
-"What ineffable twaddle!" I cried, slapping the magazine down on the
-table, "I never read such rubbish in my life."
-
-"What is it?" asked Sherlock Holmes.
-
-"Why, this article," I said, pointing at it with my egg spoon as I sat
-down to my breakfast. "I see that you have read it since you have marked
-it. I don't deny that it is smartly written. It irritates me though. It
-is evidently the theory of some arm-chair lounger who evolves all these
-neat little paradoxes in the seclusion of his own study. It is not
-practical. I should like to see him clapped down in a third class
-carriage on the Underground, and asked to give the trades of all his
-fellow-travellers. I would lay a thousand to one against him."
-
-"You would lose your money," Sherlock Holmes remarked calmly. "As for
-the article I wrote it myself."
-
-"You!"
-
-"Yes, I have a turn both for observation and for deduction. The
-theories which I have expressed there, and which appear to you to be so
-chimerical are really extremely practical--so practical that I depend
-upon them for my bread and cheese."
-
-"And how?" I asked involuntarily.
-
-"Well, I have a trade of my own. I suppose I am the only one in the
-world. I'm a consulting detective, if you can understand what that is.
-Here in London we have lots of Government detectives and lots of private
-ones. When these fellows are at fault they come to me, and I manage to
-put them on the right scent. They lay all the evidence before me, and I
-am generally able, by the help of my knowledge of the history of
-crime, to set them straight. There is a strong family resemblance about
-misdeeds, and if you have all the details of a thousand at your finger
-ends, it is odd if you can't unravel the thousand and first. Lestrade
-is a well-known detective. He got himself into a fog recently over a
-forgery case, and that was what brought him here."
-
-"And these other people?"
-
-"They are mostly sent on by private inquiry agencies. They are
-all people who are in trouble about something, and want a little
-enlightening. I listen to their story, they listen to my comments, and
-then I pocket my fee."
-
-"But do you mean to say," I said, "that without leaving your room you
-can unravel some knot which other men can make nothing of, although they
-have seen every detail for themselves?"
-
-"Quite so. I have a kind of intuition that way. Now and again a case
-turns up which is a little more complex. Then I have to bustle about and
-see things with my own eyes. You see I have a lot of special knowledge
-which I apply to the problem, and which facilitates matters wonderfully.
-Those rules of deduction laid down in that article which aroused your
-scorn, are invaluable to me in practical work. Observation with me is
-second nature. You appeared to be surprised when I told you, on our
-first meeting, that you had come from Afghanistan."
-
-"You were told, no doubt."
-
-"Nothing of the sort. I _knew_ you came from Afghanistan. From long
-habit the train of thoughts ran so swiftly through my mind, that I
-arrived at the conclusion without being conscious of intermediate steps.
-There were such steps, however. The train of reasoning ran, 'Here is a
-gentleman of a medical type, but with the air of a military man. Clearly
-an army doctor, then. He has just come from the tropics, for his face is
-dark, and that is not the natural tint of his skin, for his wrists are
-fair. He has undergone hardship and sickness, as his haggard face says
-clearly. His left arm has been injured. He holds it in a stiff and
-unnatural manner. Where in the tropics could an English army doctor have
-seen much hardship and got his arm wounded? Clearly in Afghanistan.' The
-whole train of thought did not occupy a second. I then remarked that you
-came from Afghanistan, and you were astonished."
-
-"It is simple enough as you explain it," I said, smiling. "You remind
-me of Edgar Allen Poe's Dupin. I had no idea that such individuals did
-exist outside of stories."
-
-Sherlock Holmes rose and lit his pipe. "No doubt you think that you are
-complimenting me in comparing me to Dupin," he observed. "Now, in my
-opinion, Dupin was a very inferior fellow. That trick of his of breaking
-in on his friends' thoughts with an apropos remark after a quarter of
-an hour's silence is really very showy and superficial. He had some
-analytical genius, no doubt; but he was by no means such a phenomenon as
-Poe appeared to imagine."
-
-"Have you read Gaboriau's works?" I asked. "Does Lecoq come up to your
-idea of a detective?"
-
-Sherlock Holmes sniffed sardonically. "Lecoq was a miserable bungler,"
-he said, in an angry voice; "he had only one thing to recommend him, and
-that was his energy. That book made me positively ill. The question was
-how to identify an unknown prisoner. I could have done it in twenty-four
-hours. Lecoq took six months or so. It might be made a text-book for
-detectives to teach them what to avoid."
-
-I felt rather indignant at having two characters whom I had admired
-treated in this cavalier style. I walked over to the window, and stood
-looking out into the busy street. "This fellow may be very clever," I
-said to myself, "but he is certainly very conceited."
-
-"There are no crimes and no criminals in these days," he said,
-querulously. "What is the use of having brains in our profession. I know
-well that I have it in me to make my name famous. No man lives or has
-ever lived who has brought the same amount of study and of natural
-talent to the detection of crime which I have done. And what is the
-result? There is no crime to detect, or, at most, some bungling villainy
-with a motive so transparent that even a Scotland Yard official can see
-through it."
-
-I was still annoyed at his bumptious style of conversation. I thought it
-best to change the topic.
-
-"I wonder what that fellow is looking for?" I asked, pointing to a
-stalwart, plainly-dressed individual who was walking slowly down the
-other side of the street, looking anxiously at the numbers. He had
-a large blue envelope in his hand, and was evidently the bearer of a
-message.
-
-"You mean the retired sergeant of Marines," said Sherlock Holmes.
-
-"Brag and bounce!" thought I to myself. "He knows that I cannot verify
-his guess."
-
-The thought had hardly passed through my mind when the man whom we were
-watching caught sight of the number on our door, and ran rapidly across
-the roadway. We heard a loud knock, a deep voice below, and heavy steps
-ascending the stair.
-
-"For Mr. Sherlock Holmes," he said, stepping into the room and handing
-my friend the letter.
-
-Here was an opportunity of taking the conceit out of him. He little
-thought of this when he made that random shot. "May I ask, my lad," I
-said, in the blandest voice, "what your trade may be?"
-
-"Commissionaire, sir," he said, gruffly. "Uniform away for repairs."
-
-"And you were?" I asked, with a slightly malicious glance at my
-companion.
-
-"A sergeant, sir, Royal Marine Light Infantry, sir. No answer? Right,
-sir."
-
-He clicked his heels together, raised his hand in a salute, and was
-gone.
-
-
-
-
-CHAPTER III. THE LAURISTON GARDEN MYSTERY [6]_
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-I CONFESS that I was considerably startled by this fresh proof of the
-practical nature of my companion's theories. My respect for his powers
-of analysis increased wondrously. There still remained some lurking
-suspicion in my mind, however, that the whole thing was a pre-arranged
-episode, intended to dazzle me, though what earthly object he could have
-in taking me in was past my comprehension. When I looked at him he
-had finished reading the note, and his eyes had assumed the vacant,
-lack-lustre expression which showed mental abstraction.
-
-"How in the world did you deduce that?" I asked.
-
-"Deduce what?" said he, petulantly.
-
-"Why, that he was a retired sergeant of Marines."
-
-"I have no time for trifles," he answered, brusquely; then with a smile,
-"Excuse my rudeness. You broke the thread of my thoughts; but perhaps
-it is as well. So you actually were not able to see that that man was a
-sergeant of Marines?"
-
-"No, indeed."
-
-"It was easier to know it than to explain why I knew it. If you
-were asked to prove that two and two made four, you might find some
-difficulty, and yet you are quite sure of the fact. Even across the
-street I could see a great blue anchor tattooed on the back of the
-fellow's hand. That smacked of the sea. He had a military carriage,
-however, and regulation side whiskers. There we have the marine. He was
-a man with some amount of self-importance and a certain air of command.
-You must have observed the way in which he held his head and swung
-his cane. A steady, respectable, middle-aged man, too, on the face of
-him--all facts which led me to believe that he had been a sergeant."
-
-"Wonderful!" I ejaculated.
-
-"Commonplace," said Holmes, though I thought from his expression that he
-was pleased at my evident surprise and admiration. "I said just now that
-there were no criminals. It appears that I am wrong--look at this!" He
-threw me over the note which the commissionaire had brought. [7]_
-
-"Why," I cried, as I cast my eye over it, "this is terrible!"
-
-"It does seem to be a little out of the common," he remarked, calmly.
-"Would you mind reading it to me aloud?"
-
-This is the letter which I read to him----
-
-
-"MY DEAR MR. SHERLOCK HOLMES,--
-
-"There has been a bad business during the night at 3, Lauriston Gardens,
-off the Brixton Road. Our man on the beat saw a light there about two in
-the morning, and as the house was an empty one, suspected that something
-was amiss. He found the door open, and in the front room, which is bare
-of furniture, discovered the body of a gentleman, well dressed, and
-having cards in his pocket bearing the name of 'Enoch J. Drebber,
-Cleveland, Ohio, U.S.A.' There had been no robbery, nor is there any
-evidence as to how the man met his death. There are marks of blood in
-the room, but there is no wound upon his person. We are at a loss as to
-how he came into the empty house; indeed, the whole affair is a puzzler.
-If you can come round to the house any time before twelve, you will find
-me there. I have left everything *in statu quo* until I hear from you.
-If you are unable to come I shall give you fuller details, and would
-esteem it a great kindness if you would favour me with your opinion.
-Yours faithfully,
-
-"TOBIAS GREGSON."
-
-
-"Gregson is the smartest of the Scotland Yarders," my friend remarked;
-"he and Lestrade are the pick of a bad lot. They are both quick and
-energetic, but conventional--shockingly so. They have their knives
-into one another, too. They are as jealous as a pair of professional
-beauties. There will be some fun over this case if they are both put
-upon the scent."
-
-I was amazed at the calm way in which he rippled on. "Surely there is
-not a moment to be lost," I cried, "shall I go and order you a cab?"
-
-"I'm not sure about whether I shall go. I am the most incurably lazy
-devil that ever stood in shoe leather--that is, when the fit is on me,
-for I can be spry enough at times."
-
-"Why, it is just such a chance as you have been longing for."
-
-"My dear fellow, what does it matter to me. Supposing I unravel the
-whole matter, you may be sure that Gregson, Lestrade, and Co. will
-pocket all the credit. That comes of being an unofficial personage."
-
-"But he begs you to help him."
-
-"Yes. He knows that I am his superior, and acknowledges it to me; but
-he would cut his tongue out before he would own it to any third person.
-However, we may as well go and have a look. I shall work it out on my
-own hook. I may have a laugh at them if I have nothing else. Come on!"
-
-He hustled on his overcoat, and bustled about in a way that showed that
-an energetic fit had superseded the apathetic one.
-
-"Get your hat," he said.
-
-"You wish me to come?"
-
-"Yes, if you have nothing better to do." A minute later we were both in
-a hansom, driving furiously for the Brixton Road.
-
-It was a foggy, cloudy morning, and a dun-coloured veil hung over the
-house-tops, looking like the reflection of the mud-coloured streets
-beneath. My companion was in the best of spirits, and prattled away
-about Cremona fiddles, and the difference between a Stradivarius and
-an Amati. As for myself, I was silent, for the dull weather and the
-melancholy business upon which we were engaged, depressed my spirits.
-
-"You don't seem to give much thought to the matter in hand," I said at
-last, interrupting Holmes' musical disquisition.
-
-"No data yet," he answered. "It is a capital mistake to theorize before
-you have all the evidence. It biases the judgment."
-
-"You will have your data soon," I remarked, pointing with my finger;
-"this is the Brixton Road, and that is the house, if I am not very much
-mistaken."
-
-"So it is. Stop, driver, stop!" We were still a hundred yards or so from
-it, but he insisted upon our alighting, and we finished our journey upon
-foot.
-
-Number 3, Lauriston Gardens wore an ill-omened and minatory look. It was
-one of four which stood back some little way from the street, two being
-occupied and two empty. The latter looked out with three tiers of vacant
-melancholy windows, which were blank and dreary, save that here and
-there a "To Let" card had developed like a cataract upon the bleared
-panes. A small garden sprinkled over with a scattered eruption of sickly
-plants separated each of these houses from the street, and was traversed
-by a narrow pathway, yellowish in colour, and consisting apparently of a
-mixture of clay and of gravel. The whole place was very sloppy from the
-rain which had fallen through the night. The garden was bounded by a
-three-foot brick wall with a fringe of wood rails upon the top, and
-against this wall was leaning a stalwart police constable, surrounded by
-a small knot of loafers, who craned their necks and strained their eyes
-in the vain hope of catching some glimpse of the proceedings within.
-
-I had imagined that Sherlock Holmes would at once have hurried into the
-house and plunged into a study of the mystery. Nothing appeared to be
-further from his intention. With an air of nonchalance which, under the
-circumstances, seemed to me to border upon affectation, he lounged up
-and down the pavement, and gazed vacantly at the ground, the sky, the
-opposite houses and the line of railings. Having finished his scrutiny,
-he proceeded slowly down the path, or rather down the fringe of grass
-which flanked the path, keeping his eyes riveted upon the ground. Twice
-he stopped, and once I saw him smile, and heard him utter an exclamation
-of satisfaction. There were many marks of footsteps upon the wet clayey
-soil, but since the police had been coming and going over it, I was
-unable to see how my companion could hope to learn anything from it.
-Still I had had such extraordinary evidence of the quickness of his
-perceptive faculties, that I had no doubt that he could see a great deal
-which was hidden from me.
-
-At the door of the house we were met by a tall, white-faced,
-flaxen-haired man, with a notebook in his hand, who rushed forward and
-wrung my companion's hand with effusion. "It is indeed kind of you to
-come," he said, "I have had everything left untouched."
-
-"Except that!" my friend answered, pointing at the pathway. "If a herd
-of buffaloes had passed along there could not be a greater mess. No
-doubt, however, you had drawn your own conclusions, Gregson, before you
-permitted this."
-
-"I have had so much to do inside the house," the detective said
-evasively. "My colleague, Mr. Lestrade, is here. I had relied upon him
-to look after this."
-
-Holmes glanced at me and raised his eyebrows sardonically. "With two
-such men as yourself and Lestrade upon the ground, there will not be
-much for a third party to find out," he said.
-
-Gregson rubbed his hands in a self-satisfied way. "I think we have done
-all that can be done," he answered; "it's a queer case though, and I
-knew your taste for such things."
-
-"You did not come here in a cab?" asked Sherlock Holmes.
-
-"No, sir."
-
-"Nor Lestrade?"
-
-"No, sir."
-
-"Then let us go and look at the room." With which inconsequent remark he
-strode on into the house, followed by Gregson, whose features expressed
-his astonishment.
-
-A short passage, bare planked and dusty, led to the kitchen and offices.
-Two doors opened out of it to the left and to the right. One of these
-had obviously been closed for many weeks. The other belonged to the
-dining-room, which was the apartment in which the mysterious affair had
-occurred. Holmes walked in, and I followed him with that subdued feeling
-at my heart which the presence of death inspires.
-
-It was a large square room, looking all the larger from the absence
-of all furniture. A vulgar flaring paper adorned the walls, but it was
-blotched in places with mildew, and here and there great strips had
-become detached and hung down, exposing the yellow plaster beneath.
-Opposite the door was a showy fireplace, surmounted by a mantelpiece of
-imitation white marble. On one corner of this was stuck the stump of a
-red wax candle. The solitary window was so dirty that the light was
-hazy and uncertain, giving a dull grey tinge to everything, which was
-intensified by the thick layer of dust which coated the whole apartment.
-
-All these details I observed afterwards. At present my attention was
-centred upon the single grim motionless figure which lay stretched upon
-the boards, with vacant sightless eyes staring up at the discoloured
-ceiling. It was that of a man about forty-three or forty-four years of
-age, middle-sized, broad shouldered, with crisp curling black hair, and
-a short stubbly beard. He was dressed in a heavy broadcloth frock coat
-and waistcoat, with light-coloured trousers, and immaculate collar
-and cuffs. A top hat, well brushed and trim, was placed upon the floor
-beside him. His hands were clenched and his arms thrown abroad, while
-his lower limbs were interlocked as though his death struggle had been a
-grievous one. On his rigid face there stood an expression of horror,
-and as it seemed to me, of hatred, such as I have never seen upon human
-features. This malignant and terrible contortion, combined with the low
-forehead, blunt nose, and prognathous jaw gave the dead man a singularly
-simious and ape-like appearance, which was increased by his writhing,
-unnatural posture. I have seen death in many forms, but never has
-it appeared to me in a more fearsome aspect than in that dark grimy
-apartment, which looked out upon one of the main arteries of suburban
-London.
-
-Lestrade, lean and ferret-like as ever, was standing by the doorway, and
-greeted my companion and myself.
-
-"This case will make a stir, sir," he remarked. "It beats anything I
-have seen, and I am no chicken."
-
-"There is no clue?" said Gregson.
-
-"None at all," chimed in Lestrade.
-
-Sherlock Holmes approached the body, and, kneeling down, examined it
-intently. "You are sure that there is no wound?" he asked, pointing to
-numerous gouts and splashes of blood which lay all round.
-
-"Positive!" cried both detectives.
-
-"Then, of course, this blood belongs to a second individual--[8]_
-presumably the murderer, if murder has been committed. It reminds me of
-the circumstances attendant on the death of Van Jansen, in Utrecht, in
-the year '34. Do you remember the case, Gregson?"
-
-"No, sir."
-
-"Read it up--you really should. There is nothing new under the sun. It
-has all been done before."
-
-As he spoke, his nimble fingers were flying here, there, and everywhere,
-feeling, pressing, unbuttoning, examining, while his eyes wore the same
-far-away expression which I have already remarked upon. So swiftly was
-the examination made, that one would hardly have guessed the minuteness
-with which it was conducted. Finally, he sniffed the dead man's lips,
-and then glanced at the soles of his patent leather boots.
-
-"He has not been moved at all?" he asked.
-
-"No more than was necessary for the purposes of our examination."
-
-"You can take him to the mortuary now," he said. "There is nothing more
-to be learned."
-
-Gregson had a stretcher and four men at hand. At his call they entered
-the room, and the stranger was lifted and carried out. As they raised
-him, a ring tinkled down and rolled across the floor. Lestrade grabbed
-it up and stared at it with mystified eyes.
-
-"There's been a woman here," he cried. "It's a woman's wedding-ring."
-
-He held it out, as he spoke, upon the palm of his hand. We all gathered
-round him and gazed at it. There could be no doubt that that circlet of
-plain gold had once adorned the finger of a bride.
-
-"This complicates matters," said Gregson. "Heaven knows, they were
-complicated enough before."
-
-"You're sure it doesn't simplify them?" observed Holmes. "There's
-nothing to be learned by staring at it. What did you find in his
-pockets?"
-
-"We have it all here," said Gregson, pointing to a litter of objects
-upon one of the bottom steps of the stairs. "A gold watch, No. 97163, by
-Barraud, of London. Gold Albert chain, very heavy and solid. Gold ring,
-with masonic device. Gold pin--bull-dog's head, with rubies as eyes.
-Russian leather card-case, with cards of Enoch J. Drebber of Cleveland,
-corresponding with the E. J. D. upon the linen. No purse, but loose
-money to the extent of seven pounds thirteen. Pocket edition of
-Boccaccio's 'Decameron,' with name of Joseph Stangerson upon the
-fly-leaf. Two letters--one addressed to E. J. Drebber and one to Joseph
-Stangerson."
-
-"At what address?"
-
-"American Exchange, Strand--to be left till called for. They are both
-from the Guion Steamship Company, and refer to the sailing of their
-boats from Liverpool. It is clear that this unfortunate man was about to
-return to New York."
-
-"Have you made any inquiries as to this man, Stangerson?"
-
-"I did it at once, sir," said Gregson. "I have had advertisements
-sent to all the newspapers, and one of my men has gone to the American
-Exchange, but he has not returned yet."
-
-"Have you sent to Cleveland?"
-
-"We telegraphed this morning."
-
-"How did you word your inquiries?"
-
-"We simply detailed the circumstances, and said that we should be glad
-of any information which could help us."
-
-"You did not ask for particulars on any point which appeared to you to
-be crucial?"
-
-"I asked about Stangerson."
-
-"Nothing else? Is there no circumstance on which this whole case appears
-to hinge? Will you not telegraph again?"
-
-"I have said all I have to say," said Gregson, in an offended voice.
-
-Sherlock Holmes chuckled to himself, and appeared to be about to make
-some remark, when Lestrade, who had been in the front room while we
-were holding this conversation in the hall, reappeared upon the scene,
-rubbing his hands in a pompous and self-satisfied manner.
-
-"Mr. Gregson," he said, "I have just made a discovery of the highest
-importance, and one which would have been overlooked had I not made a
-careful examination of the walls."
-
-The little man's eyes sparkled as he spoke, and he was evidently in
-a state of suppressed exultation at having scored a point against his
-colleague.
-
-"Come here," he said, bustling back into the room, the atmosphere of
-which felt clearer since the removal of its ghastly inmate. "Now, stand
-there!"
-
-He struck a match on his boot and held it up against the wall.
-
-"Look at that!" he said, triumphantly.
-
-I have remarked that the paper had fallen away in parts. In this
-particular corner of the room a large piece had peeled off, leaving a
-yellow square of coarse plastering. Across this bare space there was
-scrawled in blood-red letters a single word--
-
- RACHE.
-
-
-"What do you think of that?" cried the detective, with the air of a
-showman exhibiting his show. "This was overlooked because it was in the
-darkest corner of the room, and no one thought of looking there. The
-murderer has written it with his or her own blood. See this smear where
-it has trickled down the wall! That disposes of the idea of suicide
-anyhow. Why was that corner chosen to write it on? I will tell you. See
-that candle on the mantelpiece. It was lit at the time, and if it was
-lit this corner would be the brightest instead of the darkest portion of
-the wall."
-
-"And what does it mean now that you _have_ found it?" asked Gregson in a
-depreciatory voice.
-
-"Mean? Why, it means that the writer was going to put the female name
-Rachel, but was disturbed before he or she had time to finish. You mark
-my words, when this case comes to be cleared up you will find that a
-woman named Rachel has something to do with it. It's all very well for
-you to laugh, Mr. Sherlock Holmes. You may be very smart and clever, but
-the old hound is the best, when all is said and done."
-
-"I really beg your pardon!" said my companion, who had ruffled the
-little man's temper by bursting into an explosion of laughter. "You
-certainly have the credit of being the first of us to find this out,
-and, as you say, it bears every mark of having been written by the other
-participant in last night's mystery. I have not had time to examine this
-room yet, but with your permission I shall do so now."
-
-As he spoke, he whipped a tape measure and a large round magnifying
-glass from his pocket. With these two implements he trotted noiselessly
-about the room, sometimes stopping, occasionally kneeling, and once
-lying flat upon his face. So engrossed was he with his occupation that
-he appeared to have forgotten our presence, for he chattered away to
-himself under his breath the whole time, keeping up a running fire
-of exclamations, groans, whistles, and little cries suggestive of
-encouragement and of hope. As I watched him I was irresistibly reminded
-of a pure-blooded well-trained foxhound as it dashes backwards and
-forwards through the covert, whining in its eagerness, until it comes
-across the lost scent. For twenty minutes or more he continued his
-researches, measuring with the most exact care the distance between
-marks which were entirely invisible to me, and occasionally applying his
-tape to the walls in an equally incomprehensible manner. In one place
-he gathered up very carefully a little pile of grey dust from the floor,
-and packed it away in an envelope. Finally, he examined with his glass
-the word upon the wall, going over every letter of it with the most
-minute exactness. This done, he appeared to be satisfied, for he
-replaced his tape and his glass in his pocket.
-
-"They say that genius is an infinite capacity for taking pains," he
-remarked with a smile. "It's a very bad definition, but it does apply to
-detective work."
-
-Gregson and Lestrade had watched the manoeuvres [9]_ of their amateur
-companion with considerable curiosity and some contempt. They evidently
-failed to appreciate the fact, which I had begun to realize, that
-Sherlock Holmes' smallest actions were all directed towards some
-definite and practical end.
-
-"What do you think of it, sir?" they both asked.
-
-"It would be robbing you of the credit of the case if I was to presume
-to help you," remarked my friend. "You are doing so well now that it
-would be a pity for anyone to interfere." There was a world of
-sarcasm in his voice as he spoke. "If you will let me know how your
-investigations go," he continued, "I shall be happy to give you any help
-I can. In the meantime I should like to speak to the constable who found
-the body. Can you give me his name and address?"
-
-Lestrade glanced at his note-book. "John Rance," he said. "He is off
-duty now. You will find him at 46, Audley Court, Kennington Park Gate."
-
-Holmes took a note of the address.
-
-"Come along, Doctor," he said; "we shall go and look him up. I'll tell
-you one thing which may help you in the case," he continued, turning to
-the two detectives. "There has been murder done, and the murderer was a
-man. He was more than six feet high, was in the prime of life, had
-small feet for his height, wore coarse, square-toed boots and smoked a
-Trichinopoly cigar. He came here with his victim in a four-wheeled cab,
-which was drawn by a horse with three old shoes and one new one on his
-off fore leg. In all probability the murderer had a florid face, and the
-finger-nails of his right hand were remarkably long. These are only a
-few indications, but they may assist you."
-
-Lestrade and Gregson glanced at each other with an incredulous smile.
-
-"If this man was murdered, how was it done?" asked the former.
-
-"Poison," said Sherlock Holmes curtly, and strode off. "One other thing,
-Lestrade," he added, turning round at the door: "'Rache,' is the German
-for 'revenge;' so don't lose your time looking for Miss Rachel."
-
-With which Parthian shot he walked away, leaving the two rivals
-open-mouthed behind him.
-
-
-
-
-CHAPTER IV. WHAT JOHN RANCE HAD TO TELL.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-IT was one o'clock when we left No. 3, Lauriston Gardens. Sherlock
-Holmes led me to the nearest telegraph office, whence he dispatched a
-long telegram. He then hailed a cab, and ordered the driver to take us
-to the address given us by Lestrade.
-
-"There is nothing like first hand evidence," he remarked; "as a matter
-of fact, my mind is entirely made up upon the case, but still we may as
-well learn all that is to be learned."
-
-"You amaze me, Holmes," said I. "Surely you are not as sure as you
-pretend to be of all those particulars which you gave."
-
-"There's no room for a mistake," he answered. "The very first thing
-which I observed on arriving there was that a cab had made two ruts with
-its wheels close to the curb. Now, up to last night, we have had no rain
-for a week, so that those wheels which left such a deep impression must
-have been there during the night. There were the marks of the horse's
-hoofs, too, the outline of one of which was far more clearly cut than
-that of the other three, showing that that was a new shoe. Since the cab
-was there after the rain began, and was not there at any time during the
-morning--I have Gregson's word for that--it follows that it must have
-been there during the night, and, therefore, that it brought those two
-individuals to the house."
-
-"That seems simple enough," said I; "but how about the other man's
-height?"
-
-"Why, the height of a man, in nine cases out of ten, can be told from
-the length of his stride. It is a simple calculation enough, though
-there is no use my boring you with figures. I had this fellow's stride
-both on the clay outside and on the dust within. Then I had a way of
-checking my calculation. When a man writes on a wall, his instinct leads
-him to write about the level of his own eyes. Now that writing was just
-over six feet from the ground. It was child's play."
-
-"And his age?" I asked.
-
-"Well, if a man can stride four and a-half feet without the smallest
-effort, he can't be quite in the sere and yellow. That was the breadth
-of a puddle on the garden walk which he had evidently walked across.
-Patent-leather boots had gone round, and Square-toes had hopped over.
-There is no mystery about it at all. I am simply applying to ordinary
-life a few of those precepts of observation and deduction which I
-advocated in that article. Is there anything else that puzzles you?"
-
-"The finger nails and the Trichinopoly," I suggested.
-
-"The writing on the wall was done with a man's forefinger dipped in
-blood. My glass allowed me to observe that the plaster was slightly
-scratched in doing it, which would not have been the case if the man's
-nail had been trimmed. I gathered up some scattered ash from the floor.
-It was dark in colour and flakey--such an ash as is only made by a
-Trichinopoly. I have made a special study of cigar ashes--in fact, I
-have written a monograph upon the subject. I flatter myself that I can
-distinguish at a glance the ash of any known brand, either of cigar
-or of tobacco. It is just in such details that the skilled detective
-differs from the Gregson and Lestrade type."
-
-"And the florid face?" I asked.
-
-"Ah, that was a more daring shot, though I have no doubt that I was
-right. You must not ask me that at the present state of the affair."
-
-I passed my hand over my brow. "My head is in a whirl," I remarked; "the
-more one thinks of it the more mysterious it grows. How came these two
-men--if there were two men--into an empty house? What has become of the
-cabman who drove them? How could one man compel another to take poison?
-Where did the blood come from? What was the object of the murderer,
-since robbery had no part in it? How came the woman's ring there? Above
-all, why should the second man write up the German word RACHE before
-decamping? I confess that I cannot see any possible way of reconciling
-all these facts."
-
-My companion smiled approvingly.
-
-"You sum up the difficulties of the situation succinctly and well," he
-said. "There is much that is still obscure, though I have quite made up
-my mind on the main facts. As to poor Lestrade's discovery it was simply
-a blind intended to put the police upon a wrong track, by suggesting
-Socialism and secret societies. It was not done by a German. The A, if
-you noticed, was printed somewhat after the German fashion. Now, a real
-German invariably prints in the Latin character, so that we may safely
-say that this was not written by one, but by a clumsy imitator who
-overdid his part. It was simply a ruse to divert inquiry into a wrong
-channel. I'm not going to tell you much more of the case, Doctor. You
-know a conjuror gets no credit when once he has explained his trick,
-and if I show you too much of my method of working, you will come to the
-conclusion that I am a very ordinary individual after all."
-
-"I shall never do that," I answered; "you have brought detection as near
-an exact science as it ever will be brought in this world."
-
-My companion flushed up with pleasure at my words, and the earnest way
-in which I uttered them. I had already observed that he was as sensitive
-to flattery on the score of his art as any girl could be of her beauty.
-
-"I'll tell you one other thing," he said. "Patent leathers [10]_ and
-Square-toes came in the same cab, and they walked down the pathway
-together as friendly as possible--arm-in-arm, in all probability.
-When they got inside they walked up and down the room--or rather,
-Patent-leathers stood still while Square-toes walked up and down. I
-could read all that in the dust; and I could read that as he walked he
-grew more and more excited. That is shown by the increased length of his
-strides. He was talking all the while, and working himself up, no doubt,
-into a fury. Then the tragedy occurred. I've told you all I know myself
-now, for the rest is mere surmise and conjecture. We have a good working
-basis, however, on which to start. We must hurry up, for I want to go to
-Halle's concert to hear Norman Neruda this afternoon."
-
-This conversation had occurred while our cab had been threading its way
-through a long succession of dingy streets and dreary by-ways. In the
-dingiest and dreariest of them our driver suddenly came to a stand.
-"That's Audley Court in there," he said, pointing to a narrow slit in
-the line of dead-coloured brick. "You'll find me here when you come
-back."
-
-Audley Court was not an attractive locality. The narrow passage led us
-into a quadrangle paved with flags and lined by sordid dwellings. We
-picked our way among groups of dirty children, and through lines of
-discoloured linen, until we came to Number 46, the door of which
-was decorated with a small slip of brass on which the name Rance was
-engraved. On enquiry we found that the constable was in bed, and we were
-shown into a little front parlour to await his coming.
-
-He appeared presently, looking a little irritable at being disturbed in
-his slumbers. "I made my report at the office," he said.
-
-Holmes took a half-sovereign from his pocket and played with it
-pensively. "We thought that we should like to hear it all from your own
-lips," he said.
-
-"I shall be most happy to tell you anything I can," the constable
-answered with his eyes upon the little golden disk.
-
-"Just let us hear it all in your own way as it occurred."
-
-Rance sat down on the horsehair sofa, and knitted his brows as though
-determined not to omit anything in his narrative.
-
-"I'll tell it ye from the beginning," he said. "My time is from ten at
-night to six in the morning. At eleven there was a fight at the 'White
-Hart'; but bar that all was quiet enough on the beat. At one o'clock it
-began to rain, and I met Harry Murcher--him who has the Holland Grove
-beat--and we stood together at the corner of Henrietta Street a-talkin'.
-Presently--maybe about two or a little after--I thought I would take
-a look round and see that all was right down the Brixton Road. It was
-precious dirty and lonely. Not a soul did I meet all the way down,
-though a cab or two went past me. I was a strollin' down, thinkin'
-between ourselves how uncommon handy a four of gin hot would be, when
-suddenly the glint of a light caught my eye in the window of that same
-house. Now, I knew that them two houses in Lauriston Gardens was empty
-on account of him that owns them who won't have the drains seen to,
-though the very last tenant what lived in one of them died o' typhoid
-fever. I was knocked all in a heap therefore at seeing a light in
-the window, and I suspected as something was wrong. When I got to the
-door----"
-
-"You stopped, and then walked back to the garden gate," my companion
-interrupted. "What did you do that for?"
-
-Rance gave a violent jump, and stared at Sherlock Holmes with the utmost
-amazement upon his features.
-
-"Why, that's true, sir," he said; "though how you come to know it,
-Heaven only knows. Ye see, when I got up to the door it was so still and
-so lonesome, that I thought I'd be none the worse for some one with me.
-I ain't afeared of anything on this side o' the grave; but I thought
-that maybe it was him that died o' the typhoid inspecting the drains
-what killed him. The thought gave me a kind o' turn, and I walked back
-to the gate to see if I could see Murcher's lantern, but there wasn't no
-sign of him nor of anyone else."
-
-"There was no one in the street?"
-
-"Not a livin' soul, sir, nor as much as a dog. Then I pulled myself
-together and went back and pushed the door open. All was quiet inside,
-so I went into the room where the light was a-burnin'. There was a
-candle flickerin' on the mantelpiece--a red wax one--and by its light I
-saw----"
-
-"Yes, I know all that you saw. You walked round the room several times,
-and you knelt down by the body, and then you walked through and tried
-the kitchen door, and then----"
-
-John Rance sprang to his feet with a frightened face and suspicion in
-his eyes. "Where was you hid to see all that?" he cried. "It seems to me
-that you knows a deal more than you should."
-
-Holmes laughed and threw his card across the table to the constable.
-"Don't get arresting me for the murder," he said. "I am one of the
-hounds and not the wolf; Mr. Gregson or Mr. Lestrade will answer for
-that. Go on, though. What did you do next?"
-
-Rance resumed his seat, without however losing his mystified expression.
-"I went back to the gate and sounded my whistle. That brought Murcher
-and two more to the spot."
-
-"Was the street empty then?"
-
-"Well, it was, as far as anybody that could be of any good goes."
-
-"What do you mean?"
-
-The constable's features broadened into a grin. "I've seen many a drunk
-chap in my time," he said, "but never anyone so cryin' drunk as
-that cove. He was at the gate when I came out, a-leanin' up agin the
-railings, and a-singin' at the pitch o' his lungs about Columbine's
-New-fangled Banner, or some such stuff. He couldn't stand, far less
-help."
-
-"What sort of a man was he?" asked Sherlock Holmes.
-
-John Rance appeared to be somewhat irritated at this digression. "He was
-an uncommon drunk sort o' man," he said. "He'd ha' found hisself in the
-station if we hadn't been so took up."
-
-"His face--his dress--didn't you notice them?" Holmes broke in
-impatiently.
-
-"I should think I did notice them, seeing that I had to prop him up--me
-and Murcher between us. He was a long chap, with a red face, the lower
-part muffled round----"
-
-"That will do," cried Holmes. "What became of him?"
-
-"We'd enough to do without lookin' after him," the policeman said, in an
-aggrieved voice. "I'll wager he found his way home all right."
-
-"How was he dressed?"
-
-"A brown overcoat."
-
-"Had he a whip in his hand?"
-
-"A whip--no."
-
-"He must have left it behind," muttered my companion. "You didn't happen
-to see or hear a cab after that?"
-
-"No."
-
-"There's a half-sovereign for you," my companion said, standing up and
-taking his hat. "I am afraid, Rance, that you will never rise in the
-force. That head of yours should be for use as well as ornament. You
-might have gained your sergeant's stripes last night. The man whom you
-held in your hands is the man who holds the clue of this mystery, and
-whom we are seeking. There is no use of arguing about it now; I tell you
-that it is so. Come along, Doctor."
-
-We started off for the cab together, leaving our informant incredulous,
-but obviously uncomfortable.
-
-"The blundering fool," Holmes said, bitterly, as we drove back to our
-lodgings. "Just to think of his having such an incomparable bit of good
-luck, and not taking advantage of it."
-
-"I am rather in the dark still. It is true that the description of this
-man tallies with your idea of the second party in this mystery. But why
-should he come back to the house after leaving it? That is not the way
-of criminals."
-
-"The ring, man, the ring: that was what he came back for. If we have no
-other way of catching him, we can always bait our line with the ring. I
-shall have him, Doctor--I'll lay you two to one that I have him. I must
-thank you for it all. I might not have gone but for you, and so have
-missed the finest study I ever came across: a study in scarlet, eh?
-Why shouldn't we use a little art jargon. There's the scarlet thread of
-murder running through the colourless skein of life, and our duty is
-to unravel it, and isolate it, and expose every inch of it. And now
-for lunch, and then for Norman Neruda. Her attack and her bowing
-are splendid. What's that little thing of Chopin's she plays so
-magnificently: Tra-la-la-lira-lira-lay."
-
-Leaning back in the cab, this amateur bloodhound carolled away like a
-lark while I meditated upon the many-sidedness of the human mind.
-
-
-
-
-CHAPTER V. OUR ADVERTISEMENT BRINGS A VISITOR.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-OUR morning's exertions had been too much for my weak health, and I was
-tired out in the afternoon. After Holmes' departure for the concert, I
-lay down upon the sofa and endeavoured to get a couple of hours' sleep.
-It was a useless attempt. My mind had been too much excited by all that
-had occurred, and the strangest fancies and surmises crowded into
-it. Every time that I closed my eyes I saw before me the distorted
-baboon-like countenance of the murdered man. So sinister was the
-impression which that face had produced upon me that I found it
-difficult to feel anything but gratitude for him who had removed its
-owner from the world. If ever human features bespoke vice of the most
-malignant type, they were certainly those of Enoch J. Drebber, of
-Cleveland. Still I recognized that justice must be done, and that the
-depravity of the victim was no condonment [11]_ in the eyes of the law.
-
-The more I thought of it the more extraordinary did my companion's
-hypothesis, that the man had been poisoned, appear. I remembered how he
-had sniffed his lips, and had no doubt that he had detected something
-which had given rise to the idea. Then, again, if not poison, what
-had caused the man's death, since there was neither wound nor marks of
-strangulation? But, on the other hand, whose blood was that which lay so
-thickly upon the floor? There were no signs of a struggle, nor had the
-victim any weapon with which he might have wounded an antagonist. As
-long as all these questions were unsolved, I felt that sleep would be
-no easy matter, either for Holmes or myself. His quiet self-confident
-manner convinced me that he had already formed a theory which explained
-all the facts, though what it was I could not for an instant conjecture.
-
-He was very late in returning--so late, that I knew that the concert
-could not have detained him all the time. Dinner was on the table before
-he appeared.
-
-"It was magnificent," he said, as he took his seat. "Do you remember
-what Darwin says about music? He claims that the power of producing and
-appreciating it existed among the human race long before the power of
-speech was arrived at. Perhaps that is why we are so subtly influenced
-by it. There are vague memories in our souls of those misty centuries
-when the world was in its childhood."
-
-"That's rather a broad idea," I remarked.
-
-"One's ideas must be as broad as Nature if they are to interpret
-Nature," he answered. "What's the matter? You're not looking quite
-yourself. This Brixton Road affair has upset you."
-
-"To tell the truth, it has," I said. "I ought to be more case-hardened
-after my Afghan experiences. I saw my own comrades hacked to pieces at
-Maiwand without losing my nerve."
-
-"I can understand. There is a mystery about this which stimulates the
-imagination; where there is no imagination there is no horror. Have you
-seen the evening paper?"
-
-"No."
-
-"It gives a fairly good account of the affair. It does not mention the
-fact that when the man was raised up, a woman's wedding ring fell upon
-the floor. It is just as well it does not."
-
-"Why?"
-
-"Look at this advertisement," he answered. "I had one sent to every
-paper this morning immediately after the affair."
-
-He threw the paper across to me and I glanced at the place indicated. It
-was the first announcement in the "Found" column. "In Brixton Road,
-this morning," it ran, "a plain gold wedding ring, found in the roadway
-between the 'White Hart' Tavern and Holland Grove. Apply Dr. Watson,
-221B, Baker Street, between eight and nine this evening."
-
-"Excuse my using your name," he said. "If I used my own some of these
-dunderheads would recognize it, and want to meddle in the affair."
-
-"That is all right," I answered. "But supposing anyone applies, I have
-no ring."
-
-"Oh yes, you have," said he, handing me one. "This will do very well. It
-is almost a facsimile."
-
-"And who do you expect will answer this advertisement."
-
-"Why, the man in the brown coat--our florid friend with the square toes.
-If he does not come himself he will send an accomplice."
-
-"Would he not consider it as too dangerous?"
-
-"Not at all. If my view of the case is correct, and I have every reason
-to believe that it is, this man would rather risk anything than lose the
-ring. According to my notion he dropped it while stooping over Drebber's
-body, and did not miss it at the time. After leaving the house he
-discovered his loss and hurried back, but found the police already in
-possession, owing to his own folly in leaving the candle burning. He had
-to pretend to be drunk in order to allay the suspicions which might have
-been aroused by his appearance at the gate. Now put yourself in that
-man's place. On thinking the matter over, it must have occurred to him
-that it was possible that he had lost the ring in the road after leaving
-the house. What would he do, then? He would eagerly look out for the
-evening papers in the hope of seeing it among the articles found. His
-eye, of course, would light upon this. He would be overjoyed. Why should
-he fear a trap? There would be no reason in his eyes why the finding
-of the ring should be connected with the murder. He would come. He will
-come. You shall see him within an hour?"
-
-"And then?" I asked.
-
-"Oh, you can leave me to deal with him then. Have you any arms?"
-
-"I have my old service revolver and a few cartridges."
-
-"You had better clean it and load it. He will be a desperate man,
-and though I shall take him unawares, it is as well to be ready for
-anything."
-
-I went to my bedroom and followed his advice. When I returned with
-the pistol the table had been cleared, and Holmes was engaged in his
-favourite occupation of scraping upon his violin.
-
-"The plot thickens," he said, as I entered; "I have just had an answer
-to my American telegram. My view of the case is the correct one."
-
-"And that is?" I asked eagerly.
-
-"My fiddle would be the better for new strings," he remarked. "Put your
-pistol in your pocket. When the fellow comes speak to him in an ordinary
-way. Leave the rest to me. Don't frighten him by looking at him too
-hard."
-
-"It is eight o'clock now," I said, glancing at my watch.
-
-"Yes. He will probably be here in a few minutes. Open the door slightly.
-That will do. Now put the key on the inside. Thank you! This is a
-queer old book I picked up at a stall yesterday--'De Jure inter
-Gentes'--published in Latin at Liege in the Lowlands, in 1642. Charles'
-head was still firm on his shoulders when this little brown-backed
-volume was struck off."
-
-"Who is the printer?"
-
-"Philippe de Croy, whoever he may have been. On the fly-leaf, in very
-faded ink, is written 'Ex libris Guliolmi Whyte.' I wonder who William
-Whyte was. Some pragmatical seventeenth century lawyer, I suppose. His
-writing has a legal twist about it. Here comes our man, I think."
-
-As he spoke there was a sharp ring at the bell. Sherlock Holmes rose
-softly and moved his chair in the direction of the door. We heard the
-servant pass along the hall, and the sharp click of the latch as she
-opened it.
-
-"Does Dr. Watson live here?" asked a clear but rather harsh voice. We
-could not hear the servant's reply, but the door closed, and some one
-began to ascend the stairs. The footfall was an uncertain and shuffling
-one. A look of surprise passed over the face of my companion as he
-listened to it. It came slowly along the passage, and there was a feeble
-tap at the door.
-
-"Come in," I cried.
-
-At my summons, instead of the man of violence whom we expected, a very
-old and wrinkled woman hobbled into the apartment. She appeared to be
-dazzled by the sudden blaze of light, and after dropping a curtsey, she
-stood blinking at us with her bleared eyes and fumbling in her pocket
-with nervous, shaky fingers. I glanced at my companion, and his face
-had assumed such a disconsolate expression that it was all I could do to
-keep my countenance.
-
-The old crone drew out an evening paper, and pointed at our
-advertisement. "It's this as has brought me, good gentlemen," she said,
-dropping another curtsey; "a gold wedding ring in the Brixton Road. It
-belongs to my girl Sally, as was married only this time twelvemonth,
-which her husband is steward aboard a Union boat, and what he'd say if
-he come 'ome and found her without her ring is more than I can think, he
-being short enough at the best o' times, but more especially when he
-has the drink. If it please you, she went to the circus last night along
-with----"
-
-"Is that her ring?" I asked.
-
-"The Lord be thanked!" cried the old woman; "Sally will be a glad woman
-this night. That's the ring."
-
-"And what may your address be?" I inquired, taking up a pencil.
-
-"13, Duncan Street, Houndsditch. A weary way from here."
-
-"The Brixton Road does not lie between any circus and Houndsditch," said
-Sherlock Holmes sharply.
-
-The old woman faced round and looked keenly at him from her little
-red-rimmed eyes. "The gentleman asked me for _my_ address," she said.
-"Sally lives in lodgings at 3, Mayfield Place, Peckham."
-
-"And your name is----?"
-
-"My name is Sawyer--her's is Dennis, which Tom Dennis married her--and
-a smart, clean lad, too, as long as he's at sea, and no steward in the
-company more thought of; but when on shore, what with the women and what
-with liquor shops----"
-
-"Here is your ring, Mrs. Sawyer," I interrupted, in obedience to a sign
-from my companion; "it clearly belongs to your daughter, and I am glad
-to be able to restore it to the rightful owner."
-
-With many mumbled blessings and protestations of gratitude the old crone
-packed it away in her pocket, and shuffled off down the stairs. Sherlock
-Holmes sprang to his feet the moment that she was gone and rushed into
-his room. He returned in a few seconds enveloped in an ulster and
-a cravat. "I'll follow her," he said, hurriedly; "she must be an
-accomplice, and will lead me to him. Wait up for me." The hall door had
-hardly slammed behind our visitor before Holmes had descended the stair.
-Looking through the window I could see her walking feebly along the
-other side, while her pursuer dogged her some little distance behind.
-"Either his whole theory is incorrect," I thought to myself, "or else he
-will be led now to the heart of the mystery." There was no need for him
-to ask me to wait up for him, for I felt that sleep was impossible until
-I heard the result of his adventure.
-
-It was close upon nine when he set out. I had no idea how long he might
-be, but I sat stolidly puffing at my pipe and skipping over the pages
-of Henri Murger's "Vie de Bohème." Ten o'clock passed, and I heard the
-footsteps of the maid as they pattered off to bed. Eleven, and the
-more stately tread of the landlady passed my door, bound for the same
-destination. It was close upon twelve before I heard the sharp sound of
-his latch-key. The instant he entered I saw by his face that he had not
-been successful. Amusement and chagrin seemed to be struggling for the
-mastery, until the former suddenly carried the day, and he burst into a
-hearty laugh.
-
-"I wouldn't have the Scotland Yarders know it for the world," he cried,
-dropping into his chair; "I have chaffed them so much that they would
-never have let me hear the end of it. I can afford to laugh, because I
-know that I will be even with them in the long run."
-
-"What is it then?" I asked.
-
-"Oh, I don't mind telling a story against myself. That creature had
-gone a little way when she began to limp and show every sign of being
-foot-sore. Presently she came to a halt, and hailed a four-wheeler which
-was passing. I managed to be close to her so as to hear the address, but
-I need not have been so anxious, for she sang it out loud enough to
-be heard at the other side of the street, 'Drive to 13, Duncan Street,
-Houndsditch,' she cried. This begins to look genuine, I thought, and
-having seen her safely inside, I perched myself behind. That's an art
-which every detective should be an expert at. Well, away we rattled, and
-never drew rein until we reached the street in question. I hopped off
-before we came to the door, and strolled down the street in an easy,
-lounging way. I saw the cab pull up. The driver jumped down, and I saw
-him open the door and stand expectantly. Nothing came out though. When
-I reached him he was groping about frantically in the empty cab, and
-giving vent to the finest assorted collection of oaths that ever I
-listened to. There was no sign or trace of his passenger, and I fear it
-will be some time before he gets his fare. On inquiring at Number 13
-we found that the house belonged to a respectable paperhanger, named
-Keswick, and that no one of the name either of Sawyer or Dennis had ever
-been heard of there."
-
-"You don't mean to say," I cried, in amazement, "that that tottering,
-feeble old woman was able to get out of the cab while it was in motion,
-without either you or the driver seeing her?"
-
-"Old woman be damned!" said Sherlock Holmes, sharply. "We were the old
-women to be so taken in. It must have been a young man, and an
-active one, too, besides being an incomparable actor. The get-up was
-inimitable. He saw that he was followed, no doubt, and used this means
-of giving me the slip. It shows that the man we are after is not as
-lonely as I imagined he was, but has friends who are ready to risk
-something for him. Now, Doctor, you are looking done-up. Take my advice
-and turn in."
-
-I was certainly feeling very weary, so I obeyed his injunction. I
-left Holmes seated in front of the smouldering fire, and long into the
-watches of the night I heard the low, melancholy wailings of his violin,
-and knew that he was still pondering over the strange problem which he
-had set himself to unravel.
-
-
-
-
-CHAPTER VI. TOBIAS GREGSON SHOWS WHAT HE CAN DO.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-THE papers next day were full of the "Brixton Mystery," as they termed
-it. Each had a long account of the affair, and some had leaders upon it
-in addition. There was some information in them which was new to me. I
-still retain in my scrap-book numerous clippings and extracts bearing
-upon the case. Here is a condensation of a few of them:--
-
-The *Daily Telegraph* remarked that in the history of crime there had
-seldom been a tragedy which presented stranger features. The German
-name of the victim, the absence of all other motive, and the sinister
-inscription on the wall, all pointed to its perpetration by political
-refugees and revolutionists. The Socialists had many branches in
-America, and the deceased had, no doubt, infringed their unwritten laws,
-and been tracked down by them. After alluding airily to the Vehmgericht,
-aqua tofana, Carbonari, the Marchioness de Brinvilliers, the Darwinian
-theory, the principles of Malthus, and the Ratcliff Highway murders, the
-article concluded by admonishing the Government and advocating a closer
-watch over foreigners in England.
-
-The _Standard_ commented upon the fact that lawless outrages of the sort
-usually occurred under a Liberal Administration. They arose from the
-unsettling of the minds of the masses, and the consequent weakening
-of all authority. The deceased was an American gentleman who had
-been residing for some weeks in the Metropolis. He had stayed at the
-boarding-house of Madame Charpentier, in Torquay Terrace, Camberwell.
-He was accompanied in his travels by his private secretary, Mr. Joseph
-Stangerson. The two bade adieu to their landlady upon Tuesday, the
-4th inst., and departed to Euston Station with the avowed intention of
-catching the Liverpool express. They were afterwards seen together upon
-the platform. Nothing more is known of them until Mr. Drebber's body
-was, as recorded, discovered in an empty house in the Brixton Road,
-many miles from Euston. How he came there, or how he met his fate, are
-questions which are still involved in mystery. Nothing is known of the
-whereabouts of Stangerson. We are glad to learn that Mr. Lestrade and
-Mr. Gregson, of Scotland Yard, are both engaged upon the case, and it
-is confidently anticipated that these well-known officers will speedily
-throw light upon the matter.
-
-The *Daily News* observed that there was no doubt as to the crime being
-a political one. The despotism and hatred of Liberalism which animated
-the Continental Governments had had the effect of driving to our shores
-a number of men who might have made excellent citizens were they not
-soured by the recollection of all that they had undergone. Among these
-men there was a stringent code of honour, any infringement of which was
-punished by death. Every effort should be made to find the secretary,
-Stangerson, and to ascertain some particulars of the habits of the
-deceased. A great step had been gained by the discovery of the address
-of the house at which he had boarded--a result which was entirely due to
-the acuteness and energy of Mr. Gregson of Scotland Yard.
-
-Sherlock Holmes and I read these notices over together at breakfast, and
-they appeared to afford him considerable amusement.
-
-"I told you that, whatever happened, Lestrade and Gregson would be sure
-to score."
-
-"That depends on how it turns out."
-
-"Oh, bless you, it doesn't matter in the least. If the man is caught, it
-will be *on account* of their exertions; if he escapes, it will be *in
-spite* of their exertions. It's heads I win and tails you lose. Whatever
-they do, they will have followers. 'Un sot trouve toujours un plus sot
-qui l'admire.'"
-
-"What on earth is this?" I cried, for at this moment there came the
-pattering of many steps in the hall and on the stairs, accompanied by
-audible expressions of disgust upon the part of our landlady.
-
-"It's the Baker Street division of the detective police force," said my
-companion, gravely; and as he spoke there rushed into the room half a
-dozen of the dirtiest and most ragged street Arabs that ever I clapped
-eyes on.
-
-"'Tention!" cried Holmes, in a sharp tone, and the six dirty little
-scoundrels stood in a line like so many disreputable statuettes. "In
-future you shall send up Wiggins alone to report, and the rest of you
-must wait in the street. Have you found it, Wiggins?"
-
-"No, sir, we hain't," said one of the youths.
-
-"I hardly expected you would. You must keep on until you do. Here are
-your wages." [13]_ He handed each of them a shilling.
-
-"Now, off you go, and come back with a better report next time."
-
-He waved his hand, and they scampered away downstairs like so many rats,
-and we heard their shrill voices next moment in the street.
-
-"There's more work to be got out of one of those little beggars than
-out of a dozen of the force," Holmes remarked. "The mere sight of an
-official-looking person seals men's lips. These youngsters, however, go
-everywhere and hear everything. They are as sharp as needles, too; all
-they want is organisation."
-
-"Is it on this Brixton case that you are employing them?" I asked.
-
-"Yes; there is a point which I wish to ascertain. It is merely a matter
-of time. Hullo! we are going to hear some news now with a vengeance!
-Here is Gregson coming down the road with beatitude written upon every
-feature of his face. Bound for us, I know. Yes, he is stopping. There he
-is!"
-
-There was a violent peal at the bell, and in a few seconds the
-fair-haired detective came up the stairs, three steps at a time, and
-burst into our sitting-room.
-
-"My dear fellow," he cried, wringing Holmes' unresponsive hand,
-"congratulate me! I have made the whole thing as clear as day."
-
-A shade of anxiety seemed to me to cross my companion's expressive face.
-
-"Do you mean that you are on the right track?" he asked.
-
-"The right track! Why, sir, we have the man under lock and key."
-
-"And his name is?"
-
-"Arthur Charpentier, sub-lieutenant in Her Majesty's navy," cried
-Gregson, pompously, rubbing his fat hands and inflating his chest.
-
-Sherlock Holmes gave a sigh of relief, and relaxed into a smile.
-
-"Take a seat, and try one of these cigars," he said. "We are anxious to
-know how you managed it. Will you have some whiskey and water?"
-
-"I don't mind if I do," the detective answered. "The tremendous
-exertions which I have gone through during the last day or two have worn
-me out. Not so much bodily exertion, you understand, as the strain upon
-the mind. You will appreciate that, Mr. Sherlock Holmes, for we are both
-brain-workers."
-
-"You do me too much honour," said Holmes, gravely. "Let us hear how you
-arrived at this most gratifying result."
-
-The detective seated himself in the arm-chair, and puffed complacently
-at his cigar. Then suddenly he slapped his thigh in a paroxysm of
-amusement.
-
-"The fun of it is," he cried, "that that fool Lestrade, who thinks
-himself so smart, has gone off upon the wrong track altogether. He is
-after the secretary Stangerson, who had no more to do with the crime
-than the babe unborn. I have no doubt that he has caught him by this
-time."
-
-The idea tickled Gregson so much that he laughed until he choked.
-
-"And how did you get your clue?"
-
-"Ah, I'll tell you all about it. Of course, Doctor Watson, this is
-strictly between ourselves. The first difficulty which we had to contend
-with was the finding of this American's antecedents. Some people would
-have waited until their advertisements were answered, or until parties
-came forward and volunteered information. That is not Tobias Gregson's
-way of going to work. You remember the hat beside the dead man?"
-
-"Yes," said Holmes; "by John Underwood and Sons, 129, Camberwell Road."
-
-Gregson looked quite crest-fallen.
-
-"I had no idea that you noticed that," he said. "Have you been there?"
-
-"No."
-
-"Ha!" cried Gregson, in a relieved voice; "you should never neglect a
-chance, however small it may seem."
-
-"To a great mind, nothing is little," remarked Holmes, sententiously.
-
-"Well, I went to Underwood, and asked him if he had sold a hat of that
-size and description. He looked over his books, and came on it at once.
-He had sent the hat to a Mr. Drebber, residing at Charpentier's Boarding
-Establishment, Torquay Terrace. Thus I got at his address."
-
-"Smart--very smart!" murmured Sherlock Holmes.
-
-"I next called upon Madame Charpentier," continued the detective.
-"I found her very pale and distressed. Her daughter was in the room,
-too--an uncommonly fine girl she is, too; she was looking red about
-the eyes and her lips trembled as I spoke to her. That didn't escape
-my notice. I began to smell a rat. You know the feeling, Mr. Sherlock
-Holmes, when you come upon the right scent--a kind of thrill in your
-nerves. 'Have you heard of the mysterious death of your late boarder Mr.
-Enoch J. Drebber, of Cleveland?' I asked.
-
-"The mother nodded. She didn't seem able to get out a word. The daughter
-burst into tears. I felt more than ever that these people knew something
-of the matter.
-
-"'At what o'clock did Mr. Drebber leave your house for the train?' I
-asked.
-
-"'At eight o'clock,' she said, gulping in her throat to keep down her
-agitation. 'His secretary, Mr. Stangerson, said that there were two
-trains--one at 9.15 and one at 11. He was to catch the first. [14]_
-
-"'And was that the last which you saw of him?'
-
-"A terrible change came over the woman's face as I asked the question.
-Her features turned perfectly livid. It was some seconds before she
-could get out the single word 'Yes'--and when it did come it was in a
-husky unnatural tone.
-
-"There was silence for a moment, and then the daughter spoke in a calm
-clear voice.
-
-"'No good can ever come of falsehood, mother,' she said. 'Let us be
-frank with this gentleman. We _did_ see Mr. Drebber again.'
-
-"'God forgive you!' cried Madame Charpentier, throwing up her hands and
-sinking back in her chair. 'You have murdered your brother.'
-
-"'Arthur would rather that we spoke the truth,' the girl answered
-firmly.
-
-"'You had best tell me all about it now,' I said. 'Half-confidences are
-worse than none. Besides, you do not know how much we know of it.'
-
-"'On your head be it, Alice!' cried her mother; and then, turning to me,
-'I will tell you all, sir. Do not imagine that my agitation on behalf
-of my son arises from any fear lest he should have had a hand in this
-terrible affair. He is utterly innocent of it. My dread is, however,
-that in your eyes and in the eyes of others he may appear to be
-compromised. That however is surely impossible. His high character, his
-profession, his antecedents would all forbid it.'
-
-"'Your best way is to make a clean breast of the facts,' I answered.
-'Depend upon it, if your son is innocent he will be none the worse.'
-
-"'Perhaps, Alice, you had better leave us together,' she said, and her
-daughter withdrew. 'Now, sir,' she continued, 'I had no intention of
-telling you all this, but since my poor daughter has disclosed it I
-have no alternative. Having once decided to speak, I will tell you all
-without omitting any particular.'
-
-"'It is your wisest course,' said I.
-
-"'Mr. Drebber has been with us nearly three weeks. He and his secretary,
-Mr. Stangerson, had been travelling on the Continent. I noticed a
-"Copenhagen" label upon each of their trunks, showing that that had been
-their last stopping place. Stangerson was a quiet reserved man, but his
-employer, I am sorry to say, was far otherwise. He was coarse in his
-habits and brutish in his ways. The very night of his arrival he became
-very much the worse for drink, and, indeed, after twelve o'clock in the
-day he could hardly ever be said to be sober. His manners towards the
-maid-servants were disgustingly free and familiar. Worst of all, he
-speedily assumed the same attitude towards my daughter, Alice, and spoke
-to her more than once in a way which, fortunately, she is too innocent
-to understand. On one occasion he actually seized her in his arms and
-embraced her--an outrage which caused his own secretary to reproach him
-for his unmanly conduct.'
-
-"'But why did you stand all this,' I asked. 'I suppose that you can get
-rid of your boarders when you wish.'
-
-"Mrs. Charpentier blushed at my pertinent question. 'Would to God that
-I had given him notice on the very day that he came,' she said. 'But
-it was a sore temptation. They were paying a pound a day each--fourteen
-pounds a week, and this is the slack season. I am a widow, and my boy in
-the Navy has cost me much. I grudged to lose the money. I acted for the
-best. This last was too much, however, and I gave him notice to leave on
-account of it. That was the reason of his going.'
-
-"'Well?'
-
-"'My heart grew light when I saw him drive away. My son is on leave
-just now, but I did not tell him anything of all this, for his temper
-is violent, and he is passionately fond of his sister. When I closed the
-door behind them a load seemed to be lifted from my mind. Alas, in
-less than an hour there was a ring at the bell, and I learned that Mr.
-Drebber had returned. He was much excited, and evidently the worse for
-drink. He forced his way into the room, where I was sitting with my
-daughter, and made some incoherent remark about having missed his train.
-He then turned to Alice, and before my very face, proposed to her that
-she should fly with him. "You are of age," he said, "and there is no law
-to stop you. I have money enough and to spare. Never mind the old girl
-here, but come along with me now straight away. You shall live like a
-princess." Poor Alice was so frightened that she shrunk away from him,
-but he caught her by the wrist and endeavoured to draw her towards the
-door. I screamed, and at that moment my son Arthur came into the room.
-What happened then I do not know. I heard oaths and the confused sounds
-of a scuffle. I was too terrified to raise my head. When I did look up
-I saw Arthur standing in the doorway laughing, with a stick in his hand.
-"I don't think that fine fellow will trouble us again," he said. "I will
-just go after him and see what he does with himself." With those words
-he took his hat and started off down the street. The next morning we
-heard of Mr. Drebber's mysterious death.'
-
-"This statement came from Mrs. Charpentier's lips with many gasps and
-pauses. At times she spoke so low that I could hardly catch the words. I
-made shorthand notes of all that she said, however, so that there should
-be no possibility of a mistake."
-
-"It's quite exciting," said Sherlock Holmes, with a yawn. "What happened
-next?"
-
-"When Mrs. Charpentier paused," the detective continued, "I saw that the
-whole case hung upon one point. Fixing her with my eye in a way which
-I always found effective with women, I asked her at what hour her son
-returned.
-
-"'I do not know,' she answered.
-
-"'Not know?'
-
-"'No; he has a latch-key, and he let himself in.'
-
-"'After you went to bed?'
-
-"'Yes.'
-
-"'When did you go to bed?'
-
-"'About eleven.'
-
-"'So your son was gone at least two hours?'
-
-"'Yes.'
-
-"'Possibly four or five?'
-
-"'Yes.'
-
-"'What was he doing during that time?'
-
-"'I do not know,' she answered, turning white to her very lips.
-
-"Of course after that there was nothing more to be done. I found
-out where Lieutenant Charpentier was, took two officers with me, and
-arrested him. When I touched him on the shoulder and warned him to come
-quietly with us, he answered us as bold as brass, 'I suppose you
-are arresting me for being concerned in the death of that scoundrel
-Drebber,' he said. We had said nothing to him about it, so that his
-alluding to it had a most suspicious aspect."
-
-"Very," said Holmes.
-
-"He still carried the heavy stick which the mother described him as
-having with him when he followed Drebber. It was a stout oak cudgel."
-
-"What is your theory, then?"
-
-"Well, my theory is that he followed Drebber as far as the Brixton Road.
-When there, a fresh altercation arose between them, in the course of
-which Drebber received a blow from the stick, in the pit of the stomach,
-perhaps, which killed him without leaving any mark. The night was so
-wet that no one was about, so Charpentier dragged the body of his victim
-into the empty house. As to the candle, and the blood, and the writing
-on the wall, and the ring, they may all be so many tricks to throw the
-police on to the wrong scent."
-
-"Well done!" said Holmes in an encouraging voice. "Really, Gregson, you
-are getting along. We shall make something of you yet."
-
-"I flatter myself that I have managed it rather neatly," the detective
-answered proudly. "The young man volunteered a statement, in which he
-said that after following Drebber some time, the latter perceived him,
-and took a cab in order to get away from him. On his way home he met an
-old shipmate, and took a long walk with him. On being asked where this
-old shipmate lived, he was unable to give any satisfactory reply. I
-think the whole case fits together uncommonly well. What amuses me is to
-think of Lestrade, who had started off upon the wrong scent. I am afraid
-he won't make much of [15]_ Why, by Jove, here's the very man himself!"
-
-It was indeed Lestrade, who had ascended the stairs while we were
-talking, and who now entered the room. The assurance and jauntiness
-which generally marked his demeanour and dress were, however, wanting.
-His face was disturbed and troubled, while his clothes were disarranged
-and untidy. He had evidently come with the intention of consulting
-with Sherlock Holmes, for on perceiving his colleague he appeared to be
-embarrassed and put out. He stood in the centre of the room, fumbling
-nervously with his hat and uncertain what to do. "This is a most
-extraordinary case," he said at last--"a most incomprehensible affair."
-
-"Ah, you find it so, Mr. Lestrade!" cried Gregson, triumphantly. "I
-thought you would come to that conclusion. Have you managed to find the
-Secretary, Mr. Joseph Stangerson?"
-
-"The Secretary, Mr. Joseph Stangerson," said Lestrade gravely, "was
-murdered at Halliday's Private Hotel about six o'clock this morning."
-
-
-
-
-CHAPTER VII. LIGHT IN THE DARKNESS.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-THE intelligence with which Lestrade greeted us was so momentous and so
-unexpected, that we were all three fairly dumfoundered. Gregson sprang
-out of his chair and upset the remainder of his whiskey and water. I
-stared in silence at Sherlock Holmes, whose lips were compressed and his
-brows drawn down over his eyes.
-
-"Stangerson too!" he muttered. "The plot thickens."
-
-"It was quite thick enough before," grumbled Lestrade, taking a chair.
-"I seem to have dropped into a sort of council of war."
-
-"Are you--are you sure of this piece of intelligence?" stammered
-Gregson.
-
-"I have just come from his room," said Lestrade. "I was the first to
-discover what had occurred."
-
-"We have been hearing Gregson's view of the matter," Holmes observed.
-"Would you mind letting us know what you have seen and done?"
-
-"I have no objection," Lestrade answered, seating himself. "I freely
-confess that I was of the opinion that Stangerson was concerned in
-the death of Drebber. This fresh development has shown me that I was
-completely mistaken. Full of the one idea, I set myself to find out
-what had become of the Secretary. They had been seen together at Euston
-Station about half-past eight on the evening of the third. At two in the
-morning Drebber had been found in the Brixton Road. The question which
-confronted me was to find out how Stangerson had been employed between
-8.30 and the time of the crime, and what had become of him afterwards.
-I telegraphed to Liverpool, giving a description of the man, and warning
-them to keep a watch upon the American boats. I then set to work calling
-upon all the hotels and lodging-houses in the vicinity of Euston. You
-see, I argued that if Drebber and his companion had become separated,
-the natural course for the latter would be to put up somewhere in the
-vicinity for the night, and then to hang about the station again next
-morning."
-
-"They would be likely to agree on some meeting-place beforehand,"
-remarked Holmes.
-
-"So it proved. I spent the whole of yesterday evening in making
-enquiries entirely without avail. This morning I began very early, and
-at eight o'clock I reached Halliday's Private Hotel, in Little George
-Street. On my enquiry as to whether a Mr. Stangerson was living there,
-they at once answered me in the affirmative.
-
-"'No doubt you are the gentleman whom he was expecting,' they said. 'He
-has been waiting for a gentleman for two days.'
-
-"'Where is he now?' I asked.
-
-"'He is upstairs in bed. He wished to be called at nine.'
-
-"'I will go up and see him at once,' I said.
-
-"It seemed to me that my sudden appearance might shake his nerves and
-lead him to say something unguarded. The Boots volunteered to show me
-the room: it was on the second floor, and there was a small corridor
-leading up to it. The Boots pointed out the door to me, and was about to
-go downstairs again when I saw something that made me feel sickish, in
-spite of my twenty years' experience. From under the door there curled
-a little red ribbon of blood, which had meandered across the passage and
-formed a little pool along the skirting at the other side. I gave a cry,
-which brought the Boots back. He nearly fainted when he saw it. The door
-was locked on the inside, but we put our shoulders to it, and knocked it
-in. The window of the room was open, and beside the window, all huddled
-up, lay the body of a man in his nightdress. He was quite dead, and had
-been for some time, for his limbs were rigid and cold. When we turned
-him over, the Boots recognized him at once as being the same gentleman
-who had engaged the room under the name of Joseph Stangerson. The cause
-of death was a deep stab in the left side, which must have penetrated
-the heart. And now comes the strangest part of the affair. What do you
-suppose was above the murdered man?"
-
-I felt a creeping of the flesh, and a presentiment of coming horror,
-even before Sherlock Holmes answered.
-
-"The word RACHE, written in letters of blood," he said.
-
-"That was it," said Lestrade, in an awe-struck voice; and we were all
-silent for a while.
-
-There was something so methodical and so incomprehensible about the
-deeds of this unknown assassin, that it imparted a fresh ghastliness to
-his crimes. My nerves, which were steady enough on the field of battle
-tingled as I thought of it.
-
-"The man was seen," continued Lestrade. "A milk boy, passing on his way
-to the dairy, happened to walk down the lane which leads from the mews
-at the back of the hotel. He noticed that a ladder, which usually lay
-there, was raised against one of the windows of the second floor, which
-was wide open. After passing, he looked back and saw a man descend the
-ladder. He came down so quietly and openly that the boy imagined him to
-be some carpenter or joiner at work in the hotel. He took no particular
-notice of him, beyond thinking in his own mind that it was early for him
-to be at work. He has an impression that the man was tall, had a reddish
-face, and was dressed in a long, brownish coat. He must have stayed in
-the room some little time after the murder, for we found blood-stained
-water in the basin, where he had washed his hands, and marks on the
-sheets where he had deliberately wiped his knife."
-
-I glanced at Holmes on hearing the description of the murderer, which
-tallied so exactly with his own. There was, however, no trace of
-exultation or satisfaction upon his face.
-
-"Did you find nothing in the room which could furnish a clue to the
-murderer?" he asked.
-
-"Nothing. Stangerson had Drebber's purse in his pocket, but it seems
-that this was usual, as he did all the paying. There was eighty odd
-pounds in it, but nothing had been taken. Whatever the motives of these
-extraordinary crimes, robbery is certainly not one of them. There were
-no papers or memoranda in the murdered man's pocket, except a single
-telegram, dated from Cleveland about a month ago, and containing
-the words, 'J. H. is in Europe.' There was no name appended to this
-message."
-
-"And there was nothing else?" Holmes asked.
-
-"Nothing of any importance. The man's novel, with which he had read
-himself to sleep was lying upon the bed, and his pipe was on a chair
-beside him. There was a glass of water on the table, and on the
-window-sill a small chip ointment box containing a couple of pills."
-
-Sherlock Holmes sprang from his chair with an exclamation of delight.
-
-"The last link," he cried, exultantly. "My case is complete."
-
-The two detectives stared at him in amazement.
-
-"I have now in my hands," my companion said, confidently, "all the
-threads which have formed such a tangle. There are, of course, details
-to be filled in, but I am as certain of all the main facts, from the
-time that Drebber parted from Stangerson at the station, up to the
-discovery of the body of the latter, as if I had seen them with my own
-eyes. I will give you a proof of my knowledge. Could you lay your hand
-upon those pills?"
-
-"I have them," said Lestrade, producing a small white box; "I took them
-and the purse and the telegram, intending to have them put in a place of
-safety at the Police Station. It was the merest chance my taking these
-pills, for I am bound to say that I do not attach any importance to
-them."
-
-"Give them here," said Holmes. "Now, Doctor," turning to me, "are those
-ordinary pills?"
-
-They certainly were not. They were of a pearly grey colour, small,
-round, and almost transparent against the light. "From their lightness
-and transparency, I should imagine that they are soluble in water," I
-remarked.
-
-"Precisely so," answered Holmes. "Now would you mind going down and
-fetching that poor little devil of a terrier which has been bad so long,
-and which the landlady wanted you to put out of its pain yesterday."
-
-I went downstairs and carried the dog upstair in my arms. It's laboured
-breathing and glazing eye showed that it was not far from its end.
-Indeed, its snow-white muzzle proclaimed that it had already exceeded
-the usual term of canine existence. I placed it upon a cushion on the
-rug.
-
-"I will now cut one of these pills in two," said Holmes, and drawing his
-penknife he suited the action to the word. "One half we return into the
-box for future purposes. The other half I will place in this wine glass,
-in which is a teaspoonful of water. You perceive that our friend, the
-Doctor, is right, and that it readily dissolves."
-
-"This may be very interesting," said Lestrade, in the injured tone of
-one who suspects that he is being laughed at, "I cannot see, however,
-what it has to do with the death of Mr. Joseph Stangerson."
-
-"Patience, my friend, patience! You will find in time that it has
-everything to do with it. I shall now add a little milk to make the
-mixture palatable, and on presenting it to the dog we find that he laps
-it up readily enough."
-
-As he spoke he turned the contents of the wine glass into a saucer and
-placed it in front of the terrier, who speedily licked it dry. Sherlock
-Holmes' earnest demeanour had so far convinced us that we all sat in
-silence, watching the animal intently, and expecting some startling
-effect. None such appeared, however. The dog continued to lie stretched
-upon tho [16]_ cushion, breathing in a laboured way, but apparently
-neither the better nor the worse for its draught.
-
-Holmes had taken out his watch, and as minute followed minute without
-result, an expression of the utmost chagrin and disappointment appeared
-upon his features. He gnawed his lip, drummed his fingers upon the
-table, and showed every other symptom of acute impatience. So great
-was his emotion, that I felt sincerely sorry for him, while the two
-detectives smiled derisively, by no means displeased at this check which
-he had met.
-
-"It can't be a coincidence," he cried, at last springing from his chair
-and pacing wildly up and down the room; "it is impossible that it should
-be a mere coincidence. The very pills which I suspected in the case of
-Drebber are actually found after the death of Stangerson. And yet they
-are inert. What can it mean? Surely my whole chain of reasoning cannot
-have been false. It is impossible! And yet this wretched dog is none the
-worse. Ah, I have it! I have it!" With a perfect shriek of delight he
-rushed to the box, cut the other pill in two, dissolved it, added milk,
-and presented it to the terrier. The unfortunate creature's tongue
-seemed hardly to have been moistened in it before it gave a convulsive
-shiver in every limb, and lay as rigid and lifeless as if it had been
-struck by lightning.
-
-Sherlock Holmes drew a long breath, and wiped the perspiration from his
-forehead. "I should have more faith," he said; "I ought to know by
-this time that when a fact appears to be opposed to a long train of
-deductions, it invariably proves to be capable of bearing some other
-interpretation. Of the two pills in that box one was of the most deadly
-poison, and the other was entirely harmless. I ought to have known that
-before ever I saw the box at all."
-
-This last statement appeared to me to be so startling, that I could
-hardly believe that he was in his sober senses. There was the dead dog,
-however, to prove that his conjecture had been correct. It seemed to me
-that the mists in my own mind were gradually clearing away, and I began
-to have a dim, vague perception of the truth.
-
-"All this seems strange to you," continued Holmes, "because you failed
-at the beginning of the inquiry to grasp the importance of the single
-real clue which was presented to you. I had the good fortune to seize
-upon that, and everything which has occurred since then has served to
-confirm my original supposition, and, indeed, was the logical sequence
-of it. Hence things which have perplexed you and made the case more
-obscure, have served to enlighten me and to strengthen my conclusions.
-It is a mistake to confound strangeness with mystery. The most
-commonplace crime is often the most mysterious because it presents no
-new or special features from which deductions may be drawn. This murder
-would have been infinitely more difficult to unravel had the body of
-the victim been simply found lying in the roadway without any of
-those _outré_ and sensational accompaniments which have rendered
-it remarkable. These strange details, far from making the case more
-difficult, have really had the effect of making it less so."
-
-Mr. Gregson, who had listened to this address with considerable
-impatience, could contain himself no longer. "Look here, Mr. Sherlock
-Holmes," he said, "we are all ready to acknowledge that you are a smart
-man, and that you have your own methods of working. We want something
-more than mere theory and preaching now, though. It is a case of taking
-the man. I have made my case out, and it seems I was wrong. Young
-Charpentier could not have been engaged in this second affair. Lestrade
-went after his man, Stangerson, and it appears that he was wrong too.
-You have thrown out hints here, and hints there, and seem to know more
-than we do, but the time has come when we feel that we have a right to
-ask you straight how much you do know of the business. Can you name the
-man who did it?"
-
-"I cannot help feeling that Gregson is right, sir," remarked Lestrade.
-"We have both tried, and we have both failed. You have remarked more
-than once since I have been in the room that you had all the evidence
-which you require. Surely you will not withhold it any longer."
-
-"Any delay in arresting the assassin," I observed, "might give him time
-to perpetrate some fresh atrocity."
-
-Thus pressed by us all, Holmes showed signs of irresolution. He
-continued to walk up and down the room with his head sunk on his chest
-and his brows drawn down, as was his habit when lost in thought.
-
-"There will be no more murders," he said at last, stopping abruptly and
-facing us. "You can put that consideration out of the question. You have
-asked me if I know the name of the assassin. I do. The mere knowing of
-his name is a small thing, however, compared with the power of laying
-our hands upon him. This I expect very shortly to do. I have good hopes
-of managing it through my own arrangements; but it is a thing which
-needs delicate handling, for we have a shrewd and desperate man to deal
-with, who is supported, as I have had occasion to prove, by another who
-is as clever as himself. As long as this man has no idea that anyone
-can have a clue there is some chance of securing him; but if he had the
-slightest suspicion, he would change his name, and vanish in an instant
-among the four million inhabitants of this great city. Without meaning
-to hurt either of your feelings, I am bound to say that I consider these
-men to be more than a match for the official force, and that is why I
-have not asked your assistance. If I fail I shall, of course, incur all
-the blame due to this omission; but that I am prepared for. At present
-I am ready to promise that the instant that I can communicate with you
-without endangering my own combinations, I shall do so."
-
-Gregson and Lestrade seemed to be far from satisfied by this assurance,
-or by the depreciating allusion to the detective police. The former had
-flushed up to the roots of his flaxen hair, while the other's beady eyes
-glistened with curiosity and resentment. Neither of them had time to
-speak, however, before there was a tap at the door, and the spokesman
-of the street Arabs, young Wiggins, introduced his insignificant and
-unsavoury person.
-
-"Please, sir," he said, touching his forelock, "I have the cab
-downstairs."
-
-"Good boy," said Holmes, blandly. "Why don't you introduce this pattern
-at Scotland Yard?" he continued, taking a pair of steel handcuffs from
-a drawer. "See how beautifully the spring works. They fasten in an
-instant."
-
-"The old pattern is good enough," remarked Lestrade, "if we can only
-find the man to put them on."
-
-"Very good, very good," said Holmes, smiling. "The cabman may as well
-help me with my boxes. Just ask him to step up, Wiggins."
-
-I was surprised to find my companion speaking as though he were about
-to set out on a journey, since he had not said anything to me about it.
-There was a small portmanteau in the room, and this he pulled out and
-began to strap. He was busily engaged at it when the cabman entered the
-room.
-
-"Just give me a help with this buckle, cabman," he said, kneeling over
-his task, and never turning his head.
-
-The fellow came forward with a somewhat sullen, defiant air, and put
-down his hands to assist. At that instant there was a sharp click, the
-jangling of metal, and Sherlock Holmes sprang to his feet again.
-
-"Gentlemen," he cried, with flashing eyes, "let me introduce you to Mr.
-Jefferson Hope, the murderer of Enoch Drebber and of Joseph Stangerson."
-
-The whole thing occurred in a moment--so quickly that I had no time
-to realize it. I have a vivid recollection of that instant, of Holmes'
-triumphant expression and the ring of his voice, of the cabman's
-dazed, savage face, as he glared at the glittering handcuffs, which had
-appeared as if by magic upon his wrists. For a second or two we might
-have been a group of statues. Then, with an inarticulate roar of fury,
-the prisoner wrenched himself free from Holmes's grasp, and hurled
-himself through the window. Woodwork and glass gave way before him; but
-before he got quite through, Gregson, Lestrade, and Holmes sprang upon
-him like so many staghounds. He was dragged back into the room, and then
-commenced a terrific conflict. So powerful and so fierce was he, that
-the four of us were shaken off again and again. He appeared to have the
-convulsive strength of a man in an epileptic fit. His face and hands
-were terribly mangled by his passage through the glass, but loss of
-blood had no effect in diminishing his resistance. It was not until
-Lestrade succeeded in getting his hand inside his neckcloth and
-half-strangling him that we made him realize that his struggles were of
-no avail; and even then we felt no security until we had pinioned his
-feet as well as his hands. That done, we rose to our feet breathless and
-panting.
-
-"We have his cab," said Sherlock Holmes. "It will serve to take him to
-Scotland Yard. And now, gentlemen," he continued, with a pleasant smile,
-"we have reached the end of our little mystery. You are very welcome to
-put any questions that you like to me now, and there is no danger that I
-will refuse to answer them."
-
-
-
-
-
-PART II. *The Country of the Saints.*
--------------------------------------
-
-
-
-CHAPTER I. ON THE GREAT ALKALI PLAIN.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-IN the central portion of the great North American Continent there lies
-an arid and repulsive desert, which for many a long year served as a
-barrier against the advance of civilisation. From the Sierra Nevada to
-Nebraska, and from the Yellowstone River in the north to the Colorado
-upon the south, is a region of desolation and silence. Nor is Nature
-always in one mood throughout this grim district. It comprises
-snow-capped and lofty mountains, and dark and gloomy valleys. There are
-swift-flowing rivers which dash through jagged cañons; and there are
-enormous plains, which in winter are white with snow, and in summer are
-grey with the saline alkali dust. They all preserve, however, the common
-characteristics of barrenness, inhospitality, and misery.
-
-There are no inhabitants of this land of despair. A band of Pawnees
-or of Blackfeet may occasionally traverse it in order to reach other
-hunting-grounds, but the hardiest of the braves are glad to lose sight
-of those awesome plains, and to find themselves once more upon their
-prairies. The coyote skulks among the scrub, the buzzard flaps heavily
-through the air, and the clumsy grizzly bear lumbers through the dark
-ravines, and picks up such sustenance as it can amongst the rocks. These
-are the sole dwellers in the wilderness.
-
-In the whole world there can be no more dreary view than that from
-the northern slope of the Sierra Blanco. As far as the eye can reach
-stretches the great flat plain-land, all dusted over with patches of
-alkali, and intersected by clumps of the dwarfish chaparral bushes. On
-the extreme verge of the horizon lie a long chain of mountain peaks,
-with their rugged summits flecked with snow. In this great stretch of
-country there is no sign of life, nor of anything appertaining to life.
-There is no bird in the steel-blue heaven, no movement upon the dull,
-grey earth--above all, there is absolute silence. Listen as one may,
-there is no shadow of a sound in all that mighty wilderness; nothing but
-silence--complete and heart-subduing silence.
-
-It has been said there is nothing appertaining to life upon the broad
-plain. That is hardly true. Looking down from the Sierra Blanco, one
-sees a pathway traced out across the desert, which winds away and is
-lost in the extreme distance. It is rutted with wheels and trodden down
-by the feet of many adventurers. Here and there there are scattered
-white objects which glisten in the sun, and stand out against the dull
-deposit of alkali. Approach, and examine them! They are bones: some
-large and coarse, others smaller and more delicate. The former have
-belonged to oxen, and the latter to men. For fifteen hundred miles one
-may trace this ghastly caravan route by these scattered remains of those
-who had fallen by the wayside.
-
-Looking down on this very scene, there stood upon the fourth of May,
-eighteen hundred and forty-seven, a solitary traveller. His appearance
-was such that he might have been the very genius or demon of the region.
-An observer would have found it difficult to say whether he was nearer
-to forty or to sixty. His face was lean and haggard, and the brown
-parchment-like skin was drawn tightly over the projecting bones; his
-long, brown hair and beard were all flecked and dashed with white; his
-eyes were sunken in his head, and burned with an unnatural lustre; while
-the hand which grasped his rifle was hardly more fleshy than that of a
-skeleton. As he stood, he leaned upon his weapon for support, and yet
-his tall figure and the massive framework of his bones suggested a wiry
-and vigorous constitution. His gaunt face, however, and his clothes,
-which hung so baggily over his shrivelled limbs, proclaimed what it
-was that gave him that senile and decrepit appearance. The man was
-dying--dying from hunger and from thirst.
-
-He had toiled painfully down the ravine, and on to this little
-elevation, in the vain hope of seeing some signs of water. Now the great
-salt plain stretched before his eyes, and the distant belt of savage
-mountains, without a sign anywhere of plant or tree, which might
-indicate the presence of moisture. In all that broad landscape there
-was no gleam of hope. North, and east, and west he looked with wild
-questioning eyes, and then he realised that his wanderings had come to
-an end, and that there, on that barren crag, he was about to die. "Why
-not here, as well as in a feather bed, twenty years hence," he muttered,
-as he seated himself in the shelter of a boulder.
-
-Before sitting down, he had deposited upon the ground his useless rifle,
-and also a large bundle tied up in a grey shawl, which he had carried
-slung over his right shoulder. It appeared to be somewhat too heavy for
-his strength, for in lowering it, it came down on the ground with some
-little violence. Instantly there broke from the grey parcel a little
-moaning cry, and from it there protruded a small, scared face, with very
-bright brown eyes, and two little speckled, dimpled fists.
-
-"You've hurt me!" said a childish voice reproachfully.
-
-"Have I though," the man answered penitently, "I didn't go for to do
-it." As he spoke he unwrapped the grey shawl and extricated a pretty
-little girl of about five years of age, whose dainty shoes and smart
-pink frock with its little linen apron all bespoke a mother's care. The
-child was pale and wan, but her healthy arms and legs showed that she
-had suffered less than her companion.
-
-"How is it now?" he answered anxiously, for she was still rubbing the
-towsy golden curls which covered the back of her head.
-
-"Kiss it and make it well," she said, with perfect gravity, shoving
-[19]_ the injured part up to him. "That's what mother used to do. Where's
-mother?"
-
-"Mother's gone. I guess you'll see her before long."
-
-"Gone, eh!" said the little girl. "Funny, she didn't say good-bye; she
-'most always did if she was just goin' over to Auntie's for tea, and now
-she's been away three days. Say, it's awful dry, ain't it? Ain't there
-no water, nor nothing to eat?"
-
-"No, there ain't nothing, dearie. You'll just need to be patient awhile,
-and then you'll be all right. Put your head up agin me like that, and
-then you'll feel bullier. It ain't easy to talk when your lips is like
-leather, but I guess I'd best let you know how the cards lie. What's
-that you've got?"
-
-"Pretty things! fine things!" cried the little girl enthusiastically,
-holding up two glittering fragments of mica. "When we goes back to home
-I'll give them to brother Bob."
-
-"You'll see prettier things than them soon," said the man confidently.
-"You just wait a bit. I was going to tell you though--you remember when
-we left the river?"
-
-"Oh, yes."
-
-"Well, we reckoned we'd strike another river soon, d'ye see. But there
-was somethin' wrong; compasses, or map, or somethin', and it didn't
-turn up. Water ran out. Just except a little drop for the likes of you
-and--and----"
-
-"And you couldn't wash yourself," interrupted his companion gravely,
-staring up at his grimy visage.
-
-"No, nor drink. And Mr. Bender, he was the fust to go, and then Indian
-Pete, and then Mrs. McGregor, and then Johnny Hones, and then, dearie,
-your mother."
-
-"Then mother's a deader too," cried the little girl dropping her face in
-her pinafore and sobbing bitterly.
-
-"Yes, they all went except you and me. Then I thought there was some
-chance of water in this direction, so I heaved you over my shoulder and
-we tramped it together. It don't seem as though we've improved matters.
-There's an almighty small chance for us now!"
-
-"Do you mean that we are going to die too?" asked the child, checking
-her sobs, and raising her tear-stained face.
-
-"I guess that's about the size of it."
-
-"Why didn't you say so before?" she said, laughing gleefully. "You gave
-me such a fright. Why, of course, now as long as we die we'll be with
-mother again."
-
-"Yes, you will, dearie."
-
-"And you too. I'll tell her how awful good you've been. I'll bet she
-meets us at the door of Heaven with a big pitcher of water, and a lot
-of buckwheat cakes, hot, and toasted on both sides, like Bob and me was
-fond of. How long will it be first?"
-
-"I don't know--not very long." The man's eyes were fixed upon the
-northern horizon. In the blue vault of the heaven there had appeared
-three little specks which increased in size every moment, so rapidly did
-they approach. They speedily resolved themselves into three large brown
-birds, which circled over the heads of the two wanderers, and then
-settled upon some rocks which overlooked them. They were buzzards, the
-vultures of the west, whose coming is the forerunner of death.
-
-"Cocks and hens," cried the little girl gleefully, pointing at their
-ill-omened forms, and clapping her hands to make them rise. "Say, did
-God make this country?"
-
-"In course He did," said her companion, rather startled by this
-unexpected question.
-
-"He made the country down in Illinois, and He made the Missouri," the
-little girl continued. "I guess somebody else made the country in these
-parts. It's not nearly so well done. They forgot the water and the
-trees."
-
-"What would ye think of offering up prayer?" the man asked diffidently.
-
-"It ain't night yet," she answered.
-
-"It don't matter. It ain't quite regular, but He won't mind that, you
-bet. You say over them ones that you used to say every night in the
-waggon when we was on the Plains."
-
-"Why don't you say some yourself?" the child asked, with wondering eyes.
-
-"I disremember them," he answered. "I hain't said none since I was half
-the height o' that gun. I guess it's never too late. You say them out,
-and I'll stand by and come in on the choruses."
-
-"Then you'll need to kneel down, and me too," she said, laying the shawl
-out for that purpose. "You've got to put your hands up like this. It
-makes you feel kind o' good."
-
-It was a strange sight had there been anything but the buzzards to see
-it. Side by side on the narrow shawl knelt the two wanderers, the little
-prattling child and the reckless, hardened adventurer. Her chubby face,
-and his haggard, angular visage were both turned up to the cloudless
-heaven in heartfelt entreaty to that dread being with whom they were
-face to face, while the two voices--the one thin and clear, the other
-deep and harsh--united in the entreaty for mercy and forgiveness. The
-prayer finished, they resumed their seat in the shadow of the boulder
-until the child fell asleep, nestling upon the broad breast of her
-protector. He watched over her slumber for some time, but Nature proved
-to be too strong for him. For three days and three nights he had allowed
-himself neither rest nor repose. Slowly the eyelids drooped over the
-tired eyes, and the head sunk lower and lower upon the breast, until the
-man's grizzled beard was mixed with the gold tresses of his companion,
-and both slept the same deep and dreamless slumber.
-
-Had the wanderer remained awake for another half hour a strange sight
-would have met his eyes. Far away on the extreme verge of the alkali
-plain there rose up a little spray of dust, very slight at first, and
-hardly to be distinguished from the mists of the distance, but gradually
-growing higher and broader until it formed a solid, well-defined cloud.
-This cloud continued to increase in size until it became evident that it
-could only be raised by a great multitude of moving creatures. In more
-fertile spots the observer would have come to the conclusion that one
-of those great herds of bisons which graze upon the prairie land was
-approaching him. This was obviously impossible in these arid wilds. As
-the whirl of dust drew nearer to the solitary bluff upon which the two
-castaways were reposing, the canvas-covered tilts of waggons and the
-figures of armed horsemen began to show up through the haze, and the
-apparition revealed itself as being a great caravan upon its journey for
-the West. But what a caravan! When the head of it had reached the base
-of the mountains, the rear was not yet visible on the horizon. Right
-across the enormous plain stretched the straggling array, waggons
-and carts, men on horseback, and men on foot. Innumerable women who
-staggered along under burdens, and children who toddled beside the
-waggons or peeped out from under the white coverings. This was evidently
-no ordinary party of immigrants, but rather some nomad people who had
-been compelled from stress of circumstances to seek themselves a new
-country. There rose through the clear air a confused clattering and
-rumbling from this great mass of humanity, with the creaking of wheels
-and the neighing of horses. Loud as it was, it was not sufficient to
-rouse the two tired wayfarers above them.
-
-At the head of the column there rode a score or more of grave ironfaced
-men, clad in sombre homespun garments and armed with rifles. On reaching
-the base of the bluff they halted, and held a short council among
-themselves.
-
-"The wells are to the right, my brothers," said one, a hard-lipped,
-clean-shaven man with grizzly hair.
-
-"To the right of the Sierra Blanco--so we shall reach the Rio Grande,"
-said another.
-
-"Fear not for water," cried a third. "He who could draw it from the
-rocks will not now abandon His own chosen people."
-
-"Amen! Amen!" responded the whole party.
-
-They were about to resume their journey when one of the youngest and
-keenest-eyed uttered an exclamation and pointed up at the rugged crag
-above them. From its summit there fluttered a little wisp of pink,
-showing up hard and bright against the grey rocks behind. At the sight
-there was a general reining up of horses and unslinging of guns, while
-fresh horsemen came galloping up to reinforce the vanguard. The word
-'Redskins' was on every lip.
-
-"There can't be any number of Injuns here," said the elderly man who
-appeared to be in command. "We have passed the Pawnees, and there are no
-other tribes until we cross the great mountains."
-
-"Shall I go forward and see, Brother Stangerson," asked one of the band.
-
-"And I," "and I," cried a dozen voices.
-
-"Leave your horses below and we will await you here," the Elder
-answered. In a moment the young fellows had dismounted, fastened their
-horses, and were ascending the precipitous slope which led up to the
-object which had excited their curiosity. They advanced rapidly and
-noiselessly, with the confidence and dexterity of practised scouts.
-The watchers from the plain below could see them flit from rock to rock
-until their figures stood out against the skyline. The young man who had
-first given the alarm was leading them. Suddenly his followers saw him
-throw up his hands, as though overcome with astonishment, and on joining
-him they were affected in the same way by the sight which met their
-eyes.
-
-On the little plateau which crowned the barren hill there stood a
-single giant boulder, and against this boulder there lay a tall man,
-long-bearded and hard-featured, but of an excessive thinness. His placid
-face and regular breathing showed that he was fast asleep. Beside him
-lay a little child, with her round white arms encircling his brown
-sinewy neck, and her golden haired head resting upon the breast of his
-velveteen tunic. Her rosy lips were parted, showing the regular line of
-snow-white teeth within, and a playful smile played over her infantile
-features. Her plump little white legs terminating in white socks and
-neat shoes with shining buckles, offered a strange contrast to the long
-shrivelled members of her companion. On the ledge of rock above this
-strange couple there stood three solemn buzzards, who, at the sight of
-the new comers uttered raucous screams of disappointment and flapped
-sullenly away.
-
-The cries of the foul birds awoke the two sleepers who stared about [20]_
-them in bewilderment. The man staggered to his feet and looked down upon
-the plain which had been so desolate when sleep had overtaken him, and
-which was now traversed by this enormous body of men and of beasts. His
-face assumed an expression of incredulity as he gazed, and he passed his
-boney hand over his eyes. "This is what they call delirium, I guess,"
-he muttered. The child stood beside him, holding on to the skirt of
-his coat, and said nothing but looked all round her with the wondering
-questioning gaze of childhood.
-
-The rescuing party were speedily able to convince the two castaways that
-their appearance was no delusion. One of them seized the little girl,
-and hoisted her upon his shoulder, while two others supported her gaunt
-companion, and assisted him towards the waggons.
-
-"My name is John Ferrier," the wanderer explained; "me and that little
-un are all that's left o' twenty-one people. The rest is all dead o'
-thirst and hunger away down in the south."
-
-"Is she your child?" asked someone.
-
-"I guess she is now," the other cried, defiantly; "she's mine 'cause I
-saved her. No man will take her from me. She's Lucy Ferrier from this
-day on. Who are you, though?" he continued, glancing with curiosity at
-his stalwart, sunburned rescuers; "there seems to be a powerful lot of
-ye."
-
-"Nigh upon ten thousand," said one of the young men; "we are the
-persecuted children of God--the chosen of the Angel Merona."
-
-"I never heard tell on him," said the wanderer. "He appears to have
-chosen a fair crowd of ye."
-
-"Do not jest at that which is sacred," said the other sternly. "We are
-of those who believe in those sacred writings, drawn in Egyptian letters
-on plates of beaten gold, which were handed unto the holy Joseph Smith
-at Palmyra. We have come from Nauvoo, in the State of Illinois, where we
-had founded our temple. We have come to seek a refuge from the violent
-man and from the godless, even though it be the heart of the desert."
-
-The name of Nauvoo evidently recalled recollections to John Ferrier. "I
-see," he said, "you are the Mormons."
-
-"We are the Mormons," answered his companions with one voice.
-
-"And where are you going?"
-
-"We do not know. The hand of God is leading us under the person of our
-Prophet. You must come before him. He shall say what is to be done with
-you."
-
-They had reached the base of the hill by this time, and were surrounded
-by crowds of the pilgrims--pale-faced meek-looking women, strong
-laughing children, and anxious earnest-eyed men. Many were the cries
-of astonishment and of commiseration which arose from them when they
-perceived the youth of one of the strangers and the destitution of the
-other. Their escort did not halt, however, but pushed on, followed by
-a great crowd of Mormons, until they reached a waggon, which was
-conspicuous for its great size and for the gaudiness and smartness of
-its appearance. Six horses were yoked to it, whereas the others were
-furnished with two, or, at most, four a-piece. Beside the driver there
-sat a man who could not have been more than thirty years of age, but
-whose massive head and resolute expression marked him as a leader. He
-was reading a brown-backed volume, but as the crowd approached he laid
-it aside, and listened attentively to an account of the episode. Then he
-turned to the two castaways.
-
-"If we take you with us," he said, in solemn words, "it can only be as
-believers in our own creed. We shall have no wolves in our fold. Better
-far that your bones should bleach in this wilderness than that you
-should prove to be that little speck of decay which in time corrupts the
-whole fruit. Will you come with us on these terms?"
-
-"Guess I'll come with you on any terms," said Ferrier, with such
-emphasis that the grave Elders could not restrain a smile. The leader
-alone retained his stern, impressive expression.
-
-"Take him, Brother Stangerson," he said, "give him food and drink,
-and the child likewise. Let it be your task also to teach him our holy
-creed. We have delayed long enough. Forward! On, on to Zion!"
-
-"On, on to Zion!" cried the crowd of Mormons, and the words rippled down
-the long caravan, passing from mouth to mouth until they died away in a
-dull murmur in the far distance. With a cracking of whips and a creaking
-of wheels the great waggons got into motion, and soon the whole caravan
-was winding along once more. The Elder to whose care the two waifs
-had been committed, led them to his waggon, where a meal was already
-awaiting them.
-
-"You shall remain here," he said. "In a few days you will have recovered
-from your fatigues. In the meantime, remember that now and for ever you
-are of our religion. Brigham Young has said it, and he has spoken with
-the voice of Joseph Smith, which is the voice of God."
-
-
-
-
-CHAPTER II. THE FLOWER OF UTAH.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-THIS is not the place to commemorate the trials and privations endured
-by the immigrant Mormons before they came to their final haven. From the
-shores of the Mississippi to the western slopes of the Rocky Mountains
-they had struggled on with a constancy almost unparalleled in history.
-The savage man, and the savage beast, hunger, thirst, fatigue, and
-disease--every impediment which Nature could place in the way, had all
-been overcome with Anglo-Saxon tenacity. Yet the long journey and the
-accumulated terrors had shaken the hearts of the stoutest among them.
-There was not one who did not sink upon his knees in heartfelt prayer
-when they saw the broad valley of Utah bathed in the sunlight beneath
-them, and learned from the lips of their leader that this was the
-promised land, and that these virgin acres were to be theirs for
-evermore.
-
-Young speedily proved himself to be a skilful administrator as well as a
-resolute chief. Maps were drawn and charts prepared, in which the future
-city was sketched out. All around farms were apportioned and allotted in
-proportion to the standing of each individual. The tradesman was put
-to his trade and the artisan to his calling. In the town streets and
-squares sprang up, as if by magic. In the country there was draining
-and hedging, planting and clearing, until the next summer saw the whole
-country golden with the wheat crop. Everything prospered in the strange
-settlement. Above all, the great temple which they had erected in the
-centre of the city grew ever taller and larger. From the first blush of
-dawn until the closing of the twilight, the clatter of the hammer
-and the rasp of the saw was never absent from the monument which the
-immigrants erected to Him who had led them safe through many dangers.
-
-The two castaways, John Ferrier and the little girl who had shared his
-fortunes and had been adopted as his daughter, accompanied the Mormons
-to the end of their great pilgrimage. Little Lucy Ferrier was borne
-along pleasantly enough in Elder Stangerson's waggon, a retreat which
-she shared with the Mormon's three wives and with his son, a headstrong
-forward boy of twelve. Having rallied, with the elasticity of childhood,
-from the shock caused by her mother's death, she soon became a pet
-with the women, and reconciled herself to this new life in her moving
-canvas-covered home. In the meantime Ferrier having recovered from his
-privations, distinguished himself as a useful guide and an indefatigable
-hunter. So rapidly did he gain the esteem of his new companions, that
-when they reached the end of their wanderings, it was unanimously agreed
-that he should be provided with as large and as fertile a tract of land
-as any of the settlers, with the exception of Young himself, and of
-Stangerson, Kemball, Johnston, and Drebber, who were the four principal
-Elders.
-
-On the farm thus acquired John Ferrier built himself a substantial
-log-house, which received so many additions in succeeding years that it
-grew into a roomy villa. He was a man of a practical turn of mind,
-keen in his dealings and skilful with his hands. His iron constitution
-enabled him to work morning and evening at improving and tilling his
-lands. Hence it came about that his farm and all that belonged to
-him prospered exceedingly. In three years he was better off than his
-neighbours, in six he was well-to-do, in nine he was rich, and in twelve
-there were not half a dozen men in the whole of Salt Lake City who could
-compare with him. From the great inland sea to the distant Wahsatch
-Mountains there was no name better known than that of John Ferrier.
-
-There was one way and only one in which he offended the susceptibilities
-of his co-religionists. No argument or persuasion could ever induce him
-to set up a female establishment after the manner of his companions. He
-never gave reasons for this persistent refusal, but contented himself by
-resolutely and inflexibly adhering to his determination. There were some
-who accused him of lukewarmness in his adopted religion, and others who
-put it down to greed of wealth and reluctance to incur expense. Others,
-again, spoke of some early love affair, and of a fair-haired girl who
-had pined away on the shores of the Atlantic. Whatever the reason,
-Ferrier remained strictly celibate. In every other respect he conformed
-to the religion of the young settlement, and gained the name of being an
-orthodox and straight-walking man.
-
-Lucy Ferrier grew up within the log-house, and assisted her adopted
-father in all his undertakings. The keen air of the mountains and the
-balsamic odour of the pine trees took the place of nurse and mother to
-the young girl. As year succeeded to year she grew taller and stronger,
-her cheek more rudy, and her step more elastic. Many a wayfarer upon
-the high road which ran by Ferrier's farm felt long-forgotten thoughts
-revive in their mind as they watched her lithe girlish figure tripping
-through the wheatfields, or met her mounted upon her father's mustang,
-and managing it with all the ease and grace of a true child of the West.
-So the bud blossomed into a flower, and the year which saw her father
-the richest of the farmers left her as fair a specimen of American
-girlhood as could be found in the whole Pacific slope.
-
-It was not the father, however, who first discovered that the child had
-developed into the woman. It seldom is in such cases. That mysterious
-change is too subtle and too gradual to be measured by dates. Least of
-all does the maiden herself know it until the tone of a voice or the
-touch of a hand sets her heart thrilling within her, and she learns,
-with a mixture of pride and of fear, that a new and a larger nature has
-awoken within her. There are few who cannot recall that day and remember
-the one little incident which heralded the dawn of a new life. In the
-case of Lucy Ferrier the occasion was serious enough in itself, apart
-from its future influence on her destiny and that of many besides.
-
-It was a warm June morning, and the Latter Day Saints were as busy as
-the bees whose hive they have chosen for their emblem. In the fields and
-in the streets rose the same hum of human industry. Down the dusty high
-roads defiled long streams of heavily-laden mules, all heading to the
-west, for the gold fever had broken out in California, and the Overland
-Route lay through the City of the Elect. There, too, were droves of
-sheep and bullocks coming in from the outlying pasture lands, and trains
-of tired immigrants, men and horses equally weary of their interminable
-journey. Through all this motley assemblage, threading her way with the
-skill of an accomplished rider, there galloped Lucy Ferrier, her fair
-face flushed with the exercise and her long chestnut hair floating out
-behind her. She had a commission from her father in the City, and was
-dashing in as she had done many a time before, with all the fearlessness
-of youth, thinking only of her task and how it was to be performed. The
-travel-stained adventurers gazed after her in astonishment, and even
-the unemotional Indians, journeying in with their pelties, relaxed their
-accustomed stoicism as they marvelled at the beauty of the pale-faced
-maiden.
-
-She had reached the outskirts of the city when she found the road
-blocked by a great drove of cattle, driven by a half-dozen wild-looking
-herdsmen from the plains. In her impatience she endeavoured to pass this
-obstacle by pushing her horse into what appeared to be a gap. Scarcely
-had she got fairly into it, however, before the beasts closed in behind
-her, and she found herself completely imbedded in the moving stream of
-fierce-eyed, long-horned bullocks. Accustomed as she was to deal with
-cattle, she was not alarmed at her situation, but took advantage of
-every opportunity to urge her horse on in the hopes of pushing her way
-through the cavalcade. Unfortunately the horns of one of the creatures,
-either by accident or design, came in violent contact with the flank of
-the mustang, and excited it to madness. In an instant it reared up upon
-its hind legs with a snort of rage, and pranced and tossed in a way that
-would have unseated any but a most skilful rider. The situation was full
-of peril. Every plunge of the excited horse brought it against the horns
-again, and goaded it to fresh madness. It was all that the girl could
-do to keep herself in the saddle, yet a slip would mean a terrible death
-under the hoofs of the unwieldy and terrified animals. Unaccustomed to
-sudden emergencies, her head began to swim, and her grip upon the bridle
-to relax. Choked by the rising cloud of dust and by the steam from the
-struggling creatures, she might have abandoned her efforts in despair,
-but for a kindly voice at her elbow which assured her of assistance. At
-the same moment a sinewy brown hand caught the frightened horse by
-the curb, and forcing a way through the drove, soon brought her to the
-outskirts.
-
-"You're not hurt, I hope, miss," said her preserver, respectfully.
-
-She looked up at his dark, fierce face, and laughed saucily. "I'm awful
-frightened," she said, naively; "whoever would have thought that Poncho
-would have been so scared by a lot of cows?"
-
-"Thank God you kept your seat," the other said earnestly. He was a tall,
-savage-looking young fellow, mounted on a powerful roan horse, and
-clad in the rough dress of a hunter, with a long rifle slung over his
-shoulders. "I guess you are the daughter of John Ferrier," he remarked,
-"I saw you ride down from his house. When you see him, ask him if he
-remembers the Jefferson Hopes of St. Louis. If he's the same Ferrier, my
-father and he were pretty thick."
-
-"Hadn't you better come and ask yourself?" she asked, demurely.
-
-The young fellow seemed pleased at the suggestion, and his dark eyes
-sparkled with pleasure. "I'll do so," he said, "we've been in the
-mountains for two months, and are not over and above in visiting
-condition. He must take us as he finds us."
-
-"He has a good deal to thank you for, and so have I," she answered,
-"he's awful fond of me. If those cows had jumped on me he'd have never
-got over it."
-
-"Neither would I," said her companion.
-
-"You! Well, I don't see that it would make much matter to you, anyhow.
-You ain't even a friend of ours."
-
-The young hunter's dark face grew so gloomy over this remark that Lucy
-Ferrier laughed aloud.
-
-"There, I didn't mean that," she said; "of course, you are a friend now.
-You must come and see us. Now I must push along, or father won't trust
-me with his business any more. Good-bye!"
-
-"Good-bye," he answered, raising his broad sombrero, and bending over
-her little hand. She wheeled her mustang round, gave it a cut with her
-riding-whip, and darted away down the broad road in a rolling cloud of
-dust.
-
-Young Jefferson Hope rode on with his companions, gloomy and taciturn.
-He and they had been among the Nevada Mountains prospecting for silver,
-and were returning to Salt Lake City in the hope of raising capital
-enough to work some lodes which they had discovered. He had been as keen
-as any of them upon the business until this sudden incident had drawn
-his thoughts into another channel. The sight of the fair young girl,
-as frank and wholesome as the Sierra breezes, had stirred his volcanic,
-untamed heart to its very depths. When she had vanished from his sight,
-he realized that a crisis had come in his life, and that neither silver
-speculations nor any other questions could ever be of such importance to
-him as this new and all-absorbing one. The love which had sprung up in
-his heart was not the sudden, changeable fancy of a boy, but rather the
-wild, fierce passion of a man of strong will and imperious temper. He
-had been accustomed to succeed in all that he undertook. He swore in
-his heart that he would not fail in this if human effort and human
-perseverance could render him successful.
-
-He called on John Ferrier that night, and many times again, until
-his face was a familiar one at the farm-house. John, cooped up in the
-valley, and absorbed in his work, had had little chance of learning
-the news of the outside world during the last twelve years. All this
-Jefferson Hope was able to tell him, and in a style which interested
-Lucy as well as her father. He had been a pioneer in California, and
-could narrate many a strange tale of fortunes made and fortunes lost
-in those wild, halcyon days. He had been a scout too, and a trapper, a
-silver explorer, and a ranchman. Wherever stirring adventures were to be
-had, Jefferson Hope had been there in search of them. He soon became a
-favourite with the old farmer, who spoke eloquently of his virtues. On
-such occasions, Lucy was silent, but her blushing cheek and her bright,
-happy eyes, showed only too clearly that her young heart was no longer
-her own. Her honest father may not have observed these symptoms,
-but they were assuredly not thrown away upon the man who had won her
-affections.
-
-It was a summer evening when he came galloping down the road and pulled
-up at the gate. She was at the doorway, and came down to meet him. He
-threw the bridle over the fence and strode up the pathway.
-
-"I am off, Lucy," he said, taking her two hands in his, and gazing
-tenderly down into her face; "I won't ask you to come with me now, but
-will you be ready to come when I am here again?"
-
-"And when will that be?" she asked, blushing and laughing.
-
-"A couple of months at the outside. I will come and claim you then, my
-darling. There's no one who can stand between us."
-
-"And how about father?" she asked.
-
-"He has given his consent, provided we get these mines working all
-right. I have no fear on that head."
-
-"Oh, well; of course, if you and father have arranged it all, there's
-no more to be said," she whispered, with her cheek against his broad
-breast.
-
-"Thank God!" he said, hoarsely, stooping and kissing her. "It is
-settled, then. The longer I stay, the harder it will be to go. They are
-waiting for me at the cañon. Good-bye, my own darling--good-bye. In two
-months you shall see me."
-
-He tore himself from her as he spoke, and, flinging himself upon his
-horse, galloped furiously away, never even looking round, as though
-afraid that his resolution might fail him if he took one glance at
-what he was leaving. She stood at the gate, gazing after him until
-he vanished from her sight. Then she walked back into the house, the
-happiest girl in all Utah.
-
-
-
-
-CHAPTER III. JOHN FERRIER TALKS WITH THE PROPHET.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-THREE weeks had passed since Jefferson Hope and his comrades had
-departed from Salt Lake City. John Ferrier's heart was sore within him
-when he thought of the young man's return, and of the impending loss of
-his adopted child. Yet her bright and happy face reconciled him to
-the arrangement more than any argument could have done. He had always
-determined, deep down in his resolute heart, that nothing would ever
-induce him to allow his daughter to wed a Mormon. Such a marriage he
-regarded as no marriage at all, but as a shame and a disgrace. Whatever
-he might think of the Mormon doctrines, upon that one point he was
-inflexible. He had to seal his mouth on the subject, however, for to
-express an unorthodox opinion was a dangerous matter in those days in
-the Land of the Saints.
-
-Yes, a dangerous matter--so dangerous that even the most saintly dared
-only whisper their religious opinions with bated breath, lest something
-which fell from their lips might be misconstrued, and bring down a
-swift retribution upon them. The victims of persecution had now turned
-persecutors on their own account, and persecutors of the most
-terrible description. Not the Inquisition of Seville, nor the German
-Vehm-gericht, nor the Secret Societies of Italy, were ever able to put
-a more formidable machinery in motion than that which cast a cloud over
-the State of Utah.
-
-Its invisibility, and the mystery which was attached to it, made
-this organization doubly terrible. It appeared to be omniscient and
-omnipotent, and yet was neither seen nor heard. The man who held out
-against the Church vanished away, and none knew whither he had gone or
-what had befallen him. His wife and his children awaited him at home,
-but no father ever returned to tell them how he had fared at the
-hands of his secret judges. A rash word or a hasty act was followed
-by annihilation, and yet none knew what the nature might be of this
-terrible power which was suspended over them. No wonder that men
-went about in fear and trembling, and that even in the heart of the
-wilderness they dared not whisper the doubts which oppressed them.
-
-At first this vague and terrible power was exercised only upon the
-recalcitrants who, having embraced the Mormon faith, wished afterwards
-to pervert or to abandon it. Soon, however, it took a wider range. The
-supply of adult women was running short, and polygamy without a female
-population on which to draw was a barren doctrine indeed. Strange
-rumours began to be bandied about--rumours of murdered immigrants and
-rifled camps in regions where Indians had never been seen. Fresh women
-appeared in the harems of the Elders--women who pined and wept, and
-bore upon their faces the traces of an unextinguishable horror. Belated
-wanderers upon the mountains spoke of gangs of armed men, masked,
-stealthy, and noiseless, who flitted by them in the darkness. These
-tales and rumours took substance and shape, and were corroborated and
-re-corroborated, until they resolved themselves into a definite name.
-To this day, in the lonely ranches of the West, the name of the Danite
-Band, or the Avenging Angels, is a sinister and an ill-omened one.
-
-Fuller knowledge of the organization which produced such terrible
-results served to increase rather than to lessen the horror which it
-inspired in the minds of men. None knew who belonged to this ruthless
-society. The names of the participators in the deeds of blood and
-violence done under the name of religion were kept profoundly secret.
-The very friend to whom you communicated your misgivings as to the
-Prophet and his mission, might be one of those who would come forth at
-night with fire and sword to exact a terrible reparation. Hence every
-man feared his neighbour, and none spoke of the things which were
-nearest his heart.
-
-One fine morning, John Ferrier was about to set out to his wheatfields,
-when he heard the click of the latch, and, looking through the window,
-saw a stout, sandy-haired, middle-aged man coming up the pathway. His
-heart leapt to his mouth, for this was none other than the great Brigham
-Young himself. Full of trepidation--for he knew that such a visit boded
-him little good--Ferrier ran to the door to greet the Mormon chief. The
-latter, however, received his salutations coldly, and followed him with
-a stern face into the sitting-room.
-
-"Brother Ferrier," he said, taking a seat, and eyeing the farmer keenly
-from under his light-coloured eyelashes, "the true believers have been
-good friends to you. We picked you up when you were starving in the
-desert, we shared our food with you, led you safe to the Chosen Valley,
-gave you a goodly share of land, and allowed you to wax rich under our
-protection. Is not this so?"
-
-"It is so," answered John Ferrier.
-
-"In return for all this we asked but one condition: that was, that you
-should embrace the true faith, and conform in every way to its usages.
-This you promised to do, and this, if common report says truly, you have
-neglected."
-
-"And how have I neglected it?" asked Ferrier, throwing out his hands in
-expostulation. "Have I not given to the common fund? Have I not attended
-at the Temple? Have I not----?"
-
-"Where are your wives?" asked Young, looking round him. "Call them in,
-that I may greet them."
-
-"It is true that I have not married," Ferrier answered. "But women
-were few, and there were many who had better claims than I. I was not a
-lonely man: I had my daughter to attend to my wants."
-
-"It is of that daughter that I would speak to you," said the leader
-of the Mormons. "She has grown to be the flower of Utah, and has found
-favour in the eyes of many who are high in the land."
-
-John Ferrier groaned internally.
-
-"There are stories of her which I would fain disbelieve--stories that
-she is sealed to some Gentile. This must be the gossip of idle tongues.
-What is the thirteenth rule in the code of the sainted Joseph Smith?
-'Let every maiden of the true faith marry one of the elect; for if
-she wed a Gentile, she commits a grievous sin.' This being so, it is
-impossible that you, who profess the holy creed, should suffer your
-daughter to violate it."
-
-John Ferrier made no answer, but he played nervously with his
-riding-whip.
-
-"Upon this one point your whole faith shall be tested--so it has been
-decided in the Sacred Council of Four. The girl is young, and we would
-not have her wed grey hairs, neither would we deprive her of all
-choice. We Elders have many heifers, [29]_ but our children must also
-be provided. Stangerson has a son, and Drebber has a son, and either of
-them would gladly welcome your daughter to their house. Let her choose
-between them. They are young and rich, and of the true faith. What say
-you to that?"
-
-Ferrier remained silent for some little time with his brows knitted.
-
-"You will give us time," he said at last. "My daughter is very
-young--she is scarce of an age to marry."
-
-"She shall have a month to choose," said Young, rising from his seat.
-"At the end of that time she shall give her answer."
-
-He was passing through the door, when he turned, with flushed face and
-flashing eyes. "It were better for you, John Ferrier," he thundered,
-"that you and she were now lying blanched skeletons upon the Sierra
-Blanco, than that you should put your weak wills against the orders of
-the Holy Four!"
-
-With a threatening gesture of his hand, he turned from the door, and
-Ferrier heard his heavy step scrunching along the shingly path.
-
-He was still sitting with his elbows upon his knees, considering how he
-should broach the matter to his daughter when a soft hand was laid upon
-his, and looking up, he saw her standing beside him. One glance at her
-pale, frightened face showed him that she had heard what had passed.
-
-"I could not help it," she said, in answer to his look. "His voice rang
-through the house. Oh, father, father, what shall we do?"
-
-"Don't you scare yourself," he answered, drawing her to him, and passing
-his broad, rough hand caressingly over her chestnut hair. "We'll fix it
-up somehow or another. You don't find your fancy kind o' lessening for
-this chap, do you?"
-
-A sob and a squeeze of his hand was her only answer.
-
-"No; of course not. I shouldn't care to hear you say you did. He's a
-likely lad, and he's a Christian, which is more than these folk here, in
-spite o' all their praying and preaching. There's a party starting for
-Nevada to-morrow, and I'll manage to send him a message letting him know
-the hole we are in. If I know anything o' that young man, he'll be back
-here with a speed that would whip electro-telegraphs."
-
-Lucy laughed through her tears at her father's description.
-
-"When he comes, he will advise us for the best. But it is for you that
-I am frightened, dear. One hears--one hears such dreadful stories about
-those who oppose the Prophet: something terrible always happens to
-them."
-
-"But we haven't opposed him yet," her father answered. "It will be time
-to look out for squalls when we do. We have a clear month before us; at
-the end of that, I guess we had best shin out of Utah."
-
-"Leave Utah!"
-
-"That's about the size of it."
-
-"But the farm?"
-
-"We will raise as much as we can in money, and let the rest go. To tell
-the truth, Lucy, it isn't the first time I have thought of doing it. I
-don't care about knuckling under to any man, as these folk do to their
-darned prophet. I'm a free-born American, and it's all new to me. Guess
-I'm too old to learn. If he comes browsing about this farm, he might
-chance to run up against a charge of buckshot travelling in the opposite
-direction."
-
-"But they won't let us leave," his daughter objected.
-
-"Wait till Jefferson comes, and we'll soon manage that. In the meantime,
-don't you fret yourself, my dearie, and don't get your eyes swelled up,
-else he'll be walking into me when he sees you. There's nothing to be
-afeared about, and there's no danger at all."
-
-John Ferrier uttered these consoling remarks in a very confident tone,
-but she could not help observing that he paid unusual care to the
-fastening of the doors that night, and that he carefully cleaned and
-loaded the rusty old shotgun which hung upon the wall of his bedroom.
-
-
-
-
-CHAPTER IV. A FLIGHT FOR LIFE.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-ON the morning which followed his interview with the Mormon Prophet,
-John Ferrier went in to Salt Lake City, and having found his
-acquaintance, who was bound for the Nevada Mountains, he entrusted him
-with his message to Jefferson Hope. In it he told the young man of the
-imminent danger which threatened them, and how necessary it was that he
-should return. Having done thus he felt easier in his mind, and returned
-home with a lighter heart.
-
-As he approached his farm, he was surprised to see a horse hitched to
-each of the posts of the gate. Still more surprised was he on entering
-to find two young men in possession of his sitting-room. One, with a
-long pale face, was leaning back in the rocking-chair, with his feet
-cocked up upon the stove. The other, a bull-necked youth with coarse
-bloated features, was standing in front of the window with his hands in
-his pocket, whistling a popular hymn. Both of them nodded to Ferrier as
-he entered, and the one in the rocking-chair commenced the conversation.
-
-"Maybe you don't know us," he said. "This here is the son of Elder
-Drebber, and I'm Joseph Stangerson, who travelled with you in the desert
-when the Lord stretched out His hand and gathered you into the true
-fold."
-
-"As He will all the nations in His own good time," said the other in a
-nasal voice; "He grindeth slowly but exceeding small."
-
-John Ferrier bowed coldly. He had guessed who his visitors were.
-
-"We have come," continued Stangerson, "at the advice of our fathers to
-solicit the hand of your daughter for whichever of us may seem good to
-you and to her. As I have but four wives and Brother Drebber here has
-seven, it appears to me that my claim is the stronger one."
-
-"Nay, nay, Brother Stangerson," cried the other; "the question is not
-how many wives we have, but how many we can keep. My father has now
-given over his mills to me, and I am the richer man."
-
-"But my prospects are better," said the other, warmly. "When the
-Lord removes my father, I shall have his tanning yard and his leather
-factory. Then I am your elder, and am higher in the Church."
-
-"It will be for the maiden to decide," rejoined young Drebber, smirking
-at his own reflection in the glass. "We will leave it all to her
-decision."
-
-During this dialogue, John Ferrier had stood fuming in the doorway,
-hardly able to keep his riding-whip from the backs of his two visitors.
-
-"Look here," he said at last, striding up to them, "when my daughter
-summons you, you can come, but until then I don't want to see your faces
-again."
-
-The two young Mormons stared at him in amazement. In their eyes this
-competition between them for the maiden's hand was the highest of
-honours both to her and her father.
-
-"There are two ways out of the room," cried Ferrier; "there is the door,
-and there is the window. Which do you care to use?"
-
-His brown face looked so savage, and his gaunt hands so threatening,
-that his visitors sprang to their feet and beat a hurried retreat. The
-old farmer followed them to the door.
-
-"Let me know when you have settled which it is to be," he said,
-sardonically.
-
-"You shall smart for this!" Stangerson cried, white with rage. "You have
-defied the Prophet and the Council of Four. You shall rue it to the end
-of your days."
-
-"The hand of the Lord shall be heavy upon you," cried young Drebber; "He
-will arise and smite you!"
-
-"Then I'll start the smiting," exclaimed Ferrier furiously, and would
-have rushed upstairs for his gun had not Lucy seized him by the arm and
-restrained him. Before he could escape from her, the clatter of horses'
-hoofs told him that they were beyond his reach.
-
-"The young canting rascals!" he exclaimed, wiping the perspiration from
-his forehead; "I would sooner see you in your grave, my girl, than the
-wife of either of them."
-
-"And so should I, father," she answered, with spirit; "but Jefferson
-will soon be here."
-
-"Yes. It will not be long before he comes. The sooner the better, for we
-do not know what their next move may be."
-
-It was, indeed, high time that someone capable of giving advice and
-help should come to the aid of the sturdy old farmer and his adopted
-daughter. In the whole history of the settlement there had never been
-such a case of rank disobedience to the authority of the Elders. If
-minor errors were punished so sternly, what would be the fate of this
-arch rebel. Ferrier knew that his wealth and position would be of no
-avail to him. Others as well known and as rich as himself had been
-spirited away before now, and their goods given over to the Church. He
-was a brave man, but he trembled at the vague, shadowy terrors which
-hung over him. Any known danger he could face with a firm lip, but
-this suspense was unnerving. He concealed his fears from his daughter,
-however, and affected to make light of the whole matter, though she,
-with the keen eye of love, saw plainly that he was ill at ease.
-
-He expected that he would receive some message or remonstrance from
-Young as to his conduct, and he was not mistaken, though it came in an
-unlooked-for manner. Upon rising next morning he found, to his surprise,
-a small square of paper pinned on to the coverlet of his bed just over
-his chest. On it was printed, in bold straggling letters:--
-
-"Twenty-nine days are given you for amendment, and then----"
-
-The dash was more fear-inspiring than any threat could have been. How
-this warning came into his room puzzled John Ferrier sorely, for his
-servants slept in an outhouse, and the doors and windows had all been
-secured. He crumpled the paper up and said nothing to his daughter, but
-the incident struck a chill into his heart. The twenty-nine days were
-evidently the balance of the month which Young had promised. What
-strength or courage could avail against an enemy armed with such
-mysterious powers? The hand which fastened that pin might have struck
-him to the heart, and he could never have known who had slain him.
-
-Still more shaken was he next morning. They had sat down to their
-breakfast when Lucy with a cry of surprise pointed upwards. In the
-centre of the ceiling was scrawled, with a burned stick apparently,
-the number 28. To his daughter it was unintelligible, and he did not
-enlighten her. That night he sat up with his gun and kept watch and
-ward. He saw and he heard nothing, and yet in the morning a great 27 had
-been painted upon the outside of his door.
-
-Thus day followed day; and as sure as morning came he found that his
-unseen enemies had kept their register, and had marked up in some
-conspicuous position how many days were still left to him out of the
-month of grace. Sometimes the fatal numbers appeared upon the walls,
-sometimes upon the floors, occasionally they were on small placards
-stuck upon the garden gate or the railings. With all his vigilance John
-Ferrier could not discover whence these daily warnings proceeded. A
-horror which was almost superstitious came upon him at the sight of
-them. He became haggard and restless, and his eyes had the troubled look
-of some hunted creature. He had but one hope in life now, and that was
-for the arrival of the young hunter from Nevada.
-
-Twenty had changed to fifteen and fifteen to ten, but there was no news
-of the absentee. One by one the numbers dwindled down, and still there
-came no sign of him. Whenever a horseman clattered down the road, or a
-driver shouted at his team, the old farmer hurried to the gate thinking
-that help had arrived at last. At last, when he saw five give way to
-four and that again to three, he lost heart, and abandoned all hope of
-escape. Single-handed, and with his limited knowledge of the mountains
-which surrounded the settlement, he knew that he was powerless. The
-more-frequented roads were strictly watched and guarded, and none could
-pass along them without an order from the Council. Turn which way he
-would, there appeared to be no avoiding the blow which hung over him.
-Yet the old man never wavered in his resolution to part with life itself
-before he consented to what he regarded as his daughter's dishonour.
-
-He was sitting alone one evening pondering deeply over his troubles, and
-searching vainly for some way out of them. That morning had shown the
-figure 2 upon the wall of his house, and the next day would be the last
-of the allotted time. What was to happen then? All manner of vague and
-terrible fancies filled his imagination. And his daughter--what was to
-become of her after he was gone? Was there no escape from the invisible
-network which was drawn all round them. He sank his head upon the table
-and sobbed at the thought of his own impotence.
-
-What was that? In the silence he heard a gentle scratching sound--low,
-but very distinct in the quiet of the night. It came from the door of
-the house. Ferrier crept into the hall and listened intently. There
-was a pause for a few moments, and then the low insidious sound was
-repeated. Someone was evidently tapping very gently upon one of the
-panels of the door. Was it some midnight assassin who had come to carry
-out the murderous orders of the secret tribunal? Or was it some agent
-who was marking up that the last day of grace had arrived. John Ferrier
-felt that instant death would be better than the suspense which shook
-his nerves and chilled his heart. Springing forward he drew the bolt and
-threw the door open.
-
-Outside all was calm and quiet. The night was fine, and the stars were
-twinkling brightly overhead. The little front garden lay before the
-farmer's eyes bounded by the fence and gate, but neither there nor on
-the road was any human being to be seen. With a sigh of relief, Ferrier
-looked to right and to left, until happening to glance straight down at
-his own feet he saw to his astonishment a man lying flat upon his face
-upon the ground, with arms and legs all asprawl.
-
-So unnerved was he at the sight that he leaned up against the wall with
-his hand to his throat to stifle his inclination to call out. His first
-thought was that the prostrate figure was that of some wounded or dying
-man, but as he watched it he saw it writhe along the ground and into the
-hall with the rapidity and noiselessness of a serpent. Once within the
-house the man sprang to his feet, closed the door, and revealed to the
-astonished farmer the fierce face and resolute expression of Jefferson
-Hope.
-
-"Good God!" gasped John Ferrier. "How you scared me! Whatever made you
-come in like that."
-
-"Give me food," the other said, hoarsely. "I have had no time for bite
-or sup for eight-and-forty hours." He flung himself upon the [21]_ cold
-meat and bread which were still lying upon the table from his host's
-supper, and devoured it voraciously. "Does Lucy bear up well?" he asked,
-when he had satisfied his hunger.
-
-"Yes. She does not know the danger," her father answered.
-
-"That is well. The house is watched on every side. That is why I crawled
-my way up to it. They may be darned sharp, but they're not quite sharp
-enough to catch a Washoe hunter."
-
-John Ferrier felt a different man now that he realized that he had
-a devoted ally. He seized the young man's leathery hand and wrung it
-cordially. "You're a man to be proud of," he said. "There are not many
-who would come to share our danger and our troubles."
-
-"You've hit it there, pard," the young hunter answered. "I have a
-respect for you, but if you were alone in this business I'd think twice
-before I put my head into such a hornet's nest. It's Lucy that brings me
-here, and before harm comes on her I guess there will be one less o' the
-Hope family in Utah."
-
-"What are we to do?"
-
-"To-morrow is your last day, and unless you act to-night you are lost.
-I have a mule and two horses waiting in the Eagle Ravine. How much money
-have you?"
-
-"Two thousand dollars in gold, and five in notes."
-
-"That will do. I have as much more to add to it. We must push for Carson
-City through the mountains. You had best wake Lucy. It is as well that
-the servants do not sleep in the house."
-
-While Ferrier was absent, preparing his daughter for the approaching
-journey, Jefferson Hope packed all the eatables that he could find into
-a small parcel, and filled a stoneware jar with water, for he knew by
-experience that the mountain wells were few and far between. He had
-hardly completed his arrangements before the farmer returned with his
-daughter all dressed and ready for a start. The greeting between the
-lovers was warm, but brief, for minutes were precious, and there was
-much to be done.
-
-"We must make our start at once," said Jefferson Hope, speaking in a low
-but resolute voice, like one who realizes the greatness of the peril,
-but has steeled his heart to meet it. "The front and back entrances are
-watched, but with caution we may get away through the side window and
-across the fields. Once on the road we are only two miles from the
-Ravine where the horses are waiting. By daybreak we should be half-way
-through the mountains."
-
-"What if we are stopped," asked Ferrier.
-
-Hope slapped the revolver butt which protruded from the front of his
-tunic. "If they are too many for us we shall take two or three of them
-with us," he said with a sinister smile.
-
-The lights inside the house had all been extinguished, and from the
-darkened window Ferrier peered over the fields which had been his own,
-and which he was now about to abandon for ever. He had long nerved
-himself to the sacrifice, however, and the thought of the honour and
-happiness of his daughter outweighed any regret at his ruined fortunes.
-All looked so peaceful and happy, the rustling trees and the broad
-silent stretch of grain-land, that it was difficult to realize that
-the spirit of murder lurked through it all. Yet the white face and set
-expression of the young hunter showed that in his approach to the house
-he had seen enough to satisfy him upon that head.
-
-Ferrier carried the bag of gold and notes, Jefferson Hope had the scanty
-provisions and water, while Lucy had a small bundle containing a few
-of her more valued possessions. Opening the window very slowly and
-carefully, they waited until a dark cloud had somewhat obscured the
-night, and then one by one passed through into the little garden. With
-bated breath and crouching figures they stumbled across it, and gained
-the shelter of the hedge, which they skirted until they came to the gap
-which opened into the cornfields. They had just reached this point when
-the young man seized his two companions and dragged them down into the
-shadow, where they lay silent and trembling.
-
-It was as well that his prairie training had given Jefferson Hope the
-ears of a lynx. He and his friends had hardly crouched down before the
-melancholy hooting of a mountain owl was heard within a few yards
-of them, which was immediately answered by another hoot at a small
-distance. At the same moment a vague shadowy figure emerged from the
-gap for which they had been making, and uttered the plaintive signal cry
-again, on which a second man appeared out of the obscurity.
-
-"To-morrow at midnight," said the first who appeared to be in authority.
-"When the Whip-poor-Will calls three times."
-
-"It is well," returned the other. "Shall I tell Brother Drebber?"
-
-"Pass it on to him, and from him to the others. Nine to seven!"
-
-"Seven to five!" repeated the other, and the two figures flitted away
-in different directions. Their concluding words had evidently been some
-form of sign and countersign. The instant that their footsteps had died
-away in the distance, Jefferson Hope sprang to his feet, and helping his
-companions through the gap, led the way across the fields at the top
-of his speed, supporting and half-carrying the girl when her strength
-appeared to fail her.
-
-"Hurry on! hurry on!" he gasped from time to time. "We are through the
-line of sentinels. Everything depends on speed. Hurry on!"
-
-Once on the high road they made rapid progress. Only once did they
-meet anyone, and then they managed to slip into a field, and so avoid
-recognition. Before reaching the town the hunter branched away into a
-rugged and narrow footpath which led to the mountains. Two dark jagged
-peaks loomed above them through the darkness, and the defile which led
-between them was the Eagle Cañon in which the horses were awaiting them.
-With unerring instinct Jefferson Hope picked his way among the great
-boulders and along the bed of a dried-up watercourse, until he came to
-the retired corner, screened with rocks, where the faithful animals had
-been picketed. The girl was placed upon the mule, and old Ferrier upon
-one of the horses, with his money-bag, while Jefferson Hope led the
-other along the precipitous and dangerous path.
-
-It was a bewildering route for anyone who was not accustomed to face
-Nature in her wildest moods. On the one side a great crag towered up a
-thousand feet or more, black, stern, and menacing, with long basaltic
-columns upon its rugged surface like the ribs of some petrified monster.
-On the other hand a wild chaos of boulders and debris made all advance
-impossible. Between the two ran the irregular track, so narrow in places
-that they had to travel in Indian file, and so rough that only practised
-riders could have traversed it at all. Yet in spite of all dangers and
-difficulties, the hearts of the fugitives were light within them,
-for every step increased the distance between them and the terrible
-despotism from which they were flying.
-
-They soon had a proof, however, that they were still within the
-jurisdiction of the Saints. They had reached the very wildest and most
-desolate portion of the pass when the girl gave a startled cry, and
-pointed upwards. On a rock which overlooked the track, showing out dark
-and plain against the sky, there stood a solitary sentinel. He saw them
-as soon as they perceived him, and his military challenge of "Who goes
-there?" rang through the silent ravine.
-
-"Travellers for Nevada," said Jefferson Hope, with his hand upon the
-rifle which hung by his saddle.
-
-They could see the lonely watcher fingering his gun, and peering down at
-them as if dissatisfied at their reply.
-
-"By whose permission?" he asked.
-
-"The Holy Four," answered Ferrier. His Mormon experiences had taught him
-that that was the highest authority to which he could refer.
-
-"Nine from seven," cried the sentinel.
-
-"Seven from five," returned Jefferson Hope promptly, remembering the
-countersign which he had heard in the garden.
-
-"Pass, and the Lord go with you," said the voice from above. Beyond his
-post the path broadened out, and the horses were able to break into a
-trot. Looking back, they could see the solitary watcher leaning upon
-his gun, and knew that they had passed the outlying post of the chosen
-people, and that freedom lay before them.
-
-
-
-
-CHAPTER V. THE AVENGING ANGELS.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-ALL night their course lay through intricate defiles and over irregular
-and rock-strewn paths. More than once they lost their way, but Hope's
-intimate knowledge of the mountains enabled them to regain the track
-once more. When morning broke, a scene of marvellous though savage
-beauty lay before them. In every direction the great snow-capped peaks
-hemmed them in, peeping over each other's shoulders to the far horizon.
-So steep were the rocky banks on either side of them, that the larch
-and the pine seemed to be suspended over their heads, and to need only a
-gust of wind to come hurtling down upon them. Nor was the fear entirely
-an illusion, for the barren valley was thickly strewn with trees and
-boulders which had fallen in a similar manner. Even as they passed,
-a great rock came thundering down with a hoarse rattle which woke
-the echoes in the silent gorges, and startled the weary horses into a
-gallop.
-
-As the sun rose slowly above the eastern horizon, the caps of the great
-mountains lit up one after the other, like lamps at a festival, until
-they were all ruddy and glowing. The magnificent spectacle cheered the
-hearts of the three fugitives and gave them fresh energy. At a wild
-torrent which swept out of a ravine they called a halt and watered their
-horses, while they partook of a hasty breakfast. Lucy and her father
-would fain have rested longer, but Jefferson Hope was inexorable. "They
-will be upon our track by this time," he said. "Everything depends upon
-our speed. Once safe in Carson we may rest for the remainder of our
-lives."
-
-During the whole of that day they struggled on through the defiles, and
-by evening they calculated that they were more than thirty miles from
-their enemies. At night-time they chose the base of a beetling crag,
-where the rocks offered some protection from the chill wind, and there
-huddled together for warmth, they enjoyed a few hours' sleep. Before
-daybreak, however, they were up and on their way once more. They had
-seen no signs of any pursuers, and Jefferson Hope began to think that
-they were fairly out of the reach of the terrible organization whose
-enmity they had incurred. He little knew how far that iron grasp could
-reach, or how soon it was to close upon them and crush them.
-
-About the middle of the second day of their flight their scanty store
-of provisions began to run out. This gave the hunter little uneasiness,
-however, for there was game to be had among the mountains, and he had
-frequently before had to depend upon his rifle for the needs of life.
-Choosing a sheltered nook, he piled together a few dried branches and
-made a blazing fire, at which his companions might warm themselves, for
-they were now nearly five thousand feet above the sea level, and the air
-was bitter and keen. Having tethered the horses, and bade Lucy adieu,
-he threw his gun over his shoulder, and set out in search of whatever
-chance might throw in his way. Looking back he saw the old man and the
-young girl crouching over the blazing fire, while the three animals
-stood motionless in the back-ground. Then the intervening rocks hid them
-from his view.
-
-He walked for a couple of miles through one ravine after another without
-success, though from the marks upon the bark of the trees, and other
-indications, he judged that there were numerous bears in the vicinity.
-At last, after two or three hours' fruitless search, he was thinking of
-turning back in despair, when casting his eyes upwards he saw a sight
-which sent a thrill of pleasure through his heart. On the edge of a
-jutting pinnacle, three or four hundred feet above him, there stood a
-creature somewhat resembling a sheep in appearance, but armed with a
-pair of gigantic horns. The big-horn--for so it is called--was acting,
-probably, as a guardian over a flock which were invisible to the hunter;
-but fortunately it was heading in the opposite direction, and had not
-perceived him. Lying on his face, he rested his rifle upon a rock, and
-took a long and steady aim before drawing the trigger. The animal sprang
-into the air, tottered for a moment upon the edge of the precipice, and
-then came crashing down into the valley beneath.
-
-The creature was too unwieldy to lift, so the hunter contented himself
-with cutting away one haunch and part of the flank. With this trophy
-over his shoulder, he hastened to retrace his steps, for the evening was
-already drawing in. He had hardly started, however, before he realized
-the difficulty which faced him. In his eagerness he had wandered far
-past the ravines which were known to him, and it was no easy matter
-to pick out the path which he had taken. The valley in which he found
-himself divided and sub-divided into many gorges, which were so like
-each other that it was impossible to distinguish one from the other.
-He followed one for a mile or more until he came to a mountain torrent
-which he was sure that he had never seen before. Convinced that he had
-taken the wrong turn, he tried another, but with the same result. Night
-was coming on rapidly, and it was almost dark before he at last found
-himself in a defile which was familiar to him. Even then it was no easy
-matter to keep to the right track, for the moon had not yet risen, and
-the high cliffs on either side made the obscurity more profound. Weighed
-down with his burden, and weary from his exertions, he stumbled along,
-keeping up his heart by the reflection that every step brought him
-nearer to Lucy, and that he carried with him enough to ensure them food
-for the remainder of their journey.
-
-He had now come to the mouth of the very defile in which he had left
-them. Even in the darkness he could recognize the outline of the cliffs
-which bounded it. They must, he reflected, be awaiting him anxiously,
-for he had been absent nearly five hours. In the gladness of his heart
-he put his hands to his mouth and made the glen re-echo to a loud halloo
-as a signal that he was coming. He paused and listened for an answer.
-None came save his own cry, which clattered up the dreary silent
-ravines, and was borne back to his ears in countless repetitions. Again
-he shouted, even louder than before, and again no whisper came back from
-the friends whom he had left such a short time ago. A vague, nameless
-dread came over him, and he hurried onwards frantically, dropping the
-precious food in his agitation.
-
-When he turned the corner, he came full in sight of the spot where the
-fire had been lit. There was still a glowing pile of wood ashes there,
-but it had evidently not been tended since his departure. The same
-dead silence still reigned all round. With his fears all changed to
-convictions, he hurried on. There was no living creature near the
-remains of the fire: animals, man, maiden, all were gone. It was only
-too clear that some sudden and terrible disaster had occurred during
-his absence--a disaster which had embraced them all, and yet had left no
-traces behind it.
-
-Bewildered and stunned by this blow, Jefferson Hope felt his head spin
-round, and had to lean upon his rifle to save himself from falling. He
-was essentially a man of action, however, and speedily recovered from
-his temporary impotence. Seizing a half-consumed piece of wood from the
-smouldering fire, he blew it into a flame, and proceeded with its help
-to examine the little camp. The ground was all stamped down by the feet
-of horses, showing that a large party of mounted men had overtaken
-the fugitives, and the direction of their tracks proved that they had
-afterwards turned back to Salt Lake City. Had they carried back both of
-his companions with them? Jefferson Hope had almost persuaded himself
-that they must have done so, when his eye fell upon an object which made
-every nerve of his body tingle within him. A little way on one side of
-the camp was a low-lying heap of reddish soil, which had assuredly
-not been there before. There was no mistaking it for anything but a
-newly-dug grave. As the young hunter approached it, he perceived that a
-stick had been planted on it, with a sheet of paper stuck in the cleft
-fork of it. The inscription upon the paper was brief, but to the point:
-
- JOHN FERRIER,
- FORMERLY OF SALT LAKE CITY, [22]_
- Died August 4th, 1860.
-
-The sturdy old man, whom he had left so short a time before, was gone,
-then, and this was all his epitaph. Jefferson Hope looked wildly round
-to see if there was a second grave, but there was no sign of one. Lucy
-had been carried back by their terrible pursuers to fulfil her original
-destiny, by becoming one of the harem of the Elder's son. As the young
-fellow realized the certainty of her fate, and his own powerlessness to
-prevent it, he wished that he, too, was lying with the old farmer in his
-last silent resting-place.
-
-Again, however, his active spirit shook off the lethargy which springs
-from despair. If there was nothing else left to him, he could at least
-devote his life to revenge. With indomitable patience and perseverance,
-Jefferson Hope possessed also a power of sustained vindictiveness, which
-he may have learned from the Indians amongst whom he had lived. As he
-stood by the desolate fire, he felt that the only one thing which could
-assuage his grief would be thorough and complete retribution, brought
-by his own hand upon his enemies. His strong will and untiring energy
-should, he determined, be devoted to that one end. With a grim, white
-face, he retraced his steps to where he had dropped the food, and having
-stirred up the smouldering fire, he cooked enough to last him for a
-few days. This he made up into a bundle, and, tired as he was, he
-set himself to walk back through the mountains upon the track of the
-avenging angels.
-
-For five days he toiled footsore and weary through the defiles which he
-had already traversed on horseback. At night he flung himself down among
-the rocks, and snatched a few hours of sleep; but before daybreak he was
-always well on his way. On the sixth day, he reached the Eagle Cañon,
-from which they had commenced their ill-fated flight. Thence he could
-look down upon the home of the saints. Worn and exhausted, he leaned
-upon his rifle and shook his gaunt hand fiercely at the silent
-widespread city beneath him. As he looked at it, he observed that
-there were flags in some of the principal streets, and other signs of
-festivity. He was still speculating as to what this might mean when he
-heard the clatter of horse's hoofs, and saw a mounted man riding towards
-him. As he approached, he recognized him as a Mormon named Cowper, to
-whom he had rendered services at different times. He therefore accosted
-him when he got up to him, with the object of finding out what Lucy
-Ferrier's fate had been.
-
-"I am Jefferson Hope," he said. "You remember me."
-
-The Mormon looked at him with undisguised astonishment--indeed, it was
-difficult to recognize in this tattered, unkempt wanderer, with ghastly
-white face and fierce, wild eyes, the spruce young hunter of former
-days. Having, however, at last, satisfied himself as to his identity,
-the man's surprise changed to consternation.
-
-"You are mad to come here," he cried. "It is as much as my own life is
-worth to be seen talking with you. There is a warrant against you from
-the Holy Four for assisting the Ferriers away."
-
-"I don't fear them, or their warrant," Hope said, earnestly. "You must
-know something of this matter, Cowper. I conjure you by everything you
-hold dear to answer a few questions. We have always been friends. For
-God's sake, don't refuse to answer me."
-
-"What is it?" the Mormon asked uneasily. "Be quick. The very rocks have
-ears and the trees eyes."
-
-"What has become of Lucy Ferrier?"
-
-"She was married yesterday to young Drebber. Hold up, man, hold up, you
-have no life left in you."
-
-"Don't mind me," said Hope faintly. He was white to the very lips, and
-had sunk down on the stone against which he had been leaning. "Married,
-you say?"
-
-"Married yesterday--that's what those flags are for on the Endowment
-House. There was some words between young Drebber and young Stangerson
-as to which was to have her. They'd both been in the party that followed
-them, and Stangerson had shot her father, which seemed to give him the
-best claim; but when they argued it out in council, Drebber's party was
-the stronger, so the Prophet gave her over to him. No one won't have
-her very long though, for I saw death in her face yesterday. She is more
-like a ghost than a woman. Are you off, then?"
-
-"Yes, I am off," said Jefferson Hope, who had risen from his seat. His
-face might have been chiselled out of marble, so hard and set was its
-expression, while its eyes glowed with a baleful light.
-
-"Where are you going?"
-
-"Never mind," he answered; and, slinging his weapon over his shoulder,
-strode off down the gorge and so away into the heart of the mountains to
-the haunts of the wild beasts. Amongst them all there was none so fierce
-and so dangerous as himself.
-
-The prediction of the Mormon was only too well fulfilled. Whether it was
-the terrible death of her father or the effects of the hateful marriage
-into which she had been forced, poor Lucy never held up her head again,
-but pined away and died within a month. Her sottish husband, who had
-married her principally for the sake of John Ferrier's property, did not
-affect any great grief at his bereavement; but his other wives mourned
-over her, and sat up with her the night before the burial, as is the
-Mormon custom. They were grouped round the bier in the early hours of
-the morning, when, to their inexpressible fear and astonishment,
-the door was flung open, and a savage-looking, weather-beaten man in
-tattered garments strode into the room. Without a glance or a word to
-the cowering women, he walked up to the white silent figure which had
-once contained the pure soul of Lucy Ferrier. Stooping over her, he
-pressed his lips reverently to her cold forehead, and then, snatching
-up her hand, he took the wedding-ring from her finger. "She shall not be
-buried in that," he cried with a fierce snarl, and before an alarm could
-be raised sprang down the stairs and was gone. So strange and so brief
-was the episode, that the watchers might have found it hard to believe
-it themselves or persuade other people of it, had it not been for the
-undeniable fact that the circlet of gold which marked her as having been
-a bride had disappeared.
-
-For some months Jefferson Hope lingered among the mountains, leading
-a strange wild life, and nursing in his heart the fierce desire for
-vengeance which possessed him. Tales were told in the City of the weird
-figure which was seen prowling about the suburbs, and which haunted
-the lonely mountain gorges. Once a bullet whistled through Stangerson's
-window and flattened itself upon the wall within a foot of him. On
-another occasion, as Drebber passed under a cliff a great boulder
-crashed down on him, and he only escaped a terrible death by throwing
-himself upon his face. The two young Mormons were not long in
-discovering the reason of these attempts upon their lives, and led
-repeated expeditions into the mountains in the hope of capturing or
-killing their enemy, but always without success. Then they adopted the
-precaution of never going out alone or after nightfall, and of having
-their houses guarded. After a time they were able to relax these
-measures, for nothing was either heard or seen of their opponent, and
-they hoped that time had cooled his vindictiveness.
-
-Far from doing so, it had, if anything, augmented it. The hunter's mind
-was of a hard, unyielding nature, and the predominant idea of revenge
-had taken such complete possession of it that there was no room for
-any other emotion. He was, however, above all things practical. He soon
-realized that even his iron constitution could not stand the incessant
-strain which he was putting upon it. Exposure and want of wholesome food
-were wearing him out. If he died like a dog among the mountains, what
-was to become of his revenge then? And yet such a death was sure to
-overtake him if he persisted. He felt that that was to play his enemy's
-game, so he reluctantly returned to the old Nevada mines, there to
-recruit his health and to amass money enough to allow him to pursue his
-object without privation.
-
-His intention had been to be absent a year at the most, but a
-combination of unforeseen circumstances prevented his leaving the mines
-for nearly five. At the end of that time, however, his memory of
-his wrongs and his craving for revenge were quite as keen as on that
-memorable night when he had stood by John Ferrier's grave. Disguised,
-and under an assumed name, he returned to Salt Lake City, careless
-what became of his own life, as long as he obtained what he knew to
-be justice. There he found evil tidings awaiting him. There had been a
-schism among the Chosen People a few months before, some of the younger
-members of the Church having rebelled against the authority of the
-Elders, and the result had been the secession of a certain number of the
-malcontents, who had left Utah and become Gentiles. Among these had been
-Drebber and Stangerson; and no one knew whither they had gone. Rumour
-reported that Drebber had managed to convert a large part of his
-property into money, and that he had departed a wealthy man, while his
-companion, Stangerson, was comparatively poor. There was no clue at all,
-however, as to their whereabouts.
-
-Many a man, however vindictive, would have abandoned all thought of
-revenge in the face of such a difficulty, but Jefferson Hope never
-faltered for a moment. With the small competence he possessed, eked out
-by such employment as he could pick up, he travelled from town to town
-through the United States in quest of his enemies. Year passed into
-year, his black hair turned grizzled, but still he wandered on, a human
-bloodhound, with his mind wholly set upon the one object upon which he
-had devoted his life. At last his perseverance was rewarded. It was
-but a glance of a face in a window, but that one glance told him that
-Cleveland in Ohio possessed the men whom he was in pursuit of. He
-returned to his miserable lodgings with his plan of vengeance all
-arranged. It chanced, however, that Drebber, looking from his window,
-had recognized the vagrant in the street, and had read murder in
-his eyes. He hurried before a justice of the peace, accompanied by
-Stangerson, who had become his private secretary, and represented to him
-that they were in danger of their lives from the jealousy and hatred of
-an old rival. That evening Jefferson Hope was taken into custody, and
-not being able to find sureties, was detained for some weeks. When at
-last he was liberated, it was only to find that Drebber's house was
-deserted, and that he and his secretary had departed for Europe.
-
-Again the avenger had been foiled, and again his concentrated hatred
-urged him to continue the pursuit. Funds were wanting, however, and
-for some time he had to return to work, saving every dollar for his
-approaching journey. At last, having collected enough to keep life in
-him, he departed for Europe, and tracked his enemies from city to
-city, working his way in any menial capacity, but never overtaking the
-fugitives. When he reached St. Petersburg they had departed for Paris;
-and when he followed them there he learned that they had just set off
-for Copenhagen. At the Danish capital he was again a few days late, for
-they had journeyed on to London, where he at last succeeded in running
-them to earth. As to what occurred there, we cannot do better than quote
-the old hunter's own account, as duly recorded in Dr. Watson's Journal,
-to which we are already under such obligations.
-
-
-
-
-CHAPTER VI. A CONTINUATION OF THE REMINISCENCES OF JOHN WATSON, M.D.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-OUR prisoner's furious resistance did not apparently indicate any
-ferocity in his disposition towards ourselves, for on finding himself
-powerless, he smiled in an affable manner, and expressed his hopes that
-he had not hurt any of us in the scuffle. "I guess you're going to take
-me to the police-station," he remarked to Sherlock Holmes. "My cab's at
-the door. If you'll loose my legs I'll walk down to it. I'm not so light
-to lift as I used to be."
-
-Gregson and Lestrade exchanged glances as if they thought this
-proposition rather a bold one; but Holmes at once took the prisoner at
-his word, and loosened the towel which we had bound round his ancles.
-[23]_ He rose and stretched his legs, as though to assure himself that
-they were free once more. I remember that I thought to myself, as I eyed
-him, that I had seldom seen a more powerfully built man; and his dark
-sunburned face bore an expression of determination and energy which was
-as formidable as his personal strength.
-
-"If there's a vacant place for a chief of the police, I reckon you
-are the man for it," he said, gazing with undisguised admiration at my
-fellow-lodger. "The way you kept on my trail was a caution."
-
-"You had better come with me," said Holmes to the two detectives.
-
-"I can drive you," said Lestrade.
-
-"Good! and Gregson can come inside with me. You too, Doctor, you have
-taken an interest in the case and may as well stick to us."
-
-I assented gladly, and we all descended together. Our prisoner made no
-attempt at escape, but stepped calmly into the cab which had been his,
-and we followed him. Lestrade mounted the box, whipped up the horse, and
-brought us in a very short time to our destination. We were ushered into
-a small chamber where a police Inspector noted down our prisoner's name
-and the names of the men with whose murder he had been charged. The
-official was a white-faced unemotional man, who went through his
-duties in a dull mechanical way. "The prisoner will be put before the
-magistrates in the course of the week," he said; "in the mean time, Mr.
-Jefferson Hope, have you anything that you wish to say? I must warn you
-that your words will be taken down, and may be used against you."
-
-"I've got a good deal to say," our prisoner said slowly. "I want to tell
-you gentlemen all about it."
-
-"Hadn't you better reserve that for your trial?" asked the Inspector.
-
-"I may never be tried," he answered. "You needn't look startled. It
-isn't suicide I am thinking of. Are you a Doctor?" He turned his fierce
-dark eyes upon me as he asked this last question.
-
-"Yes; I am," I answered.
-
-"Then put your hand here," he said, with a smile, motioning with his
-manacled wrists towards his chest.
-
-I did so; and became at once conscious of an extraordinary throbbing and
-commotion which was going on inside. The walls of his chest seemed to
-thrill and quiver as a frail building would do inside when some powerful
-engine was at work. In the silence of the room I could hear a dull
-humming and buzzing noise which proceeded from the same source.
-
-"Why," I cried, "you have an aortic aneurism!"
-
-"That's what they call it," he said, placidly. "I went to a Doctor last
-week about it, and he told me that it is bound to burst before many days
-passed. It has been getting worse for years. I got it from over-exposure
-and under-feeding among the Salt Lake Mountains. I've done my work now,
-and I don't care how soon I go, but I should like to leave some account
-of the business behind me. I don't want to be remembered as a common
-cut-throat."
-
-The Inspector and the two detectives had a hurried discussion as to the
-advisability of allowing him to tell his story.
-
-"Do you consider, Doctor, that there is immediate danger?" the former
-asked, [24]_
-
-"Most certainly there is," I answered.
-
-"In that case it is clearly our duty, in the interests of justice, to
-take his statement," said the Inspector. "You are at liberty, sir, to
-give your account, which I again warn you will be taken down."
-
-"I'll sit down, with your leave," the prisoner said, suiting the action
-to the word. "This aneurism of mine makes me easily tired, and the
-tussle we had half an hour ago has not mended matters. I'm on the brink
-of the grave, and I am not likely to lie to you. Every word I say is the
-absolute truth, and how you use it is a matter of no consequence to me."
-
-With these words, Jefferson Hope leaned back in his chair and began
-the following remarkable statement. He spoke in a calm and methodical
-manner, as though the events which he narrated were commonplace enough.
-I can vouch for the accuracy of the subjoined account, for I have had
-access to Lestrade's note-book, in which the prisoner's words were taken
-down exactly as they were uttered.
-
-"It don't much matter to you why I hated these men," he said; "it's
-enough that they were guilty of the death of two human beings--a father
-and a daughter--and that they had, therefore, forfeited their own
-lives. After the lapse of time that has passed since their crime, it was
-impossible for me to secure a conviction against them in any court. I
-knew of their guilt though, and I determined that I should be judge,
-jury, and executioner all rolled into one. You'd have done the same, if
-you have any manhood in you, if you had been in my place.
-
-"That girl that I spoke of was to have married me twenty years ago. She
-was forced into marrying that same Drebber, and broke her heart over
-it. I took the marriage ring from her dead finger, and I vowed that his
-dying eyes should rest upon that very ring, and that his last thoughts
-should be of the crime for which he was punished. I have carried
-it about with me, and have followed him and his accomplice over two
-continents until I caught them. They thought to tire me out, but they
-could not do it. If I die to-morrow, as is likely enough, I die knowing
-that my work in this world is done, and well done. They have perished,
-and by my hand. There is nothing left for me to hope for, or to desire.
-
-"They were rich and I was poor, so that it was no easy matter for me to
-follow them. When I got to London my pocket was about empty, and I found
-that I must turn my hand to something for my living. Driving and riding
-are as natural to me as walking, so I applied at a cabowner's office,
-and soon got employment. I was to bring a certain sum a week to the
-owner, and whatever was over that I might keep for myself. There was
-seldom much over, but I managed to scrape along somehow. The hardest job
-was to learn my way about, for I reckon that of all the mazes that ever
-were contrived, this city is the most confusing. I had a map beside me
-though, and when once I had spotted the principal hotels and stations, I
-got on pretty well.
-
-"It was some time before I found out where my two gentlemen were living;
-but I inquired and inquired until at last I dropped across them. They
-were at a boarding-house at Camberwell, over on the other side of the
-river. When once I found them out I knew that I had them at my mercy. I
-had grown my beard, and there was no chance of their recognizing me.
-I would dog them and follow them until I saw my opportunity. I was
-determined that they should not escape me again.
-
-"They were very near doing it for all that. Go where they would about
-London, I was always at their heels. Sometimes I followed them on my
-cab, and sometimes on foot, but the former was the best, for then they
-could not get away from me. It was only early in the morning or late
-at night that I could earn anything, so that I began to get behind hand
-with my employer. I did not mind that, however, as long as I could lay
-my hand upon the men I wanted.
-
-"They were very cunning, though. They must have thought that there was
-some chance of their being followed, for they would never go out alone,
-and never after nightfall. During two weeks I drove behind them every
-day, and never once saw them separate. Drebber himself was drunk half
-the time, but Stangerson was not to be caught napping. I watched them
-late and early, but never saw the ghost of a chance; but I was not
-discouraged, for something told me that the hour had almost come. My
-only fear was that this thing in my chest might burst a little too soon
-and leave my work undone.
-
-"At last, one evening I was driving up and down Torquay Terrace, as the
-street was called in which they boarded, when I saw a cab drive up to
-their door. Presently some luggage was brought out, and after a time
-Drebber and Stangerson followed it, and drove off. I whipped up my horse
-and kept within sight of them, feeling very ill at ease, for I feared
-that they were going to shift their quarters. At Euston Station they
-got out, and I left a boy to hold my horse, and followed them on to the
-platform. I heard them ask for the Liverpool train, and the guard answer
-that one had just gone and there would not be another for some hours.
-Stangerson seemed to be put out at that, but Drebber was rather pleased
-than otherwise. I got so close to them in the bustle that I could hear
-every word that passed between them. Drebber said that he had a little
-business of his own to do, and that if the other would wait for him he
-would soon rejoin him. His companion remonstrated with him, and reminded
-him that they had resolved to stick together. Drebber answered that the
-matter was a delicate one, and that he must go alone. I could not catch
-what Stangerson said to that, but the other burst out swearing, and
-reminded him that he was nothing more than his paid servant, and that he
-must not presume to dictate to him. On that the Secretary gave it up
-as a bad job, and simply bargained with him that if he missed the last
-train he should rejoin him at Halliday's Private Hotel; to which Drebber
-answered that he would be back on the platform before eleven, and made
-his way out of the station.
-
-"The moment for which I had waited so long had at last come. I had my
-enemies within my power. Together they could protect each other,
-but singly they were at my mercy. I did not act, however, with undue
-precipitation. My plans were already formed. There is no satisfaction in
-vengeance unless the offender has time to realize who it is that strikes
-him, and why retribution has come upon him. I had my plans arranged by
-which I should have the opportunity of making the man who had wronged me
-understand that his old sin had found him out. It chanced that some days
-before a gentleman who had been engaged in looking over some houses in
-the Brixton Road had dropped the key of one of them in my carriage. It
-was claimed that same evening, and returned; but in the interval I had
-taken a moulding of it, and had a duplicate constructed. By means of
-this I had access to at least one spot in this great city where I could
-rely upon being free from interruption. How to get Drebber to that house
-was the difficult problem which I had now to solve.
-
-"He walked down the road and went into one or two liquor shops, staying
-for nearly half-an-hour in the last of them. When he came out he
-staggered in his walk, and was evidently pretty well on. There was a
-hansom just in front of me, and he hailed it. I followed it so close
-that the nose of my horse was within a yard of his driver the whole way.
-We rattled across Waterloo Bridge and through miles of streets, until,
-to my astonishment, we found ourselves back in the Terrace in which he
-had boarded. I could not imagine what his intention was in returning
-there; but I went on and pulled up my cab a hundred yards or so from
-the house. He entered it, and his hansom drove away. Give me a glass of
-water, if you please. My mouth gets dry with the talking."
-
-I handed him the glass, and he drank it down.
-
-"That's better," he said. "Well, I waited for a quarter of an hour, or
-more, when suddenly there came a noise like people struggling inside the
-house. Next moment the door was flung open and two men appeared, one of
-whom was Drebber, and the other was a young chap whom I had never seen
-before. This fellow had Drebber by the collar, and when they came to
-the head of the steps he gave him a shove and a kick which sent him half
-across the road. 'You hound,' he cried, shaking his stick at him; 'I'll
-teach you to insult an honest girl!' He was so hot that I think he would
-have thrashed Drebber with his cudgel, only that the cur staggered away
-down the road as fast as his legs would carry him. He ran as far as the
-corner, and then, seeing my cab, he hailed me and jumped in. 'Drive me
-to Halliday's Private Hotel,' said he.
-
-"When I had him fairly inside my cab, my heart jumped so with joy that
-I feared lest at this last moment my aneurism might go wrong. I drove
-along slowly, weighing in my own mind what it was best to do. I might
-take him right out into the country, and there in some deserted lane
-have my last interview with him. I had almost decided upon this, when he
-solved the problem for me. The craze for drink had seized him again, and
-he ordered me to pull up outside a gin palace. He went in, leaving word
-that I should wait for him. There he remained until closing time, and
-when he came out he was so far gone that I knew the game was in my own
-hands.
-
-"Don't imagine that I intended to kill him in cold blood. It would only
-have been rigid justice if I had done so, but I could not bring myself
-to do it. I had long determined that he should have a show for his life
-if he chose to take advantage of it. Among the many billets which I
-have filled in America during my wandering life, I was once janitor and
-sweeper out of the laboratory at York College. One day the professor was
-lecturing on poisions, [25]_ and he showed his students some alkaloid,
-as he called it, which he had extracted from some South American arrow
-poison, and which was so powerful that the least grain meant instant
-death. I spotted the bottle in which this preparation was kept, and when
-they were all gone, I helped myself to a little of it. I was a fairly
-good dispenser, so I worked this alkaloid into small, soluble pills, and
-each pill I put in a box with a similar pill made without the poison.
-I determined at the time that when I had my chance, my gentlemen should
-each have a draw out of one of these boxes, while I ate the pill that
-remained. It would be quite as deadly, and a good deal less noisy than
-firing across a handkerchief. From that day I had always my pill boxes
-about with me, and the time had now come when I was to use them.
-
-"It was nearer one than twelve, and a wild, bleak night, blowing hard
-and raining in torrents. Dismal as it was outside, I was glad within--so
-glad that I could have shouted out from pure exultation. If any of you
-gentlemen have ever pined for a thing, and longed for it during twenty
-long years, and then suddenly found it within your reach, you would
-understand my feelings. I lit a cigar, and puffed at it to steady my
-nerves, but my hands were trembling, and my temples throbbing with
-excitement. As I drove, I could see old John Ferrier and sweet Lucy
-looking at me out of the darkness and smiling at me, just as plain as I
-see you all in this room. All the way they were ahead of me, one on each
-side of the horse until I pulled up at the house in the Brixton Road.
-
-"There was not a soul to be seen, nor a sound to be heard, except the
-dripping of the rain. When I looked in at the window, I found Drebber
-all huddled together in a drunken sleep. I shook him by the arm, 'It's
-time to get out,' I said.
-
-"'All right, cabby,' said he.
-
-"I suppose he thought we had come to the hotel that he had mentioned,
-for he got out without another word, and followed me down the garden.
-I had to walk beside him to keep him steady, for he was still a little
-top-heavy. When we came to the door, I opened it, and led him into the
-front room. I give you my word that all the way, the father and the
-daughter were walking in front of us.
-
-"'It's infernally dark,' said he, stamping about.
-
-"'We'll soon have a light,' I said, striking a match and putting it to
-a wax candle which I had brought with me. 'Now, Enoch Drebber,' I
-continued, turning to him, and holding the light to my own face, 'who am
-I?'
-
-"He gazed at me with bleared, drunken eyes for a moment, and then I
-saw a horror spring up in them, and convulse his whole features, which
-showed me that he knew me. He staggered back with a livid face, and I
-saw the perspiration break out upon his brow, while his teeth chattered
-in his head. At the sight, I leaned my back against the door and laughed
-loud and long. I had always known that vengeance would be sweet, but I
-had never hoped for the contentment of soul which now possessed me.
-
-"'You dog!' I said; 'I have hunted you from Salt Lake City to St.
-Petersburg, and you have always escaped me. Now, at last your wanderings
-have come to an end, for either you or I shall never see to-morrow's sun
-rise.' He shrunk still further away as I spoke, and I could see on his
-face that he thought I was mad. So I was for the time. The pulses in my
-temples beat like sledge-hammers, and I believe I would have had a fit
-of some sort if the blood had not gushed from my nose and relieved me.
-
-"'What do you think of Lucy Ferrier now?' I cried, locking the door, and
-shaking the key in his face. 'Punishment has been slow in coming, but it
-has overtaken you at last.' I saw his coward lips tremble as I spoke. He
-would have begged for his life, but he knew well that it was useless.
-
-"'Would you murder me?' he stammered.
-
-"'There is no murder,' I answered. 'Who talks of murdering a mad dog?
-What mercy had you upon my poor darling, when you dragged her from her
-slaughtered father, and bore her away to your accursed and shameless
-harem.'
-
-"'It was not I who killed her father,' he cried.
-
-"'But it was you who broke her innocent heart,' I shrieked, thrusting
-the box before him. 'Let the high God judge between us. Choose and
-eat. There is death in one and life in the other. I shall take what you
-leave. Let us see if there is justice upon the earth, or if we are ruled
-by chance.'
-
-"He cowered away with wild cries and prayers for mercy, but I drew my
-knife and held it to his throat until he had obeyed me. Then I swallowed
-the other, and we stood facing one another in silence for a minute or
-more, waiting to see which was to live and which was to die. Shall I
-ever forget the look which came over his face when the first warning
-pangs told him that the poison was in his system? I laughed as I saw
-it, and held Lucy's marriage ring in front of his eyes. It was but for
-a moment, for the action of the alkaloid is rapid. A spasm of pain
-contorted his features; he threw his hands out in front of him,
-staggered, and then, with a hoarse cry, fell heavily upon the floor. I
-turned him over with my foot, and placed my hand upon his heart. There
-was no movement. He was dead!
-
-"The blood had been streaming from my nose, but I had taken no notice of
-it. I don't know what it was that put it into my head to write upon the
-wall with it. Perhaps it was some mischievous idea of setting the police
-upon a wrong track, for I felt light-hearted and cheerful. I remembered
-a German being found in New York with RACHE written up above him, and it
-was argued at the time in the newspapers that the secret societies must
-have done it. I guessed that what puzzled the New Yorkers would puzzle
-the Londoners, so I dipped my finger in my own blood and printed it on
-a convenient place on the wall. Then I walked down to my cab and found
-that there was nobody about, and that the night was still very wild. I
-had driven some distance when I put my hand into the pocket in which
-I usually kept Lucy's ring, and found that it was not there. I was
-thunderstruck at this, for it was the only memento that I had of her.
-Thinking that I might have dropped it when I stooped over Drebber's
-body, I drove back, and leaving my cab in a side street, I went boldly
-up to the house--for I was ready to dare anything rather than lose
-the ring. When I arrived there, I walked right into the arms of a
-police-officer who was coming out, and only managed to disarm his
-suspicions by pretending to be hopelessly drunk.
-
-"That was how Enoch Drebber came to his end. All I had to do then was
-to do as much for Stangerson, and so pay off John Ferrier's debt. I knew
-that he was staying at Halliday's Private Hotel, and I hung about all
-day, but he never came out. [26]_ fancy that he suspected something when
-Drebber failed to put in an appearance. He was cunning, was Stangerson,
-and always on his guard. If he thought he could keep me off by staying
-indoors he was very much mistaken. I soon found out which was the window
-of his bedroom, and early next morning I took advantage of some ladders
-which were lying in the lane behind the hotel, and so made my way into
-his room in the grey of the dawn. I woke him up and told him that the
-hour had come when he was to answer for the life he had taken so long
-before. I described Drebber's death to him, and I gave him the same
-choice of the poisoned pills. Instead of grasping at the chance of
-safety which that offered him, he sprang from his bed and flew at my
-throat. In self-defence I stabbed him to the heart. It would have been
-the same in any case, for Providence would never have allowed his guilty
-hand to pick out anything but the poison.
-
-"I have little more to say, and it's as well, for I am about done up.
-I went on cabbing it for a day or so, intending to keep at it until I
-could save enough to take me back to America. I was standing in the
-yard when a ragged youngster asked if there was a cabby there called
-Jefferson Hope, and said that his cab was wanted by a gentleman at 221B,
-Baker Street. I went round, suspecting no harm, and the next thing I
-knew, this young man here had the bracelets on my wrists, and as neatly
-snackled [27]_ as ever I saw in my life. That's the whole of my story,
-gentlemen. You may consider me to be a murderer; but I hold that I am
-just as much an officer of justice as you are."
-
-So thrilling had the man's narrative been, and his manner was so
-impressive that we had sat silent and absorbed. Even the professional
-detectives, _blasé_ as they were in every detail of crime, appeared to
-be keenly interested in the man's story. When he finished we sat for
-some minutes in a stillness which was only broken by the scratching
-of Lestrade's pencil as he gave the finishing touches to his shorthand
-account.
-
-"There is only one point on which I should like a little more
-information," Sherlock Holmes said at last. "Who was your accomplice who
-came for the ring which I advertised?"
-
-The prisoner winked at my friend jocosely. "I can tell my own secrets,"
-he said, "but I don't get other people into trouble. I saw your
-advertisement, and I thought it might be a plant, or it might be the
-ring which I wanted. My friend volunteered to go and see. I think you'll
-own he did it smartly."
-
-"Not a doubt of that," said Holmes heartily.
-
-"Now, gentlemen," the Inspector remarked gravely, "the forms of the law
-must be complied with. On Thursday the prisoner will be brought before
-the magistrates, and your attendance will be required. Until then I will
-be responsible for him." He rang the bell as he spoke, and Jefferson
-Hope was led off by a couple of warders, while my friend and I made our
-way out of the Station and took a cab back to Baker Street.
-
-
-
-
-CHAPTER VII. THE CONCLUSION.
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-WE had all been warned to appear before the magistrates upon the
-Thursday; but when the Thursday came there was no occasion for our
-testimony. A higher Judge had taken the matter in hand, and Jefferson
-Hope had been summoned before a tribunal where strict justice would
-be meted out to him. On the very night after his capture the aneurism
-burst, and he was found in the morning stretched upon the floor of the
-cell, with a placid smile upon his face, as though he had been able
-in his dying moments to look back upon a useful life, and on work well
-done.
-
-"Gregson and Lestrade will be wild about his death," Holmes remarked, as
-we chatted it over next evening. "Where will their grand advertisement
-be now?"
-
-"I don't see that they had very much to do with his capture," I
-answered.
-
-"What you do in this world is a matter of no consequence," returned my
-companion, bitterly. "The question is, what can you make people believe
-that you have done. Never mind," he continued, more brightly, after a
-pause. "I would not have missed the investigation for anything. There
-has been no better case within my recollection. Simple as it was, there
-were several most instructive points about it."
-
-"Simple!" I ejaculated.
-
-"Well, really, it can hardly be described as otherwise," said Sherlock
-Holmes, smiling at my surprise. "The proof of its intrinsic simplicity
-is, that without any help save a few very ordinary deductions I was able
-to lay my hand upon the criminal within three days."
-
-"That is true," said I.
-
-"I have already explained to you that what is out of the common is
-usually a guide rather than a hindrance. In solving a problem of this
-sort, the grand thing is to be able to reason backwards. That is a very
-useful accomplishment, and a very easy one, but people do not practise
-it much. In the every-day affairs of life it is more useful to reason
-forwards, and so the other comes to be neglected. There are fifty who
-can reason synthetically for one who can reason analytically."
-
-"I confess," said I, "that I do not quite follow you."
-
-"I hardly expected that you would. Let me see if I can make it clearer.
-Most people, if you describe a train of events to them, will tell you
-what the result would be. They can put those events together in their
-minds, and argue from them that something will come to pass. There are
-few people, however, who, if you told them a result, would be able to
-evolve from their own inner consciousness what the steps were which led
-up to that result. This power is what I mean when I talk of reasoning
-backwards, or analytically."
-
-"I understand," said I.
-
-"Now this was a case in which you were given the result and had to
-find everything else for yourself. Now let me endeavour to show you the
-different steps in my reasoning. To begin at the beginning. I approached
-the house, as you know, on foot, and with my mind entirely free from all
-impressions. I naturally began by examining the roadway, and there, as I
-have already explained to you, I saw clearly the marks of a cab, which,
-I ascertained by inquiry, must have been there during the night. I
-satisfied myself that it was a cab and not a private carriage by the
-narrow gauge of the wheels. The ordinary London growler is considerably
-less wide than a gentleman's brougham.
-
-"This was the first point gained. I then walked slowly down the garden
-path, which happened to be composed of a clay soil, peculiarly suitable
-for taking impressions. No doubt it appeared to you to be a mere
-trampled line of slush, but to my trained eyes every mark upon its
-surface had a meaning. There is no branch of detective science which
-is so important and so much neglected as the art of tracing footsteps.
-Happily, I have always laid great stress upon it, and much practice
-has made it second nature to me. I saw the heavy footmarks of the
-constables, but I saw also the track of the two men who had first passed
-through the garden. It was easy to tell that they had been before the
-others, because in places their marks had been entirely obliterated by
-the others coming upon the top of them. In this way my second link was
-formed, which told me that the nocturnal visitors were two in number,
-one remarkable for his height (as I calculated from the length of his
-stride), and the other fashionably dressed, to judge from the small and
-elegant impression left by his boots.
-
-"On entering the house this last inference was confirmed. My well-booted
-man lay before me. The tall one, then, had done the murder, if murder
-there was. There was no wound upon the dead man's person, but the
-agitated expression upon his face assured me that he had foreseen his
-fate before it came upon him. Men who die from heart disease, or any
-sudden natural cause, never by any chance exhibit agitation upon their
-features. Having sniffed the dead man's lips I detected a slightly sour
-smell, and I came to the conclusion that he had had poison forced upon
-him. Again, I argued that it had been forced upon him from the hatred
-and fear expressed upon his face. By the method of exclusion, I had
-arrived at this result, for no other hypothesis would meet the facts.
-Do not imagine that it was a very unheard of idea. The forcible
-administration of poison is by no means a new thing in criminal annals.
-The cases of Dolsky in Odessa, and of Leturier in Montpellier, will
-occur at once to any toxicologist.
-
-"And now came the great question as to the reason why. Robbery had not
-been the object of the murder, for nothing was taken. Was it politics,
-then, or was it a woman? That was the question which confronted me.
-I was inclined from the first to the latter supposition. Political
-assassins are only too glad to do their work and to fly. This murder
-had, on the contrary, been done most deliberately, and the perpetrator
-had left his tracks all over the room, showing that he had been there
-all the time. It must have been a private wrong, and not a political
-one, which called for such a methodical revenge. When the inscription
-was discovered upon the wall I was more inclined than ever to my
-opinion. The thing was too evidently a blind. When the ring was found,
-however, it settled the question. Clearly the murderer had used it to
-remind his victim of some dead or absent woman. It was at this point
-that I asked Gregson whether he had enquired in his telegram to
-Cleveland as to any particular point in Mr. Drebber's former career. He
-answered, you remember, in the negative.
-
-"I then proceeded to make a careful examination of the room, which
-confirmed me in my opinion as to the murderer's height, and furnished me
-with the additional details as to the Trichinopoly cigar and the length
-of his nails. I had already come to the conclusion, since there were no
-signs of a struggle, that the blood which covered the floor had burst
-from the murderer's nose in his excitement. I could perceive that the
-track of blood coincided with the track of his feet. It is seldom that
-any man, unless he is very full-blooded, breaks out in this way through
-emotion, so I hazarded the opinion that the criminal was probably a
-robust and ruddy-faced man. Events proved that I had judged correctly.
-
-"Having left the house, I proceeded to do what Gregson had neglected. I
-telegraphed to the head of the police at Cleveland, limiting my enquiry
-to the circumstances connected with the marriage of Enoch Drebber. The
-answer was conclusive. It told me that Drebber had already applied for
-the protection of the law against an old rival in love, named Jefferson
-Hope, and that this same Hope was at present in Europe. I knew now that
-I held the clue to the mystery in my hand, and all that remained was to
-secure the murderer.
-
-"I had already determined in my own mind that the man who had walked
-into the house with Drebber, was none other than the man who had driven
-the cab. The marks in the road showed me that the horse had wandered
-on in a way which would have been impossible had there been anyone in
-charge of it. Where, then, could the driver be, unless he were inside
-the house? Again, it is absurd to suppose that any sane man would carry
-out a deliberate crime under the very eyes, as it were, of a third
-person, who was sure to betray him. Lastly, supposing one man wished
-to dog another through London, what better means could he adopt than
-to turn cabdriver. All these considerations led me to the irresistible
-conclusion that Jefferson Hope was to be found among the jarveys of the
-Metropolis.
-
-"If he had been one there was no reason to believe that he had ceased to
-be. On the contrary, from his point of view, any sudden change would be
-likely to draw attention to himself. He would, probably, for a time at
-least, continue to perform his duties. There was no reason to suppose
-that he was going under an assumed name. Why should he change his name
-in a country where no one knew his original one? I therefore organized
-my Street Arab detective corps, and sent them systematically to every
-cab proprietor in London until they ferreted out the man that I wanted.
-How well they succeeded, and how quickly I took advantage of it, are
-still fresh in your recollection. The murder of Stangerson was an
-incident which was entirely unexpected, but which could hardly in
-any case have been prevented. Through it, as you know, I came into
-possession of the pills, the existence of which I had already surmised.
-You see the whole thing is a chain of logical sequences without a break
-or flaw."
-
-"It is wonderful!" I cried. "Your merits should be publicly recognized.
-You should publish an account of the case. If you won't, I will for
-you."
-
-"You may do what you like, Doctor," he answered. "See here!" he
-continued, handing a paper over to me, "look at this!"
-
-It was the _Echo_ for the day, and the paragraph to which he pointed was
-devoted to the case in question.
-
-"The public," it said, "have lost a sensational treat through the sudden
-death of the man Hope, who was suspected of the murder of Mr. Enoch
-Drebber and of Mr. Joseph Stangerson. The details of the case will
-probably be never known now, though we are informed upon good authority
-that the crime was the result of an old standing and romantic feud, in
-which love and Mormonism bore a part. It seems that both the victims
-belonged, in their younger days, to the Latter Day Saints, and Hope, the
-deceased prisoner, hails also from Salt Lake City. If the case has had
-no other effect, it, at least, brings out in the most striking manner
-the efficiency of our detective police force, and will serve as a lesson
-to all foreigners that they will do wisely to settle their feuds at
-home, and not to carry them on to British soil. It is an open secret
-that the credit of this smart capture belongs entirely to the well-known
-Scotland Yard officials, Messrs. Lestrade and Gregson. The man was
-apprehended, it appears, in the rooms of a certain Mr. Sherlock Holmes,
-who has himself, as an amateur, shown some talent in the detective
-line, and who, with such instructors, may hope in time to attain to some
-degree of their skill. It is expected that a testimonial of some sort
-will be presented to the two officers as a fitting recognition of their
-services."
-
-"Didn't I tell you so when we started?" cried Sherlock Holmes with a
-laugh. "That's the result of all our Study in Scarlet: to get them a
-testimonial!"
-
-"Never mind," I answered, "I have all the facts in my journal, and the
-public shall know them. In the meantime you must make yourself contented
-by the consciousness of success, like the Roman miser--
-
- "'Populus me sibilat, at mihi plaudo
- Ipse domi simul ac nummos contemplor in arca.'"
-
-
-
-
-
-ORIGINAL TRANSCRIBER'S NOTES:
------------------------------
-
-.. [1] Frontispiece, with the caption: "He examined with his glass
- the word upon the wall, going over every letter of it with the most
- minute exactness."
-
-.. [2] "JOHN H. WATSON, M.D.": the initial letters in the name are
- capitalized, the other letters in small caps. All chapter titles are in
- small caps. The initial words of chapters are in small caps with first
- letter capitalized.
-
-.. [3] "lodgings.": the period should be a comma, as in later
- editions.
-
-.. [4] "hoemoglobin": should be haemoglobin. The o&e are
- concatenated.
-
-.. [5] "221B": the B is in small caps
-
-.. [6] "THE LAURISTON GARDEN MYSTERY": the table-of-contents
- lists this chapter as "...GARDENS MYSTERY"--plural, and probably more
- correct.
-
-.. [7] "brought."": the text has an extra double-quote mark
-
-.. [8] "individual--": illustration this page, with the
- caption: "As he spoke, his nimble fingers were flying here, there, and
- everywhere."
-
-.. [9] "manoeuvres": the o&e are concatenated.
-
-.. [10] "Patent leathers": the hyphen is missing.
-
-.. [11] "condonment": should be condonement.
-
-.. [13] "wages.": ending quote is missing.
-
-.. [14] "the first.": ending quote is missing.
-
-.. [15] "make much of...": Other editions complete this sentence
- with an "it." But there is a gap in the text at this point, and, given
- the context, it may have actually been an interjection, a dash. The gap
- is just the right size for the characters "it." and the start of a new
- sentence, or for a "----"
-
-.. [16] "tho cushion": "tho" should be "the"
-
-.. [19] "shoving": later editions have "showing". The original is
- clearly superior.
-
-.. [20] "stared about...": illustration, with the caption: "One of
- them seized the little girl, and hoisted her upon his shoulder."
-
-.. [21] "upon the": illustration, with the caption: "As he watched
- it he saw it writhe along the ground."
-
-.. [22] "FORMERLY...": F,S,L,C in caps, other letters in this line
- in small caps.
-
-.. [23] "ancles": ankles.
-
-.. [24] "asked,": should be "asked."
-
-.. [25] "poisions": should be "poisons"
-
-.. [26] "...fancy": should be "I fancy". There is a gap in the text.
-
-.. [27] "snackled": "shackled" in later texts.
-
-.. [29] Heber C. Kemball, in one of his sermons, alludes to his hundred wives under this endearing epithet.
-
-
-END OF THIS PROJECT GUTENBERG EBOOK A STUDY IN SCARLET
-------------------------------------------------------
-
-***** This file should be named 244-8.txt or 244-8.zip *****
-This and all associated files of various formats will be found in:
-http://www.gutenberg.org/2/4/244/
-
-Produced by Roger Squires
-
-Updated editions will replace the previous one--the old editions
-will be renamed.
-
-Creating the works from public domain print editions means that no
-one owns a United States copyright in these works, so the Foundation
-(and you!) can copy and distribute it in the United States without
-permission and without paying copyright royalties. Special rules,
-set forth in the General Terms of Use part of this license, apply to
-copying and distributing Project Gutenberg-tm electronic works to
-protect the PROJECT GUTENBERG-tm concept and trademark. Project
-Gutenberg is a registered trademark, and may not be used if you
-charge for the eBooks, unless you receive specific permission. If you
-do not charge anything for copies of this eBook, complying with the
-rules is very easy. You may use this eBook for nearly any purpose
-such as creation of derivative works, reports, performances and
-research. They may be modified and printed and given away--you may do
-practically ANYTHING with public domain eBooks. Redistribution is
-subject to the trademark license, especially commercial
-redistribution.
-
-
-
-*** START: FULL LICENSE ***
-
-THE FULL PROJECT GUTENBERG LICENSE
-PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK
-
-To protect the Project Gutenberg-tm mission of promoting the free
-distribution of electronic works, by using or distributing this work
-(or any other work associated in any way with the phrase "Project
-Gutenberg"), you agree to comply with all the terms of the Full Project
-Gutenberg-tm License (available with this file or online at
-http://gutenberg.org/license).
-
-
-Section 1. General Terms of Use and Redistributing Project Gutenberg-tm
-electronic works
-
-1.A. By reading or using any part of this Project Gutenberg-tm
-electronic work, you indicate that you have read, understand, agree to
-and accept all the terms of this license and intellectual property
-(trademark/copyright) agreement. If you do not agree to abide by all
-the terms of this agreement, you must cease using and return or destroy
-all copies of Project Gutenberg-tm electronic works in your possession.
-If you paid a fee for obtaining a copy of or access to a Project
-Gutenberg-tm electronic work and you do not agree to be bound by the
-terms of this agreement, you may obtain a refund from the person or
-entity to whom you paid the fee as set forth in paragraph 1.E.8.
-
-1.B. "Project Gutenberg" is a registered trademark. It may only be
-used on or associated in any way with an electronic work by people who
-agree to be bound by the terms of this agreement. There are a few
-things that you can do with most Project Gutenberg-tm electronic works
-even without complying with the full terms of this agreement. See
-paragraph 1.C below. There are a lot of things you can do with Project
-Gutenberg-tm electronic works if you follow the terms of this agreement
-and help preserve free future access to Project Gutenberg-tm electronic
-works. See paragraph 1.E below.
-
-1.C. The Project Gutenberg Literary Archive Foundation ("the Foundation"
-or PGLAF), owns a compilation copyright in the collection of Project
-Gutenberg-tm electronic works. Nearly all the individual works in the
-collection are in the public domain in the United States. If an
-individual work is in the public domain in the United States and you are
-located in the United States, we do not claim a right to prevent you from
-copying, distributing, performing, displaying or creating derivative
-works based on the work as long as all references to Project Gutenberg
-are removed. Of course, we hope that you will support the Project
-Gutenberg-tm mission of promoting free access to electronic works by
-freely sharing Project Gutenberg-tm works in compliance with the terms of
-this agreement for keeping the Project Gutenberg-tm name associated with
-the work. You can easily comply with the terms of this agreement by
-keeping this work in the same format with its attached full Project
-Gutenberg-tm License when you share it without charge with others.
-
-1.D. The copyright laws of the place where you are located also govern
-what you can do with this work. Copyright laws in most countries are in
-a constant state of change. If you are outside the United States, check
-the laws of your country in addition to the terms of this agreement
-before downloading, copying, displaying, performing, distributing or
-creating derivative works based on this work or any other Project
-Gutenberg-tm work. The Foundation makes no representations concerning
-the copyright status of any work in any country outside the United
-States.
-
-1.E. Unless you have removed all references to Project Gutenberg:
-
-1.E.1. The following sentence, with active links to, or other immediate
-access to, the full Project Gutenberg-tm License must appear prominently
-whenever any copy of a Project Gutenberg-tm work (any work on which the
-phrase "Project Gutenberg" appears, or with which the phrase "Project
-Gutenberg" is associated) is accessed, displayed, performed, viewed,
-copied or distributed:
-
-This eBook is for the use of anyone anywhere at no cost and with
-almost no restrictions whatsoever. You may copy it, give it away or
-re-use it under the terms of the Project Gutenberg License included
-with this eBook or online at www.gutenberg.org
-
-1.E.2. If an individual Project Gutenberg-tm electronic work is derived
-from the public domain (does not contain a notice indicating that it is
-posted with permission of the copyright holder), the work can be copied
-and distributed to anyone in the United States without paying any fees
-or charges. If you are redistributing or providing access to a work
-with the phrase "Project Gutenberg" associated with or appearing on the
-work, you must comply either with the requirements of paragraphs 1.E.1
-through 1.E.7 or obtain permission for the use of the work and the
-Project Gutenberg-tm trademark as set forth in paragraphs 1.E.8 or
-1.E.9.
-
-1.E.3. If an individual Project Gutenberg-tm electronic work is posted
-with the permission of the copyright holder, your use and distribution
-must comply with both paragraphs 1.E.1 through 1.E.7 and any additional
-terms imposed by the copyright holder. Additional terms will be linked
-to the Project Gutenberg-tm License for all works posted with the
-permission of the copyright holder found at the beginning of this work.
-
-1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm
-License terms from this work, or any files containing a part of this
-work or any other work associated with Project Gutenberg-tm.
-
-1.E.5. Do not copy, display, perform, distribute or redistribute this
-electronic work, or any part of this electronic work, without
-prominently displaying the sentence set forth in paragraph 1.E.1 with
-active links or immediate access to the full terms of the Project
-Gutenberg-tm License.
-
-1.E.6. You may convert to and distribute this work in any binary,
-compressed, marked up, nonproprietary or proprietary form, including any
-word processing or hypertext form. However, if you provide access to or
-distribute copies of a Project Gutenberg-tm work in a format other than
-"Plain Vanilla ASCII" or other format used in the official version
-posted on the official Project Gutenberg-tm web site (www.gutenberg.org),
-you must, at no additional cost, fee or expense to the user, provide a
-copy, a means of exporting a copy, or a means of obtaining a copy upon
-request, of the work in its original "Plain Vanilla ASCII" or other
-form. Any alternate format must include the full Project Gutenberg-tm
-License as specified in paragraph 1.E.1.
-
-1.E.7. Do not charge a fee for access to, viewing, displaying,
-performing, copying or distributing any Project Gutenberg-tm works
-unless you comply with paragraph 1.E.8 or 1.E.9.
-
-1.E.8. You may charge a reasonable fee for copies of or providing
-access to or distributing Project Gutenberg-tm electronic works provided
-that
-
-- You pay a royalty fee of 20% of the gross profits you derive from
- the use of Project Gutenberg-tm works calculated using the method
- you already use to calculate your applicable taxes. The fee is
- owed to the owner of the Project Gutenberg-tm trademark, but he
- has agreed to donate royalties under this paragraph to the
- Project Gutenberg Literary Archive Foundation. Royalty payments
- must be paid within 60 days following each date on which you
- prepare (or are legally required to prepare) your periodic tax
- returns. Royalty payments should be clearly marked as such and
- sent to the Project Gutenberg Literary Archive Foundation at the
- address specified in Section 4, "Information about donations to
- the Project Gutenberg Literary Archive Foundation."
-
-- You provide a full refund of any money paid by a user who notifies
- you in writing (or by e-mail) within 30 days of receipt that s/he
- does not agree to the terms of the full Project Gutenberg-tm
- License. You must require such a user to return or
- destroy all copies of the works possessed in a physical medium
- and discontinue all use of and all access to other copies of
- Project Gutenberg-tm works.
-
-- You provide, in accordance with paragraph 1.F.3, a full refund of any
- money paid for a work or a replacement copy, if a defect in the
- electronic work is discovered and reported to you within 90 days
- of receipt of the work.
-
-- You comply with all other terms of this agreement for free
- distribution of Project Gutenberg-tm works.
-
-1.E.9. If you wish to charge a fee or distribute a Project Gutenberg-tm
-electronic work or group of works on different terms than are set
-forth in this agreement, you must obtain permission in writing from
-both the Project Gutenberg Literary Archive Foundation and Michael
-Hart, the owner of the Project Gutenberg-tm trademark. Contact the
-Foundation as set forth in Section 3 below.
-
-1.F.
-
-1.F.1. Project Gutenberg volunteers and employees expend considerable
-effort to identify, do copyright research on, transcribe and proofread
-public domain works in creating the Project Gutenberg-tm
-collection. Despite these efforts, Project Gutenberg-tm electronic
-works, and the medium on which they may be stored, may contain
-"Defects," such as, but not limited to, incomplete, inaccurate or
-corrupt data, transcription errors, a copyright or other intellectual
-property infringement, a defective or damaged disk or other medium, a
-computer virus, or computer codes that damage or cannot be read by
-your equipment.
-
-1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right
-of Replacement or Refund" described in paragraph 1.F.3, the Project
-Gutenberg Literary Archive Foundation, the owner of the Project
-Gutenberg-tm trademark, and any other party distributing a Project
-Gutenberg-tm electronic work under this agreement, disclaim all
-liability to you for damages, costs and expenses, including legal
-fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT
-LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE
-PROVIDED IN PARAGRAPH F3. YOU AGREE THAT THE FOUNDATION, THE
-TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE
-LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR
-INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH
-DAMAGE.
-
-1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a
-defect in this electronic work within 90 days of receiving it, you can
-receive a refund of the money (if any) you paid for it by sending a
-written explanation to the person you received the work from. If you
-received the work on a physical medium, you must return the medium with
-your written explanation. The person or entity that provided you with
-the defective work may elect to provide a replacement copy in lieu of a
-refund. If you received the work electronically, the person or entity
-providing it to you may choose to give you a second opportunity to
-receive the work electronically in lieu of a refund. If the second copy
-is also defective, you may demand a refund in writing without further
-opportunities to fix the problem.
-
-1.F.4. Except for the limited right of replacement or refund set forth
-in paragraph 1.F.3, this work is provided to you 'AS-IS' WITH NO OTHER
-WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
-WARRANTIES OF MERCHANTIBILITY OR FITNESS FOR ANY PURPOSE.
-
-1.F.5. Some states do not allow disclaimers of certain implied
-warranties or the exclusion or limitation of certain types of damages.
-If any disclaimer or limitation set forth in this agreement violates the
-law of the state applicable to this agreement, the agreement shall be
-interpreted to make the maximum disclaimer or limitation permitted by
-the applicable state law. The invalidity or unenforceability of any
-provision of this agreement shall not void the remaining provisions.
-
-1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the
-trademark owner, any agent or employee of the Foundation, anyone
-providing copies of Project Gutenberg-tm electronic works in accordance
-with this agreement, and any volunteers associated with the production,
-promotion and distribution of Project Gutenberg-tm electronic works,
-harmless from all liability, costs and expenses, including legal fees,
-that arise directly or indirectly from any of the following which you do
-or cause to occur: (a) distribution of this or any Project Gutenberg-tm
-work, (b) alteration, modification, or additions or deletions to any
-Project Gutenberg-tm work, and (c) any Defect you cause.
-
-
-Section 2. Information about the Mission of Project Gutenberg-tm
-
-Project Gutenberg-tm is synonymous with the free distribution of
-electronic works in formats readable by the widest variety of computers
-including obsolete, old, middle-aged and new computers. It exists
-because of the efforts of hundreds of volunteers and donations from
-people in all walks of life.
-
-Volunteers and financial support to provide volunteers with the
-assistance they need, is critical to reaching Project Gutenberg-tm's
-goals and ensuring that the Project Gutenberg-tm collection will
-remain freely available for generations to come. In 2001, the Project
-Gutenberg Literary Archive Foundation was created to provide a secure
-and permanent future for Project Gutenberg-tm and future generations.
-To learn more about the Project Gutenberg Literary Archive Foundation
-and how your efforts and donations can help, see Sections 3 and 4
-and the Foundation web page at http://www.pglaf.org.
-
-
-Section 3. Information about the Project Gutenberg Literary Archive
-Foundation
-
-The Project Gutenberg Literary Archive Foundation is a non profit
-501(c)(3) educational corporation organized under the laws of the
-state of Mississippi and granted tax exempt status by the Internal
-Revenue Service. The Foundation's EIN or federal tax identification
-number is 64-6221541. Its 501(c)(3) letter is posted at
-http://pglaf.org/fundraising. Contributions to the Project Gutenberg
-Literary Archive Foundation are tax deductible to the full extent
-permitted by U.S. federal laws and your state's laws.
-
-The Foundation's principal office is located at 4557 Melan Dr. S.
-Fairbanks, AK, 99712., but its volunteers and employees are scattered
-throughout numerous locations. Its business office is located at
-809 North 1500 West, Salt Lake City, UT 84116, (801) 596-1887, email
-business@pglaf.org. Email contact links and up to date contact
-information can be found at the Foundation's web site and official
-page at http://pglaf.org
-
-For additional contact information:
- Dr. Gregory B. Newby
- Chief Executive and Director
- gbnewby@pglaf.org
-
-
-Section 4. Information about Donations to the Project Gutenberg
-Literary Archive Foundation
-
-Project Gutenberg-tm depends upon and cannot survive without wide
-spread public support and donations to carry out its mission of
-increasing the number of public domain and licensed works that can be
-freely distributed in machine readable form accessible by the widest
-array of equipment including outdated equipment. Many small donations
-($1 to $5,000) are particularly important to maintaining tax exempt
-status with the IRS.
-
-The Foundation is committed to complying with the laws regulating
-charities and charitable donations in all 50 states of the United
-States. Compliance requirements are not uniform and it takes a
-considerable effort, much paperwork and many fees to meet and keep up
-with these requirements. We do not solicit donations in locations
-where we have not received written confirmation of compliance. To
-SEND DONATIONS or determine the status of compliance for any
-particular state visit http://pglaf.org
-
-While we cannot and do not solicit contributions from states where we
-have not met the solicitation requirements, we know of no prohibition
-against accepting unsolicited donations from donors in such states who
-approach us with offers to donate.
-
-International donations are gratefully accepted, but we cannot make
-any statements concerning tax treatment of donations received from
-outside the United States. U.S. laws alone swamp our small staff.
-
-Please check the Project Gutenberg Web pages for current donation
-methods and addresses. Donations are accepted in a number of other
-ways including checks, online payments and credit card donations.
-To donate, please visit: http://pglaf.org/donate
-
-
-Section 5. General Information About Project Gutenberg-tm electronic
-works.
-
-Professor Michael S. Hart is the originator of the Project Gutenberg-tm
-concept of a library of electronic works that could be freely shared
-with anyone. For thirty years, he produced and distributed Project
-Gutenberg-tm eBooks with only a loose network of volunteer support.
-
-
-Project Gutenberg-tm eBooks are often created from several printed
-editions, all of which are confirmed as Public Domain in the U.S.
-unless a copyright notice is included. Thus, we do not necessarily
-keep eBooks in compliance with any particular paper edition.
-
-
-Most people start at our Web site which has the main PG search facility:
-
- http://www.gutenberg.org
-
-This Web site includes information about Project Gutenberg-tm,
-including how to make donations to the Project Gutenberg Literary
-Archive Foundation, how to help produce our new eBooks, and how to
-subscribe to our email newsletter to hear about new eBooks.
diff --git a/nikola/data/samplesite/stories/dr-nikolas-vendetta.rst b/nikola/data/samplesite/stories/dr-nikolas-vendetta.rst
new file mode 100644
index 0000000..6175355
--- /dev/null
+++ b/nikola/data/samplesite/stories/dr-nikolas-vendetta.rst
@@ -0,0 +1,468 @@
+.. title: A BID FOR FORTUNE OR; DR. NIKOLA'S VENDETTA
+.. template: book.tmpl
+.. hyphenate: yes
+.. filters: filters.typogrify
+
+.. class:: subtitle
+
+By `GUY BOOTHBY <http://www.gutenberg.org/ebooks/author/3587>`__
+
+Author of "Dr. Nikola," "The Beautiful White Devil," etc., etc.
+
+.. figure:: /images/frontispiece.jpg
+ :class: bookfig
+
+.. topic:: The Project Gutenberg EBook of A Bid for Fortune, by Guy Boothby
+
+ This eBook is for the use of anyone anywhere at no cost and with
+ almost no restrictions whatsoever. You may copy it, give it away or
+ re-use it under the terms of the Project Gutenberg License included
+ with this eBook or online at www.gutenberg.org
+
+
+ Title: A Bid for Fortune
+ or Dr. Nikola's Vendetta
+
+ Author: `Guy Boothby <http://www.gutenberg.org/ebooks/author/3587>`__
+
+ Release Date: May 29, 2007 [EBook #21640]
+
+ Language: English
+
+ Produced by Marilynda Fraser-Cunliffe, Mary Meehan and the
+ Online Distributed Proofreading Team at http://www.pgdp.net
+
+ Originally published by:
+
+ WARD, LOCK & CO., LIMITED
+ LONDON, MELBOURNE AND TORONTO
+ 1918
+
+.. figure:: /images/illus_001.jpg
+ :class: bookfig
+
+PART I
+======
+
+PROLOGUE
+--------
+
+.. role:: smallcaps
+
+
+:smallcaps:`The` manager of the new Imperial Restaurant on the Thames Embankment went
+into his luxurious private office and shut the door. Having done so, he
+first scratched his chin reflectively, and then took a letter from the
+drawer in which it had reposed for more than two months and perused it
+carefully. Though he was not aware of it, this was the thirtieth time he
+had read it since breakfast that morning. And yet he was not a whit
+nearer understanding it than he had been at the beginning. He turned it
+over and scrutinized the back, where not a sign of writing was to be
+seen; he held it up to the window, as if he might hope to discover
+something from the water-mark; but there was nothing in either of these
+places of a nature calculated to set his troubled mind at rest. Then he
+took a magnificent repeater watch from his waistcoat pocket and glanced
+at the dial; the hands stood at half-past seven. He immediately threw
+the letter on the table, and as he did so his anxiety found relief in
+words.
+
+"It's really the most extraordinary affair I ever had to do with," he
+remarked. "And as I've been in the business just three-and-thirty years
+at eleven a.m. next Monday morning, I ought to know something about it.
+I only hope I've done right, that's all."
+
+As he spoke, the chief bookkeeper, who had the treble advantage of being
+tall, pretty, and just eight-and-twenty years of age, entered the room.
+She noticed the open letter and the look upon her chief's face, and her
+curiosity was proportionately excited.
+
+"You seem worried, Mr. McPherson," she said tenderly, as she put down
+the papers she had brought in for his signature.
+
+"You have just hit it, Miss O'Sullivan," he answered, pushing them
+farther on to the table. "I am worried about many things, but
+particularly about this letter."
+
+He handed the epistle to her, and she, being desirous of impressing him
+with her business capabilities, read it with ostentatious care. But it
+was noticeable that when she reached the signature she too turned back
+to the beginning, and then deliberately read it over again. The manager
+rose, crossed to the mantelpiece, and rang for the head waiter. Having
+relieved his feelings in this way, he seated himself again at his
+writing-table, put on his glasses, and stared at his companion, while
+waiting for her to speak.
+
+"It's very funny," she said. "Very funny indeed!"
+
+"It's the most extraordinary communication I have ever received," he
+replied with conviction. "You see it is written from Cuyaba, Brazil. The
+date is three months ago to a day. Now I have taken the trouble to find
+out where and what Cuyaba is."
+
+He made this confession with an air of conscious pride, and having done
+so, laid himself back in his chair, stuck his thumbs into the armholes
+of his waistcoat, and looked at his fair subordinate for approval. Nor
+was he destined to be disappointed. He was a bachelor in possession of a
+snug income, and she, besides being pretty, was a lady with a keen eye
+to the main chance.
+
+"And where *is* Cuyaba?" she asked humbly.
+
+"Cuyaba," he replied, rolling his tongue with considerable relish round
+his unconscious mispronunciation of the name, "is a town almost on the
+western or Bolivian border of Brazil. It is of moderate size, is
+situated on the banks of the river Cuyaba, and is considerably connected
+with the famous Brazilian Diamond Fields."
+
+"And does the writer of this letter live there?"
+
+"I cannot say. He writes from there--that is enough for us."
+
+"And he orders dinner for four--here, in a private room overlooking the
+river, three months ahead--punctually at eight o'clock, gives you a list
+of the things he wants, and even arranges the decoration of the table.
+Says he has never seen either of his three friends before; that one of
+them hails from (here she consulted the letter again) Hang-chow, another
+from Bloemfontein, while the third resides, at present, in England. Each
+one is to present an ordinary visiting card with a red dot on it to the
+porter in the hall, and to be shown to the room at once. I don't
+understand it at all."
+
+The manager paused for a moment, and then said deliberately,--"Hang-chow
+is in China, Bloemfontein is in South Africa."
+
+"What a wonderful man you are, to be sure, Mr. McPherson! I never can
+*think* how you manage to carry so much in your head."
+
+There spoke the true woman. And it was a move in the right direction,
+for the manager was susceptible to her gentle influence, as she had
+occasion to know.
+
+At this juncture the head waiter appeared upon the scene, and took up a
+position just inside the doorway, as if he were afraid of injuring the
+carpet by coming farther.
+
+"Is No. 22 ready, Williams?"
+
+"Quite ready, sir. The wine is on the ice, and cook tells me he'll be
+ready to dish punctual to the moment."
+
+"The letter says, 'no electric light; candles with red shades.' Have you
+put on those shades I got this morning?"
+
+"Just seen it done this very minute, sir."
+
+"And let me see, there was one other thing." He took the letter from the
+chief bookkeeper's hand and glanced at it. "Ah, yes, a porcelain saucer,
+and a small jug of new milk upon the mantelpiece. An extraordinary
+request, but has it been attended to?"
+
+"I put it there myself, sir."
+
+"Who wait?"
+
+"Jones, Edmunds, Brooks, and Tomkins."
+
+"Very good. Then I think that will do. Stay! You had better tell the
+hall porter to look out for three gentlemen presenting plain visiting
+cards with a little red spot on them. Let Brooks wait in the hall, and
+when they arrive tell him to show them straight up to the room."
+
+"It shall be done, sir."
+
+The head waiter left the room, and the manager stretched himself in his
+chair, yawned by way of showing his importance, and then said
+solemnly,--
+
+"I don't believe they'll any of them turn up; but if they do, this Dr.
+Nikola, whoever he may be, won't be able to find fault with my
+arrangements."
+
+Then, leaving the dusty high road of Business, he and his companion
+wandered in the shady bridle-paths of Love--to the end that when the
+chief bookkeeper returned to her own department she had forgotten the
+strange dinner party about to take place upstairs, and was busily
+engaged upon a calculation as to how she would look in white satin and
+orange blossoms, and, that settled, fell to wondering whether it was
+true, as Miss Joyce, a subordinate, had been heard to declare, that the
+manager had once shown himself partial to a certain widow with reputed
+savings and a share in an extensive egg and dairy business.
+
+At ten minutes to eight precisely a hansom drew up at the steps of the
+hotel. As soon as it stopped, an undersized gentleman, with a clean
+shaven countenance, a canonical corporation, and bow legs, dressed in a
+decidedly clerical garb, alighted. He paid and discharged his cabman,
+and then took from his ticket pocket an ordinary white visiting card,
+which he presented to the gold-laced individual who had opened the
+apron. The latter, having noted the red spot, called a waiter, and the
+reverend gentleman was immediately escorted upstairs.
+
+Hardly had the attendant time to return to his station in the hall,
+before a second cab made its appearance, closely followed by a third.
+Out of the second jumped a tall, active, well-built man of about thirty
+years of age. He was dressed in evening dress of the latest fashion, and
+to conceal it from the vulgar gaze, wore a large Inverness cape of heavy
+texture. He also in his turn handed a white card to the porter, and,
+having done so, proceeded into the hall, followed by the occupant of the
+last cab, who had closely copied his example. This individual was also
+in evening dress, but it was of a different stamp. It was old-fashioned
+and had seen much use. The wearer, too, was taller than the ordinary run
+of men, while it was noticeable that his hair was snow-white, and that
+his face was deeply pitted with smallpox. After disposing of their hats
+and coats in an ante-room, they reached room No. 22, where they found
+the gentleman in clerical costume pacing impatiently up and down.
+
+Left alone, the tallest of the trio, who for want of a better title we
+may call the Best Dressed Man, took out his watch, and having glanced at
+it, looked at his companions. "Gentlemen," he said, with a slight
+American accent, "it is three minutes to eight o'clock. My name is
+Eastover!"
+
+"I'm glad to hear it, for I'm most uncommonly hungry," said the next
+tallest, whom I have already described as being so marked by disease.
+"My name is Prendergast!"
+
+"We only wait for our friend and host," remarked the clerical gentleman,
+as if he felt he ought to take a share in the conversation, and then, as
+an afterthought, he continued, "My name is Baxter!"
+
+They shook hands all round with marked cordiality, seated themselves
+again, and took it in turns to examine the clock.
+
+"Have you ever had the pleasure of meeting our host before?" asked Mr.
+Baxter of Mr. Prendergast.
+
+"Never," replied that gentleman, with a shake of his head. "Perhaps Mr.
+Eastover has been more fortunate?"
+
+"Not I," was the brief rejoinder. "I've had to do with him off and on
+for longer than I care to reckon, but I've never set eyes on him up to
+date."
+
+"And where may he have been the first time you heard from him?"
+
+"In Nashville, Tennessee," said Eastover. "After that, Tahupapa, New
+Zealand; after that, Papeete, in the Society Islands; then Pekin, China.
+And you?"
+
+"First time, Brussels; second, Monte Video; third, Mandalay, and then
+the Gold Coast, Africa. It's your turn, Mr. Baxter."
+
+The clergyman glanced at the timepiece. It was exactly eight o'clock.
+"First time, Cabul, Afghanistan; second, Nijni Novgorod, Russia; third,
+Wilcannia, Darling River, Australia; fourth, Valparaiso, Chili; fifth,
+Nagasaki, Japan."
+
+"He is evidently a great traveller and a most mysterious person."
+
+"He is more than that," said Eastover with conviction; "he is late for
+dinner!"
+
+Prendergast looked at his watch.
+
+"That clock is two minutes fast. Hark, there goes Big Ben! Eight
+exactly."
+
+As he spoke the door was thrown open and a voice announced "Dr. Nikola."
+
+The three men sprang to their feet simultaneously, with exclamations of
+astonishment, as the man they had been discussing made his appearance.
+
+It would take more time than I can spare the subject to give you an
+adequate and inclusive description of the person who entered the room at
+that moment. In stature he was slightly above the ordinary, his
+shoulders were broad, his limbs perfectly shaped and plainly muscular,
+but very slim. His head, which was magnificently set upon his shoulders,
+was adorned with a profusion of glossy black hair; his face was
+destitute of beard or moustache, and was of oval shape and handsome
+moulding; while his skin was of a dark olive hue, a colour which
+harmonized well with his piercing black eyes and pearly teeth. His hands
+and feet were small, and the greatest dandy must have admitted that he
+was irreproachably dressed, with a neatness that bordered on the
+puritanical. In age he might have been anything from eight-and-twenty to
+forty; in reality he was thirty-three. He advanced into the room and
+walked with out-stretched hand directly across to where Eastover was
+standing by the fireplace.
+
+"Mr. Eastover, I feel certain," he said, fixing his glittering eyes upon
+the man he addressed, and allowing a curious smile to play upon his
+face.
+
+"That is my name, Dr. Nikola," the other answered with evident surprise.
+"But how on earth can you distinguish me from your other guests?"
+
+"Ah! it would surprise you if you knew. And Mr. Prendergast, and Mr.
+Baxter. This is delightful; I hope I am not late. We had a collision in
+the Channel this morning, and I was almost afraid I might not be up to
+time. Dinner seems ready; shall we sit down to it?" They seated
+themselves, and the meal commenced. The Imperial Restaurant has earned
+an enviable reputation for doing things well, and the dinner that night
+did not in any way detract from its lustre. But, delightful as it all
+was, it was noticeable that the three guests paid more attention to
+their host than to his excellent *menu*. As they had said before his
+arrival, they had all had dealings with him for several years, but what
+those dealings were they were careful not to describe. It was more than
+possible that they hardly liked to remember them themselves.
+
+When coffee had been served and the servants had withdrawn, Dr. Nikola
+rose from the table, and went across to the massive sideboard. On it
+stood a basket of very curious shape and workmanship. This he opened,
+and as he did so, to the astonishment of his guests, an enormous cat, as
+black as his master's coat, leaped out on to the floor. The reason for
+the saucer and jug of milk became evident.
+
+Seating himself at the table again, the host followed the example of his
+guests and lit a cigar, blowing a cloud of smoke luxuriously through his
+delicately chiselled nostrils. His eyes wandered round the cornice of
+the room, took in the pictures and decorations, and then came down to
+meet the faces of his companions. As they did so, the black cat, having
+finished its meal, sprang on to his shoulder to crouch there, watching
+the three men through the curling smoke drift with its green blinking,
+fiendish eyes. Dr. Nikola smiled as he noticed the effect the animal had
+upon his guests.
+
+"Now shall we get to business?" he said briskly.
+
+The others almost simultaneously knocked the ashes off their cigars and
+brought themselves to attention. Dr. Nikola's dainty, languid manner
+seemed to drop from him like a cloak, his eyes brightened, and his
+voice, when he spoke, was clean cut as chiselled silver.
+
+"You are doubtless anxious to be informed why I summoned you from all
+parts of the globe to meet me here to-night? And it is very natural you
+should be. But then, from what you know of me, you should not be
+surprised at anything I do."
+
+His voice dropped back into its old tone of gentle languor. He drew in a
+great breath of smoke and then sent it slowly out from his lips again.
+His eyes were half closed, and he drummed with one finger on the table
+edge. The cat looked through the smoke at the three men, and it seemed
+to them that he grew every moment larger and more ferocious. Presently
+his owner took him from his perch, and seating him on his knee fell to
+stroking his fur, from head to tail, with his long slim fingers. It was
+as if he were drawing inspiration for some deadly mischief from the
+uncanny beast.
+
+"To preface what I have to say to you, let me tell you that this is by
+far the most important business for which I have ever required your
+help. (Three slow strokes down the centre of the back, and one round
+each ear.) When it first came into my mind I was at a loss who to trust
+in the matter. I thought of Vendon, but I found Vendon was dead. I
+thought of Brownlow, but Brownlow was no longer faithful. (Two strokes
+down the back and two on the throat.) Then bit by bit I remembered you.
+I was in Brazil at the time. So I sent for you. You came. So far so
+good."
+
+He rose, and crossed over to the fireplace. As he went the cat crawled
+back to its original position on his shoulder. Then his voice changed
+once more to its former business-like tone.
+
+"I am not going to tell you very much about it. But from what I do tell
+you, you will be able to gather a great deal and imagine the rest. To
+begin with, there is a man living in this world to-day who has done me a
+great and lasting injury. What that injury is is no concern of yours.
+You would not understand if I told you. So we'll leave that out of the
+question. He is immensely rich. His cheque for £300,000 would be
+honoured by his bank at any minute. Obviously he is a power. He has had
+reason to know that I am pitting my wits against his, and he flatters
+himself that so far he has got the better of me. That is because I am
+drawing him on. I am maturing a plan which will make him a poor and a
+very miserable man at one and the same time. If that scheme succeeds,
+and I am satisfied with the way you three men have performed the parts I
+shall call on you to play in it, I shall pay to each of you the sum of
+£10,000. If it doesn't succeed, then you will each receive a thousand
+and your expenses. Do you follow me?"
+
+It was evident from their faces that they hung upon his every word.
+
+"But, remember, I demand from you your whole and entire labour. While
+you are serving me you are mine body and soul. I know you are
+trustworthy. I have had good proof that you are--pardon the
+expression--unscrupulous, and I flatter myself you are silent. What is
+more, I shall tell you nothing beyond what is necessary for the carrying
+out of my scheme, so that you could not betray me if you would. Now for
+my plans!"
+
+He sat down again and took a paper from his pocket. Having perused it,
+he turned to Eastover.
+
+"You will leave at once--that is to say, by the boat on Wednesday--for
+Sydney. You will book your passage to-morrow morning, first thing, and
+join her in Plymouth. You will meet me to-morrow evening at an address I
+will send you, and receive your final instructions. Good-night."
+
+Seeing that he was expected to go, Eastover rose, shook hands, and left
+the room without a word. He was too astonished to hesitate or to say
+anything.
+
+Nikola took another letter from his pocket and turned to Prendergast.
+"*You* will go down to Dover to-night, cross to Paris to-morrow morning,
+and leave this letter personally at the address you will find written on
+it. On Thursday, at half-past two precisely, you will deliver me an
+answer in the porch at Charing Cross. You will find sufficient money in
+that envelope to pay all your expenses. Now go!"
+
+"At half-past two you shall have your answer. Good-night."
+
+"Good-night."
+
+When Prendergast had left the room, Dr. Nikola lit another cigar and
+turned his attentions to Mr. Baxter.
+
+"Six months ago, Mr. Baxter, I found for you a situation as tutor to the
+young Marquis of Beckenham. You still hold it, I suppose?"
+
+"I do."
+
+"Is the father well disposed towards you?"
+
+"In every way. I have done my best to ingratiate myself with him. That
+was one of your instructions."
+
+"Yes, yes! But I was not certain that you would succeed. If the old man
+is anything like what he was when I last met him he must still be a
+difficult person to deal with. Does the boy like you?"
+
+"I hope so."
+
+"Have you brought me his photograph as I directed?"
+
+"I have. Here it is."
+
+Baxter took a photograph from his pocket and handed it across the table.
+
+"Good. You have done very well, Mr. Baxter. I am pleased with you.
+To-morrow morning you will go back to Yorkshire----"
+
+"I beg your pardon, Bournemouth. His Grace owns a house near
+Bournemouth, which he occupies during the summer months."
+
+"Very well--then to-morrow morning you will go back to Bournemouth and
+continue to ingratiate yourself with father and son. You will also begin
+to implant in the boy's mind a desire for travel. Don't let him become
+aware that his desire has its source in you--but do not fail to foster
+it all you can. I will communicate with you further in a day or two. Now
+go."
+
+Baxter in his turn left the room. The door closed. Dr. Nikola picked up
+the photograph and studied it.
+
+"The likeness is unmistakable--or it ought to be. My friend, my very
+dear friend, Wetherell, my toils are closing on you. My arrangements are
+perfecting themselves admirably. Presently, when all is complete, I
+shall press the lever, the machinery will be set in motion, and you will
+find yourself being slowly but surely ground into powder. Then you will
+hand over what I want, and be sorry you thought fit to baulk Dr.
+Nikola!"
+
+He rang the bell and ordered his bill. This duty discharged, he placed
+the cat back in its prison, shut the lid, descended with the basket to
+the hall, and called a hansom. The porter inquired to what address he
+should order the cabman to drive. Dr. Nikola did not reply for a moment,
+then he said, as if he had been thinking something out: "The *Green
+Sailor* public-house, East India Dock Road."
+
+
+------------------------
+
+You can read the rest of "A Bid For Fortune; Or, Dr. Nikola's Vendetta" at `Open Library <https://archive.org/stream/bidforfortunenov00bootiala#page/12/mode/2up>`__
diff --git a/nikola/data/samplesite/stories/path_handlers.txt b/nikola/data/samplesite/stories/path_handlers.txt
new file mode 120000
index 0000000..cce056b
--- /dev/null
+++ b/nikola/data/samplesite/stories/path_handlers.txt
@@ -0,0 +1 @@
+../../../../docs/path_handlers.txt \ No newline at end of file
diff --git a/nikola/data/samplesite/stories/quickref.rst b/nikola/data/samplesite/stories/quickref.rst
index bf5324f..7cc91bd 100644
--- a/nikola/data/samplesite/stories/quickref.rst
+++ b/nikola/data/samplesite/stories/quickref.rst
@@ -1,9 +1,10 @@
.. title: A reStructuredText Reference
.. slug: quickref
.. date: 2012-03-30 23:00:00 UTC-03:00
-.. tags:
-.. link:
-.. description:
+.. tags:
+.. link:
+.. description:
+.. author: docutils contributors
.. raw:: html
@@ -78,7 +79,7 @@
character styles (like italics and boldface) and functionality
(like hyperlinks).
- <p><table border="1" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" class="table" border="1" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th>Plain text
@@ -212,7 +213,7 @@
themselves. To get a literal backslash, use an escaped backslash
("\\"). For example:
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Raw reStructuredText
@@ -232,7 +233,7 @@
<em>reach</em> reStructuredText.
The simplest way to do this is to use raw strings:
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Python string
@@ -255,7 +256,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#sections">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -301,7 +302,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#paragraphs">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -329,7 +330,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#bullet-lists">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -367,7 +368,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#enumerated-lists">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -405,7 +406,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#definition-lists">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -446,7 +447,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#field-lists">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -464,7 +465,7 @@
<p><samp>:Version:&nbsp;1.0&nbsp;of&nbsp;2001/08/08</samp>
<br><samp>:Dedication:&nbsp;To&nbsp;my&nbsp;father.</samp>
<td>
- <table>
+ <table class="table" >
<tr valign="top">
<td><strong>Authors:</strong>
<td>Tony J. (Tibs) Ibbs,
@@ -485,7 +486,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#option-lists">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -505,7 +506,7 @@
</samp>
<td>
- <table border="0" width="100%">
+ <table class="table" border="0" width="100%">
<tbody valign="top">
<tr>
<td width="30%"><samp>-a</samp>
@@ -533,7 +534,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#literal-blocks">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -622,7 +623,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#line-blocks">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -664,7 +665,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#block-quotes">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -696,7 +697,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#doctest-blocks">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -736,7 +737,7 @@
tables are complete but cumbersome to create. Simple tables are
easy to create but limited (no row spans, etc.).</p>
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -760,7 +761,7 @@
<br><samp>+------------+------------+-----------+</samp></p>
<td>
<p>Grid table:</p>
- <table border="1">
+ <table class="table" border="1">
<thead valign="bottom">
<tr>
<th>Header 1
@@ -809,7 +810,7 @@
<td>
<p>Simple table:</p>
- <table border="1">
+ <table class="table" border="1">
<colgroup>
<col width="31%">
<col width="31%">
@@ -849,7 +850,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#transitions">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -899,7 +900,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#footnotes">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -922,7 +923,7 @@
Note that footnotes may get rearranged, e.g., to the bottom of
the "page".
- <p><table>
+ <p><table class="table" >
<tr><td colspan="2"><hr>
<!-- <tr><td colspan="2">Footnotes: -->
<tr><td><a name="5"><strong>[5]</strong></a><td> A numerical footnote.
@@ -950,7 +951,7 @@
<sup><a href="#fourth">4</a></sup> and <sup><a
href="#third">3</a></sup>.
- <p><table>
+ <p><table class="table" >
<tr><td colspan="2"><hr>
<!-- <tr><td colspan="2">Footnotes: -->
<tr><td><a name="auto1"><strong>[1]</strong></a><td> This is the first one.
@@ -971,7 +972,7 @@
possible, like this: <sup><a href="#symbol1">*</a></sup>
and <sup><a href="#symbol2">&dagger;</a></sup>.
- <p><table>
+ <p><table class="table" >
<tr><td colspan="2"><hr>
<!-- <tr><td colspan="2">Footnotes: -->
<tr><td><a name="symbol1"><strong>[*]</strong></a><td> This is the first symbol footnote
@@ -992,7 +993,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#citations">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1030,7 +1031,7 @@
<p>Given a citation like <a href="#this">[this]</a>, one
can also refer to it like <a href="#this">this</a>.
- <p><table>
+ <p><table class="table" >
<tr><td colspan="2"><hr>
<!-- <tr><td colspan="2">Citations: -->
<tr><td><a name="cit2002"><strong>[CIT2002]</strong></a><td> A citation
@@ -1048,7 +1049,7 @@
<h4><a href="#contents" name="external-hyperlink-targets" class="backref"
>External Hyperlink Targets</a></h4>
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1062,19 +1063,19 @@
<p><samp>..&nbsp;_Python:&nbsp;http://www.python.org/</samp>
<td>
- <table width="100%">
+ <table class="table" width="100%">
<tr bgcolor="#99CCFF"><td><em>Fold-in form</em>
<tr><td>External hyperlinks, like
<a href="http://www.python.org/">Python</a>.
</table>
<tr valign="top">
<td>
- <table width="100%">
+ <table class="table" width="100%">
<tr bgcolor="#99CCFF"><td><em>Call-out form</em>
<tr><td>External hyperlinks, like
<a href="#labPython"><i>Python</i></a>.
- <p><table>
+ <p><table class="table" >
<tr><td colspan="2"><hr>
<tr><td><a name="labPython"><i>Python:</i></a>
<td> <a href="http://www.python.org/">http://www.python.org/</a>
@@ -1097,7 +1098,7 @@
reference may directly embed a target URI inline, within angle
brackets. The following is exactly equivalent to the example above:
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1116,7 +1117,7 @@
<h4><a href="#contents" name="internal-hyperlink-targets" class="backref"
>Internal Hyperlink Targets</a></h4>
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1131,7 +1132,7 @@
<p><samp>This&nbsp;is&nbsp;an&nbsp;example&nbsp;crossreference&nbsp;target.</samp>
<td>
- <table width="100%">
+ <table class="table" width="100%">
<tr bgcolor="#99CCFF"><td><em>Fold-in form</em>
<!-- Note that some browsers may not like an "a" tag that -->
<!-- does not have any content, so we could arbitrarily -->
@@ -1143,7 +1144,7 @@
</table>
<tr valign="top">
<td>
- <table width="100%">
+ <table class="table" width="100%">
<tr><td bgcolor="#99CCFF"><em>Call-out form</em>
<tr><td>Internal crossreferences, like <a href="#example-callout">example</a>
@@ -1158,7 +1159,7 @@
<p>(<a href="http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#indirect-hyperlink-targets">details</a>)
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1202,7 +1203,7 @@
hyperlink targets (the title text or footnote/citation label is
used as the hyperlink name).
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead><tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
<th width="50%">Typical result
@@ -1232,7 +1233,7 @@
href="http://docutils.sourceforge.net/docs/ref/rst/directives.html" >reStructuredText
Directives</a>.
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1257,7 +1258,7 @@
<p>Substitutions are like inline directives, allowing graphics and
arbitrary constructs within text.
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
@@ -1287,7 +1288,7 @@
<p>Any text which begins with an explicit markup start but doesn't
use the syntax of any of the constructs above, is a comment.
- <p><table border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
+ <p><table class="table" border="1" width="100%" bgcolor="#ffffcc" cellpadding="3">
<thead>
<tr align="left" bgcolor="#99CCFF">
<th width="50%">Plain text
diff --git a/nikola/data/samplesite/templates/book.tmpl b/nikola/data/samplesite/templates/book.tmpl
new file mode 100644
index 0000000..a44f088
--- /dev/null
+++ b/nikola/data/samplesite/templates/book.tmpl
@@ -0,0 +1,117 @@
+## -*- coding: utf-8 -*-
+<%namespace name="helper" file="post_helper.tmpl"/>
+<%namespace name="pheader" file="post_header.tmpl"/>
+<%namespace name="comments" file="comments_helper.tmpl"/>
+<%inherit file="post.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ <link href='https://fonts.googleapis.com/css?family=Gentium+Book+Basic' rel='stylesheet' type='text/css'>
+ <style>
+ .smallcaps {
+ font-variant: small-caps;
+ }
+ .chapter {
+ width: 100%;
+ padding: 10px;
+ -webkit-column-gap: 40px;
+ -moz-column-gap: 40px;
+ column-gap: 40px;
+ -webkit-column-width: 400px;
+ -moz-column-width: 400px;
+ column-width: 400px;
+ -webkit-column-count: 2;
+ -moz-column-count: 2;
+ column-count: 2;
+ -webkit-column-rule: 1px solid #ddd;
+ -moz-column-rule: 1px solid #ddd;
+ column-rule: 1px solid #ddd;
+ height: 90vh;
+ font-family: 'Gentium Book Basic', serif;
+ color: #2d2e2e;
+ font-weight: 500;
+ }
+ div.frame {
+ overflow: hidden;
+ padding: 0;
+ margin: 0;
+ }
+ div.scrolling-cont {
+ overflow-x: scroll;
+ padding: 0;
+ margin: 0;
+ }
+ h1, h2, h3, h4 {
+ text-align: center;
+ width: 100%;
+ font-family: 'Gentium Book Basic', serif;
+ font-size: 120%;
+ font-weight: 900;
+ }
+ h1 {
+ font-size: 150%;
+ }
+ .subtitle {
+ text-align: center;
+ width: 100%;
+ }
+ .bookfig {
+ width: 100%;
+ height: auto;
+ max-width: 100%;
+ max-height: 100%;
+ }
+ div.figure {
+ height: 88vh;
+ margin: 0;
+ }
+ div.topic {
+ margin: 0;
+ }
+ div.section > p {
+ text-indent: 1em;
+ margin-bottom: 0;
+ text-align: justify;
+ }
+ </style>
+</%block>
+
+<%block name="content">
+<article class="storypage" itemscope="itemscope" itemtype="http://schema.org/Article">
+ <div class="frame">
+ <div class="scrolling-cont" id="scrolling-cont" name="scrolling-cont">
+ <div class="e-content entry-content chapter" itemprop="articleBody text">
+ <h1>${post.title()}</h1>
+ ${post.text()}
+ </div>
+ </div>
+ </div>
+</article>
+</%block>
+
+<%block name="extra_js">
+ <script src="//cdnjs.cloudflare.com/ajax/libs/Flowtype.js/1.1.0/flowtype.min.js"></script>
+ <script>
+ $('#scrolling-cont').flowtype({
+ minimum: 500,
+ maximum: 1200,
+ minFont: 20,
+ maxFont: 40,
+ fontRatio: 50
+ });
+ $(document).ready(function() {
+ var elem = $('#scrolling-cont');
+ elem.click(function(event) {
+ var x1 = elem.position().left;
+ var pw = elem.width() + 20;
+ var x2 = event.pageX;
+ if (x2 - x1 < pw / 2) {
+ pw = -pw;
+ }
+ elem.animate({
+ scrollLeft: '+=' + pw
+ }, 500)
+ });
+ });
+ </script>
+</%block>
diff --git a/nikola/data/symlinked.txt b/nikola/data/symlinked.txt
index ce34ddf..a5d48b2 100644
--- a/nikola/data/symlinked.txt
+++ b/nikola/data/symlinked.txt
@@ -3,12 +3,14 @@ docs/sphinx/creating-a-theme.txt
docs/sphinx/extending.txt
docs/sphinx/internals.txt
docs/sphinx/manual.txt
+docs/sphinx/path_handlers.txt
docs/sphinx/social_buttons.txt
docs/sphinx/theming.txt
nikola/data/samplesite/stories/creating-a-theme.rst
nikola/data/samplesite/stories/extending.txt
nikola/data/samplesite/stories/internals.txt
nikola/data/samplesite/stories/manual.rst
+nikola/data/samplesite/stories/path_handlers.txt
nikola/data/samplesite/stories/social_buttons.txt
nikola/data/samplesite/stories/theming.rst
nikola/data/symlink-test-link.txt
diff --git a/nikola/data/themes/base-jinja/templates/author.tmpl b/nikola/data/themes/base-jinja/templates/author.tmpl
new file mode 100644
index 0000000..1604939
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/author.tmpl
@@ -0,0 +1,43 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'list_post.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if translations|length > 1 and generate_rss %}
+ {% for language in translations|sort %}
+ <link rel="alternate" type="application/rss+xml" title="RSS for {{ kind }} {{ author|e }} ({{ language }})" href="{{ _link(kind + "_rss", author, language) }}">
+ {% endfor %}
+ {% elif generate_rss %}
+ <link rel="alternate" type="application/rss+xml" title="RSS for {{ kind }} {{ author|e }}" href="{{ _link(kind + "_rss", author) }}">
+ {% endif %}
+{% endblock %}
+
+
+{% block content %}
+<article class="authorpage">
+ <header>
+ <h1>{{ title|e }}</h1>
+ {% if description %}
+ <p>{{ description }}</p>
+ {% endif %}
+ <div class="metadata">
+ {% if translations|length > 1 and generate_rss %}
+ {% for language in translations|sort %}
+ <p class="feedlink">
+ <a href="{{ _link(kind + "_rss", author, language) }}" hreflang="{{ language }}" type="application/rss+xml">{{ messages('RSS feed', language) }} ({{ language }})</a>&nbsp;
+ </p>
+ {% endfor %}
+ {% elif generate_rss %}
+ <p class="feedlink"><a href="{{ _link(kind + "_rss", author) }}" type="application/rss+xml">{{ messages('RSS feed') }}</a></p>
+ {% endif %}
+ </div>
+ </header>
+ {% if posts %}
+ <ul class="postlist">
+ {% for post in posts %}
+ <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title()|e }}</a><time class="listdate" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format)|e }}">{{ post.formatted_date(date_format)|e }}</time></li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/authorindex.tmpl b/nikola/data/themes/base-jinja/templates/authorindex.tmpl
new file mode 100644
index 0000000..3c40ee1
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/authorindex.tmpl
@@ -0,0 +1,13 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'index.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if tranlations|length > 1 and generate_atom %}
+ {% for language in translations|sort %}
+ <link rel="alternate" type="application/atom+xml" title="Atom for the {{ author|e }} section ({{ language }})" href="{{ _link(kind + "_atom", author, language) }}">
+ {% endfor %}
+ {% elif generate_atom %}
+ <link rel="alternate" type="application/atom+xml" title="Atom for the {{ author|e }} section" href="{{ _link("author" + "_atom", author) }}">
+ {% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/authors.tmpl b/nikola/data/themes/base-jinja/templates/authors.tmpl
new file mode 100644
index 0000000..8b6ea64
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/authors.tmpl
@@ -0,0 +1,17 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+<article class="authorindex">
+ {% if items %}
+ <h2>{{ messages("Authors") }}</h2>
+ <ul class="postlist">
+ {% for text, link in items %}
+ {% if text not in hidden_authors %}
+ <li><a class="reference listtitle" href="{{ link }}">{{ text|e }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+ {% endif %}
+</article>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/base_header.tmpl b/nikola/data/themes/base-jinja/templates/base_header.tmpl
index 092abd8..d9370d7 100644
--- a/nikola/data/themes/base-jinja/templates/base_header.tmpl
+++ b/nikola/data/themes/base-jinja/templates/base_header.tmpl
@@ -16,13 +16,13 @@
{% endmacro %}
{% macro html_site_title() %}
- <h1 id="brand"><a href="{{ abs_link(_link("root", None, lang)) }}" title="{{ blog_title }}" rel="home">
+ <h1 id="brand"><a href="{{ abs_link(_link("root", None, lang)) }}" title="{{ blog_title|e }}" rel="home">
{% if logo_url %}
- <img src="{{ logo_url }}" alt="{{ blog_title }}" id="logo">
+ <img src="{{ logo_url }}" alt="{{ blog_title|e }}" id="logo">
{% endif %}
{% if show_blog_title %}
- <span id="blog-title">{{ blog_title }}</span>
+ <span id="blog-title">{{ blog_title|e }}</span>
{% endif %}
</a></h1>
{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/base_helper.tmpl b/nikola/data/themes/base-jinja/templates/base_helper.tmpl
index 8b4ed97..66d82e9 100644
--- a/nikola/data/themes/base-jinja/templates/base_helper.tmpl
+++ b/nikola/data/themes/base-jinja/templates/base_helper.tmpl
@@ -21,9 +21,11 @@ dir="rtl"
lang="{{ lang }}">
<head>
<meta charset="utf-8">
+ {% if use_base_tag %}
<base href="{{ abs_link(permalink) }}">
+ {% endif %}
{% if description %}
- <meta name="description" content="{{ description }}">
+ <meta name="description" content="{{ description|e }}">
{% endif %}
<meta name="viewport" content="width=device-width">
{% if title == blog_title %}
@@ -33,6 +35,7 @@ lang="{{ lang }}">
{% endif %}
{{ html_stylesheets() }}
+ <meta content="{{ theme_color }}" name="theme-color">
{{ html_feedlinks() }}
<link rel="canonical" href="{{ abs_link(permalink) }}">
diff --git a/nikola/data/themes/base-jinja/templates/gallery.tmpl b/nikola/data/themes/base-jinja/templates/gallery.tmpl
index 0a53ebe..01452e4 100644
--- a/nikola/data/themes/base-jinja/templates/gallery.tmpl
+++ b/nikola/data/themes/base-jinja/templates/gallery.tmpl
@@ -17,8 +17,8 @@
{% if folders %}
<ul>
{% for folder, ftitle in folders %}
- <li><a href="{{ folder }}"><i
- class="icon-folder-open"></i>&nbsp;{{ ftitle }}</a></li>
+ <li><a href="{{ folder|urlencode }}"><i
+ class="icon-folder-open"></i>&nbsp;{{ ftitle|e }}</a></li>
{% endfor %}
</ul>
{% endif %}
@@ -26,7 +26,7 @@
<ul class="thumbnails">
{% for image in photo_array %}
<li><a href="{{ image['url'] }}" class="thumbnail image-reference" title="{{ image['title'] }}">
- <img src="{{ image['url_thumb'] }}" alt="{{ image['title'] }}" /></a>
+ <img src="{{ image['url_thumb'] }}" alt="{{ image['title']|e }}" /></a>
{% endfor %}
</ul>
{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/index.tmpl b/nikola/data/themes/base-jinja/templates/index.tmpl
index 222da43..a36bac3 100644
--- a/nikola/data/themes/base-jinja/templates/index.tmpl
+++ b/nikola/data/themes/base-jinja/templates/index.tmpl
@@ -18,8 +18,14 @@
<header>
<h1 class="p-name entry-title"><a href="{{ post.permalink() }}" class="u-url">{{ post.title()|e }}</a></h1>
<div class="metadata">
- <p class="byline author vcard"><span class="byline-name fn">{{ post.author() }}</span></p>
- <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format) }}">{{ post.formatted_date(date_format) }}</time></a></p>
+ <p class="byline author vcard"><span class="byline-name fn">
+ {% if author_pages_generated %}
+ <a href="{{ _link('author', post.author()) }}">{{ post.author()|e }}</a>
+ {% else %}
+ {{ post.author()|e }}
+ {% endif %}
+ </span></p>
+ <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format)|e }}">{{ post.formatted_date(date_format)|e }}</time></a></p>
{% if not post.meta('nocomments') and site_has_comments %}
<p class="commentline">{{ comments.comment_link(post.permalink(), post._base_path) }}
{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/index_helper.tmpl b/nikola/data/themes/base-jinja/templates/index_helper.tmpl
index 2f9e8ea..64b4d12 100644
--- a/nikola/data/themes/base-jinja/templates/index_helper.tmpl
+++ b/nikola/data/themes/base-jinja/templates/index_helper.tmpl
@@ -20,8 +20,17 @@
{% macro mathjax_script(posts) %}
{% if posts|selectattr("is_mathjax")|list %}
- <script type="text/x-mathjax-config">
- MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
- <script src="/assets/js/mathjax.js"></script>
+ {% if use_katex %}
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/contrib/auto-render.min.js"></script>
+ <script>
+ renderMathInElement(document.body);
+ </script>
+ {% else %}
+ <script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script>
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
+ </script>
+ {% endif %}
{% endif %}
{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/list.tmpl b/nikola/data/themes/base-jinja/templates/list.tmpl
index e442864..c9c330b 100644
--- a/nikola/data/themes/base-jinja/templates/list.tmpl
+++ b/nikola/data/themes/base-jinja/templates/list.tmpl
@@ -4,12 +4,15 @@
{% block content %}
<article class="listpage">
<header>
- <h1>{{ title }}</h1>
+ <h1>{{ title|e }}</h1>
</header>
{% if items %}
<ul class="postlist">
- {% for text, link in items %}
- <li><a href="{{ link }}">{{ text }}</a>
+ {% for text, link, count in items %}
+ <li><a href="{{ link }}">{{ text|e }}</a>
+ {% if count %}
+ ({{ count }})
+ {% endif %}
{% endfor %}
</ul>
{% else %}
diff --git a/nikola/data/themes/base-jinja/templates/list_post.tmpl b/nikola/data/themes/base-jinja/templates/list_post.tmpl
index 919d6f0..83f4bcf 100644
--- a/nikola/data/themes/base-jinja/templates/list_post.tmpl
+++ b/nikola/data/themes/base-jinja/templates/list_post.tmpl
@@ -4,12 +4,12 @@
{% block content %}
<article class="listpage">
<header>
- <h1>{{ title }}</h1>
+ <h1>{{ title|e }}</h1>
</header>
{% if posts %}
<ul class="postlist">
{% for post in posts %}
- <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title()|e }}</a> <time class="listdate" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format) }}">{{ post.formatted_date(date_format) }}</time></li>
+ <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title()|e }}</a> <time class="listdate" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format)|e }}">{{ post.formatted_date(date_format)|e }}</time></li>
{% endfor %}
</ul>
{% else %}
diff --git a/nikola/data/themes/base-jinja/templates/listing.tmpl b/nikola/data/themes/base-jinja/templates/listing.tmpl
index ccbc5ba..281630d 100644
--- a/nikola/data/themes/base-jinja/templates/listing.tmpl
+++ b/nikola/data/themes/base-jinja/templates/listing.tmpl
@@ -6,10 +6,10 @@
{% if folders or files %}
<ul>
{% for name in folders %}
- <li><a href="{{ name }}"><i class="icon-folder-open"></i> {{ name }}</a>
+ <li><a href="{{ name|urlencode }}"><i class="icon-folder-open"></i> {{ name|e }}</a>
{% endfor %}
{% for name in files %}
- <li><a href="{{ name }}.html"><i class="icon-file"></i> {{ name }}</a>
+ <li><a href="{{ name|urlencode }}.html"><i class="icon-file"></i> {{ name|e }}</a>
{% endfor %}
</ul>
{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/post.tmpl b/nikola/data/themes/base-jinja/templates/post.tmpl
index 28da35e..5e4d9a5 100644
--- a/nikola/data/themes/base-jinja/templates/post.tmpl
+++ b/nikola/data/themes/base-jinja/templates/post.tmpl
@@ -10,9 +10,9 @@
<meta name="keywords" content="{{ post.meta('keywords')|e }}">
{% endif %}
{% if post.description() %}
- <meta name="description" content="{{ post.description() }}">
+ <meta name="description" content="{{ post.description()|e }}">
{% endif %}
- <meta name="author" content="{{ post.author() }}">
+ <meta name="author" content="{{ post.author()|e }}">
{% if post.prev_post %}
<link rel="prev" href="{{ post.prev_post.permalink() }}" title="{{ post.prev_post.title()|e }}" type="text/html">
{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/post_header.tmpl b/nikola/data/themes/base-jinja/templates/post_header.tmpl
index dc844e3..6b81120 100644
--- a/nikola/data/themes/base-jinja/templates/post_header.tmpl
+++ b/nikola/data/themes/base-jinja/templates/post_header.tmpl
@@ -31,17 +31,23 @@
<header>
{{ html_title() }}
<div class="metadata">
- <p class="byline author vcard"><span class="byline-name fn">{{ post.author() }}</span></p>
- <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.formatted_date('webiso') }}" itemprop="datePublished" title="{{ post.formatted_date(date_format) }}">{{ post.formatted_date(date_format) }}</time></a></p>
+ <p class="byline author vcard"><span class="byline-name fn">
+ {% if author_pages_generated %}
+ <a href="{{ _link('author', post.author()) }}">{{ post.author()|e }}</a>
+ {% else %}
+ {{ post.author()|e }}
+ {% endif %}
+ </span></p>
+ <p class="dateline"><a href="{{ post.permalink() }}" rel="bookmark"><time class="published dt-published" datetime="{{ post.formatted_date('webiso') }}" itemprop="datePublished" title="{{ post.formatted_date(date_format)|e }}">{{ post.formatted_date(date_format)|e }}</time></a></p>
{% if not post.meta('nocomments') and site_has_comments %}
<p class="commentline">{{ comments.comment_link(post.permalink(), post._base_path) }}
{% endif %}
{{ html_sourcelink() }}
{% if post.meta('link') %}
- <p class="linkline"><a href='{{ post.meta('link') }}'>{{ messages("Original site") }}</a></p>
+ <p class="linkline"><a href="{{ post.meta('link') }}">{{ messages("Original site") }}</a></p>
{% endif %}
{% if post.description() %}
- <meta name="description" itemprop="description" content="{{ post.description() }}">
+ <meta name="description" itemprop="description" content="{{ post.description()|e }}">
{% endif %}
</div>
{{ html_translations(post) }}
diff --git a/nikola/data/themes/base-jinja/templates/post_helper.tmpl b/nikola/data/themes/base-jinja/templates/post_helper.tmpl
index b4826eb..f5de54a 100644
--- a/nikola/data/themes/base-jinja/templates/post_helper.tmpl
+++ b/nikola/data/themes/base-jinja/templates/post_helper.tmpl
@@ -15,7 +15,7 @@
<ul itemprop="keywords" class="tags">
{% for tag in post.tags %}
{% if tag not in hidden_tags %}
- <li><a class="tag p-category" href="{{ _link('tag', tag) }}" rel="tag">{{ tag }}</a></li>
+ <li><a class="tag p-category" href="{{ _link('tag', tag) }}" rel="tag">{{ tag|e }}</a></li>
{% endif %}
{% endfor %}
</ul>
@@ -55,14 +55,14 @@
<meta property="og:type" content="article">
{# Will only work with Pintrest and breaks everywhere else who expect a [Facebook] URI. #}
{# %if post.author(): #}
-{# <meta property="article:author" content="{{ post.author() }}"> #}
+{# <meta property="article:author" content="{{ post.author()|e }}"> #}
{# %endif #}
{% if post.date.isoformat() %}
<meta property="article:published_time" content="{{ post.formatted_date('webiso') }}">
{% endif %}
{% if post.tags %}
{% for tag in post.tags %}
- <meta property="article:tag" content="{{ tag }}">
+ <meta property="article:tag" content="{{ tag|e }}">
{% endfor %}
{% endif %}
{% endif %}
@@ -86,8 +86,17 @@
{% macro mathjax_script(post) %}
{% if post.is_mathjax %}
- <script type="text/x-mathjax-config">
- MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
- <script src="/assets/js/mathjax.js"></script>
+ {% if use_katex %}
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/contrib/auto-render.min.js"></script>
+ <script>
+ renderMathInElement(document.body);
+ </script>
+ {% else %}
+ <script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script>
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
+ </script>
+ {% endif %}
{% endif %}
{% endmacro %}
diff --git a/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl b/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl
index 92c1b7d..f8c53cc 100644
--- a/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl
+++ b/nikola/data/themes/base-jinja/templates/post_list_directive.tmpl
@@ -6,7 +6,7 @@
<ul class="post-list">
{% for post in posts %}
<li class="post-list-item">
- {{ post.formatted_date(date_format) }}
+ {{ post.formatted_date(date_format)|e }}
&nbsp;
<a href="{{ post.permalink(lang) }}">{{ post.title(lang)|e }}</a>
</li>
diff --git a/nikola/data/themes/base-jinja/templates/sectionindex.tmpl b/nikola/data/themes/base-jinja/templates/sectionindex.tmpl
new file mode 100644
index 0000000..f1d3d5b
--- /dev/null
+++ b/nikola/data/themes/base-jinja/templates/sectionindex.tmpl
@@ -0,0 +1,21 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'index.tmpl' %}
+
+{% block extra_head %}
+ {{ super() }}
+ {% if generate_atom %}
+ <link rel="alternate" type="application/atom+xml" title="Atom for the {{ posts[0].section_name()|e }} section" href="{{ _link('section_index_atom', posts[0].section_slug()) }}">
+ {% endif %}
+{% endblock %}
+
+{% block content %}
+<div class="sectionindex">
+ <header>
+ <h2><a href="{{ _link('section_index', posts[0].section_slug()) }}">{{ title|e }}</a></h2>
+ {% if generate_atom %}
+ <p class="feedlink"><a href="{{ _link('section_index_atom', posts[0].section_slug()) }}" type="application/atom+xml">{{ messages('Updates') }}</a></p>
+ {% endif %}
+ </header>
+ {{ super() }}
+</div>
+{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/tag.tmpl b/nikola/data/themes/base-jinja/templates/tag.tmpl
index 0928a5f..f9adc63 100644
--- a/nikola/data/themes/base-jinja/templates/tag.tmpl
+++ b/nikola/data/themes/base-jinja/templates/tag.tmpl
@@ -5,10 +5,10 @@
{{ super() }}
{% if translations|length > 1 and generate_rss %}
{% for language in translations|sort %}
- <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for {{ kind }} {{ tag }} ({{ language }})" href="{{ _link(kind + "_rss", tag, language) }}">
+ <link rel="alternate" type="application/rss+xml" title="RSS for {{ kind }} {{ tag|e }} ({{ language }})" href="{{ _link(kind + "_rss", tag, language) }}">
{% endfor %}
{% elif generate_rss %}
- <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for {{ kind }} {{ tag }}" href="{{ _link(kind + "_rss", tag) }}">
+ <link rel="alternate" type="application/rss+xml" title="RSS for {{ kind }} {{ tag|e }}" href="{{ _link(kind + "_rss", tag) }}">
{% endif %}
{% endblock %}
@@ -24,7 +24,7 @@
{{ messages('Subcategories:') }}
<ul>
{% for name, link in subcategories %}
- <li><a href="{{ link }}">{{ name }}</a></li>
+ <li><a href="{{ link }}">{{ name|e }}</a></li>
{% endfor %}
</ul>
{% endif %}
@@ -43,7 +43,7 @@
{% if posts %}
<ul class="postlist">
{% for post in posts %}
- <li><a href="{{ post.permalink() }}" class="listtitle">{{ post.title()|e }}</a> <time class="listdate" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format) }}">{{ post.formatted_date(date_format) }}</time></li>
+ <li><time class="listdate" datetime="{{ post.formatted_date('webiso') }}" title="{{ post.formatted_date(date_format)|e }}">{{ post.formatted_date(date_format)|e }}</time><a href="{{ post.permalink() }}" class="listtitle">{{ post.title()|e }}<a></li>
{% endfor %}
</ul>
{% endif %}
diff --git a/nikola/data/themes/base-jinja/templates/tagindex.tmpl b/nikola/data/themes/base-jinja/templates/tagindex.tmpl
index f2d2d7a..bc1b02d 100644
--- a/nikola/data/themes/base-jinja/templates/tagindex.tmpl
+++ b/nikola/data/themes/base-jinja/templates/tagindex.tmpl
@@ -6,7 +6,7 @@
{{ messages('Subcategories:') }}
<ul>
{% for name, link in subcategories %}
- <li><a href="{{ link }}">{{ name }}</a></li>
+ <li><a href="{{ link }}">{{ name|e }}</a></li>
{% endfor %}
</ul>
{% endif %}
@@ -16,9 +16,9 @@
{{ super() }}
{% if translations|length > 1 and generate_atom %}
{% for language in translations|sort %}
- <link rel="alternate" type="application/atom+xml" title="Atom for the {{ tag }} section ({{ language }})" href="{{ _link(kind + "_atom", tag, language) }}">
+ <link rel="alternate" type="application/atom+xml" title="Atom for the {{ tag|e }} section ({{ language }})" href="{{ _link(kind + "_atom", tag, language) }}">
{% endfor %}
{% elif generate_atom %}
- <link rel="alternate" type="application/atom+xml" title="Atom for the {{ tag }} section" href="{{ _link("tag" + "_atom", tag) }}">
+ <link rel="alternate" type="application/atom+xml" title="Atom for the {{ tag|e }} section" href="{{ _link("tag" + "_atom", tag) }}">
{% endif %}
{% endblock %}
diff --git a/nikola/data/themes/base-jinja/templates/tags.tmpl b/nikola/data/themes/base-jinja/templates/tags.tmpl
index 4605fc9..936ed21 100644
--- a/nikola/data/themes/base-jinja/templates/tags.tmpl
+++ b/nikola/data/themes/base-jinja/templates/tags.tmpl
@@ -4,7 +4,7 @@
{% block content %}
<article class="tagindex">
<header>
- <h1>{{ title }}</h1>
+ <h1>{{ title|e }}</h1>
</header>
{% if cat_items %}
{% if items %}
@@ -33,7 +33,7 @@
<ul class="postlist">
{% for text, link in items %}
{% if text not in hidden_tags %}
- <li><a class="reference listtitle" href="{{ link }}">{{ text }}</a></li>
+ <li><a class="reference listtitle" href="{{ link }}">{{ text|e }}</a></li>
{% endif %}
{% endfor %}
</ul>
diff --git a/nikola/data/themes/base/assets/css/ipython.min.css b/nikola/data/themes/base/assets/css/ipython.min.css
new file mode 100644
index 0000000..f9934c2
--- /dev/null
+++ b/nikola/data/themes/base/assets/css/ipython.min.css
@@ -0,0 +1,9 @@
+/*!
+*
+* IPython base
+*
+*/.modal.fade .modal-dialog{-webkit-transform:translate(0, 0);-ms-transform:translate(0, 0);-o-transform:translate(0, 0);transform:translate(0, 0)}code{color:#000}pre{font-size:inherit;line-height:inherit}label{font-weight:normal}.border-box-sizing{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}.corner-all{border-radius:2px}.no-padding{padding:0}.hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.hbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}.vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}.vbox>*{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none}.hbox.reverse,.vbox.reverse,.reverse{-webkit-box-direction:reverse;-moz-box-direction:reverse;box-direction:reverse;flex-direction:row-reverse}.hbox.box-flex0,.vbox.box-flex0,.box-flex0{-webkit-box-flex:0;-moz-box-flex:0;box-flex:0;flex:none;width:auto}.hbox.box-flex1,.vbox.box-flex1,.box-flex1{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.hbox.box-flex,.vbox.box-flex,.box-flex{-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.hbox.box-flex2,.vbox.box-flex2,.box-flex2{-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2}.box-group1{-webkit-box-flex-group:1;-moz-box-flex-group:1;box-flex-group:1}.box-group2{-webkit-box-flex-group:2;-moz-box-flex-group:2;box-flex-group:2}.hbox.start,.vbox.start,.start{-webkit-box-pack:start;-moz-box-pack:start;box-pack:start;justify-content:flex-start}.hbox.end,.vbox.end,.end{-webkit-box-pack:end;-moz-box-pack:end;box-pack:end;justify-content:flex-end}.hbox.center,.vbox.center,.center{-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;justify-content:center}.hbox.baseline,.vbox.baseline,.baseline{-webkit-box-pack:baseline;-moz-box-pack:baseline;box-pack:baseline;justify-content:baseline}.hbox.stretch,.vbox.stretch,.stretch{-webkit-box-pack:stretch;-moz-box-pack:stretch;box-pack:stretch;justify-content:stretch}.hbox.align-start,.vbox.align-start,.align-start{-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}.hbox.align-end,.vbox.align-end,.align-end{-webkit-box-align:end;-moz-box-align:end;box-align:end;align-items:flex-end}.hbox.align-center,.vbox.align-center,.align-center{-webkit-box-align:center;-moz-box-align:center;box-align:center;align-items:center}.hbox.align-baseline,.vbox.align-baseline,.align-baseline{-webkit-box-align:baseline;-moz-box-align:baseline;box-align:baseline;align-items:baseline}.hbox.align-stretch,.vbox.align-stretch,.align-stretch{-webkit-box-align:stretch;-moz-box-align:stretch;box-align:stretch;align-items:stretch}div.error{margin:2em;text-align:center}div.error>h1{font-size:500%;line-height:normal}div.error>p{font-size:200%;line-height:normal}div.traceback-wrapper{text-align:left;max-width:800px;margin:auto}/*!
+*
+* IPython notebook
+*
+*/.ansibold{font-weight:bold}.ansiblack{color:black}.ansired{color:darkred}.ansigreen{color:darkgreen}.ansiyellow{color:#c4a000}.ansiblue{color:darkblue}.ansipurple{color:darkviolet}.ansicyan{color:steelblue}.ansigray{color:gray}.ansibgblack{background-color:black}.ansibgred{background-color:red}.ansibggreen{background-color:green}.ansibgyellow{background-color:yellow}.ansibgblue{background-color:blue}.ansibgpurple{background-color:magenta}.ansibgcyan{background-color:cyan}.ansibggray{background-color:gray}div.cell{border:1px solid transparent;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;border-radius:2px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;border-width:thin;border-style:solid;width:100%;padding:5px;margin:0;outline:none}div.cell.selected{border-color:#ababab}@media print{div.cell.selected{border-color:transparent}}.edit_mode div.cell.selected{border-color:green}@media print{.edit_mode div.cell.selected{border-color:transparent}}.prompt{min-width:14ex;padding:.4em;margin:0;font-family:monospace;text-align:right;line-height:1.21429em}@media (max-width:540px){.prompt{text-align:left}}div.inner_cell{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}@-moz-document url-prefix(){div.inner_cell{overflow-x:hidden}}div.input_area{border:1px solid #cfcfcf;border-radius:2px;background:#f7f7f7;line-height:1.21429em}div.prompt:empty{padding-top:0;padding-bottom:0}div.unrecognized_cell{padding:5px 5px 5px 0;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.unrecognized_cell .inner_cell{border-radius:2px;padding:5px;font-weight:bold;color:red;border:1px solid #cfcfcf;background:#eaeaea}div.unrecognized_cell .inner_cell a{color:inherit;text-decoration:none}div.unrecognized_cell .inner_cell a:hover{color:inherit;text-decoration:none}@media (max-width:540px){div.unrecognized_cell>div.prompt{display:none}}@media print{div.code_cell{page-break-inside:avoid}}div.input{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}@media (max-width:540px){div.input{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}div.input_prompt{color:navy;border-top:1px solid transparent}div.input_area>div.highlight{margin:.4em;border:none;padding:0;background-color:transparent}div.input_area>div.highlight>pre{margin:0;border:none;padding:0;background-color:transparent}.CodeMirror{line-height:1.21429em;font-size:14px;height:auto;background:none}.CodeMirror-scroll{overflow-y:hidden;overflow-x:auto}.CodeMirror-lines{padding:.4em}.CodeMirror-linenumber{padding:0 8px 0 4px}.CodeMirror-gutters{border-bottom-left-radius:2px;border-top-left-radius:2px}.CodeMirror pre{padding:0;border:0;border-radius:0}.highlight-base{color:#000}.highlight-variable{color:#000}.highlight-variable-2{color:#1a1a1a}.highlight-variable-3{color:#333}.highlight-string{color:#ba2121}.highlight-comment{color:#408080;font-style:italic}.highlight-number{color:#080}.highlight-atom{color:#88f}.highlight-keyword{color:#008000;font-weight:bold}.highlight-builtin{color:#008000}.highlight-error{color:#f00}.highlight-operator{color:#a2f;font-weight:bold}.highlight-meta{color:#a2f}.highlight-def{color:#00f}.highlight-string-2{color:#f50}.highlight-qualifier{color:#555}.highlight-bracket{color:#997}.highlight-tag{color:#170}.highlight-attribute{color:#00c}.highlight-header{color:blue}.highlight-quote{color:#090}.highlight-link{color:#00c}.cm-s-ipython span.cm-keyword{color:#008000;font-weight:bold}.cm-s-ipython span.cm-atom{color:#88f}.cm-s-ipython span.cm-number{color:#080}.cm-s-ipython span.cm-def{color:#00f}.cm-s-ipython span.cm-variable{color:#000}.cm-s-ipython span.cm-operator{color:#a2f;font-weight:bold}.cm-s-ipython span.cm-variable-2{color:#1a1a1a}.cm-s-ipython span.cm-variable-3{color:#333}.cm-s-ipython span.cm-comment{color:#408080;font-style:italic}.cm-s-ipython span.cm-string{color:#ba2121}.cm-s-ipython span.cm-string-2{color:#f50}.cm-s-ipython span.cm-meta{color:#a2f}.cm-s-ipython span.cm-qualifier{color:#555}.cm-s-ipython span.cm-builtin{color:#008000}.cm-s-ipython span.cm-bracket{color:#997}.cm-s-ipython span.cm-tag{color:#170}.cm-s-ipython span.cm-attribute{color:#00c}.cm-s-ipython span.cm-header{color:blue}.cm-s-ipython span.cm-quote{color:#090}.cm-s-ipython span.cm-link{color:#00c}.cm-s-ipython span.cm-error{color:#f00}.cm-s-ipython span.cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=);background-position:right;background-repeat:no-repeat}div.output_wrapper{position:relative;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;z-index:1}div.output_scroll{height:24em;width:100%;overflow:auto;border-radius:2px;-webkit-box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);box-shadow:inset 0 2px 8px rgba(0,0,0,0.8);display:block}div.output_collapsed{margin:0;padding:0;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}div.out_prompt_overlay{height:100%;padding:0 .4em;position:absolute;border-radius:2px}div.out_prompt_overlay:hover{-webkit-box-shadow:inset 0 0 1px #000;box-shadow:inset 0 0 1px #000;background:rgba(240,240,240,0.5)}div.output_prompt{color:darkred}div.output_area{padding:0;page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}div.output_area .MathJax_Display{text-align:left !important}div.output_area .rendered_html table{margin-left:0;margin-right:0}div.output_area .rendered_html img{margin-left:0;margin-right:0}div.output_area img,div.output_area svg{max-width:100%;height:auto}div.output_area img.unconfined,div.output_area svg.unconfined{max-width:none}.output{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}@media (max-width:540px){div.output_area{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}}div.output_area pre{margin:0;padding:0;border:0;vertical-align:baseline;color:black;background-color:transparent;border-radius:0}div.output_subarea{overflow-x:auto;padding:.4em;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1;max-width:calc(100% - 14ex)}div.output_text{text-align:left;color:#000;line-height:1.21429em}div.output_stderr{background:#fdd}div.output_latex{text-align:left}div.output_javascript:empty{padding:0}.js-error{color:darkred}div.raw_input_container{font-family:monospace;padding-top:5px}input.raw_input{font-family:inherit;font-size:inherit;color:inherit;width:auto;vertical-align:baseline;padding:0 .25em;margin:0 .25em}input.raw_input:focus{box-shadow:none}p.p-space{margin-bottom:10px}div.output_unrecognized{padding:5px;font-weight:bold;color:red}div.output_unrecognized a{color:inherit;text-decoration:none}div.output_unrecognized a:hover{color:inherit;text-decoration:none}.rendered_html{color:#000}.rendered_html em{font-style:italic}.rendered_html strong{font-weight:bold}.rendered_html u{text-decoration:underline}.rendered_html :link{text-decoration:underline}.rendered_html :visited{text-decoration:underline}.rendered_html h1{font-size:185.7%;margin:1.08em 0 0 0;font-weight:bold;line-height:1}.rendered_html h2{font-size:157.1%;margin:1.27em 0 0 0;font-weight:bold;line-height:1}.rendered_html h3{font-size:128.6%;margin:1.55em 0 0 0;font-weight:bold;line-height:1}.rendered_html h4{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1}.rendered_html h5{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}.rendered_html h6{font-size:100%;margin:2em 0 0 0;font-weight:bold;line-height:1;font-style:italic}.rendered_html h1:first-child{margin-top:.538em}.rendered_html h2:first-child{margin-top:.636em}.rendered_html h3:first-child{margin-top:.777em}.rendered_html h4:first-child{margin-top:1em}.rendered_html h5:first-child{margin-top:1em}.rendered_html h6:first-child{margin-top:1em}.rendered_html ul{list-style:disc;margin:0 2em;padding-left:0}.rendered_html ul ul{list-style:square;margin:0 2em}.rendered_html ul ul ul{list-style:circle;margin:0 2em}.rendered_html ol{list-style:decimal;margin:0 2em;padding-left:0}.rendered_html ol ol{list-style:upper-alpha;margin:0 2em}.rendered_html ol ol ol{list-style:lower-alpha;margin:0 2em}.rendered_html ol ol ol ol{list-style:lower-roman;margin:0 2em}.rendered_html ol ol ol ol ol{list-style:decimal;margin:0 2em}.rendered_html *+ul{margin-top:1em}.rendered_html *+ol{margin-top:1em}.rendered_html hr{color:black;background-color:black}.rendered_html pre{margin:1em 2em}.rendered_html pre,.rendered_html code{border:0;background-color:#fff;color:#000;font-size:100%;padding:0}.rendered_html blockquote{margin:1em 2em}.rendered_html table{margin-left:auto;margin-right:auto;border:1px solid black;border-collapse:collapse}.rendered_html tr,.rendered_html th,.rendered_html td{border:1px solid black;border-collapse:collapse;margin:1em 2em}.rendered_html td,.rendered_html th{text-align:left;vertical-align:middle;padding:4px}.rendered_html th{font-weight:bold}.rendered_html *+table{margin-top:1em}.rendered_html p{text-align:left}.rendered_html *+p{margin-top:1em}.rendered_html img{display:block;margin-left:auto;margin-right:auto}.rendered_html *+img{margin-top:1em}.rendered_html img,.rendered_html svg{max-width:100%;height:auto}.rendered_html img.unconfined,.rendered_html svg.unconfined{max-width:none}div.text_cell{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}@media (max-width:540px){div.text_cell>div.prompt{display:none}}div.text_cell_render{outline:none;resize:none;width:inherit;border-style:none;padding:.5em .5em .5em .4em;color:#000;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box}a.anchor-link:link{text-decoration:none;padding:0 20px;visibility:hidden}h1:hover .anchor-link,h2:hover .anchor-link,h3:hover .anchor-link,h4:hover .anchor-link,h5:hover .anchor-link,h6:hover .anchor-link{visibility:visible}.text_cell.rendered .input_area{display:none}.text_cell.rendered .rendered_html{overflow-x:auto}.text_cell.unrendered .text_cell_render{display:none}.cm-header-1,.cm-header-2,.cm-header-3,.cm-header-4,.cm-header-5,.cm-header-6{font-weight:bold;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}.cm-header-1{font-size:185.7%}.cm-header-2{font-size:157.1%}.cm-header-3{font-size:128.6%}.cm-header-4{font-size:110%}.cm-header-5{font-size:100%;font-style:italic}.cm-header-6{font-size:100%;font-style:italic}.widget-interact>div,.widget-interact>input{padding:2.5px}.widget-area{page-break-inside:avoid;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-area .widget-subarea{padding:.44em .4em .4em 1px;margin-left:6px;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:2;-moz-box-flex:2;box-flex:2;flex:2;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}.widget-area.connection-problems .prompt:after{content:"\f127";font-family:'FontAwesome';color:#d9534f;font-size:14px;top:3px;padding:3px}.slide-track{border:1px solid #ccc;background:#fff;border-radius:2px}.widget-hslider{padding-left:8px;padding-right:2px;overflow:visible;width:350px;height:5px;max-height:5px;margin-top:13px;margin-bottom:10px;border:1px solid #ccc;background:#fff;border-radius:2px;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hslider .ui-slider{border:0;background:none;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-hslider .ui-slider .ui-slider-handle{width:12px;height:28px;margin-top:-8px;border-radius:2px}.widget-hslider .ui-slider .ui-slider-range{height:12px;margin-top:-4px;background:#eee}.widget-vslider{padding-bottom:5px;overflow:visible;width:5px;max-width:5px;height:250px;margin-left:12px;border:1px solid #ccc;background:#fff;border-radius:2px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}.widget-vslider .ui-slider{border:0;background:none;margin-left:-4px;margin-top:5px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;-webkit-box-flex:1;-moz-box-flex:1;box-flex:1;flex:1}.widget-vslider .ui-slider .ui-slider-handle{width:28px;height:12px;margin-left:-9px;border-radius:2px}.widget-vslider .ui-slider .ui-slider-range{width:12px;margin-left:-1px;background:#eee}.widget-text{width:350px;margin:0}.widget-listbox{width:350px;margin-bottom:0}.widget-numeric-text{width:150px;margin:0}.widget-progress{margin-top:6px;min-width:350px}.widget-progress .progress-bar{-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}.widget-combo-btn{min-width:125px}.widget_item .dropdown-menu li a{color:inherit}.widget-hbox{display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:horizontal;-moz-box-align:stretch;display:box;box-orient:horizontal;box-align:stretch;display:flex;flex-direction:row;align-items:stretch}.widget-hbox input[type="checkbox"]{margin-top:9px;margin-bottom:10px}.widget-hbox .widget-label{min-width:10ex;padding-right:8px;padding-top:5px;text-align:right;vertical-align:text-top}.widget-hbox .widget-readout{padding-left:8px;padding-top:5px;text-align:left;vertical-align:text-top}.widget-vbox{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch}.widget-vbox .widget-label{padding-bottom:5px;text-align:center;vertical-align:text-bottom}.widget-vbox .widget-readout{padding-top:5px;text-align:center;vertical-align:text-top}.widget-box{box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-webkit-box-align:start;-moz-box-align:start;box-align:start;align-items:flex-start}.widget-radio-box{display:-webkit-box;-webkit-box-orient:vertical;-webkit-box-align:stretch;display:-moz-box;-moz-box-orient:vertical;-moz-box-align:stretch;display:box;box-orient:vertical;box-align:stretch;display:flex;flex-direction:column;align-items:stretch;box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding-top:4px}.widget-radio-box label{margin-top:0;margin-left:20px}/*# sourceMappingURL=ipython.min.css.map */ \ No newline at end of file
diff --git a/nikola/data/themes/base/assets/css/ipython.min.css.map b/nikola/data/themes/base/assets/css/ipython.min.css.map
new file mode 100644
index 0000000..3e36e5e
--- /dev/null
+++ b/nikola/data/themes/base/assets/css/ipython.min.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../base/less/variables.less","../components/bootstrap/less/mixins/vendor-prefixes.less","../base/less/mixins.less","../base/less/flexbox.less","../base/less/error.less","../notebook/less/ansicolors.less","../notebook/less/cell.less","../notebook/less/codecell.less","../notebook/less/codemirror.less","../notebook/less/highlight.less","../components/codemirror/lib/codemirror.css","../notebook/less/outputarea.less","../notebook/less/renderedhtml.less","../notebook/less/textcell.less","../components/bootstrap/less/variables.less","../widgets/less/widgets.less","../components/font-awesome/less/variables.less"],"names":[],"mappings":"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","file":"ipython.min.css"} \ No newline at end of file
diff --git a/nikola/data/themes/base/assets/js/jquery.min.map b/nikola/data/themes/base/assets/js/jquery.min.map
new file mode 100644
index 0000000..1528143
--- /dev/null
+++ b/nikola/data/themes/base/assets/js/jquery.min.map
@@ -0,0 +1 @@
+{"version":3,"file":"jquery.min.js","sources":["jquery.js"],"names":["global","factory","module","exports","document","w","Error","window","this","noGlobal","deletedIds","slice","concat","push","indexOf","class2type","toString","hasOwn","hasOwnProperty","support","version","jQuery","selector","context","fn","init","rtrim","rmsPrefix","rdashAlpha","fcamelCase","all","letter","toUpperCase","prototype","jquery","constructor","length","toArray","call","get","num","pushStack","elems","ret","merge","prevObject","each","callback","args","map","elem","i","apply","arguments","first","eq","last","len","j","end","sort","splice","extend","src","copyIsArray","copy","name","options","clone","target","deep","isFunction","isPlainObject","isArray","undefined","expando","Math","random","replace","isReady","error","msg","noop","obj","type","Array","isWindow","isNumeric","parseFloat","isEmptyObject","key","nodeType","e","ownLast","globalEval","data","trim","execScript","camelCase","string","nodeName","toLowerCase","value","isArraylike","text","makeArray","arr","results","Object","inArray","max","second","grep","invert","callbackInverse","matches","callbackExpect","arg","guid","proxy","tmp","now","Date","split","Sizzle","Expr","getText","isXML","tokenize","compile","select","outermostContext","sortInput","hasDuplicate","setDocument","docElem","documentIsHTML","rbuggyQSA","rbuggyMatches","contains","preferredDoc","dirruns","done","classCache","createCache","tokenCache","compilerCache","sortOrder","a","b","MAX_NEGATIVE","pop","push_native","list","booleans","whitespace","characterEncoding","identifier","attributes","pseudos","rwhitespace","RegExp","rcomma","rcombinators","rattributeQuotes","rpseudo","ridentifier","matchExpr","ID","CLASS","TAG","ATTR","PSEUDO","CHILD","bool","needsContext","rinputs","rheader","rnative","rquickExpr","rsibling","rescape","runescape","funescape","_","escaped","escapedWhitespace","high","String","fromCharCode","unloadHandler","childNodes","els","seed","match","m","groups","old","nid","newContext","newSelector","ownerDocument","exec","getElementById","parentNode","id","getElementsByTagName","getElementsByClassName","qsa","test","getAttribute","setAttribute","toSelector","testContext","join","querySelectorAll","qsaError","removeAttribute","keys","cache","cacheLength","shift","markFunction","assert","div","createElement","removeChild","addHandle","attrs","handler","attrHandle","siblingCheck","cur","diff","sourceIndex","nextSibling","createInputPseudo","createButtonPseudo","createPositionalPseudo","argument","matchIndexes","documentElement","node","hasCompare","parent","doc","defaultView","top","addEventListener","attachEvent","className","appendChild","createComment","getById","getElementsByName","find","filter","attrId","getAttributeNode","tag","innerHTML","input","matchesSelector","webkitMatchesSelector","mozMatchesSelector","oMatchesSelector","msMatchesSelector","disconnectedMatch","compareDocumentPosition","adown","bup","compare","sortDetached","aup","ap","bp","unshift","expr","elements","attr","val","specified","uniqueSort","duplicates","detectDuplicates","sortStable","textContent","firstChild","nodeValue","selectors","createPseudo","relative",">","dir"," ","+","~","preFilter","excess","unquoted","nodeNameSelector","pattern","operator","check","result","what","simple","forward","ofType","xml","outerCache","nodeIndex","start","useCache","lastChild","pseudo","setFilters","idx","matched","not","matcher","unmatched","has","innerText","lang","elemLang","hash","location","root","focus","activeElement","hasFocus","href","tabIndex","enabled","disabled","checked","selected","selectedIndex","empty","header","button","even","odd","lt","gt","radio","checkbox","file","password","image","submit","reset","filters","parseOnly","tokens","soFar","preFilters","cached","addCombinator","combinator","base","checkNonElements","doneName","oldCache","newCache","elementMatcher","matchers","multipleContexts","contexts","condense","newUnmatched","mapped","setMatcher","postFilter","postFinder","postSelector","temp","preMap","postMap","preexisting","matcherIn","matcherOut","matcherFromTokens","checkContext","leadingRelative","implicitRelative","matchContext","matchAnyContext","matcherFromGroupMatchers","elementMatchers","setMatchers","bySet","byElement","superMatcher","outermost","matchedCount","setMatched","contextBackup","dirrunsUnique","token","compiled","div1","defaultValue","unique","isXMLDoc","rneedsContext","rsingleTag","risSimple","winnow","qualifier","self","is","rootjQuery","charAt","parseHTML","ready","rparentsprev","guaranteedUnique","children","contents","next","prev","until","sibling","n","r","targets","closest","l","pos","index","prevAll","add","addBack","parents","parentsUntil","nextAll","nextUntil","prevUntil","siblings","contentDocument","contentWindow","reverse","rnotwhite","optionsCache","createOptions","object","flag","Callbacks","firing","memory","fired","firingLength","firingIndex","firingStart","stack","once","fire","stopOnFalse","disable","remove","lock","locked","fireWith","Deferred","func","tuples","state","promise","always","deferred","fail","then","fns","newDefer","tuple","returned","resolve","reject","progress","notify","pipe","stateString","when","subordinate","resolveValues","remaining","updateFunc","values","progressValues","notifyWith","resolveWith","progressContexts","resolveContexts","readyList","readyWait","holdReady","hold","wait","body","setTimeout","triggerHandler","off","detach","removeEventListener","completed","detachEvent","event","readyState","frameElement","doScroll","doScrollCheck","strundefined","inlineBlockNeedsLayout","container","style","cssText","zoom","offsetWidth","deleteExpando","acceptData","noData","rbrace","rmultiDash","dataAttr","parseJSON","isEmptyDataObject","internalData","pvt","thisCache","internalKey","isNode","toJSON","internalRemoveData","cleanData","applet ","embed ","object ","hasData","removeData","_data","_removeData","queue","dequeue","startLength","hooks","_queueHooks","stop","setter","clearQueue","count","defer","pnum","source","cssExpand","isHidden","el","css","access","chainable","emptyGet","raw","bulk","rcheckableType","fragment","createDocumentFragment","leadingWhitespace","tbody","htmlSerialize","html5Clone","cloneNode","outerHTML","appendChecked","noCloneChecked","checkClone","noCloneEvent","click","eventName","change","focusin","rformElems","rkeyEvent","rmouseEvent","rfocusMorph","rtypenamespace","returnTrue","returnFalse","safeActiveElement","err","types","events","t","handleObjIn","special","eventHandle","handleObj","handlers","namespaces","origType","elemData","handle","triggered","dispatch","delegateType","bindType","namespace","delegateCount","setup","mappedTypes","origCount","teardown","removeEvent","trigger","onlyHandlers","ontype","bubbleType","eventPath","Event","isTrigger","namespace_re","noBubble","parentWindow","isPropagationStopped","preventDefault","isDefaultPrevented","_default","fix","handlerQueue","delegateTarget","preDispatch","currentTarget","isImmediatePropagationStopped","stopPropagation","postDispatch","sel","prop","originalEvent","fixHook","fixHooks","mouseHooks","keyHooks","props","srcElement","metaKey","original","which","charCode","keyCode","eventDoc","fromElement","pageX","clientX","scrollLeft","clientLeft","pageY","clientY","scrollTop","clientTop","relatedTarget","toElement","load","blur","beforeunload","returnValue","simulate","bubble","isSimulated","defaultPrevented","timeStamp","cancelBubble","stopImmediatePropagation","mouseenter","mouseleave","pointerenter","pointerleave","orig","related","submitBubbles","form","_submit_bubble","changeBubbles","propertyName","_just_changed","focusinBubbles","attaches","on","one","origFn","createSafeFragment","nodeNames","safeFrag","rinlinejQuery","rnoshimcache","rleadingWhitespace","rxhtmlTag","rtagName","rtbody","rhtml","rnoInnerhtml","rchecked","rscriptType","rscriptTypeMasked","rcleanScript","wrapMap","option","legend","area","param","thead","tr","col","td","safeFragment","fragmentDiv","optgroup","tfoot","colgroup","caption","th","getAll","found","fixDefaultChecked","defaultChecked","manipulationTarget","content","disableScript","restoreScript","setGlobalEval","refElements","cloneCopyEvent","dest","oldData","curData","fixCloneNodeIssues","defaultSelected","dataAndEvents","deepDataAndEvents","destElements","srcElements","inPage","buildFragment","scripts","selection","wrap","safe","nodes","createTextNode","append","domManip","prepend","insertBefore","before","after","keepData","html","replaceWith","replaceChild","hasScripts","set","iNoClone","_evalUrl","appendTo","prependTo","insertAfter","replaceAll","insert","iframe","elemdisplay","actualDisplay","display","getDefaultComputedStyle","defaultDisplay","write","close","shrinkWrapBlocksVal","shrinkWrapBlocks","width","rmargin","rnumnonpx","getStyles","curCSS","rposition","getComputedStyle","opener","computed","minWidth","maxWidth","getPropertyValue","currentStyle","left","rs","rsLeft","runtimeStyle","pixelLeft","addGetHookIf","conditionFn","hookFn","condition","pixelPositionVal","boxSizingReliableVal","reliableHiddenOffsetsVal","reliableMarginRightVal","opacity","cssFloat","backgroundClip","clearCloneStyle","boxSizing","MozBoxSizing","WebkitBoxSizing","reliableHiddenOffsets","computeStyleTests","boxSizingReliable","pixelPosition","reliableMarginRight","marginRight","offsetHeight","swap","ralpha","ropacity","rdisplayswap","rnumsplit","rrelNum","cssShow","position","visibility","cssNormalTransform","letterSpacing","fontWeight","cssPrefixes","vendorPropName","capName","origName","showHide","show","hidden","setPositiveNumber","subtract","augmentWidthOrHeight","extra","isBorderBox","styles","getWidthOrHeight","valueIsBorderBox","cssHooks","cssNumber","columnCount","fillOpacity","flexGrow","flexShrink","lineHeight","order","orphans","widows","zIndex","cssProps","float","$1","margin","padding","border","prefix","suffix","expand","expanded","parts","hide","toggle","Tween","easing","unit","propHooks","run","percent","eased","duration","step","tween","fx","linear","p","swing","cos","PI","fxNow","timerId","rfxtypes","rfxnum","rrun","animationPrefilters","defaultPrefilter","tweeners","*","createTween","scale","maxIterations","createFxNow","genFx","includeWidth","height","animation","collection","opts","oldfire","checkDisplay","anim","dataShow","unqueued","overflow","overflowX","overflowY","propFilter","specialEasing","Animation","properties","stopped","tick","currentTime","startTime","tweens","originalProperties","originalOptions","gotoEnd","rejectWith","timer","complete","tweener","prefilter","speed","opt","speeds","fadeTo","to","animate","optall","doAnimation","finish","stopQueue","timers","cssFn","slideDown","slideUp","slideToggle","fadeIn","fadeOut","fadeToggle","interval","setInterval","clearInterval","slow","fast","delay","time","timeout","clearTimeout","getSetAttribute","hrefNormalized","checkOn","optSelected","enctype","optDisabled","radioValue","rreturn","valHooks","optionSet","scrollHeight","nodeHook","boolHook","ruseDefault","getSetInput","removeAttr","nType","attrHooks","propName","attrNames","propFix","getter","setAttributeNode","createAttribute","coords","contenteditable","rfocusable","rclickable","removeProp","for","class","notxml","tabindex","parseInt","rclass","addClass","classes","clazz","finalValue","proceed","removeClass","toggleClass","stateVal","classNames","hasClass","hover","fnOver","fnOut","bind","unbind","delegate","undelegate","nonce","rquery","rvalidtokens","JSON","parse","requireNonComma","depth","str","comma","open","Function","parseXML","DOMParser","parseFromString","ActiveXObject","async","loadXML","ajaxLocParts","ajaxLocation","rhash","rts","rheaders","rlocalProtocol","rnoContent","rprotocol","rurl","prefilters","transports","allTypes","addToPrefiltersOrTransports","structure","dataTypeExpression","dataType","dataTypes","inspectPrefiltersOrTransports","jqXHR","inspected","seekingTransport","inspect","prefilterOrFactory","dataTypeOrTransport","ajaxExtend","flatOptions","ajaxSettings","ajaxHandleResponses","s","responses","firstDataType","ct","finalDataType","mimeType","getResponseHeader","converters","ajaxConvert","response","isSuccess","conv2","current","conv","responseFields","dataFilter","active","lastModified","etag","url","isLocal","processData","contentType","accepts","json","* text","text html","text json","text xml","ajaxSetup","settings","ajaxPrefilter","ajaxTransport","ajax","cacheURL","responseHeadersString","timeoutTimer","fireGlobals","transport","responseHeaders","callbackContext","globalEventContext","completeDeferred","statusCode","requestHeaders","requestHeadersNames","strAbort","getAllResponseHeaders","setRequestHeader","lname","overrideMimeType","code","status","abort","statusText","finalText","success","method","crossDomain","traditional","hasContent","ifModified","headers","beforeSend","send","nativeStatusText","modified","getJSON","getScript","throws","wrapAll","wrapInner","unwrap","visible","r20","rbracket","rCRLF","rsubmitterTypes","rsubmittable","buildParams","v","encodeURIComponent","serialize","serializeArray","xhr","createStandardXHR","createActiveXHR","xhrId","xhrCallbacks","xhrSupported","cors","username","xhrFields","isAbort","onreadystatechange","responseText","XMLHttpRequest","script","text script","head","scriptCharset","charset","onload","oldCallbacks","rjsonp","jsonp","jsonpCallback","originalSettings","callbackName","overwritten","responseContainer","jsonProp","keepScripts","parsed","_load","params","animated","getWindow","offset","setOffset","curPosition","curLeft","curCSSTop","curTop","curOffset","curCSSLeft","calculatePosition","curElem","using","win","box","getBoundingClientRect","pageYOffset","pageXOffset","offsetParent","parentOffset","scrollTo","Height","Width","defaultExtra","funcName","size","andSelf","define","amd","_jQuery","_$","$","noConflict"],"mappings":"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"} \ No newline at end of file
diff --git a/nikola/data/themes/base/assets/js/mathjax.js b/nikola/data/themes/base/assets/js/mathjax.js
deleted file mode 100644
index 6ef2dd7..0000000
--- a/nikola/data/themes/base/assets/js/mathjax.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// We wait for the onload function to load MathJax after the page is completely loaded.
-// MathJax is loaded 1 unit of time after the page is ready.
-// This hack prevent problems when you use social button from addthis.
-//
-window.onload = function () {
- setTimeout(function () {
- var script = document.createElement("script");
- script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
- document.getElementsByTagName("body")[0].appendChild(script);
- },1)
-}
diff --git a/nikola/data/themes/base/assets/js/moment-with-locales.min.js b/nikola/data/themes/base/assets/js/moment-with-locales.min.js
new file mode 120000
index 0000000..1caedc6
--- /dev/null
+++ b/nikola/data/themes/base/assets/js/moment-with-locales.min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/moment/min/moment-with-locales.min.js \ No newline at end of file
diff --git a/nikola/data/themes/base/messages/messages_ar.py b/nikola/data/themes/base/messages/messages_ar.py
index 07c38b2..6796b6b 100644
--- a/nikola/data/themes/base/messages/messages_ar.py
+++ b/nikola/data/themes/base/messages/messages_ar.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "أيضا متوفر في:",
"Archive": "الأرشيف",
+ "Authors": "",
"Categories": "فئات",
"Comments": "التّعليقات",
"LANGUAGE": "العربيّة",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "الموقع الأصلي",
"Posted:": "نشر:",
"Posts about %s": "مقالات عن s%",
+ "Posts by %s": "",
"Posts for year %s": "مقالات سنة s%",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "تصنيفات و فئات",
"Tags": "تصنيفات",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "مقالات قديمة, صفحة d%",
diff --git a/nikola/data/themes/base/messages/messages_az.py b/nikola/data/themes/base/messages/messages_az.py
index 76c15fc..15b2341 100644
--- a/nikola/data/themes/base/messages/messages_az.py
+++ b/nikola/data/themes/base/messages/messages_az.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Həmçinin mövcuddur:",
"Archive": "Arxiv",
+ "Authors": "",
"Categories": "Kateqoriyalar",
"Comments": "Şərhlər",
"LANGUAGE": "Azərbaycan dili",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Original sayt",
"Posted:": "yazılma tarixi:",
"Posts about %s": "%s ilə bağlı yazılar",
+ "Posts by %s": "",
"Posts for year %s": "%s ilindəki yazılar",
"Posts for {month} {day}, {year}": "{month} {day}, {year} üçün yazılar",
"Posts for {month} {year}": "{month} {year} üçün yazılar",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Teqlər və Kateqoriyalar",
"Tags": "Teqlər",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "köhnə yazılar, səhifə %s",
diff --git a/nikola/data/themes/base/messages/messages_bg.py b/nikola/data/themes/base/messages/messages_bg.py
index 96ac878..bd6d301 100644
--- a/nikola/data/themes/base/messages/messages_bg.py
+++ b/nikola/data/themes/base/messages/messages_bg.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Също достъпно в:",
"Archive": "Архив",
+ "Authors": "",
"Categories": "Категории",
"Comments": "",
"LANGUAGE": "Български",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Оригиналния сайт",
"Posted:": "Публиковано:",
"Posts about %s": "Публикации относно %s",
+ "Posts by %s": "",
"Posts for year %s": "Публикации за %s година",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "Публикации за {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Тагове и Категории",
"Tags": "Тагове",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "стари публикации, страница %d",
diff --git a/nikola/data/themes/base/messages/messages_bs.py b/nikola/data/themes/base/messages/messages_bs.py
index 23a1f64..d2bef18 100644
--- a/nikola/data/themes/base/messages/messages_bs.py
+++ b/nikola/data/themes/base/messages/messages_bs.py
@@ -6,23 +6,25 @@ MESSAGES = {
"(active)": "(aktivno)",
"Also available in:": "Takođe dostupan u:",
"Archive": "Arhiva",
+ "Authors": "Autori",
"Categories": "Kategorije",
"Comments": "Komentari",
"LANGUAGE": "Bosanski",
"Languages:": "Jezici:",
- "More posts about %s": "Više objava o %s",
+ "More posts about %s": "Više članaka o %s",
"Newer posts": "Novije objave",
- "Next post": "Naredna objava",
- "No posts found.": "Nema objava.",
+ "Next post": "Naredni članak",
+ "No posts found.": "Nema članaka.",
"Nothing found.": "Ništa nije pronađeno.",
"Older posts": "Starije objave",
"Original site": "Izvorni sajt",
"Posted:": "Objavljeno:",
"Posts about %s": "Objave o %s",
+ "Posts by %s": "Objave prema %s",
"Posts for year %s": "Objave u godini %s",
- "Posts for {month} {day}, {year}": "Objave za {month} {day}, {year}",
+ "Posts for {month} {day}, {year}": "Objave za {day}.{month}.{year}",
"Posts for {month} {year}": "Objave za {month} {year}",
- "Previous post": "Prethodne objave",
+ "Previous post": "Prethodni članak",
"Publication date": "Datum objavljivanja",
"RSS feed": "RSS feed",
"Read in English": "Pročitaj na bosanskom",
@@ -32,8 +34,10 @@ MESSAGES = {
"Subcategories:": "Podkategorije:",
"Tags and Categories": "Oznake i kategorije",
"Tags": "Oznake",
+ "Uncategorized": "Bez kategorije",
+ "Updates": "Ažuriranja",
"Write your page here.": "Vašu stranicu napišite ovdje.",
- "Write your post here.": "Vašu objavu napišite ovdje.",
+ "Write your post here.": "Vaš članak napišite ovdje.",
"old posts, page %d": "stare objave, strana %d",
"page %d": "strana %d",
}
diff --git a/nikola/data/themes/base/messages/messages_ca.py b/nikola/data/themes/base/messages/messages_ca.py
index f45b1a6..bd4cacc 100644
--- a/nikola/data/themes/base/messages/messages_ca.py
+++ b/nikola/data/themes/base/messages/messages_ca.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "També disponibles en:",
"Archive": "Arxiu",
+ "Authors": "",
"Categories": "Categories",
"Comments": "Comentaris",
"LANGUAGE": "Català",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Lloc original",
"Posted:": "Publicat:",
"Posts about %s": "Entrades sobre %s",
+ "Posts by %s": "",
"Posts for year %s": "Entrades de l'any %s",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "Publicat en {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Etiquetes i Categories",
"Tags": "Etiquetes",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "entrades antigues, pàgina %d",
diff --git a/nikola/data/themes/base/messages/messages_cs.py b/nikola/data/themes/base/messages/messages_cs.py
index 6e1bdd2..b509043 100644
--- a/nikola/data/themes/base/messages/messages_cs.py
+++ b/nikola/data/themes/base/messages/messages_cs.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Dostupné také v",
"Archive": "Archiv",
+ "Authors": "",
"Categories": "Kategorie",
"Comments": "Komentáře",
"LANGUAGE": "Čeština",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Původní stránka",
"Posted:": "Zveřejněno:",
"Posts about %s": "Příspěvky o %s",
+ "Posts by %s": "",
"Posts for year %s": "Příspěvky v roce %s",
"Posts for {month} {day}, {year}": "Příspěvky v {month} {day}, {year}",
"Posts for {month} {year}": "Příspěvky v {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Štítky a kategorie",
"Tags": "Štítky",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "staré příspěvky, strana %d",
diff --git a/nikola/data/themes/base/messages/messages_da.py b/nikola/data/themes/base/messages/messages_da.py
index 73b71cb..34a92f5 100644
--- a/nikola/data/themes/base/messages/messages_da.py
+++ b/nikola/data/themes/base/messages/messages_da.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Fås også i:",
"Archive": "Arkiv",
+ "Authors": "",
"Categories": "Kategorier",
"Comments": "Kommentarer",
"LANGUAGE": "Dansk",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Oprindeligt hjemmeside",
"Posted:": "Opslået:",
"Posts about %s": "Indlæg om %s",
+ "Posts by %s": "",
"Posts for year %s": "Indlæg for %s",
"Posts for {month} {day}, {year}": "Indlæs for {month} {day}, {year}",
"Posts for {month} {year}": "Indlæg for {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Nøgleord og kategorier",
"Tags": "Nøgleord",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "gamle indlæg, side %d",
diff --git a/nikola/data/themes/base/messages/messages_de.py b/nikola/data/themes/base/messages/messages_de.py
index 324dd14..fd2c293 100644
--- a/nikola/data/themes/base/messages/messages_de.py
+++ b/nikola/data/themes/base/messages/messages_de.py
@@ -3,9 +3,10 @@ from __future__ import unicode_literals
MESSAGES = {
"%d min remaining to read": "%d min verbleiben zum Lesen",
- "(active)": "",
+ "(active)": "(aktiv)",
"Also available in:": "Auch verfügbar in:",
"Archive": "Archiv",
+ "Authors": "Autoren",
"Categories": "Kategorien",
"Comments": "Kommentare",
"LANGUAGE": "Deutsch",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Original-Seite",
"Posted:": "Veröffentlicht:",
"Posts about %s": "Einträge über %s",
+ "Posts by %s": "Einträge von %s",
"Posts for year %s": "Einträge aus dem Jahr %s",
"Posts for {month} {day}, {year}": "Einträge vom {day}. {month} {year}",
"Posts for {month} {year}": "Einträge aus {month} {year}",
@@ -32,8 +34,10 @@ MESSAGES = {
"Subcategories:": "Unterkategorien:",
"Tags and Categories": "Tags und Kategorien",
"Tags": "Tags",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "Nicht kategorisiert",
+ "Updates": "Updates",
+ "Write your page here.": "Schreibe hier deinen Seiteninhalt hin.",
+ "Write your post here.": "Schreibe hier deinen Eintrag hin.",
"old posts, page %d": "Ältere Einträge, Seite %d",
"page %d": "Seite %d",
}
diff --git a/nikola/data/themes/base/messages/messages_el.py b/nikola/data/themes/base/messages/messages_el.py
index 68cf91f..9775b30 100644
--- a/nikola/data/themes/base/messages/messages_el.py
+++ b/nikola/data/themes/base/messages/messages_el.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Διαθέσιμο και στα:",
"Archive": "Αρχείο",
+ "Authors": "",
"Categories": "Κατηγορίες",
"Comments": "Σχόλια",
"LANGUAGE": "Ελληνικά",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Ιστοσελίδα αρχικής ανάρτησης",
"Posted:": "Αναρτήθηκε:",
"Posts about %s": "Αναρτήσεις για %s",
+ "Posts by %s": "",
"Posts for year %s": "Αναρτήσεις για το έτος %s",
"Posts for {month} {day}, {year}": "Αναρτήσεις στις {day} {month}, {year}",
"Posts for {month} {year}": "Αναρτήσεις για τον {month} του {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Ετικέτες και κατηγορίες",
"Tags": "Ετικέτες",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "σελίδα παλαιότερων αναρτήσεων %d",
diff --git a/nikola/data/themes/base/messages/messages_en.py b/nikola/data/themes/base/messages/messages_en.py
index 29af257..f17ce18 100644
--- a/nikola/data/themes/base/messages/messages_en.py
+++ b/nikola/data/themes/base/messages/messages_en.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(active)",
"Also available in:": "Also available in:",
"Archive": "Archive",
+ "Authors": "Authors",
"Categories": "Categories",
"Comments": "Comments",
"LANGUAGE": "English",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Original site",
"Posted:": "Posted:",
"Posts about %s": "Posts about %s",
+ "Posts by %s": "Posts by %s",
"Posts for year %s": "Posts for year %s",
"Posts for {month} {day}, {year}": "Posts for {month} {day}, {year}",
"Posts for {month} {year}": "Posts for {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Subcategories:",
"Tags and Categories": "Tags and Categories",
"Tags": "Tags",
+ "Uncategorized": "Uncategorized",
+ "Updates": "Updates",
"Write your page here.": "Write your page here.",
"Write your post here.": "Write your post here.",
"old posts, page %d": "old posts, page %d",
diff --git a/nikola/data/themes/base/messages/messages_eo.py b/nikola/data/themes/base/messages/messages_eo.py
index 8938707..126c98f 100644
--- a/nikola/data/themes/base/messages/messages_eo.py
+++ b/nikola/data/themes/base/messages/messages_eo.py
@@ -2,38 +2,42 @@
from __future__ import unicode_literals
MESSAGES = {
- "%d min remaining to read": "",
- "(active)": "",
+ "%d min remaining to read": "%d minutoj por legi",
+ "(active)": "(aktiva)",
"Also available in:": "Ankaŭ disponebla en:",
- "Archive": "Arĥivo",
+ "Archive": "Arkivo",
+ "Authors": "Aŭtoroj",
"Categories": "Kategorioj",
- "Comments": "",
- "LANGUAGE": "Anglalingve",
- "Languages:": "",
- "More posts about %s": "Pli artikoloj pri %s",
+ "Comments": "Komentoj",
+ "LANGUAGE": "Esperante",
+ "Languages:": "Lingvoj:",
+ "More posts about %s": "Pli da artikoloj pri %s",
"Newer posts": "Pli novaj artikoloj",
"Next post": "Venonta artikolo",
- "No posts found.": "",
- "Nothing found.": "",
+ "No posts found.": "Neniu artikoloj trovitaj.",
+ "Nothing found.": "Nenio trovita.",
"Older posts": "Pli malnovaj artikoloj",
- "Original site": "Originala interretejo",
+ "Original site": "Originala retejo",
"Posted:": "Skribita:",
"Posts about %s": "Artikoloj pri %s",
+ "Posts by %s": "Artikoloj de %s",
"Posts for year %s": "Artikoloj de la jaro %s",
- "Posts for {month} {day}, {year}": "",
- "Posts for {month} {year}": "Artikoloj skribitaj en {month} {year}",
+ "Posts for {month} {day}, {year}": "Artikoloj de la {day}a de {month} {year}",
+ "Posts for {month} {year}": "Artikoloj de {month} {year}",
"Previous post": "Antaŭa artikolo",
- "Publication date": "",
- "RSS feed": "",
+ "Publication date": "Eldona dato",
+ "RSS feed": "RSS fluo",
"Read in English": "Legu ĝin en Esperanto",
- "Read more": "Legu plu",
- "Skip to main content": "",
+ "Read more": "Legu pli",
+ "Skip to main content": "Salti al ĉefenhavo",
"Source": "Fonto",
- "Subcategories:": "",
- "Tags and Categories": "Etikedoj kaj Kategorioj",
+ "Subcategories:": "Subkategorioj:",
+ "Tags and Categories": "Etikedoj kaj kategorioj",
"Tags": "Etikedoj",
- "Write your page here.": "",
- "Write your post here.": "",
- "old posts, page %d": "paĝo de malnovaj artikoloj %d",
+ "Uncategorized": "Sen kategorioj",
+ "Updates": "Ĝisdatigoj",
+ "Write your page here.": "Skribu tie vian paĝon.",
+ "Write your post here.": "Skribu tie vian artikolon.",
+ "old posts, page %d": "%da paĝo de malnovaj artikoloj",
"page %d": "paĝo %d",
}
diff --git a/nikola/data/themes/base/messages/messages_es.py b/nikola/data/themes/base/messages/messages_es.py
index e3f0f03..7457c89 100644
--- a/nikola/data/themes/base/messages/messages_es.py
+++ b/nikola/data/themes/base/messages/messages_es.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(activo)",
"Also available in:": "También disponible en:",
"Archive": "Archivo",
+ "Authors": "Autores",
"Categories": "Categorías",
"Comments": "Comentarios",
"LANGUAGE": "Español",
@@ -19,9 +20,10 @@ MESSAGES = {
"Original site": "Sitio original",
"Posted:": "Publicado:",
"Posts about %s": "Publicaciones sobre %s",
+ "Posts by %s": "Publicaciones de %s",
"Posts for year %s": "Publicaciones del año %s",
- "Posts for {month} {day}, {year}": "Publicaciones de {day}, {month}, {year}",
- "Posts for {month} {year}": "Posts de {month} {year}",
+ "Posts for {month} {day}, {year}": "Publicaciones del {day} de {month} de {year}",
+ "Posts for {month} {year}": "Posts de {month} de {year}",
"Previous post": "Publicación anterior",
"Publication date": "Fecha de publicación",
"RSS feed": "Canal RSS",
@@ -32,8 +34,10 @@ MESSAGES = {
"Subcategories:": "Subcategorías:",
"Tags and Categories": "Etiquetas y Categorías",
"Tags": "Etiquetas",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "Sin categoría",
+ "Updates": "Actualizaciones",
+ "Write your page here.": "Escriba su página aquí.",
+ "Write your post here.": "Escriba su publicación aquí.",
"old posts, page %d": "publicaciones antiguas, página %d",
"page %d": "página %d",
}
diff --git a/nikola/data/themes/base/messages/messages_et.py b/nikola/data/themes/base/messages/messages_et.py
index c67cbb2..bfe58e4 100644
--- a/nikola/data/themes/base/messages/messages_et.py
+++ b/nikola/data/themes/base/messages/messages_et.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Saadaval ka:",
"Archive": "Arhiiv",
+ "Authors": "",
"Categories": "Kategooriad",
"Comments": "",
"LANGUAGE": "Eesti",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Algallikas",
"Posted:": "Postitatud:",
"Posts about %s": "Postitused %s kohta",
+ "Posts by %s": "",
"Posts for year %s": "Postitused aastast %s",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "Postitused {year} aasta kuust {month} ",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Sildid ja kategooriad",
"Tags": "Märksõnad",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "vanade postituste, leht %d",
diff --git a/nikola/data/themes/base/messages/messages_eu.py b/nikola/data/themes/base/messages/messages_eu.py
index 1588cd6..8635f21 100644
--- a/nikola/data/themes/base/messages/messages_eu.py
+++ b/nikola/data/themes/base/messages/messages_eu.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Eskuragarria hemen ere:",
"Archive": "Artxiboa",
+ "Authors": "",
"Categories": "Kategoriak",
"Comments": "",
"LANGUAGE": "Euskara",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Jatorrizko orria",
"Posted:": "Argitaratuta:",
"Posts about %s": "%s-ri buruzko postak",
+ "Posts by %s": "",
"Posts for year %s": "%s. urteko postak",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "{year}ko {month}ren postak",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Etiketak eta Kategoriak",
"Tags": "Etiketak",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "Post zaharren, orria %d",
diff --git a/nikola/data/themes/base/messages/messages_fa.py b/nikola/data/themes/base/messages/messages_fa.py
index b69d57a..1d96da8 100644
--- a/nikola/data/themes/base/messages/messages_fa.py
+++ b/nikola/data/themes/base/messages/messages_fa.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "همچنین قابل دسترس از:",
"Archive": "آرشیو",
+ "Authors": "",
"Categories": "دسته‌ها",
"Comments": "دیدگاه‌‌‌ها",
"LANGUAGE": "فارسی",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "سایت اصلی",
"Posted:": "ارسال شده:",
"Posts about %s": "ارسال‌ها دربارهٔ %s",
+ "Posts by %s": "",
"Posts for year %s": "ارسال‌ها برای سال %s",
"Posts for {month} {day}, {year}": "ارسال برای {month} {day}. {year}",
"Posts for {month} {year}": "ارسال برای {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "برچسب‌ها و دسته‌ها",
"Tags": "برچسب‌ها",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "صفحهٔ ارسال‌های قدیمی %d",
diff --git a/nikola/data/themes/base/messages/messages_fi.py b/nikola/data/themes/base/messages/messages_fi.py
index 1bcd6ad..b7ba141 100644
--- a/nikola/data/themes/base/messages/messages_fi.py
+++ b/nikola/data/themes/base/messages/messages_fi.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktiivinen)",
"Also available in:": "Saatavilla myös:",
"Archive": "Arkisto",
+ "Authors": "",
"Categories": "Kategoriat",
"Comments": "Kommentit",
"LANGUAGE": "Suomi",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Alkuperäinen sivusto",
"Posted:": "Postattu:",
"Posts about %s": "Postauksia aiheesta %s",
+ "Posts by %s": "",
"Posts for year %s": "Postauksia vuodelta %s",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "Postauksia ajalle {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Alakategoriat:",
"Tags and Categories": "Tagit ja kategoriat",
"Tags": "Tagit",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "vanhoja postauksia, sivu %d",
diff --git a/nikola/data/themes/base/messages/messages_fil.py b/nikola/data/themes/base/messages/messages_fil.py
index fd26d77..f661c0e 100644
--- a/nikola/data/themes/base/messages/messages_fil.py
+++ b/nikola/data/themes/base/messages/messages_fil.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "",
+ "Authors": "",
"Categories": "",
"Comments": "",
"LANGUAGE": "",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "",
"Posted:": "",
"Posts about %s": "",
+ "Posts by %s": "",
"Posts for year %s": "",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "",
"Tags": "",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "",
diff --git a/nikola/data/themes/base/messages/messages_fr.py b/nikola/data/themes/base/messages/messages_fr.py
index 327b3f7..1c2025c 100644
--- a/nikola/data/themes/base/messages/messages_fr.py
+++ b/nikola/data/themes/base/messages/messages_fr.py
@@ -4,12 +4,13 @@ from __future__ import unicode_literals
MESSAGES = {
"%d min remaining to read": "Il reste encore %d min. de lecture",
"(active)": "(actif)",
- "Also available in:": "Également disponible en:",
+ "Also available in:": "Également disponible en :",
"Archive": "Archives",
+ "Authors": "Auteurs",
"Categories": "Catégories",
"Comments": "Commentaires",
"LANGUAGE": "Français",
- "Languages:": "Langues:",
+ "Languages:": "Langues :",
"More posts about %s": "Plus d'articles sur %s",
"Newer posts": "Articles récents",
"Next post": "Article suivant",
@@ -17,8 +18,9 @@ MESSAGES = {
"Nothing found.": "Pas de résultats.",
"Older posts": "Anciens articles",
"Original site": "Site d'origine",
- "Posted:": "Publié:",
+ "Posted:": "Publié :",
"Posts about %s": "Articles sur %s",
+ "Posts by %s": "Publiés par %s",
"Posts for year %s": "Articles de l'année %s",
"Posts for {month} {day}, {year}": "Articles du {day} {month} {year}",
"Posts for {month} {year}": "Articles de {month} {year}",
@@ -32,8 +34,10 @@ MESSAGES = {
"Subcategories:": "Sous-catégories",
"Tags and Categories": "Étiquettes et catégories",
"Tags": "Étiquettes",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "Sans catégorie",
+ "Updates": "Mises à jour",
+ "Write your page here.": "Écrivez votre page ici.",
+ "Write your post here.": "Écrivez votre billet ici.",
"old posts, page %d": "anciens articles, page %d",
"page %d": "page %d",
}
diff --git a/nikola/data/themes/base/messages/messages_gl.py b/nikola/data/themes/base/messages/messages_gl.py
index fd26d77..f661c0e 100644
--- a/nikola/data/themes/base/messages/messages_gl.py
+++ b/nikola/data/themes/base/messages/messages_gl.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "",
+ "Authors": "",
"Categories": "",
"Comments": "",
"LANGUAGE": "",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "",
"Posted:": "",
"Posts about %s": "",
+ "Posts by %s": "",
"Posts for year %s": "",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "",
"Tags": "",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "",
diff --git a/nikola/data/themes/base/messages/messages_hi.py b/nikola/data/themes/base/messages/messages_hi.py
index 7804b60..afbd8d5 100644
--- a/nikola/data/themes/base/messages/messages_hi.py
+++ b/nikola/data/themes/base/messages/messages_hi.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "उपलब्ध भाषाएँ:",
"Archive": "आर्काइव",
+ "Authors": "",
"Categories": "श्रेणियाँ",
"Comments": "टिप्पणियाँ",
"LANGUAGE": "हिन्दी",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "असली साइट",
"Posted:": "पोस्टेड:",
"Posts about %s": "%s के बारे में पोस्टें",
+ "Posts by %s": "",
"Posts for year %s": "साल %s की पोस्टें",
"Posts for {month} {day}, {year}": "{day} {month} {year} की पोस्टें",
"Posts for {month} {year}": "{month} {year} की पोस्टें",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "टैग्स और श्रेणियाँ",
"Tags": "टैग्स",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "पुरानी पोस्टें, पृष्‍ठ %d",
diff --git a/nikola/data/themes/base/messages/messages_hr.py b/nikola/data/themes/base/messages/messages_hr.py
index 11e07d8..79bd050 100644
--- a/nikola/data/themes/base/messages/messages_hr.py
+++ b/nikola/data/themes/base/messages/messages_hr.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktivno)",
"Also available in:": "Također dostupno i u:",
"Archive": "Arhiva",
+ "Authors": "",
"Categories": "Kategorije",
"Comments": "Komentari",
"LANGUAGE": "hrvatski",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Izvorna stranica",
"Posted:": "Objavljeno:",
"Posts about %s": "Postovi o %s",
+ "Posts by %s": "",
"Posts for year %s": "Postovi za godinu %s",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "Postovi za {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Podkategorije:",
"Tags and Categories": "Tagovi i kategorije",
"Tags": "Tagovi",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "stari postovi, stranice %d",
diff --git a/nikola/data/themes/base/messages/messages_hu.py b/nikola/data/themes/base/messages/messages_hu.py
new file mode 100644
index 0000000..e1dc354
--- /dev/null
+++ b/nikola/data/themes/base/messages/messages_hu.py
@@ -0,0 +1,43 @@
+# -*- encoding:utf-8 -*-
+from __future__ import unicode_literals
+
+MESSAGES = {
+ "%d min remaining to read": "%d perc van hátra olvasni",
+ "(active)": "(aktív)",
+ "Also available in:": "Olvasható még:",
+ "Archive": "Archív",
+ "Authors": "Szerzők",
+ "Categories": "Kategóriák",
+ "Comments": "Hozzászólások",
+ "LANGUAGE": "Magyarul",
+ "Languages:": "Nyelvek:",
+ "More posts about %s": "Több bejegyzés erről: %s",
+ "Newer posts": "Újabb bejegyzések",
+ "Next post": "A következő bejegyzés",
+ "No posts found.": "Nincs ilyen bejegyzés.",
+ "Nothing found.": "Nincs találat.",
+ "Older posts": "Régebbi bejegyzések",
+ "Original site": "Eredeti honlap",
+ "Posted:": "Megjelent:",
+ "Posts about %s": "Bejegyzések erről: %s",
+ "Posts by %s": "Bejegyzések %s által",
+ "Posts for year %s": "%s. bejegyzések",
+ "Posts for {month} {day}, {year}": "{year}. {month}. {day}.-i bejegyzések",
+ "Posts for {month} {year}": "{year}. {month}.-i bejegyzések",
+ "Previous post": "Az előző bejegyzés ",
+ "Publication date": "A megjelenés dátuma",
+ "RSS feed": "RSS",
+ "Read in English": "Olvass magyarul",
+ "Read more": "Olvass tovább",
+ "Skip to main content": "Ugrás a főtartalomra",
+ "Source": "Forrás",
+ "Subcategories:": "Alkategóriák:",
+ "Tags and Categories": "Címkék és kategóriák",
+ "Tags": "Címkék",
+ "Uncategorized": "Nincs kategorizálva",
+ "Updates": "Frissítések",
+ "Write your page here.": "Ide írd az oldalad.",
+ "Write your post here.": "Ide írd a bejegyzésed.",
+ "old posts, page %d": "régi bejegyzések, %d. oldal",
+ "page %d": "%d. oldal",
+}
diff --git a/nikola/data/themes/base/messages/messages_id.py b/nikola/data/themes/base/messages/messages_id.py
index 475299f..3682b5b 100644
--- a/nikola/data/themes/base/messages/messages_id.py
+++ b/nikola/data/themes/base/messages/messages_id.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktif)",
"Also available in:": "Juga tersedia dalam:",
"Archive": "Arsip",
+ "Authors": "",
"Categories": "Kategori",
"Comments": "Komentar",
"LANGUAGE": "Inggris",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Situs orisinal",
"Posted:": "Ditulis oleh:",
"Posts about %s": "Tulisan tentang %s",
+ "Posts by %s": "",
"Posts for year %s": "Tulisan untuk tahun %s",
"Posts for {month} {day}, {year}": "Tulisan untuk {month} {day}, {year}",
"Posts for {month} {year}": "Tulisan untuk {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Sub kategori:",
"Tags and Categories": "Tag dan Kategori",
"Tags": "Tag",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "tulisan lama, halaman %d",
diff --git a/nikola/data/themes/base/messages/messages_it.py b/nikola/data/themes/base/messages/messages_it.py
index 9f6d8be..65481e0 100644
--- a/nikola/data/themes/base/messages/messages_it.py
+++ b/nikola/data/themes/base/messages/messages_it.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(attivo)",
"Also available in:": "Disponibile anche in:",
"Archive": "Archivio",
+ "Authors": "Autori",
"Categories": "Categorie",
"Comments": "Commenti",
"LANGUAGE": "Italiano",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Sito originale",
"Posted:": "Pubblicato:",
"Posts about %s": "Articoli su %s",
+ "Posts by %s": "Articoli di %s",
"Posts for year %s": "Articoli per l'anno %s",
"Posts for {month} {day}, {year}": "Articoli per il {day} {month} {year}",
"Posts for {month} {year}": "Articoli per {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Sottocategorie:",
"Tags and Categories": "Tag e categorie",
"Tags": "Tag",
+ "Uncategorized": "Senza categorie",
+ "Updates": "Aggiornamenti",
"Write your page here.": "Scrivi qui la tua pagina.",
"Write your post here.": "Scrivi qui il tuo post.",
"old posts, page %d": "vecchi articoli, pagina %d",
diff --git a/nikola/data/themes/base/messages/messages_ja.py b/nikola/data/themes/base/messages/messages_ja.py
index 972794d..c94c79c 100644
--- a/nikola/data/themes/base/messages/messages_ja.py
+++ b/nikola/data/themes/base/messages/messages_ja.py
@@ -2,38 +2,42 @@
from __future__ import unicode_literals
MESSAGES = {
- "%d min remaining to read": "読込むまで残り %d 分",
- "(active)": "",
- "Also available in:": "他の言語で読む:",
- "Archive": "過去の記事",
- "Categories": "カテゴリー",
+ "%d min remaining to read": "残りを読むのに必要な時間は%d分",
+ "(active)": "(有効)",
+ "Also available in:": "他の言語で読む:",
+ "Archive": "文書一覧",
+ "Authors": "著者一覧",
+ "Categories": "カテゴリ",
"Comments": "コメント",
"LANGUAGE": "日本語",
- "Languages:": "言語 :",
- "More posts about %s": "タグ: %s",
- "Newer posts": "新しい記事",
- "Next post": "次の記事",
- "No posts found.": "記事はありません",
- "Nothing found.": "なにも見つかりませんでした",
- "Older posts": "過去の記事",
- "Original site": "元のサイト",
- "Posted:": "投稿日時:",
- "Posts about %s": "%sについての記事",
- "Posts for year %s": "%s年の記事",
- "Posts for {month} {day}, {year}": "{year}年{month}月{day}日の記事",
- "Posts for {month} {year}": "{year}年{month}月の記事",
- "Previous post": "前の記事",
- "Publication date": "投稿日",
- "RSS feed": "RSS フィード",
+ "Languages:": "言語:",
+ "More posts about %s": "%sに関する文書一覧",
+ "Newer posts": "新しい文書",
+ "Next post": "次の文書",
+ "No posts found.": "文書はありません。",
+ "Nothing found.": "なにも見つかりませんでした。",
+ "Older posts": "過去の文書",
+ "Original site": "翻訳元のサイト",
+ "Posted:": "公開日時:",
+ "Posts about %s": "%sについての文書",
+ "Posts by %s": "%sの文書一覧",
+ "Posts for year %s": "%s年の文書",
+ "Posts for {month} {day}, {year}": "{year}年{month}{day}日の文書",
+ "Posts for {month} {year}": "{year}年{month}の文書",
+ "Previous post": "一つ前の文書",
+ "Publication date": "公開日",
+ "RSS feed": "RSSフィード",
"Read in English": "日本語で読む",
"Read more": "続きを読む",
- "Skip to main content": "メインコンテンツをスキップ",
+ "Skip to main content": "本文を読み飛ばす",
"Source": "ソース",
- "Subcategories:": "",
- "Tags and Categories": "タグとカテゴリー",
+ "Subcategories:": "サブカテゴリ",
+ "Tags and Categories": "カテゴリおよびタグ一覧",
"Tags": "タグ",
- "Write your page here.": "",
- "Write your post here.": "",
- "old posts, page %d": "前の記事 %dページ目",
- "page %d": "ページ %d",
+ "Uncategorized": "uncategorized",
+ "Updates": "フィード",
+ "Write your page here.": "ここに文書を記述してください。",
+ "Write your post here.": "ここに文書を記述してください。",
+ "old posts, page %d": "過去の文書 %dページ目",
+ "page %d": "ページ%d",
}
diff --git a/nikola/data/themes/base/messages/messages_ko.py b/nikola/data/themes/base/messages/messages_ko.py
index 6904492..7f06c28 100644
--- a/nikola/data/themes/base/messages/messages_ko.py
+++ b/nikola/data/themes/base/messages/messages_ko.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "저장소",
+ "Authors": "",
"Categories": "분류",
"Comments": "댓글",
"LANGUAGE": "영어",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "출처",
"Posted:": "",
"Posts about %s": "%s에 대한 포스트",
+ "Posts by %s": "",
"Posts for year %s": "%s년도 포스트",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "{year}년 {month}월에 쓴 포스트",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "태그와 분류",
"Tags": "태그",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "이전 포스트, 페이지 %d",
diff --git a/nikola/data/themes/base/messages/messages_nb.py b/nikola/data/themes/base/messages/messages_nb.py
index 30b798e..fd98f88 100644
--- a/nikola/data/themes/base/messages/messages_nb.py
+++ b/nikola/data/themes/base/messages/messages_nb.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktiv)",
"Also available in:": "Også tilgjengelig på:",
"Archive": "Arkiv",
+ "Authors": "",
"Categories": "Kategorier",
"Comments": "Kommentarer",
"LANGUAGE": "norsk",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Opprinnelig side",
"Posted:": "Publisert:",
"Posts about %s": "Innlegg om %s",
+ "Posts by %s": "",
"Posts for year %s": "Innlegg fra %s",
"Posts for {month} {day}, {year}": "Innlegg fra {day}. {month} {year}",
"Posts for {month} {year}": "Innlegg fra {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Underkategorier:",
"Tags and Categories": "Merker og kategorier",
"Tags": "Merker",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Skriv siden din her.",
"Write your post here.": "Skriv innlegget din her.",
"old posts, page %d": "eldre innlegg, side %d",
diff --git a/nikola/data/themes/base/messages/messages_nl.py b/nikola/data/themes/base/messages/messages_nl.py
index 0661ce1..42becd9 100644
--- a/nikola/data/themes/base/messages/messages_nl.py
+++ b/nikola/data/themes/base/messages/messages_nl.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(actief)",
"Also available in:": "Ook beschikbaar in:",
"Archive": "Archief",
+ "Authors": "Auteurs",
"Categories": "Categorieën",
"Comments": "Commentaar",
"LANGUAGE": "Nederlands",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Originele site",
"Posted:": "Geplaatst:",
"Posts about %s": "Berichten over %s",
+ "Posts by %s": "Berichten van %s",
"Posts for year %s": "Berichten voor het jaar %s",
"Posts for {month} {day}, {year}": "Berichten voor {month} {day}, {year}",
"Posts for {month} {year}": "Berichten voor {month} {year}",
@@ -32,8 +34,10 @@ MESSAGES = {
"Subcategories:": "Subcategorieën",
"Tags and Categories": "Tags en Categorieën",
"Tags": "Tags",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "Ongeordend",
+ "Updates": "Bijgewerkte versies",
+ "Write your page here.": "Schrijf hier je pagina.",
+ "Write your post here.": "Schrijf hier je bericht.",
"old posts, page %d": "oude berichten, pagina %d",
"page %d": "pagina %d",
}
diff --git a/nikola/data/themes/base/messages/messages_pa.py b/nikola/data/themes/base/messages/messages_pa.py
index 392a38b..13996ac 100644
--- a/nikola/data/themes/base/messages/messages_pa.py
+++ b/nikola/data/themes/base/messages/messages_pa.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(ਚਲੰਤ)",
"Also available in:": "ਹੋਰ ਉਪਲਬਧ ਬੋਲੀਆਂ:",
"Archive": "ਆਰਕਾਈਵ",
+ "Authors": "",
"Categories": "ਸ਼੍ਰੇਣੀ",
"Comments": "ਟਿੱਪਣੀਆਂ",
"LANGUAGE": "ਅੰਗਰੇਜ਼ੀ",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "ਅਸਲ ਸਾਈਟ",
"Posted:": "ਲਿਖਤ ਛਪੀ:",
"Posts about %s": "%s ਬਾਰੇ ਲਿਖਤਾਂ",
+ "Posts by %s": "",
"Posts for year %s": "ਸਾਲ %s ਦੀਆਂ ਲਿਖਤਾਂ",
"Posts for {month} {day}, {year}": "{day} {month} {year} ਦੀਆਂ ਲਿਖਤਾਂ",
"Posts for {month} {year}": "{month} {year} ਦੀਆਂ ਲਿਖਤਾਂ",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "ਉਪਸ਼੍ਰੇਣੀਆਂ:",
"Tags and Categories": "ਟੈਗ ਅਤੇ ਸ਼੍ਰੇਣੀਆਂ",
"Tags": "ਟੈਗ",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "ਆਪਣਾ ਸਫ਼ਾ ਏਥੇ ਲਿਖੋ |",
"Write your post here.": "ਆਪਣੀ ਲਿਖਤ ਏਥੇ ਲਿਖੋ |",
"old posts, page %d": "ਪੁਰਾਣੀਆਂ ਲਿਖਤਾਂ , ਸਫ਼ਾ %d",
diff --git a/nikola/data/themes/base/messages/messages_pl.py b/nikola/data/themes/base/messages/messages_pl.py
index 89aae0f..3e24bfc 100644
--- a/nikola/data/themes/base/messages/messages_pl.py
+++ b/nikola/data/themes/base/messages/messages_pl.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktywne)",
"Also available in:": "Również dostępny w językach:",
"Archive": "Archiwum",
+ "Authors": "Autorzy",
"Categories": "Kategorie",
"Comments": "Komentarze",
"LANGUAGE": "Polski",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Oryginalna strona",
"Posted:": "Opublikowano:",
"Posts about %s": "Posty o %s",
+ "Posts by %s": "Posty autora %s",
"Posts for year %s": "Posty z roku %s",
"Posts for {month} {day}, {year}": "Posty z {day} {month} {year}",
"Posts for {month} {year}": "Posty z {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Podkategorie:",
"Tags and Categories": "Tagi i Kategorie",
"Tags": "Tagi",
+ "Uncategorized": "Nieskategoryzowane",
+ "Updates": "Aktualności",
"Write your page here.": "Tu wpisz treść strony.",
"Write your post here.": "Tu wpisz treść postu.",
"old posts, page %d": "stare posty, strona %d",
diff --git a/nikola/data/themes/base/messages/messages_pt.py b/nikola/data/themes/base/messages/messages_pt.py
index 91ea52e..3c4bd55 100644
--- a/nikola/data/themes/base/messages/messages_pt.py
+++ b/nikola/data/themes/base/messages/messages_pt.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(ativo)",
"Also available in:": "Também disponível em:",
"Archive": "Arquivo",
+ "Authors": "",
"Categories": "Categorias",
"Comments": "Comentários",
"LANGUAGE": "Português",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Sítio original",
"Posted:": "Publicado:",
"Posts about %s": "Textos publicados sobre %s",
+ "Posts by %s": "",
"Posts for year %s": "Textos publicados do ano %s",
"Posts for {month} {day}, {year}": "Textos publicados de {day} {month} {year}",
"Posts for {month} {year}": "Textos publicados de {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Sub-Categorias:",
"Tags and Categories": "Etiquetas e Categorias",
"Tags": "Etiqueta",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Escreva a sua página aqui.",
"Write your post here.": "Escreva o seu texto para publicar aqui.",
"old posts, page %d": "Textos publicados antigos, página %d",
diff --git a/nikola/data/themes/base/messages/messages_pt_br.py b/nikola/data/themes/base/messages/messages_pt_br.py
index 58ad63f..7dcc8a8 100644
--- a/nikola/data/themes/base/messages/messages_pt_br.py
+++ b/nikola/data/themes/base/messages/messages_pt_br.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Também disponível em:",
"Archive": "Arquivo",
+ "Authors": "",
"Categories": "Categorias",
"Comments": "Comentários",
"LANGUAGE": "Português",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Site original",
"Posted:": "Publicado:",
"Posts about %s": "Posts sobre %s",
+ "Posts by %s": "",
"Posts for year %s": "Posts do ano %s",
"Posts for {month} {day}, {year}": "Posts do {day} {month}, {year}",
"Posts for {month} {year}": "Posts de {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Tags e Categorias",
"Tags": "Tags",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "Posts antigos, página %d",
diff --git a/nikola/data/themes/base/messages/messages_ru.py b/nikola/data/themes/base/messages/messages_ru.py
index cfbe536..bdf3873 100644
--- a/nikola/data/themes/base/messages/messages_ru.py
+++ b/nikola/data/themes/base/messages/messages_ru.py
@@ -3,9 +3,10 @@ from __future__ import unicode_literals
MESSAGES = {
"%d min remaining to read": "%d минут чтения осталось",
- "(active)": "",
+ "(active)": "(активная)",
"Also available in:": "Также доступно на:",
"Archive": "Архив",
+ "Authors": "",
"Categories": "Категории",
"Comments": "Комментарии",
"LANGUAGE": "Русский",
@@ -19,8 +20,9 @@ MESSAGES = {
"Original site": "Оригинальный сайт",
"Posted:": "Опубликовано:",
"Posts about %s": "Записи о %s",
+ "Posts by %s": "",
"Posts for year %s": "Записи за %s год",
- "Posts for {month} {day}, {year}": "",
+ "Posts for {month} {day}, {year}": "Записи за {day} {month} {year}",
"Posts for {month} {year}": "Записи за {month} {year}",
"Previous post": "Предыдущая запись",
"Publication date": "Дата опубликования",
@@ -29,11 +31,13 @@ MESSAGES = {
"Read more": "Читать далее",
"Skip to main content": "Перейти к главному содержимому",
"Source": "Источник",
- "Subcategories:": "",
+ "Subcategories:": "Подкатегории:",
"Tags and Categories": "Тэги и категории",
"Tags": "Тэги",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "",
+ "Updates": "",
+ "Write your page here.": "Создайте Вашу страницу здесь.",
+ "Write your post here.": "Создайте Вашу запись здесь.",
"old posts, page %d": "%d страница со старыми записями",
"page %d": "%d страница",
}
diff --git a/nikola/data/themes/base/messages/messages_si_lk.py b/nikola/data/themes/base/messages/messages_si_lk.py
index fd26d77..f661c0e 100644
--- a/nikola/data/themes/base/messages/messages_si_lk.py
+++ b/nikola/data/themes/base/messages/messages_si_lk.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "",
+ "Authors": "",
"Categories": "",
"Comments": "",
"LANGUAGE": "",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "",
"Posted:": "",
"Posts about %s": "",
+ "Posts by %s": "",
"Posts for year %s": "",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "",
"Tags": "",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "",
diff --git a/nikola/data/themes/base/messages/messages_sk.py b/nikola/data/themes/base/messages/messages_sk.py
index acd7364..03cce43 100644
--- a/nikola/data/themes/base/messages/messages_sk.py
+++ b/nikola/data/themes/base/messages/messages_sk.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktívne)",
"Also available in:": "Tiež dostupné v:",
"Archive": "Archív",
+ "Authors": "",
"Categories": "Kategórie",
"Comments": "Komentáre",
"LANGUAGE": "Slovenčina",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Pôvodná stránka",
"Posted:": "Zverejnené:",
"Posts about %s": "Príspevky o %s",
+ "Posts by %s": "",
"Posts for year %s": "Príspevky z roku %s",
"Posts for {month} {day}, {year}": "Príspevky zo dňa {day}. {month} {year}",
"Posts for {month} {year}": "Príspevky za mesiac {month} z roku {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Podkategórie:",
"Tags and Categories": "Štítky a kategórie",
"Tags": "Štítky",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Tu napíšte svoju stránku.",
"Write your post here.": "Tu napíšte svoj príspevok.",
"old posts, page %d": "staré príspevky, strana %d",
diff --git a/nikola/data/themes/base/messages/messages_sl.py b/nikola/data/themes/base/messages/messages_sl.py
index 992787b..a531ca5 100644
--- a/nikola/data/themes/base/messages/messages_sl.py
+++ b/nikola/data/themes/base/messages/messages_sl.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Na voljo tudi v:",
"Archive": "Arhiv",
+ "Authors": "",
"Categories": "Kategorije",
"Comments": "Komentarji",
"LANGUAGE": "Slovenščina",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Izvorna spletna stran",
"Posted:": "Objavljeno:",
"Posts about %s": "Objave o %s",
+ "Posts by %s": "",
"Posts for year %s": "Objave za leto %s",
"Posts for {month} {day}, {year}": "Objave za {day}. {month}, {year}",
"Posts for {month} {year}": "Objave za {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Značke in kategorije",
"Tags": "Značke",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "stare objave, stran %d",
diff --git a/nikola/data/themes/base/messages/messages_sr.py b/nikola/data/themes/base/messages/messages_sr.py
index 2b0aaf5..13137c3 100644
--- a/nikola/data/themes/base/messages/messages_sr.py
+++ b/nikola/data/themes/base/messages/messages_sr.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(активно)",
"Also available in:": "Такође доступан у:",
"Archive": "Архива",
+ "Authors": "",
"Categories": "Категорије",
"Comments": "Коментари",
"LANGUAGE": "Српски",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Оригинал сајт",
"Posted:": "Објављено:",
"Posts about %s": "Постови о %s",
+ "Posts by %s": "",
"Posts for year %s": "Постови за годину %s",
"Posts for {month} {day}, {year}": "Објаве за {month} {day}, {year}",
"Posts for {month} {year}": "Постови за {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Подкатегорије:",
"Tags and Categories": "Тагови и категорије",
"Tags": "Тагови",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Вашу страницу напишите овдје.",
"Write your post here.": "Вашу објаву напишите овдје.",
"old posts, page %d": "стари постови, страна %d",
diff --git a/nikola/data/themes/base/messages/messages_sr@latin.py b/nikola/data/themes/base/messages/messages_sr_latin.py
index 23a1f64..db60c76 100644
--- a/nikola/data/themes/base/messages/messages_sr@latin.py
+++ b/nikola/data/themes/base/messages/messages_sr_latin.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktivno)",
"Also available in:": "Takođe dostupan u:",
"Archive": "Arhiva",
+ "Authors": "",
"Categories": "Kategorije",
"Comments": "Komentari",
"LANGUAGE": "Bosanski",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Izvorni sajt",
"Posted:": "Objavljeno:",
"Posts about %s": "Objave o %s",
+ "Posts by %s": "",
"Posts for year %s": "Objave u godini %s",
"Posts for {month} {day}, {year}": "Objave za {month} {day}, {year}",
"Posts for {month} {year}": "Objave za {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Podkategorije:",
"Tags and Categories": "Oznake i kategorije",
"Tags": "Oznake",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Vašu stranicu napišite ovdje.",
"Write your post here.": "Vašu objavu napišite ovdje.",
"old posts, page %d": "stare objave, strana %d",
diff --git a/nikola/data/themes/base/messages/messages_sv.py b/nikola/data/themes/base/messages/messages_sv.py
index 52df00d..d1357e7 100644
--- a/nikola/data/themes/base/messages/messages_sv.py
+++ b/nikola/data/themes/base/messages/messages_sv.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "(aktiv)",
"Also available in:": "Även tillgänglig på:",
"Archive": "Arkiv",
+ "Authors": "",
"Categories": "Kategorier",
"Comments": "Kommentarer",
"LANGUAGE": "Svenska",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Originalsida",
"Posted:": "Publicerad:",
"Posts about %s": "Inlägg om %s",
+ "Posts by %s": "",
"Posts for year %s": "Inlägg för år %s",
"Posts for {month} {day}, {year}": "Inlägg för {month} {day}, {year}",
"Posts for {month} {year}": "Inlägg för {month} {year}",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "Underkategorier:",
"Tags and Categories": "Taggar och Kategorier",
"Tags": "Taggar",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "Skriv din sida här.",
"Write your post here.": "Skriv ditt inlägg här.",
"old posts, page %d": "gamla inlägg, sida %d",
diff --git a/nikola/data/themes/base/messages/messages_tl.py b/nikola/data/themes/base/messages/messages_tl.py
index f748edd..303ea36 100644
--- a/nikola/data/themes/base/messages/messages_tl.py
+++ b/nikola/data/themes/base/messages/messages_tl.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "",
+ "Authors": "",
"Categories": "",
"Comments": "",
"LANGUAGE": "Ingles",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "",
"Posted:": "",
"Posts about %s": "",
+ "Posts by %s": "",
"Posts for year %s": "",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "",
"Tags": "Mga Tag",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "",
diff --git a/nikola/data/themes/base/messages/messages_tr.py b/nikola/data/themes/base/messages/messages_tr.py
index 21eb534..e173a40 100644
--- a/nikola/data/themes/base/messages/messages_tr.py
+++ b/nikola/data/themes/base/messages/messages_tr.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "Şu dilde de mevcut:",
"Archive": "Arşiv",
+ "Authors": "",
"Categories": "Kategoriler",
"Comments": "Yorumlar",
"LANGUAGE": "Türkçe",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Orjinal web sayfası",
"Posted:": "Yayın tarihi:",
"Posts about %s": "%s ile ilgili yazılar",
+ "Posts by %s": "",
"Posts for year %s": "%s yılındaki yazılar",
"Posts for {month} {day}, {year}": "{month} {day}, {year} 'den beri olan yazılar",
"Posts for {month} {year}": "{month} {year} göre yazılar",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "Etiketler ve Kategoriler",
"Tags": "Etiketler",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "eski yazılar, sayfa %d",
diff --git a/nikola/data/themes/base/messages/messages_uk.py b/nikola/data/themes/base/messages/messages_uk.py
index 16913da..4f19568 100644
--- a/nikola/data/themes/base/messages/messages_uk.py
+++ b/nikola/data/themes/base/messages/messages_uk.py
@@ -3,15 +3,16 @@ from __future__ import unicode_literals
MESSAGES = {
"%d min remaining to read": "Залишилось читати %d хвилин",
- "(active)": "",
+ "(active)": "(активне)",
"Also available in:": "Іншою мовою:",
"Archive": "Архів",
+ "Authors": "",
"Categories": "Категорії",
"Comments": "Коментарі",
"LANGUAGE": "Українська",
"Languages:": "Мови:",
"More posts about %s": "Більше статей про %s",
- "Newer posts": "Нові статті",
+ "Newer posts": "Новіші статті",
"Next post": "Наступна стаття",
"No posts found.": "Не знайдено жодної статті",
"Nothing found.": "Нічого не знайдено",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "Оригінал сайту",
"Posted:": "Опублікована:",
"Posts about %s": "Статті про %s",
+ "Posts by %s": "",
"Posts for year %s": "Статті за %s рік",
"Posts for {month} {day}, {year}": "Статті за {month} {day}, {year}",
"Posts for {month} {year}": "Статті за {month} {year}",
@@ -29,11 +31,13 @@ MESSAGES = {
"Read more": "Читати далі",
"Skip to main content": "Перейти до основного матеріалу",
"Source": "Джерело",
- "Subcategories:": "",
+ "Subcategories:": "Підкатегорії:",
"Tags and Categories": "Теги і категорії",
"Tags": "Теги",
- "Write your page here.": "",
- "Write your post here.": "",
+ "Uncategorized": "",
+ "Updates": "",
+ "Write your page here.": "Напишіть Вашу сторінку тут.",
+ "Write your post here.": "Напишить Вашу статтю тут.",
"old posts, page %d": "старі статті, сторінка %d",
"page %d": "сторінка %d",
}
diff --git a/nikola/data/themes/base/messages/messages_ur.py b/nikola/data/themes/base/messages/messages_ur.py
index 074cb06..92cdccd 100644
--- a/nikola/data/themes/base/messages/messages_ur.py
+++ b/nikola/data/themes/base/messages/messages_ur.py
@@ -4,8 +4,9 @@ from __future__ import unicode_literals
MESSAGES = {
"%d min remaining to read": "%d منٹ کا مطالعہ باقی",
"(active)": "(فعال)",
- "Also available in:": "ان زبانوں میں بھی دستیاب:",
+ "Also available in:": "ان میں بھی دستیاب:",
"Archive": "آرکائیو",
+ "Authors": "مصنفین",
"Categories": "زمرے",
"Comments": "تبصرے",
"LANGUAGE": "اردو",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "اصلی سائٹ",
"Posted:": "اشاعت:",
"Posts about %s": "%s کے بارے میں تحاریر",
+ "Posts by %s": "%s کی تحاریر",
"Posts for year %s": "سال %s کی تحاریر",
"Posts for {month} {day}, {year}": "{day} {month}، {year} کی تحاریر",
"Posts for {month} {year}": "{month} {year} کی تحاریر",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "ذیلی زمرے",
"Tags and Categories": "ٹیگز اور زمرے",
"Tags": "ٹیگز",
+ "Uncategorized": "",
+ "Updates": "تازہ ترین",
"Write your page here.": "اپنے صفحے کا متن یہاں لکھیں۔",
"Write your post here.": "اپنی تحریر یہاں لکھیں۔",
"old posts, page %d": "پرانی تحاریر صفحہ %d",
diff --git a/nikola/data/themes/base/messages/messages_zh_cn.py b/nikola/data/themes/base/messages/messages_zh_cn.py
index c21b4f0..888b50e 100644
--- a/nikola/data/themes/base/messages/messages_zh_cn.py
+++ b/nikola/data/themes/base/messages/messages_zh_cn.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "其他语言版本:",
"Archive": "文章存档",
+ "Authors": "",
"Categories": "分类",
"Comments": "",
"LANGUAGE": "简体中文",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "原文地址",
"Posted:": "发表于:",
"Posts about %s": "文章分类:%s",
+ "Posts by %s": "",
"Posts for year %s": "%s年文章",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "{year}年{month}月文章",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "标签和分类",
"Tags": "标签",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "旧文章页 %d",
diff --git a/nikola/data/themes/base/messages/messages_zh_tw.py b/nikola/data/themes/base/messages/messages_zh_tw.py
index fd26d77..f661c0e 100644
--- a/nikola/data/themes/base/messages/messages_zh_tw.py
+++ b/nikola/data/themes/base/messages/messages_zh_tw.py
@@ -6,6 +6,7 @@ MESSAGES = {
"(active)": "",
"Also available in:": "",
"Archive": "",
+ "Authors": "",
"Categories": "",
"Comments": "",
"LANGUAGE": "",
@@ -19,6 +20,7 @@ MESSAGES = {
"Original site": "",
"Posted:": "",
"Posts about %s": "",
+ "Posts by %s": "",
"Posts for year %s": "",
"Posts for {month} {day}, {year}": "",
"Posts for {month} {year}": "",
@@ -32,6 +34,8 @@ MESSAGES = {
"Subcategories:": "",
"Tags and Categories": "",
"Tags": "",
+ "Uncategorized": "",
+ "Updates": "",
"Write your page here.": "",
"Write your post here.": "",
"old posts, page %d": "",
diff --git a/nikola/data/themes/base/templates/author.tmpl b/nikola/data/themes/base/templates/author.tmpl
new file mode 100644
index 0000000..3ad5140
--- /dev/null
+++ b/nikola/data/themes/base/templates/author.tmpl
@@ -0,0 +1,43 @@
+## -*- coding: utf-8 -*-
+<%inherit file="list_post.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ %if len(translations) > 1 and generate_rss:
+ %for language in sorted(translations):
+ <link rel="alternate" type="application/rss+xml" title="RSS for ${kind} ${author|h} (${language})" href="${_link(kind + "_rss", author, language)}">
+ %endfor
+ %elif generate_rss:
+ <link rel="alternate" type="application/rss+xml" title="RSS for ${kind} ${author|h}" href="${_link(kind + "_rss", author)}">
+ %endif
+</%block>
+
+
+<%block name="content">
+<article class="authorpage">
+ <header>
+ <h1>${title|h}</h1>
+ %if description:
+ <p>${description}</p>
+ %endif
+ <div class="metadata">
+ %if len(translations) > 1 and generate_rss:
+ %for language in sorted(translations):
+ <p class="feedlink">
+ <a href="${_link(kind + "_rss", author, language)}" hreflang="${language}" type="application/rss+xml">${messages('RSS feed', language)} (${language})</a>&nbsp;
+ </p>
+ %endfor
+ %elif generate_rss:
+ <p class="feedlink"><a href="${_link(kind + "_rss", author)}" type="application/rss+xml">${messages('RSS feed')}</a></p>
+ %endif
+ </div>
+ </header>
+ %if posts:
+ <ul class="postlist">
+ % for post in posts:
+ <li><a href="${post.permalink()}" class="listtitle">${post.title()|h}</a><time class="listdate" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)|h}">${post.formatted_date(date_format)|h}</time></li>
+ % endfor
+ </ul>
+ %endif
+</article>
+</%block>
diff --git a/nikola/data/themes/base/templates/authorindex.tmpl b/nikola/data/themes/base/templates/authorindex.tmpl
new file mode 100644
index 0000000..34cb20b
--- /dev/null
+++ b/nikola/data/themes/base/templates/authorindex.tmpl
@@ -0,0 +1,13 @@
+## -*- coding: utf-8 -*-
+<%inherit file="index.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ %if len(tranlations) > 1 and generate_atom:
+ %for language in sorted(translations):
+ <link rel="alternate" type="application/atom+xml" title="Atom for the ${author|h} section (${language})" href="${_link(kind + "_atom", author, language)}">
+ %endfor
+ %elif generate_atom:
+ <link rel="alternate" type="application/atom+xml" title="Atom for the ${author|h} section" href="${_link("author" + "_atom", author)}">
+ %endif
+</%block>
diff --git a/nikola/data/themes/base/templates/authors.tmpl b/nikola/data/themes/base/templates/authors.tmpl
new file mode 100644
index 0000000..141c560
--- /dev/null
+++ b/nikola/data/themes/base/templates/authors.tmpl
@@ -0,0 +1,17 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+
+<%block name="content">
+<article class="authorindex">
+ %if items:
+ <h2>${messages("Authors")}</h2>
+ <ul class="postlist">
+ % for text, link in items:
+ % if text not in hidden_authors:
+ <li><a class="reference listtitle" href="${link}">${text|h}</a></li>
+ % endif
+ % endfor
+ </ul>
+ %endif
+</article>
+</%block>
diff --git a/nikola/data/themes/base/templates/base_header.tmpl b/nikola/data/themes/base/templates/base_header.tmpl
index e29e2b3..2ffcfee 100644
--- a/nikola/data/themes/base/templates/base_header.tmpl
+++ b/nikola/data/themes/base/templates/base_header.tmpl
@@ -16,13 +16,13 @@
</%def>
<%def name="html_site_title()">
- <h1 id="brand"><a href="${abs_link(_link("root", None, lang))}" title="${blog_title}" rel="home">
+ <h1 id="brand"><a href="${abs_link(_link("root", None, lang))}" title="${blog_title|h}" rel="home">
%if logo_url:
- <img src="${logo_url}" alt="${blog_title}" id="logo">
+ <img src="${logo_url}" alt="${blog_title|h}" id="logo">
%endif
% if show_blog_title:
- <span id="blog-title">${blog_title}</span>
+ <span id="blog-title">${blog_title|h}</span>
% endif
</a></h1>
</%def>
diff --git a/nikola/data/themes/base/templates/base_helper.tmpl b/nikola/data/themes/base/templates/base_helper.tmpl
index 948cfba..35ed983 100644
--- a/nikola/data/themes/base/templates/base_helper.tmpl
+++ b/nikola/data/themes/base/templates/base_helper.tmpl
@@ -21,9 +21,11 @@ dir="rtl" \
lang="${lang}">
<head>
<meta charset="utf-8">
+ % if use_base_tag:
<base href="${abs_link(permalink)}">
+ % endif
%if description:
- <meta name="description" content="${description}">
+ <meta name="description" content="${description|h}">
%endif
<meta name="viewport" content="width=device-width">
%if title == blog_title:
@@ -33,6 +35,7 @@ lang="${lang}">
%endif
${html_stylesheets()}
+ <meta content="${theme_color}" name="theme-color">
${html_feedlinks()}
<link rel="canonical" href="${abs_link(permalink)}">
diff --git a/nikola/data/themes/base/templates/gallery.tmpl b/nikola/data/themes/base/templates/gallery.tmpl
index 0ee07ac..126d51c 100644
--- a/nikola/data/themes/base/templates/gallery.tmpl
+++ b/nikola/data/themes/base/templates/gallery.tmpl
@@ -17,8 +17,8 @@
%if folders:
<ul>
% for folder, ftitle in folders:
- <li><a href="${folder}"><i
- class="icon-folder-open"></i>&nbsp;${ftitle}</a></li>
+ <li><a href="${folder|u}"><i
+ class="icon-folder-open"></i>&nbsp;${ftitle|h}</a></li>
% endfor
</ul>
%endif
@@ -26,7 +26,7 @@
<ul class="thumbnails">
%for image in photo_array:
<li><a href="${image['url']}" class="thumbnail image-reference" title="${image['title']}">
- <img src="${image['url_thumb']}" alt="${image['title']}" /></a>
+ <img src="${image['url_thumb']}" alt="${image['title']|h}" /></a>
%endfor
</ul>
%endif
diff --git a/nikola/data/themes/base/templates/index.tmpl b/nikola/data/themes/base/templates/index.tmpl
index 88bb25c..294bdaf 100644
--- a/nikola/data/themes/base/templates/index.tmpl
+++ b/nikola/data/themes/base/templates/index.tmpl
@@ -18,8 +18,14 @@
<header>
<h1 class="p-name entry-title"><a href="${post.permalink()}" class="u-url">${post.title()|h}</a></h1>
<div class="metadata">
- <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
- <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></a></p>
+ <p class="byline author vcard"><span class="byline-name fn">
+ % if author_pages_generated:
+ <a href="${_link('author', post.author())}">${post.author()|h}</a>
+ % else:
+ ${post.author()|h}
+ % endif
+ </span></p>
+ <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)|h}">${post.formatted_date(date_format)|h}</time></a></p>
% if not post.meta('nocomments') and site_has_comments:
<p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
% endif
diff --git a/nikola/data/themes/base/templates/index_helper.tmpl b/nikola/data/themes/base/templates/index_helper.tmpl
index 9331b93..fae046d 100644
--- a/nikola/data/themes/base/templates/index_helper.tmpl
+++ b/nikola/data/themes/base/templates/index_helper.tmpl
@@ -20,8 +20,17 @@
<%def name="mathjax_script(posts)">
%if any(post.is_mathjax for post in posts):
- <script type="text/x-mathjax-config">
- MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
- <script src="/assets/js/mathjax.js"></script>
+ %if use_katex:
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/contrib/auto-render.min.js"></script>
+ <script>
+ renderMathInElement(document.body);
+ </script>
+ %else:
+ <script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script>
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
+ </script>
+ %endif
%endif
</%def>
diff --git a/nikola/data/themes/base/templates/list.tmpl b/nikola/data/themes/base/templates/list.tmpl
index 4082516..5a8843d 100644
--- a/nikola/data/themes/base/templates/list.tmpl
+++ b/nikola/data/themes/base/templates/list.tmpl
@@ -4,12 +4,15 @@
<%block name="content">
<article class="listpage">
<header>
- <h1>${title}</h1>
+ <h1>${title|h}</h1>
</header>
%if items:
<ul class="postlist">
- % for text, link in items:
- <li><a href="${link}">${text}</a>
+ % for text, link, count in items:
+ <li><a href="${link}">${text|h}</a>
+ % if count:
+ (${count})
+ % endif
% endfor
</ul>
%else:
diff --git a/nikola/data/themes/base/templates/list_post.tmpl b/nikola/data/themes/base/templates/list_post.tmpl
index 3335fa6..5fd4df1 100644
--- a/nikola/data/themes/base/templates/list_post.tmpl
+++ b/nikola/data/themes/base/templates/list_post.tmpl
@@ -4,12 +4,12 @@
<%block name="content">
<article class="listpage">
<header>
- <h1>${title}</h1>
+ <h1>${title|h}</h1>
</header>
%if posts:
<ul class="postlist">
% for post in posts:
- <li><a href="${post.permalink()}" class="listtitle">${post.title()|h}</a> <time class="listdate" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></li>
+ <li><a href="${post.permalink()}" class="listtitle">${post.title()|h}</a> <time class="listdate" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)|h}">${post.formatted_date(date_format)|h}</time></li>
% endfor
</ul>
%else:
diff --git a/nikola/data/themes/base/templates/listing.tmpl b/nikola/data/themes/base/templates/listing.tmpl
index e0bf91b..1800bd9 100644
--- a/nikola/data/themes/base/templates/listing.tmpl
+++ b/nikola/data/themes/base/templates/listing.tmpl
@@ -6,10 +6,10 @@ ${ui.bar(crumbs)}
%if folders or files:
<ul>
% for name in folders:
- <li><a href="${name}"><i class="icon-folder-open"></i> ${name}</a>
+ <li><a href="${name|u}"><i class="icon-folder-open"></i> ${name|h}</a>
% endfor
% for name in files:
- <li><a href="${name}.html"><i class="icon-file"></i> ${name}</a>
+ <li><a href="${name|u}.html"><i class="icon-file"></i> ${name|h}</a>
% endfor
</ul>
%endif
diff --git a/nikola/data/themes/base/templates/post.tmpl b/nikola/data/themes/base/templates/post.tmpl
index cbb81ef..da616bf 100644
--- a/nikola/data/themes/base/templates/post.tmpl
+++ b/nikola/data/themes/base/templates/post.tmpl
@@ -10,9 +10,9 @@
<meta name="keywords" content="${post.meta('keywords')|h}">
% endif
%if post.description():
- <meta name="description" content="${post.description()}">
+ <meta name="description" content="${post.description()|h}">
%endif
- <meta name="author" content="${post.author()}">
+ <meta name="author" content="${post.author()|h}">
%if post.prev_post:
<link rel="prev" href="${post.prev_post.permalink()}" title="${post.prev_post.title()|h}" type="text/html">
%endif
diff --git a/nikola/data/themes/base/templates/post_header.tmpl b/nikola/data/themes/base/templates/post_header.tmpl
index 75383cb..480c36a 100644
--- a/nikola/data/themes/base/templates/post_header.tmpl
+++ b/nikola/data/themes/base/templates/post_header.tmpl
@@ -31,17 +31,23 @@
<header>
${html_title()}
<div class="metadata">
- <p class="byline author vcard"><span class="byline-name fn">${post.author()}</span></p>
- <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.formatted_date('webiso')}" itemprop="datePublished" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></a></p>
+ <p class="byline author vcard"><span class="byline-name fn">
+ % if author_pages_generated:
+ <a href="${_link('author', post.author())}">${post.author()|h}</a>
+ % else:
+ ${post.author()|h}
+ % endif
+ </span></p>
+ <p class="dateline"><a href="${post.permalink()}" rel="bookmark"><time class="published dt-published" datetime="${post.formatted_date('webiso')}" itemprop="datePublished" title="${post.formatted_date(date_format)|h}">${post.formatted_date(date_format)|h}</time></a></p>
% if not post.meta('nocomments') and site_has_comments:
<p class="commentline">${comments.comment_link(post.permalink(), post._base_path)}
% endif
${html_sourcelink()}
% if post.meta('link'):
- <p class="linkline"><a href='${post.meta('link')}'>${messages("Original site")}</a></p>
+ <p class="linkline"><a href="${post.meta('link')}">${messages("Original site")}</a></p>
% endif
%if post.description():
- <meta name="description" itemprop="description" content="${post.description()}">
+ <meta name="description" itemprop="description" content="${post.description()|h}">
%endif
</div>
${html_translations(post)}
diff --git a/nikola/data/themes/base/templates/post_helper.tmpl b/nikola/data/themes/base/templates/post_helper.tmpl
index 424d134..f8572ec 100644
--- a/nikola/data/themes/base/templates/post_helper.tmpl
+++ b/nikola/data/themes/base/templates/post_helper.tmpl
@@ -15,7 +15,7 @@
<ul itemprop="keywords" class="tags">
%for tag in post.tags:
% if tag not in hidden_tags:
- <li><a class="tag p-category" href="${_link('tag', tag)}" rel="tag">${tag}</a></li>
+ <li><a class="tag p-category" href="${_link('tag', tag)}" rel="tag">${tag|h}</a></li>
% endif
%endfor
</ul>
@@ -41,7 +41,7 @@
<%def name="open_graph_metadata(post)">
%if use_open_graph:
- <meta property="og:site_name" content="${blog_title|striphtml}">
+ <meta property="og:site_name" content="${blog_title|h}">
<meta property="og:title" content="${post.title()[:70]|h}">
<meta property="og:url" content="${abs_link(permalink)}">
%if post.description():
@@ -55,14 +55,14 @@
<meta property="og:type" content="article">
### Will only work with Pintrest and breaks everywhere else who expect a [Facebook] URI.
### %if post.author():
-### <meta property="article:author" content="${post.author()}">
+### <meta property="article:author" content="${post.author()|h}">
### %endif
%if post.date.isoformat():
<meta property="article:published_time" content="${post.formatted_date('webiso')}">
%endif
%if post.tags:
%for tag in post.tags:
- <meta property="article:tag" content="${tag}">
+ <meta property="article:tag" content="${tag|h}">
%endfor
%endif
%endif
@@ -86,8 +86,17 @@
<%def name="mathjax_script(post)">
%if post.is_mathjax:
- <script type="text/x-mathjax-config">
- MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});</script>
- <script src="/assets/js/mathjax.js"></script>
+ %if use_katex:
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.js"></script>
+ <script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/contrib/auto-render.min.js"></script>
+ <script>
+ renderMathInElement(document.body);
+ </script>
+ %else:
+ <script type="text/javascript" src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"> </script>
+ <script type="text/x-mathjax-config">
+ MathJax.Hub.Config({tex2jax: {inlineMath: [['$latex ','$'], ['\\(','\\)']]}});
+ </script>
+ %endif
%endif
</%def>
diff --git a/nikola/data/themes/base/templates/post_list_directive.tmpl b/nikola/data/themes/base/templates/post_list_directive.tmpl
index e080a81..4a136a1 100644
--- a/nikola/data/themes/base/templates/post_list_directive.tmpl
+++ b/nikola/data/themes/base/templates/post_list_directive.tmpl
@@ -6,7 +6,7 @@
<ul class="post-list">
% for post in posts:
<li class="post-list-item">
- ${post.formatted_date(date_format)}
+ ${post.formatted_date(date_format)|h}
&nbsp;
<a href="${post.permalink(lang)}">${post.title(lang)|h}</a>
</li>
diff --git a/nikola/data/themes/base/templates/sectionindex.tmpl b/nikola/data/themes/base/templates/sectionindex.tmpl
new file mode 100644
index 0000000..7fb4f1e
--- /dev/null
+++ b/nikola/data/themes/base/templates/sectionindex.tmpl
@@ -0,0 +1,21 @@
+## -*- coding: utf-8 -*-
+<%inherit file="index.tmpl"/>
+
+<%block name="extra_head">
+ ${parent.extra_head()}
+ % if generate_atom:
+ <link rel="alternate" type="application/atom+xml" title="Atom for the ${posts[0].section_name()|h} section" href="${_link('section_index_atom', posts[0].section_slug())}">
+ % endif
+</%block>
+
+<%block name="content">
+<div class="sectionindex">
+ <header>
+ <h2><a href="${_link('section_index', posts[0].section_slug())}">${title|h}</a></h2>
+ % if generate_atom:
+ <p class="feedlink"><a href="${_link('section_index_atom', posts[0].section_slug())}" type="application/atom+xml">${messages('Updates')}</a></p>
+ % endif
+ </header>
+ ${parent.content()}
+</div>
+</%block>
diff --git a/nikola/data/themes/base/templates/tag.tmpl b/nikola/data/themes/base/templates/tag.tmpl
index 7509f3e..d07c434 100644
--- a/nikola/data/themes/base/templates/tag.tmpl
+++ b/nikola/data/themes/base/templates/tag.tmpl
@@ -5,10 +5,10 @@
${parent.extra_head()}
%if len(translations) > 1 and generate_rss:
%for language in sorted(translations):
- <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for ${kind} ${tag} (${language})" href="${_link(kind + "_rss", tag, language)}">
+ <link rel="alternate" type="application/rss+xml" title="RSS for ${kind} ${tag|h} (${language})" href="${_link(kind + "_rss", tag, language)}">
%endfor
%elif generate_rss:
- <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for ${kind} ${tag}" href="${_link(kind + "_rss", tag)}">
+ <link rel="alternate" type="application/rss+xml" title="RSS for ${kind} ${tag|h}" href="${_link(kind + "_rss", tag)}">
%endif
</%block>
@@ -24,7 +24,7 @@
${messages('Subcategories:')}
<ul>
%for name, link in subcategories:
- <li><a href="${link}">${name}</a></li>
+ <li><a href="${link}">${name|h}</a></li>
%endfor
</ul>
%endif
@@ -43,7 +43,7 @@
%if posts:
<ul class="postlist">
% for post in posts:
- <li><a href="${post.permalink()}" class="listtitle">${post.title()|h}</a> <time class="listdate" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)}">${post.formatted_date(date_format)}</time></li>
+ <li><time class="listdate" datetime="${post.formatted_date('webiso')}" title="${post.formatted_date(date_format)|h}">${post.formatted_date(date_format)|h}</time><a href="${post.permalink()}" class="listtitle">${post.title()|h}<a></li>
% endfor
</ul>
%endif
diff --git a/nikola/data/themes/base/templates/tagindex.tmpl b/nikola/data/themes/base/templates/tagindex.tmpl
index 0834411..047d638 100644
--- a/nikola/data/themes/base/templates/tagindex.tmpl
+++ b/nikola/data/themes/base/templates/tagindex.tmpl
@@ -6,7 +6,7 @@
${messages('Subcategories:')}
<ul>
%for name, link in subcategories:
- <li><a href="${link}">${name}</a></li>
+ <li><a href="${link}">${name|h}</a></li>
%endfor
</ul>
%endif
@@ -16,9 +16,9 @@
${parent.extra_head()}
%if len(translations) > 1 and generate_atom:
%for language in sorted(translations):
- <link rel="alternate" type="application/atom+xml" title="Atom for the ${tag} section (${language})" href="${_link(kind + "_atom", tag, language)}">
+ <link rel="alternate" type="application/atom+xml" title="Atom for the ${tag|h} section (${language})" href="${_link(kind + "_atom", tag, language)}">
%endfor
%elif generate_atom:
- <link rel="alternate" type="application/atom+xml" title="Atom for the ${tag} section" href="${_link("tag" + "_atom", tag)}">
+ <link rel="alternate" type="application/atom+xml" title="Atom for the ${tag|h} section" href="${_link("tag" + "_atom", tag)}">
%endif
</%block>
diff --git a/nikola/data/themes/base/templates/tags.tmpl b/nikola/data/themes/base/templates/tags.tmpl
index a9d2dd7..6c329d9 100644
--- a/nikola/data/themes/base/templates/tags.tmpl
+++ b/nikola/data/themes/base/templates/tags.tmpl
@@ -4,7 +4,7 @@
<%block name="content">
<article class="tagindex">
<header>
- <h1>${title}</h1>
+ <h1>${title|h}</h1>
</header>
% if cat_items:
% if items:
@@ -33,7 +33,7 @@
<ul class="postlist">
% for text, link in items:
% if text not in hidden_tags:
- <li><a class="reference listtitle" href="${link}">${text}</a></li>
+ <li><a class="reference listtitle" href="${link}">${text|h}</a></li>
% endif
% endfor
</ul>
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css
new file mode 120000
index 0000000..78d39af
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap-theme.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.min.css b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.min.css
new file mode 120000
index 0000000..200c765
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap-theme.min.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap-theme.min.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css
new file mode 120000
index 0000000..013623e
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.min.css b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.min.css
new file mode 120000
index 0000000..5bc6076
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/css/bootstrap.min.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap.min.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.js b/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.js
new file mode 120000
index 0000000..26aa1fd
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.js
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/js/bootstrap.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.min.js b/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.min.js
new file mode 120000
index 0000000..c4cdf6c
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/bootstrap.min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/js/bootstrap.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/flowr.plugin.js b/nikola/data/themes/bootstrap3-jinja/assets/js/flowr.plugin.js
index c0d986b..a6ab900 100644
--- a/nikola/data/themes/bootstrap3-jinja/assets/js/flowr.plugin.js
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/flowr.plugin.js
@@ -1,265 +1,271 @@
/**
- * Flowr.js - Simple jQuery plugin to emulate Flickr's justified view
- * For usage information refer to http://github.com/kalyan02/flowr-js
- *
- *
- * @author: Kalyan Chakravarthy (http://KalyanChakravarthy.net)
- * @version: v0.1
- */
-(function($){
- //$("#container2").css( 'border', '1px solid #ccc');
- $.fn.flowr = function(options) {
-
- $this = this;
- var ROW_CLASS_NAME = 'flowr-row'; // Class name for the row of flowy
- var MAX_LAST_ROW_GAP = 25; // If the width of last row is lesser than max-width, recalculation is needed
- var NO_COPY_FIELDS = [ 'complete', 'data', 'responsive' ]; // these attributes will not be carried forward for append related calls
- var DEFAULTS = {
- 'data' : [],
- 'padding' : 5, // whats the padding between flowy items
- 'height' : 240, // Minimum height an image row should take
- 'render' : null, // callback function to get the tag
- 'append' : false, // TODO
- 'widthAttr' : 'width', // a custom data structure can specify which attribute refers to height/width
- 'heightAttr' : 'height',
- 'maxScale' : 1.5, // In case there is only 1 elment in last row
- 'maxWidth' : this.width()-1, // 1px is just for offset
- 'itemWidth' : null, // callback function for width
- 'itemHeight' : null, // callback function for height
- 'complete' : null, // complete callback
- 'rowClassName' : ROW_CLASS_NAME,
- 'rows' : -1, // Maximum number of rows to render. -1 for no limit.
- 'responsive' : true // make content responsive
- };
- var settings = $.extend( DEFAULTS, options);
-
- // If data is being appended, we already have settings
- // If we already have settings, retrieve them
- if( settings.append && $this.data('lastSettings') ) {
- lastSettings = $this.data('lastSettings');
-
- // Copy over the settings from previous init
- for( attr in DEFAULTS ) {
- if( NO_COPY_FIELDS.indexOf(attr)<0 && settings[attr] == DEFAULTS[attr] ) {
- settings[attr] = lastSettings[attr];
- }
- }
-
- // Check if we have an incomplete last row
- lastRow = $this.data('lastRow');
- if( lastRow.data.length > 0 && settings.maxWidth-lastRow.width > MAX_LAST_ROW_GAP ) {
- // Prepend the incomplete row to newly loaded data and redraw
- lastRowData = lastSettings.data.slice( lastSettings.data.length - lastRow.data.length - 1 );
- settings.data = lastRowData.concat(settings.data);
-
- // Remove the incomplete row
- // TODO: Don't reload this stuff later. Reattach to new row.
- $( '.' + settings.rowClassName + ':last', $this ).detach();
- } else {
- // console.log( lastRow.data.length );
- // console.log( lastRow.width );
- }
- }
-
- // only on the first initial call
- if( !settings.responsive && !settings.append )
- $this.width( $this.width() );
-
- // Basic sanity checks
- if( !(settings.data instanceof Array) )
- return;
-
- if( typeof(settings.padding) != 'number' )
- settings.padding = parseInt( settings.padding );
-
- if( typeof(settings.itemWidth) != 'function' ) {
- settings.itemWidth = function(data) {
- return data[ settings.widthAttr ];
- }
- }
-
- if( typeof(settings.itemHeight) != 'function' ) {
- settings.itemHeight = function(data) {
- return data[ settings.heightAttr ];
- }
- }
-
- // A standalone utility to calculate the item widths for a particular row
- // Returns rowWidth: width occupied & data : the items in the new row
- var utils = {
- getNextRow : function( data, settings ) {
- var itemIndex = 0;
- var itemsLength = data.length;
- var lineItems = [];
- var lineWidth = 0;
- var maxWidth = settings.maxWidth;
- var paddingSize = settings.padding;
-
- // console.log( 'maxItems=' + data.length );
-
- requiredPadding = function() {
- var extraPads = arguments.length == 1 ? arguments[0] : 0;
- return (lineItems.length - 1 + extraPads) * settings.padding;
- }
-
- while( lineWidth + requiredPadding() < settings.maxWidth && (itemIndex < itemsLength) ) {
- var itemData = data[ itemIndex ];
- var itemWidth = settings.itemWidth.call( $this, itemData );
- var itemHeight = settings.itemHeight.call( $this, itemData );
-
- var minHeight = settings.height;
- var minWidth = Math.floor( itemWidth * settings.height / itemHeight );
-
- var newLineWidth = lineWidth + minWidth + requiredPadding(1);
-
- if (minWidth > settings.maxWidth) {
- // very short+wide images like panoramas
- // show them even if ugly, as wide as possible
- minWidth = settings.maxWidth-1;
- minHeight = settings.height * minHeight / minWidth;
- }
-
- // console.log( 'lineWidth = ' + lineWidth );
- // console.log( 'newLineWidth = ' + newLineWidth );
- if( newLineWidth < settings.maxWidth ) {
- lineItems.push({
- 'height' : minHeight,
- 'width' : minWidth,
- 'itemData' : itemData
- });
-
- lineWidth += minWidth;
- itemIndex ++;
- } else {
- // We'd have exceeded width. So break off to scale.
- // console.log( 'breaking off = ' + itemIndex );
- // console.log( 'leave off size = ' + lineItems.length );
- break;
- }
- } //while
-
- // Scale the size to max width
- testWidth=0;
- if( lineWidth < settings.maxWidth ) {
- var fullScaleWidth = settings.maxWidth - requiredPadding() - 10;
- var currScaleWidth = lineWidth;
- var scaleFactor = fullScaleWidth / currScaleWidth;
- if( scaleFactor > settings.maxScale )
- scaleFactor = 1;
-
- var newHeight = Math.round( settings.height * scaleFactor );
- for( i=0; i<lineItems.length; i++ ) {
- var lineItem = lineItems[ i ];
- lineItem.width = Math.floor(lineItem.width * scaleFactor);
- lineItem.height = newHeight;
-
- testWidth += lineItem.width;
- }
- }
-
- return {
- data : lineItems,
- width : testWidth + requiredPadding()
- };
- }, //getNextRow
- reorderContent : function(){
- /*
- TODO: optimize for faster resizing by reusing dom objects instead of killing the dom
- */
- var _initialWidth = $this.data('width');
- var _newWidth = $this.width();
- var _change = _initialWidth - _newWidth;
-
- if(_initialWidth!=_newWidth) {
- $this.html('');
- var _settings = $this.data( 'lastSettings' );
- _settings.data = $this.data( 'data' );
- _settings.maxWidth = $this.width() - 1;
- $this.flowr( _settings );
- }
- }
- } //utils
-
- // If the resposive var is set to true then listen for resize method
- // and prevent resizing from happening twice if responsive is set again during append phase!
- if( settings.responsive && !$this.data('__responsive') ) {
- $(window).resize(function(){
- initialWidth = $this.data('width');
- newWidth = $this.width();
-
- //initiate resize
- if( initialWidth != newWidth ) {
- var task_id = $this.data('task_id');
- if( task_id ) {
- task_id = clearTimeout( task_id );
- task_id = null;
- }
- task_id = setTimeout( utils.reorderContent, 80 );
- $this.data('task_id', task_id );
- }
- });
- $this.data('__responsive',true);
- }
-
-
- return this.each(function(){
-
- // Get a copy of original data. 1 level deep copy is sufficient.
- var data = settings.data.slice(0);
- var rowData = null;
- var currentRow = 0;
- var currentItem = 0;
-
- // Store all the data
- var allData = $this.data( 'data' ) || [];
- for(i=0;i<data.length;i++) {
- allData.push( data[i] );
- }
- $this.data( 'data', allData );
-
- // While we have a new row
- while( ( rowData = utils.getNextRow(data,settings) ) != null && rowData.data.length > 0 ) {
- if( settings.rows > 0 && currentRow >= settings.rows )
- break;
- // remove the number of elements in the new row from the top of data stack
- data.splice( 0, rowData.data.length );
-
- // Create a new row div, add class, append the htmls and insert the flowy items
- var $row = $('<div>').addClass(settings.rowClassName);
- for( i=0; i<rowData.data.length; i++ ) {
- var displayData = rowData.data[i];
- // Get the HTML object from custom render function passed as argument
- var displayObject = settings.render.call( $this, displayData );
- displayObject = $(displayObject);
- // Set some basic stuff
- displayObject
- .css( 'width', displayData.width )
- .css( 'height', displayData.height )
- .css( 'margin-left', i==0 ? '0' : settings.padding + "px" ); //TODO:Refactor
- $row.append( displayObject );
-
- currentItem++;
- }
- $this.append( $row );
- // console.log ( "I> rowData.data.length="+rowData.data.length +" rowData.width="+rowData.width );
-
- currentRow++;
- $this.data('lastRow', rowData );
- }
- // store the current state of settings and the items in last row
- // we'll need this info when we append more items
- $this.data('lastSettings', settings );
-
- // onComplete callback
- // pass back info about list of rows and items rendered
- if( typeof (settings.complete) == 'function' ) {
- var completeData = {
- renderedRows : currentRow,
- renderedItems : currentItem
- }
- settings.complete.call( $this, completeData );
- }
- });
- };
+ * Flowr.js - Simple jQuery plugin to emulate Flickr's justified view
+ * For usage information refer to http://github.com/kalyan02/flowr-js
+ *
+ *
+ * @author: Kalyan Chakravarthy (http://KalyanChakravarthy.net)
+ * @version: v0.1
+ */
+(function($) {
+ //$("#container2").css( 'border', '1px solid #ccc');
+ $.fn.flowr = function(options) {
+
+ $this = this;
+ var ROW_CLASS_NAME = 'flowr-row'; // Class name for the row of flowy
+ var MAX_LAST_ROW_GAP = 25; // If the width of last row is lesser than max-width, recalculation is needed
+ var NO_COPY_FIELDS = ['complete', 'data', 'responsive']; // these attributes will not be carried forward for append related calls
+ var DEFAULTS = {
+ 'data': [],
+ 'padding': 5, // whats the padding between flowy items
+ 'height': 240, // Minimum height an image row should take
+ 'render': null, // callback function to get the tag
+ 'append': false, // TODO
+ 'widthAttr': 'width', // a custom data structure can specify which attribute refers to height/width
+ 'heightAttr': 'height',
+ 'maxScale': 1.5, // In case there is only 1 elment in last row
+ 'maxWidth': this.width() - 1, // 1px is just for offset
+ 'itemWidth': null, // callback function for width
+ 'itemHeight': null, // callback function for height
+ 'complete': null, // complete callback
+ 'rowClassName': ROW_CLASS_NAME,
+ 'rows': -1, // Maximum number of rows to render. -1 for no limit.
+ 'responsive': true // make content responsive
+ };
+ var settings = $.extend(DEFAULTS, options);
+
+ // If data is being appended, we already have settings
+ // If we already have settings, retrieve them
+ if (settings.append && $this.data('lastSettings')) {
+ lastSettings = $this.data('lastSettings');
+
+ // Copy over the settings from previous init
+ for (attr in DEFAULTS) {
+ if (NO_COPY_FIELDS.indexOf(attr) < 0 && settings[attr] == DEFAULTS[attr]) {
+ settings[attr] = lastSettings[attr];
+ }
+ }
+
+ // Check if we have an incomplete last row
+ lastRow = $this.data('lastRow');
+ if (lastRow.data.length > 0 && settings.maxWidth - lastRow.width > MAX_LAST_ROW_GAP) {
+ // Prepend the incomplete row to newly loaded data and redraw
+ lastRowData = lastSettings.data.slice(lastSettings.data.length - lastRow.data.length - 1);
+ settings.data = lastRowData.concat(settings.data);
+
+ // Remove the incomplete row
+ // TODO: Don't reload this stuff later. Reattach to new row.
+ $('.' + settings.rowClassName + ':last', $this).detach();
+ } else {
+ // console.log( lastRow.data.length );
+ // console.log( lastRow.width );
+ }
+ }
+
+ // only on the first initial call
+ if (!settings.responsive && !settings.append)
+ $this.width($this.width());
+
+ // Basic sanity checks
+ if (!(settings.data instanceof Array))
+ return;
+
+ if (typeof(settings.padding) != 'number')
+ settings.padding = parseInt(settings.padding);
+
+ if (typeof(settings.itemWidth) != 'function') {
+ settings.itemWidth = function(data) {
+ return data[settings.widthAttr];
+ }
+ }
+
+ if (typeof(settings.itemHeight) != 'function') {
+ settings.itemHeight = function(data) {
+ return data[settings.heightAttr];
+ }
+ }
+
+ // A standalone utility to calculate the item widths for a particular row
+ // Returns rowWidth: width occupied & data : the items in the new row
+ var utils = {
+ getNextRow: function(data, settings) {
+ var itemIndex = 0;
+ var itemsLength = data.length;
+ var lineItems = [];
+ var lineWidth = 0;
+ var maxWidth = settings.maxWidth;
+ var paddingSize = settings.padding;
+
+ // console.log( 'maxItems=' + data.length );
+
+ requiredPadding = function() {
+ var extraPads = arguments.length == 1 ? arguments[0] : 0;
+ return (lineItems.length - 1 + extraPads) * settings.padding;
+ }
+
+ while (lineWidth + requiredPadding() < settings.maxWidth && (itemIndex < itemsLength)) {
+ var itemData = data[itemIndex];
+ var itemWidth = settings.itemWidth.call($this, itemData);
+ var itemHeight = settings.itemHeight.call($this, itemData);
+
+ var minHeight = settings.height;
+ var minWidth = Math.floor(itemWidth * settings.height / itemHeight);
+
+
+ if (minWidth > settings.maxWidth) {
+ // very short+wide images like panoramas
+ // show them even if ugly, as wide as possible
+ minWidth = settings.maxWidth - 1 - requiredPadding(1);
+ minHeight = settings.height * minHeight / minWidth;
+ }
+ var newLineWidth = lineWidth + minWidth;
+
+ // console.log( 'lineWidth = ' + lineWidth );
+ // console.log( 'newLineWidth = ' + newLineWidth );
+ if (newLineWidth < settings.maxWidth) {
+ lineItems.push({
+ 'height': minHeight,
+ 'width': minWidth,
+ 'itemData': itemData
+ });
+
+ lineWidth += minWidth;
+ itemIndex++;
+ } else {
+ // We'd have exceeded width. So break off to scale.
+ // console.log( 'breaking off = ' + itemIndex );
+ // console.log( 'leave off size = ' + lineItems.length );
+ break;
+ }
+ } //while
+
+ // Scale the size to max width
+ testWidth = 0;
+ if (lineWidth < settings.maxWidth) {
+ var fullScaleWidth = settings.maxWidth - requiredPadding() - 10;
+ var currScaleWidth = lineWidth;
+ var scaleFactor = fullScaleWidth / currScaleWidth;
+ if (scaleFactor > settings.maxScale)
+ scaleFactor = 1;
+
+ var newHeight = Math.round(settings.height * scaleFactor);
+ for (i = 0; i < lineItems.length; i++) {
+ var lineItem = lineItems[i];
+ lineItem.width = Math.floor(lineItem.width * scaleFactor);
+ lineItem.height = newHeight;
+
+ testWidth += lineItem.width;
+ }
+ }
+
+ return {
+ data: lineItems,
+ width: testWidth + requiredPadding()
+ };
+ }, //getNextRow
+ reorderContent: function() {
+ /*
+ TODO: optimize for faster resizing by reusing dom objects instead of killing the dom
+ */
+ var _initialWidth = $this.data('width');
+ var _newWidth = $this.width();
+ var _change = _initialWidth - _newWidth;
+
+ if (_initialWidth != _newWidth) {
+ $this.html('');
+ var _settings = $this.data('lastSettings');
+ _settings.data = $this.data('data');
+ _settings.maxWidth = $this.width() - 1;
+ $this.flowr(_settings);
+ }
+ }
+ } //utils
+
+ // If the resposive var is set to true then listen for resize method
+ // and prevent resizing from happening twice if responsive is set again during append phase!
+ if (settings.responsive && !$this.data('__responsive')) {
+ $(window).resize(function() {
+ initialWidth = $this.data('width');
+ newWidth = $this.width();
+
+ //initiate resize
+ if (initialWidth != newWidth) {
+ var task_id = $this.data('task_id');
+ if (task_id) {
+ task_id = clearTimeout(task_id);
+ task_id = null;
+ }
+ task_id = setTimeout(utils.reorderContent, 80);
+ $this.data('task_id', task_id);
+ }
+ });
+ $this.data('__responsive', true);
+ }
+
+
+ return this.each(function() {
+
+ // Get a copy of original data. 1 level deep copy is sufficient.
+ var data = settings.data.slice(0);
+ var rowData = null;
+ var currentRow = 0;
+ var currentItem = 0;
+
+ // Store all the data
+ var allData = $this.data('data') || [];
+ for (i = 0; i < data.length; i++) {
+ allData.push(data[i]);
+ }
+ $this.data('data', allData);
+
+ // While we have a new row
+ while ((rowData = utils.getNextRow(data, settings)) != null && rowData.data.length > 0) {
+ if (settings.rows > 0 && currentRow >= settings.rows)
+ break;
+ // remove the number of elements in the new row from the top of data stack
+ data.splice(0, rowData.data.length);
+
+ // Create a new row div, add class, append the htmls and insert the flowy items
+ var $row = $('<div>').addClass(settings.rowClassName);
+ var slack = $this[0].clientWidth - rowData.width - 2 * settings.padding
+ for (i = 0; i < rowData.data.length; i++) {
+ var displayData = rowData.data[i];
+ // Get the HTML object from custom render function passed as argument
+ var displayObject = settings.render.call($this, displayData);
+ displayObject = $(displayObject);
+ extraw = Math.floor(slack/rowData.data.length)
+ if (i == 0) {
+ extraw += slack % rowData.data.length
+ }
+ // Set some basic stuff
+ displayObject
+ .css('width', displayData.width + extraw)
+ .css('height', displayData.height)
+ .css('margin-bottom', settings.padding + "px")
+ .css('margin-left', i == 0 ? '0' : settings.padding + "px"); //TODO:Refactor
+ $row.append(displayObject);
+
+ currentItem++;
+ }
+ $this.append($row);
+ // console.log ( "I> rowData.data.length="+rowData.data.length +" rowData.width="+rowData.width );
+
+ currentRow++;
+ $this.data('lastRow', rowData);
+ }
+ // store the current state of settings and the items in last row
+ // we'll need this info when we append more items
+ $this.data('lastSettings', settings);
+
+ // onComplete callback
+ // pass back info about list of rows and items rendered
+ if (typeof(settings.complete) == 'function') {
+ var completeData = {
+ renderedRows: currentRow,
+ renderedItems: currentItem
+ }
+ settings.complete.call($this, completeData);
+ }
+ });
+ };
})(jQuery);
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.colorbox-min.js b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.colorbox-min.js
new file mode 120000
index 0000000..9e40fd4
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.colorbox-min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery-colorbox/jquery.colorbox-min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.js b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.js
new file mode 120000
index 0000000..5c080da
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery/dist/jquery.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.map b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.map
new file mode 120000
index 0000000..7e2c217
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/assets/js/jquery.min.map
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery/dist/jquery.min.map \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/authors.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/authors.tmpl
new file mode 100644
index 0000000..d65c727
--- /dev/null
+++ b/nikola/data/themes/bootstrap3-jinja/templates/authors.tmpl
@@ -0,0 +1,17 @@
+{# -*- coding: utf-8 -*- #}
+{% extends 'base.tmpl' %}
+
+{% block content %}
+{% if items %}
+ <h2>{{ messages("Authors") }}</h2>
+{% endif %}
+{% if items %}
+ <ul class="list-inline">
+ {% for text, link in items %}
+ {% if text not in hidden_authors %}
+ <li><a class="reference badge" href="{{ link }}">{{ text|e }}</a></li>
+ {% endif %}
+ {% endfor %}
+ </ul>
+{% endif %}
+{% endblock %}
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/base.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/base.tmpl
index 46d145a..21b93cd 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/base.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/base.tmpl
@@ -24,11 +24,11 @@
</button>
<a class="navbar-brand" href="{{ abs_link(_link("root", None, lang)) }}">
{% if logo_url %}
- <img src="{{ logo_url }}" alt="{{ blog_title }}" id="logo">
+ <img src="{{ logo_url }}" alt="{{ blog_title|e }}" id="logo">
{% endif %}
{% if show_blog_title %}
- <span id="blog-title">{{ blog_title }}</span>
+ <span id="blog-title">{{ blog_title|e }}</span>
{% endif %}
</a>
</div><!-- /.navbar-header -->
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/base_helper.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/base_helper.tmpl
index 5ab4dcb..d9ea683 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/base_helper.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/base_helper.tmpl
@@ -26,9 +26,11 @@ dir="rtl"
lang="{{ lang }}">
<head>
<meta charset="utf-8">
+ {% if use_base_tag %}
<base href="{{ abs_link(permalink) }}">
+ {% endif %}
{% if description %}
- <meta name="description" content="{{ description }}">
+ <meta name="description" content="{{ description|e }}">
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=1">
{% if title == blog_title %}
@@ -38,6 +40,7 @@ lang="{{ lang }}">
{% endif %}
{{ html_stylesheets() }}
+ <meta content="{{ theme_color }}" name="theme-color">
{{ html_feedlinks() }}
<link rel="canonical" href="{{ abs_link(permalink) }}">
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/gallery.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/gallery.tmpl
index 00fda11..2ae0457 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/gallery.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/gallery.tmpl
@@ -17,7 +17,7 @@
{% if folders %}
<ul>
{% for folder, ftitle in folders %}
- <li><a href="{{ folder }}"><i class="glyphicon glyphicon-folder-open"></i>&nbsp;{{ ftitle }}</a></li>
+ <li><a href="{{ folder }}"><i class="glyphicon glyphicon-folder-open"></i>&nbsp;{{ ftitle|e }}</a></li>
{% endfor %}
</ul>
{% endif %}
@@ -27,8 +27,8 @@
<noscript>
<ul class="thumbnails">
{% for image in photo_array %}
- <li><a href="{{ image['url'] }}" class="thumbnail image-reference" title="{{ image['title'] }}">
- <img src="{{ image['url_thumb'] }}" alt="{{ image['title'] }}" /></a>
+ <li><a href="{{ image['url'] }}" class="thumbnail image-reference" title="{{ image['title']|e }}">
+ <img src="{{ image['url_thumb'] }}" alt="{{ image['title']|e }}" /></a>
{% endfor %}
</ul>
</noscript>
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/listing.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/listing.tmpl
index 634c482..f0d8050 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/listing.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/listing.tmpl
@@ -7,10 +7,10 @@
{% if folders or files %}
<ul class="list-unstyled">
{% for name in folders %}
- <li><a href="{{ name }}"><i class="glyphicon glyphicon-folder-open"></i> {{ name }}</a>
+ <li><a href="{{ name|urlencode }}"><i class="glyphicon glyphicon-folder-open"></i> {{ name|e }}</a>
{% endfor %}
{% for name in files %}
- <li><a href="{{ name }}.html"><i class="glyphicon glyphicon-file"></i> {{ name }}</a>
+ <li><a href="{{ name|urlencode }}.html"><i class="glyphicon glyphicon-file"></i> {{ name|e }}</a>
{% endfor %}
</ul>
{% endif %}
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/post.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/post.tmpl
index df4109c..3cf4c4b 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/post.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/post.tmpl
@@ -10,9 +10,9 @@
<meta name="keywords" content="{{ post.meta('keywords')|e }}">
{% endif %}
{% if post.description() %}
- <meta name="description" itemprop="description" content="{{ post.description() }}">
+ <meta name="description" itemprop="description" content="{{ post.description()|e }}">
{% endif %}
- <meta name="author" content="{{ post.author() }}">
+ <meta name="author" content="{{ post.author()|e }}">
{% if post.prev_post %}
<link rel="prev" href="{{ post.prev_post.permalink() }}" title="{{ post.prev_post.title()|e }}" type="text/html">
{% endif %}
diff --git a/nikola/data/themes/bootstrap3-jinja/templates/tags.tmpl b/nikola/data/themes/bootstrap3-jinja/templates/tags.tmpl
index c308f19..4afd4d2 100644
--- a/nikola/data/themes/bootstrap3-jinja/templates/tags.tmpl
+++ b/nikola/data/themes/bootstrap3-jinja/templates/tags.tmpl
@@ -2,16 +2,16 @@
{% extends 'base.tmpl' %}
{% block content %}
-<h1>{{ title }}</h1>
+<h1>{{ title|e }}</h1>
{% if cat_items %}
{% if items %}
<h2>{{ messages("Categories") }}</h2>
{% endif %}
{% for text, full_name, path, link, indent_levels, indent_change_before, indent_change_after in cat_hierarchy %}
{% for i in range(indent_change_before) %}
- <ul class="unstyled">
+ <ul class="list-inline">
{% endfor %}
- <li><a class="reference badge" href="{{ link }}">{{ text }}</a>
+ <li><a class="reference badge" href="{{ link }}">{{ text|e }}</a>
{% if indent_change_after <= 0 %}
</li>
{% endif %}
@@ -30,7 +30,7 @@
<ul class="list-inline">
{% for text, link in items %}
{% if text not in hidden_tags %}
- <li><a class="reference badge" href="{{ link }}">{{ text }}</a></li>
+ <li><a class="reference badge" href="{{ link }}">{{ text|e }}</a></li>
{% endif %}
{% endfor %}
</ul>
diff --git a/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css b/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css
new file mode 120000
index 0000000..78d39af
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap-theme.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.min.css b/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.min.css
new file mode 120000
index 0000000..200c765
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/css/bootstrap-theme.min.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap-theme.min.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/css/bootstrap.css b/nikola/data/themes/bootstrap3/assets/css/bootstrap.css
new file mode 120000
index 0000000..013623e
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/css/bootstrap.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/css/bootstrap.min.css b/nikola/data/themes/bootstrap3/assets/css/bootstrap.min.css
new file mode 120000
index 0000000..5bc6076
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/css/bootstrap.min.css
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/css/bootstrap.min.css \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/js/bootstrap.js b/nikola/data/themes/bootstrap3/assets/js/bootstrap.js
new file mode 120000
index 0000000..26aa1fd
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/js/bootstrap.js
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/js/bootstrap.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/js/bootstrap.min.js b/nikola/data/themes/bootstrap3/assets/js/bootstrap.min.js
new file mode 120000
index 0000000..c4cdf6c
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/js/bootstrap.min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/bootstrap/dist/js/bootstrap.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/js/flowr.plugin.js b/nikola/data/themes/bootstrap3/assets/js/flowr.plugin.js
index c0d986b..a6ab900 100644
--- a/nikola/data/themes/bootstrap3/assets/js/flowr.plugin.js
+++ b/nikola/data/themes/bootstrap3/assets/js/flowr.plugin.js
@@ -1,265 +1,271 @@
/**
- * Flowr.js - Simple jQuery plugin to emulate Flickr's justified view
- * For usage information refer to http://github.com/kalyan02/flowr-js
- *
- *
- * @author: Kalyan Chakravarthy (http://KalyanChakravarthy.net)
- * @version: v0.1
- */
-(function($){
- //$("#container2").css( 'border', '1px solid #ccc');
- $.fn.flowr = function(options) {
-
- $this = this;
- var ROW_CLASS_NAME = 'flowr-row'; // Class name for the row of flowy
- var MAX_LAST_ROW_GAP = 25; // If the width of last row is lesser than max-width, recalculation is needed
- var NO_COPY_FIELDS = [ 'complete', 'data', 'responsive' ]; // these attributes will not be carried forward for append related calls
- var DEFAULTS = {
- 'data' : [],
- 'padding' : 5, // whats the padding between flowy items
- 'height' : 240, // Minimum height an image row should take
- 'render' : null, // callback function to get the tag
- 'append' : false, // TODO
- 'widthAttr' : 'width', // a custom data structure can specify which attribute refers to height/width
- 'heightAttr' : 'height',
- 'maxScale' : 1.5, // In case there is only 1 elment in last row
- 'maxWidth' : this.width()-1, // 1px is just for offset
- 'itemWidth' : null, // callback function for width
- 'itemHeight' : null, // callback function for height
- 'complete' : null, // complete callback
- 'rowClassName' : ROW_CLASS_NAME,
- 'rows' : -1, // Maximum number of rows to render. -1 for no limit.
- 'responsive' : true // make content responsive
- };
- var settings = $.extend( DEFAULTS, options);
-
- // If data is being appended, we already have settings
- // If we already have settings, retrieve them
- if( settings.append && $this.data('lastSettings') ) {
- lastSettings = $this.data('lastSettings');
-
- // Copy over the settings from previous init
- for( attr in DEFAULTS ) {
- if( NO_COPY_FIELDS.indexOf(attr)<0 && settings[attr] == DEFAULTS[attr] ) {
- settings[attr] = lastSettings[attr];
- }
- }
-
- // Check if we have an incomplete last row
- lastRow = $this.data('lastRow');
- if( lastRow.data.length > 0 && settings.maxWidth-lastRow.width > MAX_LAST_ROW_GAP ) {
- // Prepend the incomplete row to newly loaded data and redraw
- lastRowData = lastSettings.data.slice( lastSettings.data.length - lastRow.data.length - 1 );
- settings.data = lastRowData.concat(settings.data);
-
- // Remove the incomplete row
- // TODO: Don't reload this stuff later. Reattach to new row.
- $( '.' + settings.rowClassName + ':last', $this ).detach();
- } else {
- // console.log( lastRow.data.length );
- // console.log( lastRow.width );
- }
- }
-
- // only on the first initial call
- if( !settings.responsive && !settings.append )
- $this.width( $this.width() );
-
- // Basic sanity checks
- if( !(settings.data instanceof Array) )
- return;
-
- if( typeof(settings.padding) != 'number' )
- settings.padding = parseInt( settings.padding );
-
- if( typeof(settings.itemWidth) != 'function' ) {
- settings.itemWidth = function(data) {
- return data[ settings.widthAttr ];
- }
- }
-
- if( typeof(settings.itemHeight) != 'function' ) {
- settings.itemHeight = function(data) {
- return data[ settings.heightAttr ];
- }
- }
-
- // A standalone utility to calculate the item widths for a particular row
- // Returns rowWidth: width occupied & data : the items in the new row
- var utils = {
- getNextRow : function( data, settings ) {
- var itemIndex = 0;
- var itemsLength = data.length;
- var lineItems = [];
- var lineWidth = 0;
- var maxWidth = settings.maxWidth;
- var paddingSize = settings.padding;
-
- // console.log( 'maxItems=' + data.length );
-
- requiredPadding = function() {
- var extraPads = arguments.length == 1 ? arguments[0] : 0;
- return (lineItems.length - 1 + extraPads) * settings.padding;
- }
-
- while( lineWidth + requiredPadding() < settings.maxWidth && (itemIndex < itemsLength) ) {
- var itemData = data[ itemIndex ];
- var itemWidth = settings.itemWidth.call( $this, itemData );
- var itemHeight = settings.itemHeight.call( $this, itemData );
-
- var minHeight = settings.height;
- var minWidth = Math.floor( itemWidth * settings.height / itemHeight );
-
- var newLineWidth = lineWidth + minWidth + requiredPadding(1);
-
- if (minWidth > settings.maxWidth) {
- // very short+wide images like panoramas
- // show them even if ugly, as wide as possible
- minWidth = settings.maxWidth-1;
- minHeight = settings.height * minHeight / minWidth;
- }
-
- // console.log( 'lineWidth = ' + lineWidth );
- // console.log( 'newLineWidth = ' + newLineWidth );
- if( newLineWidth < settings.maxWidth ) {
- lineItems.push({
- 'height' : minHeight,
- 'width' : minWidth,
- 'itemData' : itemData
- });
-
- lineWidth += minWidth;
- itemIndex ++;
- } else {
- // We'd have exceeded width. So break off to scale.
- // console.log( 'breaking off = ' + itemIndex );
- // console.log( 'leave off size = ' + lineItems.length );
- break;
- }
- } //while
-
- // Scale the size to max width
- testWidth=0;
- if( lineWidth < settings.maxWidth ) {
- var fullScaleWidth = settings.maxWidth - requiredPadding() - 10;
- var currScaleWidth = lineWidth;
- var scaleFactor = fullScaleWidth / currScaleWidth;
- if( scaleFactor > settings.maxScale )
- scaleFactor = 1;
-
- var newHeight = Math.round( settings.height * scaleFactor );
- for( i=0; i<lineItems.length; i++ ) {
- var lineItem = lineItems[ i ];
- lineItem.width = Math.floor(lineItem.width * scaleFactor);
- lineItem.height = newHeight;
-
- testWidth += lineItem.width;
- }
- }
-
- return {
- data : lineItems,
- width : testWidth + requiredPadding()
- };
- }, //getNextRow
- reorderContent : function(){
- /*
- TODO: optimize for faster resizing by reusing dom objects instead of killing the dom
- */
- var _initialWidth = $this.data('width');
- var _newWidth = $this.width();
- var _change = _initialWidth - _newWidth;
-
- if(_initialWidth!=_newWidth) {
- $this.html('');
- var _settings = $this.data( 'lastSettings' );
- _settings.data = $this.data( 'data' );
- _settings.maxWidth = $this.width() - 1;
- $this.flowr( _settings );
- }
- }
- } //utils
-
- // If the resposive var is set to true then listen for resize method
- // and prevent resizing from happening twice if responsive is set again during append phase!
- if( settings.responsive && !$this.data('__responsive') ) {
- $(window).resize(function(){
- initialWidth = $this.data('width');
- newWidth = $this.width();
-
- //initiate resize
- if( initialWidth != newWidth ) {
- var task_id = $this.data('task_id');
- if( task_id ) {
- task_id = clearTimeout( task_id );
- task_id = null;
- }
- task_id = setTimeout( utils.reorderContent, 80 );
- $this.data('task_id', task_id );
- }
- });
- $this.data('__responsive',true);
- }
-
-
- return this.each(function(){
-
- // Get a copy of original data. 1 level deep copy is sufficient.
- var data = settings.data.slice(0);
- var rowData = null;
- var currentRow = 0;
- var currentItem = 0;
-
- // Store all the data
- var allData = $this.data( 'data' ) || [];
- for(i=0;i<data.length;i++) {
- allData.push( data[i] );
- }
- $this.data( 'data', allData );
-
- // While we have a new row
- while( ( rowData = utils.getNextRow(data,settings) ) != null && rowData.data.length > 0 ) {
- if( settings.rows > 0 && currentRow >= settings.rows )
- break;
- // remove the number of elements in the new row from the top of data stack
- data.splice( 0, rowData.data.length );
-
- // Create a new row div, add class, append the htmls and insert the flowy items
- var $row = $('<div>').addClass(settings.rowClassName);
- for( i=0; i<rowData.data.length; i++ ) {
- var displayData = rowData.data[i];
- // Get the HTML object from custom render function passed as argument
- var displayObject = settings.render.call( $this, displayData );
- displayObject = $(displayObject);
- // Set some basic stuff
- displayObject
- .css( 'width', displayData.width )
- .css( 'height', displayData.height )
- .css( 'margin-left', i==0 ? '0' : settings.padding + "px" ); //TODO:Refactor
- $row.append( displayObject );
-
- currentItem++;
- }
- $this.append( $row );
- // console.log ( "I> rowData.data.length="+rowData.data.length +" rowData.width="+rowData.width );
-
- currentRow++;
- $this.data('lastRow', rowData );
- }
- // store the current state of settings and the items in last row
- // we'll need this info when we append more items
- $this.data('lastSettings', settings );
-
- // onComplete callback
- // pass back info about list of rows and items rendered
- if( typeof (settings.complete) == 'function' ) {
- var completeData = {
- renderedRows : currentRow,
- renderedItems : currentItem
- }
- settings.complete.call( $this, completeData );
- }
- });
- };
+ * Flowr.js - Simple jQuery plugin to emulate Flickr's justified view
+ * For usage information refer to http://github.com/kalyan02/flowr-js
+ *
+ *
+ * @author: Kalyan Chakravarthy (http://KalyanChakravarthy.net)
+ * @version: v0.1
+ */
+(function($) {
+ //$("#container2").css( 'border', '1px solid #ccc');
+ $.fn.flowr = function(options) {
+
+ $this = this;
+ var ROW_CLASS_NAME = 'flowr-row'; // Class name for the row of flowy
+ var MAX_LAST_ROW_GAP = 25; // If the width of last row is lesser than max-width, recalculation is needed
+ var NO_COPY_FIELDS = ['complete', 'data', 'responsive']; // these attributes will not be carried forward for append related calls
+ var DEFAULTS = {
+ 'data': [],
+ 'padding': 5, // whats the padding between flowy items
+ 'height': 240, // Minimum height an image row should take
+ 'render': null, // callback function to get the tag
+ 'append': false, // TODO
+ 'widthAttr': 'width', // a custom data structure can specify which attribute refers to height/width
+ 'heightAttr': 'height',
+ 'maxScale': 1.5, // In case there is only 1 elment in last row
+ 'maxWidth': this.width() - 1, // 1px is just for offset
+ 'itemWidth': null, // callback function for width
+ 'itemHeight': null, // callback function for height
+ 'complete': null, // complete callback
+ 'rowClassName': ROW_CLASS_NAME,
+ 'rows': -1, // Maximum number of rows to render. -1 for no limit.
+ 'responsive': true // make content responsive
+ };
+ var settings = $.extend(DEFAULTS, options);
+
+ // If data is being appended, we already have settings
+ // If we already have settings, retrieve them
+ if (settings.append && $this.data('lastSettings')) {
+ lastSettings = $this.data('lastSettings');
+
+ // Copy over the settings from previous init
+ for (attr in DEFAULTS) {
+ if (NO_COPY_FIELDS.indexOf(attr) < 0 && settings[attr] == DEFAULTS[attr]) {
+ settings[attr] = lastSettings[attr];
+ }
+ }
+
+ // Check if we have an incomplete last row
+ lastRow = $this.data('lastRow');
+ if (lastRow.data.length > 0 && settings.maxWidth - lastRow.width > MAX_LAST_ROW_GAP) {
+ // Prepend the incomplete row to newly loaded data and redraw
+ lastRowData = lastSettings.data.slice(lastSettings.data.length - lastRow.data.length - 1);
+ settings.data = lastRowData.concat(settings.data);
+
+ // Remove the incomplete row
+ // TODO: Don't reload this stuff later. Reattach to new row.
+ $('.' + settings.rowClassName + ':last', $this).detach();
+ } else {
+ // console.log( lastRow.data.length );
+ // console.log( lastRow.width );
+ }
+ }
+
+ // only on the first initial call
+ if (!settings.responsive && !settings.append)
+ $this.width($this.width());
+
+ // Basic sanity checks
+ if (!(settings.data instanceof Array))
+ return;
+
+ if (typeof(settings.padding) != 'number')
+ settings.padding = parseInt(settings.padding);
+
+ if (typeof(settings.itemWidth) != 'function') {
+ settings.itemWidth = function(data) {
+ return data[settings.widthAttr];
+ }
+ }
+
+ if (typeof(settings.itemHeight) != 'function') {
+ settings.itemHeight = function(data) {
+ return data[settings.heightAttr];
+ }
+ }
+
+ // A standalone utility to calculate the item widths for a particular row
+ // Returns rowWidth: width occupied & data : the items in the new row
+ var utils = {
+ getNextRow: function(data, settings) {
+ var itemIndex = 0;
+ var itemsLength = data.length;
+ var lineItems = [];
+ var lineWidth = 0;
+ var maxWidth = settings.maxWidth;
+ var paddingSize = settings.padding;
+
+ // console.log( 'maxItems=' + data.length );
+
+ requiredPadding = function() {
+ var extraPads = arguments.length == 1 ? arguments[0] : 0;
+ return (lineItems.length - 1 + extraPads) * settings.padding;
+ }
+
+ while (lineWidth + requiredPadding() < settings.maxWidth && (itemIndex < itemsLength)) {
+ var itemData = data[itemIndex];
+ var itemWidth = settings.itemWidth.call($this, itemData);
+ var itemHeight = settings.itemHeight.call($this, itemData);
+
+ var minHeight = settings.height;
+ var minWidth = Math.floor(itemWidth * settings.height / itemHeight);
+
+
+ if (minWidth > settings.maxWidth) {
+ // very short+wide images like panoramas
+ // show them even if ugly, as wide as possible
+ minWidth = settings.maxWidth - 1 - requiredPadding(1);
+ minHeight = settings.height * minHeight / minWidth;
+ }
+ var newLineWidth = lineWidth + minWidth;
+
+ // console.log( 'lineWidth = ' + lineWidth );
+ // console.log( 'newLineWidth = ' + newLineWidth );
+ if (newLineWidth < settings.maxWidth) {
+ lineItems.push({
+ 'height': minHeight,
+ 'width': minWidth,
+ 'itemData': itemData
+ });
+
+ lineWidth += minWidth;
+ itemIndex++;
+ } else {
+ // We'd have exceeded width. So break off to scale.
+ // console.log( 'breaking off = ' + itemIndex );
+ // console.log( 'leave off size = ' + lineItems.length );
+ break;
+ }
+ } //while
+
+ // Scale the size to max width
+ testWidth = 0;
+ if (lineWidth < settings.maxWidth) {
+ var fullScaleWidth = settings.maxWidth - requiredPadding() - 10;
+ var currScaleWidth = lineWidth;
+ var scaleFactor = fullScaleWidth / currScaleWidth;
+ if (scaleFactor > settings.maxScale)
+ scaleFactor = 1;
+
+ var newHeight = Math.round(settings.height * scaleFactor);
+ for (i = 0; i < lineItems.length; i++) {
+ var lineItem = lineItems[i];
+ lineItem.width = Math.floor(lineItem.width * scaleFactor);
+ lineItem.height = newHeight;
+
+ testWidth += lineItem.width;
+ }
+ }
+
+ return {
+ data: lineItems,
+ width: testWidth + requiredPadding()
+ };
+ }, //getNextRow
+ reorderContent: function() {
+ /*
+ TODO: optimize for faster resizing by reusing dom objects instead of killing the dom
+ */
+ var _initialWidth = $this.data('width');
+ var _newWidth = $this.width();
+ var _change = _initialWidth - _newWidth;
+
+ if (_initialWidth != _newWidth) {
+ $this.html('');
+ var _settings = $this.data('lastSettings');
+ _settings.data = $this.data('data');
+ _settings.maxWidth = $this.width() - 1;
+ $this.flowr(_settings);
+ }
+ }
+ } //utils
+
+ // If the resposive var is set to true then listen for resize method
+ // and prevent resizing from happening twice if responsive is set again during append phase!
+ if (settings.responsive && !$this.data('__responsive')) {
+ $(window).resize(function() {
+ initialWidth = $this.data('width');
+ newWidth = $this.width();
+
+ //initiate resize
+ if (initialWidth != newWidth) {
+ var task_id = $this.data('task_id');
+ if (task_id) {
+ task_id = clearTimeout(task_id);
+ task_id = null;
+ }
+ task_id = setTimeout(utils.reorderContent, 80);
+ $this.data('task_id', task_id);
+ }
+ });
+ $this.data('__responsive', true);
+ }
+
+
+ return this.each(function() {
+
+ // Get a copy of original data. 1 level deep copy is sufficient.
+ var data = settings.data.slice(0);
+ var rowData = null;
+ var currentRow = 0;
+ var currentItem = 0;
+
+ // Store all the data
+ var allData = $this.data('data') || [];
+ for (i = 0; i < data.length; i++) {
+ allData.push(data[i]);
+ }
+ $this.data('data', allData);
+
+ // While we have a new row
+ while ((rowData = utils.getNextRow(data, settings)) != null && rowData.data.length > 0) {
+ if (settings.rows > 0 && currentRow >= settings.rows)
+ break;
+ // remove the number of elements in the new row from the top of data stack
+ data.splice(0, rowData.data.length);
+
+ // Create a new row div, add class, append the htmls and insert the flowy items
+ var $row = $('<div>').addClass(settings.rowClassName);
+ var slack = $this[0].clientWidth - rowData.width - 2 * settings.padding
+ for (i = 0; i < rowData.data.length; i++) {
+ var displayData = rowData.data[i];
+ // Get the HTML object from custom render function passed as argument
+ var displayObject = settings.render.call($this, displayData);
+ displayObject = $(displayObject);
+ extraw = Math.floor(slack/rowData.data.length)
+ if (i == 0) {
+ extraw += slack % rowData.data.length
+ }
+ // Set some basic stuff
+ displayObject
+ .css('width', displayData.width + extraw)
+ .css('height', displayData.height)
+ .css('margin-bottom', settings.padding + "px")
+ .css('margin-left', i == 0 ? '0' : settings.padding + "px"); //TODO:Refactor
+ $row.append(displayObject);
+
+ currentItem++;
+ }
+ $this.append($row);
+ // console.log ( "I> rowData.data.length="+rowData.data.length +" rowData.width="+rowData.width );
+
+ currentRow++;
+ $this.data('lastRow', rowData);
+ }
+ // store the current state of settings and the items in last row
+ // we'll need this info when we append more items
+ $this.data('lastSettings', settings);
+
+ // onComplete callback
+ // pass back info about list of rows and items rendered
+ if (typeof(settings.complete) == 'function') {
+ var completeData = {
+ renderedRows: currentRow,
+ renderedItems: currentItem
+ }
+ settings.complete.call($this, completeData);
+ }
+ });
+ };
})(jQuery);
diff --git a/nikola/data/themes/bootstrap3/assets/js/jquery.colorbox-min.js b/nikola/data/themes/bootstrap3/assets/js/jquery.colorbox-min.js
new file mode 120000
index 0000000..9e40fd4
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/js/jquery.colorbox-min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery-colorbox/jquery.colorbox-min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/js/jquery.min.js b/nikola/data/themes/bootstrap3/assets/js/jquery.min.js
new file mode 120000
index 0000000..5c080da
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/js/jquery.min.js
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery/dist/jquery.min.js \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/assets/js/jquery.min.map b/nikola/data/themes/bootstrap3/assets/js/jquery.min.map
new file mode 120000
index 0000000..7e2c217
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/assets/js/jquery.min.map
@@ -0,0 +1 @@
+../../../../../../bower_components/jquery/dist/jquery.min.map \ No newline at end of file
diff --git a/nikola/data/themes/bootstrap3/templates/authors.tmpl b/nikola/data/themes/bootstrap3/templates/authors.tmpl
new file mode 100644
index 0000000..2d3bbf5
--- /dev/null
+++ b/nikola/data/themes/bootstrap3/templates/authors.tmpl
@@ -0,0 +1,17 @@
+## -*- coding: utf-8 -*-
+<%inherit file="base.tmpl"/>
+
+<%block name="content">
+% if items:
+ <h2>${messages("Authors")}</h2>
+% endif
+% if items:
+ <ul class="list-inline">
+ % for text, link in items:
+ % if text not in hidden_authors:
+ <li><a class="reference badge" href="${link}">${text|h}</a></li>
+ % endif
+ % endfor
+ </ul>
+% endif
+</%block>
diff --git a/nikola/data/themes/bootstrap3/templates/base.tmpl b/nikola/data/themes/bootstrap3/templates/base.tmpl
index 5f90733..ab7805b 100644
--- a/nikola/data/themes/bootstrap3/templates/base.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/base.tmpl
@@ -24,11 +24,11 @@ ${template_hooks['extra_head']()}
</button>
<a class="navbar-brand" href="${abs_link(_link("root", None, lang))}">
%if logo_url:
- <img src="${logo_url}" alt="${blog_title}" id="logo">
+ <img src="${logo_url}" alt="${blog_title|h}" id="logo">
%endif
% if show_blog_title:
- <span id="blog-title">${blog_title}</span>
+ <span id="blog-title">${blog_title|h}</span>
% endif
</a>
</div><!-- /.navbar-header -->
diff --git a/nikola/data/themes/bootstrap3/templates/base_helper.tmpl b/nikola/data/themes/bootstrap3/templates/base_helper.tmpl
index a1e7508..587a933 100644
--- a/nikola/data/themes/bootstrap3/templates/base_helper.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/base_helper.tmpl
@@ -26,9 +26,11 @@ dir="rtl" \
lang="${lang}">
<head>
<meta charset="utf-8">
+ % if use_base_tag:
<base href="${abs_link(permalink)}">
+ % endif
%if description:
- <meta name="description" content="${description}">
+ <meta name="description" content="${description|h}">
%endif
<meta name="viewport" content="width=device-width, initial-scale=1">
%if title == blog_title:
@@ -38,6 +40,7 @@ lang="${lang}">
%endif
${html_stylesheets()}
+ <meta content="${theme_color}" name="theme-color">
${html_feedlinks()}
<link rel="canonical" href="${abs_link(permalink)}">
diff --git a/nikola/data/themes/bootstrap3/templates/gallery.tmpl b/nikola/data/themes/bootstrap3/templates/gallery.tmpl
index 3d6c01a..af0c194 100644
--- a/nikola/data/themes/bootstrap3/templates/gallery.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/gallery.tmpl
@@ -17,7 +17,7 @@
%if folders:
<ul>
% for folder, ftitle in folders:
- <li><a href="${folder}"><i class="glyphicon glyphicon-folder-open"></i>&nbsp;${ftitle}</a></li>
+ <li><a href="${folder}"><i class="glyphicon glyphicon-folder-open"></i>&nbsp;${ftitle|h}</a></li>
% endfor
</ul>
%endif
@@ -27,8 +27,8 @@
<noscript>
<ul class="thumbnails">
%for image in photo_array:
- <li><a href="${image['url']}" class="thumbnail image-reference" title="${image['title']}">
- <img src="${image['url_thumb']}" alt="${image['title']}" /></a>
+ <li><a href="${image['url']}" class="thumbnail image-reference" title="${image['title']|h}">
+ <img src="${image['url_thumb']}" alt="${image['title']|h}" /></a>
%endfor
</ul>
</noscript>
diff --git a/nikola/data/themes/bootstrap3/templates/listing.tmpl b/nikola/data/themes/bootstrap3/templates/listing.tmpl
index 7b09e3e..8c43806 100644
--- a/nikola/data/themes/bootstrap3/templates/listing.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/listing.tmpl
@@ -7,10 +7,10 @@ ${ui.bar(crumbs)}
%if folders or files:
<ul class="list-unstyled">
% for name in folders:
- <li><a href="${name}"><i class="glyphicon glyphicon-folder-open"></i> ${name}</a>
+ <li><a href="${name|u}"><i class="glyphicon glyphicon-folder-open"></i> ${name|h}</a>
% endfor
% for name in files:
- <li><a href="${name}.html"><i class="glyphicon glyphicon-file"></i> ${name}</a>
+ <li><a href="${name|u}.html"><i class="glyphicon glyphicon-file"></i> ${name|h}</a>
% endfor
</ul>
%endif
diff --git a/nikola/data/themes/bootstrap3/templates/post.tmpl b/nikola/data/themes/bootstrap3/templates/post.tmpl
index 8d9f88a..469c1e1 100644
--- a/nikola/data/themes/bootstrap3/templates/post.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/post.tmpl
@@ -10,9 +10,9 @@
<meta name="keywords" content="${post.meta('keywords')|h}">
% endif
%if post.description():
- <meta name="description" itemprop="description" content="${post.description()}">
+ <meta name="description" itemprop="description" content="${post.description()|h}">
%endif
- <meta name="author" content="${post.author()}">
+ <meta name="author" content="${post.author()|h}">
%if post.prev_post:
<link rel="prev" href="${post.prev_post.permalink()}" title="${post.prev_post.title()|h}" type="text/html">
%endif
diff --git a/nikola/data/themes/bootstrap3/templates/tags.tmpl b/nikola/data/themes/bootstrap3/templates/tags.tmpl
index ead3b0a..061bb39 100644
--- a/nikola/data/themes/bootstrap3/templates/tags.tmpl
+++ b/nikola/data/themes/bootstrap3/templates/tags.tmpl
@@ -2,16 +2,16 @@
<%inherit file="base.tmpl"/>
<%block name="content">
-<h1>${title}</h1>
+<h1>${title|h}</h1>
% if cat_items:
% if items:
<h2>${messages("Categories")}</h2>
% endif
% for text, full_name, path, link, indent_levels, indent_change_before, indent_change_after in cat_hierarchy:
% for i in range(indent_change_before):
- <ul class="unstyled">
+ <ul class="list-inline">
% endfor
- <li><a class="reference badge" href="${link}">${text}</a>
+ <li><a class="reference badge" href="${link}">${text|h}</a>
% if indent_change_after <= 0:
</li>
% endif
@@ -30,7 +30,7 @@
<ul class="list-inline">
% for text, link in items:
% if text not in hidden_tags:
- <li><a class="reference badge" href="${link}">${text}</a></li>
+ <li><a class="reference badge" href="${link}">${text|h}</a></li>
% endif
% endfor
</ul>
diff --git a/nikola/filters.py b/nikola/filters.py
index 4304860..0c477c2 100644
--- a/nikola/filters.py
+++ b/nikola/filters.py
@@ -26,19 +26,23 @@
"""Utility functions to help run filters on files."""
-from .utils import req_missing
from functools import wraps
import os
import io
+import json
import shutil
import subprocess
import tempfile
import shlex
+import lxml
try:
import typogrify.filters as typo
except ImportError:
typo = None # NOQA
+import requests
+
+from .utils import req_missing, LOGGER
def apply_to_binary_file(f):
@@ -232,8 +236,10 @@ def minify_lines(data):
def typogrify(data):
"""Prettify text with typogrify."""
if typo is None:
- req_missing(['typogrify'], 'use the typogrify filter')
+ req_missing(['typogrify'], 'use the typogrify filter', optional=True)
+ return data
+ data = _normalize_html(data)
data = typo.amp(data)
data = typo.widont(data)
data = typo.smartypants(data)
@@ -251,6 +257,7 @@ def typogrify_sans_widont(data):
if typo is None:
req_missing(['typogrify'], 'use the typogrify_sans_widont filter')
+ data = _normalize_html(data)
data = typo.amp(data)
data = typo.smartypants(data)
# Disabled because of typogrify bug where it breaks <title>
@@ -274,3 +281,56 @@ def php_template_injection(data):
return phpdata
else:
return data
+
+
+@apply_to_text_file
+def cssminify(data):
+ """Minify CSS using http://cssminifier.com/."""
+ try:
+ url = 'http://cssminifier.com/raw'
+ _data = {'input': data}
+ response = requests.post(url, data=_data)
+ return response.text
+ except Exception as exc:
+ LOGGER.error("can't use cssminifier.com: {}", exc)
+ return data
+
+
+@apply_to_text_file
+def jsminify(data):
+ """Minify JS using http://javascript-minifier.com/."""
+ try:
+ url = 'http://javascript-minifier.com/raw'
+ _data = {'input': data}
+ response = requests.post(url, data=_data)
+ return response.text
+ except Exception as exc:
+ LOGGER.error("can't use javascript-minifier.com: {}", exc)
+ return data
+
+
+@apply_to_text_file
+def jsonminify(data):
+ """Minify JSON files (strip whitespace and use minimal separators)."""
+ data = json.dumps(json.loads(data), indent=None, separators=(',', ':'))
+ return data
+
+
+@apply_to_binary_file
+def xmlminify(data):
+ """Minify XML files (strip whitespace and use minimal separators)."""
+ parser = lxml.etree.XMLParser(remove_blank_text=True)
+ newdata = lxml.etree.XML(data, parser=parser)
+ return lxml.etree.tostring(newdata, encoding='utf-8', method='xml', xml_declaration=True)
+
+
+def _normalize_html(data):
+ """Pass HTML through LXML to clean it up, if possible."""
+ try:
+ data = lxml.html.tostring(lxml.html.fromstring(data), encoding='unicode')
+ except:
+ pass
+ return data
+
+
+normalize_html = apply_to_text_file(_normalize_html)
diff --git a/nikola/image_processing.py b/nikola/image_processing.py
index 0ba139f..b6f8215 100644
--- a/nikola/image_processing.py
+++ b/nikola/image_processing.py
@@ -29,6 +29,9 @@
from __future__ import unicode_literals
import datetime
import os
+import lxml
+import re
+import gzip
from nikola import utils
@@ -45,15 +48,14 @@ except ImportError:
class ImageProcessor(object):
-
"""Apply image operations."""
image_ext_list_builtin = ['.jpg', '.png', '.jpeg', '.gif', '.svg', '.bmp', '.tiff']
def resize_image(self, src, dst, max_size, bigger_panoramas=True):
"""Make a copy of the image in the requested size."""
- if not Image:
- utils.copy_file(src, dst)
+ if not Image or os.path.splitext(src)[1] in ['.svg', '.svgz']:
+ self.resize_svg(src, dst, max_size, bigger_panoramas)
return
im = Image.open(src)
w, h = im.size
@@ -90,6 +92,48 @@ class ImageProcessor(object):
else: # Image is small
utils.copy_file(src, dst)
+ def resize_svg(self, src, dst, max_size, bigger_panoramas):
+ """Make a copy of an svg at the requested size."""
+ try:
+ # Resize svg based on viewport hacking.
+ # note that this can also lead to enlarged svgs
+ if src.endswith('.svgz'):
+ with gzip.GzipFile(src) as op:
+ xml = op.read()
+ else:
+ with open(src) as op:
+ xml = op.read()
+ tree = lxml.etree.XML(xml)
+ width = tree.attrib['width']
+ height = tree.attrib['height']
+ w = int(re.search("[0-9]+", width).group(0))
+ h = int(re.search("[0-9]+", height).group(0))
+ # calculate new size preserving aspect ratio.
+ ratio = float(w) / h
+ # Panoramas get larger thumbnails because they look *awful*
+ if bigger_panoramas and w > 2 * h:
+ max_size = max_size * 4
+ if w > h:
+ w = max_size
+ h = max_size / ratio
+ else:
+ w = max_size * ratio
+ h = max_size
+ w = int(w)
+ h = int(h)
+ tree.attrib.pop("width")
+ tree.attrib.pop("height")
+ tree.attrib['viewport'] = "0 0 %ipx %ipx" % (w, h)
+ if dst.endswith('.svgz'):
+ op = gzip.GzipFile(dst, 'w')
+ else:
+ op = open(dst, 'w')
+ op.write(lxml.etree.tostring(tree))
+ op.close()
+ except (KeyError, AttributeError) as e:
+ self.logger.warn("No width/height in %s. Original exception: %s" % (src, e))
+ utils.copy_file(src, dst)
+
def image_date(self, src):
"""Try to figure out the date of the image."""
if src not in self.dates:
@@ -103,8 +147,10 @@ class ImageProcessor(object):
decoded = ExifTags.TAGS.get(tag, tag)
if decoded in ('DateTimeOriginal', 'DateTimeDigitized'):
try:
+ if isinstance(value, tuple):
+ value = value[0]
self.dates[src] = datetime.datetime.strptime(
- value, r'%Y:%m:%d %H:%M:%S')
+ value, '%Y:%m:%d %H:%M:%S')
break
except ValueError: # Invalid EXIF date.
pass
diff --git a/nikola/nikola.py b/nikola/nikola.py
index e0af7ad..9e9b849 100644
--- a/nikola/nikola.py
+++ b/nikola/nikola.py
@@ -80,7 +80,7 @@ else:
# Default "Read more..." link
DEFAULT_INDEX_READ_MORE_LINK = '<p class="more"><a href="{link}">{read_more}…</a></p>'
-DEFAULT_RSS_READ_MORE_LINK = '<p><a href="{link}">{read_more}…</a> ({min_remaining_read})</p>'
+DEFAULT_FEED_READ_MORE_LINK = '<p><a href="{link}">{read_more}…</a> ({min_remaining_read})</p>'
# Default pattern for translation files' names
DEFAULT_TRANSLATIONS_PATTERN = '{path}.{lang}.{ext}'
@@ -105,6 +105,7 @@ LEGAL_VALUES = {
'ar': 'Arabic',
'az': 'Azerbaijani',
'bg': 'Bulgarian',
+ 'bs': 'Bosnian',
'ca': 'Catalan',
('cs', 'cz'): 'Czech',
'da': 'Danish',
@@ -120,6 +121,7 @@ LEGAL_VALUES = {
'fr': 'French',
'hi': 'Hindi',
'hr': 'Croatian',
+ 'hu': 'Hungarian',
'id': 'Indonesian',
'it': 'Italian',
('ja', '!jp'): 'Japanese',
@@ -128,11 +130,13 @@ LEGAL_VALUES = {
'nl': 'Dutch',
'pa': 'Punjabi',
'pl': 'Polish',
- 'pt_br': 'Portuguese (Brasil)',
+ 'pt': 'Portuguese',
+ 'pt_br': 'Portuguese (Brazil)',
'ru': 'Russian',
'sk': 'Slovak',
'sl': 'Slovene',
'sr': 'Serbian (Cyrillic)',
+ 'sr_latin': 'Serbian (Latin)',
'sv': 'Swedish',
('tr', '!tr_TR'): 'Turkish',
'ur': 'Urdu',
@@ -152,6 +156,7 @@ LEGAL_VALUES = {
"fa": "Farsi", # Persian
"fr": "French",
"hr": "Croatian",
+ "hu": "Hungarian",
"it": "Italian",
"jp": "Japanese",
"nl": "Dutch",
@@ -167,7 +172,6 @@ LEGAL_VALUES = {
# country specifier. If there is no other locale that has the same
# language with a different country, ``nikola init`` (but nobody else!)
# will accept it, warning the user about it.
- 'pt': 'pt_br',
'zh': 'zh_cn',
},
'RTL_LANGUAGES': ('ar', 'fa', 'ur'),
@@ -187,6 +191,7 @@ LEGAL_VALUES = {
fi='fi',
fr='fr',
hr='hr',
+ hu='hu',
id='id',
it='it',
ja='ja',
@@ -194,11 +199,13 @@ LEGAL_VALUES = {
nb='no',
nl='nl',
pl='pl',
+ pt='pt-BR', # hope nobody will mind
pt_br='pt-BR',
ru='ru',
sk='sk',
sl='si', # country code is si, language code is sl, colorbox is wrong
sr='sr', # warning: this is serbian in Latin alphabet
+ sr_latin='sr',
sv='sv',
tr='tr',
uk='uk',
@@ -207,20 +214,27 @@ LEGAL_VALUES = {
'MOMENTJS_LOCALES': defaultdict(
str,
ar='ar',
+ az='az',
bg='bg',
bn='bn',
+ bs='bs',
ca='ca',
cs='cs',
cz='cs',
da='da',
de='de',
- en='',
+ el='el',
+ en='en',
+ eo='eo',
es='es',
et='et',
+ eu='eu',
fa='fa',
fi='fi',
fr='fr',
+ hi='hi',
hr='hr',
+ hu='hu',
id='id',
it='it',
ja='ja',
@@ -228,13 +242,16 @@ LEGAL_VALUES = {
nb='nb',
nl='nl',
pl='pl',
+ pt='pt',
pt_br='pt-br',
ru='ru',
sk='sk',
sl='sl',
sr='sr-cyrl',
+ sr_latin='sr',
sv='sv',
tr='tr',
+ uk='uk',
zh_cn='zh-cn'
),
'PYPHEN_LOCALES': {
@@ -250,16 +267,19 @@ LEGAL_VALUES = {
'et': 'et',
'fr': 'fr',
'hr': 'hr',
+ 'hu': 'hu',
'it': 'it',
'nb': 'nb',
'nl': 'nl',
'pl': 'pl',
+ 'pt': 'pt',
'pt_br': 'pt_BR',
'ru': 'ru',
'sk': 'sk',
'sl': 'sl',
'sr': 'sr',
'sv': 'sv',
+ 'uk': 'uk',
},
}
@@ -275,7 +295,6 @@ def _enclosure(post, lang):
class Nikola(object):
-
"""Class that handles site generation.
Takes a site config as argument on creation.
@@ -335,6 +354,10 @@ class Nikola(object):
'ARCHIVE_PATH': "",
'ARCHIVE_FILENAME': "archive.html",
'ARCHIVES_ARE_INDEXES': False,
+ 'AUTHOR_PATH': 'authors',
+ 'AUTHOR_PAGES_ARE_INDEXES': False,
+ 'AUTHOR_PAGES_DESCRIPTIONS': {},
+ 'AUTHORLIST_MINIMUM_POSTS': 1,
'BLOG_AUTHOR': 'Default Author',
'BLOG_TITLE': 'Default Title',
'BLOG_DESCRIPTION': 'Default Description',
@@ -343,6 +366,7 @@ class Nikola(object):
'CATEGORY_PATH': None, # None means: same as TAG_PATH
'CATEGORY_PAGES_ARE_INDEXES': None, # None means: same as TAG_PAGES_ARE_INDEXES
'CATEGORY_PAGES_DESCRIPTIONS': {},
+ 'CATEGORY_PAGES_TITLES': {},
'CATEGORY_PREFIX': 'cat_',
'CATEGORY_ALLOW_HIERARCHIES': False,
'CATEGORY_OUTPUT_FLAT_HIERARCHY': False,
@@ -375,6 +399,7 @@ class Nikola(object):
'DISABLED_PLUGINS': [],
'EXTRA_PLUGINS_DIRS': [],
'COMMENT_SYSTEM_ID': 'nikolademo',
+ 'ENABLE_AUTHOR_PAGES': True,
'EXTRA_HEAD_DATA': '',
'FAVICONS': (),
'FEED_LENGTH': 10,
@@ -389,6 +414,7 @@ class Nikola(object):
'GZIP_COMMAND': None,
'GZIP_FILES': False,
'GZIP_EXTENSIONS': ('.txt', '.htm', '.html', '.css', '.js', '.json', '.xml'),
+ 'HIDDEN_AUTHORS': [],
'HIDDEN_TAGS': [],
'HIDDEN_CATEGORIES': [],
'HYPHENATE': False,
@@ -417,27 +443,35 @@ class Nikola(object):
'OLD_THEME_SUPPORT': True,
'OUTPUT_FOLDER': 'output',
'POSTS': (("posts/*.txt", "posts", "post.tmpl"),),
+ 'POSTS_SECTIONS': True,
+ 'POSTS_SECTION_ARE_INDEXES': True,
+ 'POSTS_SECTION_DESCRIPTIONS': "",
+ 'POSTS_SECTION_FROM_META': False,
+ 'POSTS_SECTION_NAME': "",
+ 'POSTS_SECTION_TITLE': "{name}",
'PAGES': (("stories/*.txt", "stories", "story.tmpl"),),
'PANDOC_OPTIONS': [],
'PRETTY_URLS': False,
'FUTURE_IS_NOW': False,
'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK,
- 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK,
- 'RSS_LINKS_APPEND_QUERY': False,
'REDIRECTIONS': [],
'ROBOTS_EXCLUSIONS': [],
'GENERATE_ATOM': False,
+ 'FEED_TEASERS': True,
+ 'FEED_PLAIN': False,
+ 'FEED_PREVIEWIMAGE': True,
+ 'FEED_READ_MORE_LINK': DEFAULT_FEED_READ_MORE_LINK,
+ 'FEED_LINKS_APPEND_QUERY': False,
'GENERATE_RSS': True,
'RSS_LINK': None,
'RSS_PATH': '',
- 'RSS_PLAIN': False,
- 'RSS_TEASERS': True,
'SASS_COMPILER': 'sass',
'SASS_OPTIONS': [],
'SEARCH_FORM': '',
'SHOW_BLOG_TITLE': True,
'SHOW_SOURCELINK': True,
'SHOW_UNTRANSLATED_POSTS': True,
+ 'SLUG_AUTHOR_PATH': True,
'SLUG_TAG_PATH': True,
'SOCIAL_BUTTONS_CODE': '',
'SITE_URL': 'https://example.com/',
@@ -447,18 +481,23 @@ class Nikola(object):
'TAG_PATH': 'categories',
'TAG_PAGES_ARE_INDEXES': False,
'TAG_PAGES_DESCRIPTIONS': {},
+ 'TAG_PAGES_TITLES': {},
+ 'TAGS_INDEX_PATH': '',
'TAGLIST_MINIMUM_POSTS': 1,
'TEMPLATE_FILTERS': {},
'THEME': 'bootstrap3',
+ 'THEME_COLOR': '#5670d4', # light "corporate blue"
'THEME_REVEAL_CONFIG_SUBTHEME': 'sky',
'THEME_REVEAL_CONFIG_TRANSITION': 'cube',
'THUMBNAIL_SIZE': 180,
'UNSLUGIFY_TITLES': False, # WARNING: conf.py.in overrides this with True for backwards compatibility
'URL_TYPE': 'rel_path',
+ 'USE_BASE_TAG': True,
'USE_BUNDLES': True,
'USE_CDN': False,
'USE_CDN_WARNING': True,
'USE_FILENAME_AS_TITLE': True,
+ 'USE_KATEX': False,
'USE_OPEN_GRAPH': True,
'USE_SLUGIFY': True,
'TIMEZONE': 'UTC',
@@ -510,10 +549,21 @@ class Nikola(object):
'EXTRA_HEAD_DATA',
'NAVIGATION_LINKS',
'INDEX_READ_MORE_LINK',
- 'RSS_READ_MORE_LINK',
+ 'FEED_READ_MORE_LINK',
'INDEXES_TITLE',
+ 'POSTS_SECTION_COLORS',
+ 'POSTS_SECTION_DESCRIPTIONS',
+ 'POSTS_SECTION_NAME',
+ 'POSTS_SECTION_TITLE',
'INDEXES_PAGES',
- 'INDEXES_PRETTY_PAGE_URL',)
+ 'INDEXES_PRETTY_PAGE_URL',
+ # PATH options (Issue #1914)
+ 'TAG_PATH',
+ 'TAGS_INDEX_PATH',
+ 'CATEGORY_PATH',
+ 'DATE_FORMAT',
+ 'JS_DATE_FORMAT',
+ )
self._GLOBAL_CONTEXT_TRANSLATABLE = ('blog_author',
'blog_title',
@@ -524,10 +574,20 @@ class Nikola(object):
'social_buttons_code',
'search_form',
'body_end',
- 'extra_head_data',)
+ 'extra_head_data',
+ 'date_format',
+ 'js_date_format',)
# WARNING: navigation_links SHOULD NOT be added to the list above.
# Themes ask for [lang] there and we should provide it.
+ # We first have to massage JS_DATE_FORMAT, otherwise we run into trouble
+ if 'JS_DATE_FORMAT' in self.config:
+ if isinstance(self.config['JS_DATE_FORMAT'], dict):
+ for k in self.config['JS_DATE_FORMAT']:
+ self.config['JS_DATE_FORMAT'][k] = json.dumps(self.config['JS_DATE_FORMAT'][k])
+ else:
+ self.config['JS_DATE_FORMAT'] = json.dumps(self.config['JS_DATE_FORMAT'])
+
for i in self.TRANSLATABLE_SETTINGS:
try:
self.config[i] = utils.TranslatableSetting(i, self.config[i], self.config['TRANSLATIONS'])
@@ -555,6 +615,38 @@ class Nikola(object):
for i1, i2, i3 in self.config['PAGES']:
self.config['post_pages'].append([i1, i2, i3, False])
+ # RSS_TEASERS has been replaced with FEED_TEASERS
+ # TODO: remove on v8
+ if 'RSS_TEASERS' in config:
+ utils.LOGGER.warn('The RSS_TEASERS option is deprecated, use FEED_TEASERS instead.')
+ if 'FEED_TEASERS' in config:
+ utils.LOGGER.warn('FEED_TEASERS conflicts with RSS_TEASERS, ignoring RSS_TEASERS.')
+ self.config['FEED_TEASERS'] = config['RSS_TEASERS']
+
+ # RSS_PLAIN has been replaced with FEED_PLAIN
+ # TODO: remove on v8
+ if 'RSS_PLAIN' in config:
+ utils.LOGGER.warn('The RSS_PLAIN option is deprecated, use FEED_PLAIN instead.')
+ if 'FEED_PLAIN' in config:
+ utils.LOGGER.warn('FEED_PLIN conflicts with RSS_PLAIN, ignoring RSS_PLAIN.')
+ self.config['FEED_PLAIN'] = config['RSS_PLAIN']
+
+ # RSS_LINKS_APPEND_QUERY has been replaced with FEED_LINKS_APPEND_QUERY
+ # TODO: remove on v8
+ if 'RSS_LINKS_APPEND_QUERY' in config:
+ utils.LOGGER.warn('The RSS_LINKS_APPEND_QUERY option is deprecated, use FEED_LINKS_APPEND_QUERY instead.')
+ if 'FEED_TEASERS' in config:
+ utils.LOGGER.warn('FEED_LINKS_APPEND_QUERY conflicts with RSS_LINKS_APPEND_QUERY, ignoring RSS_LINKS_APPEND_QUERY.')
+ self.config['FEED_LINKS_APPEND_QUERY'] = config['RSS_LINKS_APPEND_QUERY']
+
+ # RSS_READ_MORE_LINK has been replaced with FEED_READ_MORE_LINK
+ # TODO: remove on v8
+ if 'RSS_READ_MORE_LINK' in config:
+ utils.LOGGER.warn('The RSS_READ_MORE_LINK option is deprecated, use FEED_READ_MORE_LINK instead.')
+ if 'FEED_READ_MORE_LINK' in config:
+ utils.LOGGER.warn('FEED_READ_MORE_LINK conflicts with RSS_READ_MORE_LINK, ignoring RSS_READ_MORE_LINK')
+ self.config['FEED_READ_MORE_LINK'] = utils.TranslatableSetting('FEED_READ_MORE_LINK', config['RSS_READ_MORE_LINK'], self.config['TRANSLATIONS'])
+
# DEFAULT_TRANSLATIONS_PATTERN was changed from "p.e.l" to "p.l.e"
# TODO: remove on v8
if 'TRANSLATIONS_PATTERN' not in self.config:
@@ -634,7 +726,7 @@ class Nikola(object):
if not self.config.get('COPY_SOURCES'):
self.config['SHOW_SOURCELINK'] = False
- if self.config['CATEGORY_PATH'] is None:
+ if self.config['CATEGORY_PATH']._inp is None:
self.config['CATEGORY_PATH'] = self.config['TAG_PATH']
if self.config['CATEGORY_PAGES_ARE_INDEXES'] is None:
self.config['CATEGORY_PAGES_ARE_INDEXES'] = self.config['TAG_PAGES_ARE_INDEXES']
@@ -775,7 +867,7 @@ class Nikola(object):
# Remove compiler extensions we don't need
if p[-1].details.has_option('Nikola', 'compiler') and p[-1].details.get('Nikola', 'compiler') in self.disabled_compilers:
bad_candidates.add(p)
- utils.LOGGER.debug('Not loading comopiler extension {}', p[-1].name)
+ utils.LOGGER.debug('Not loading compiler extension {}', p[-1].name)
self.plugin_manager._candidates = list(set(self.plugin_manager._candidates) - bad_candidates)
self.plugin_manager.loadPlugins()
@@ -828,13 +920,16 @@ class Nikola(object):
self._GLOBAL_CONTEXT['rel_link'] = self.rel_link
self._GLOBAL_CONTEXT['abs_link'] = self.abs_link
self._GLOBAL_CONTEXT['exists'] = self.file_exists
+ self._GLOBAL_CONTEXT['SLUG_AUTHOR_PATH'] = self.config['SLUG_AUTHOR_PATH']
self._GLOBAL_CONTEXT['SLUG_TAG_PATH'] = self.config['SLUG_TAG_PATH']
self._GLOBAL_CONTEXT['annotations'] = self.config['ANNOTATIONS']
self._GLOBAL_CONTEXT['index_display_post_count'] = self.config[
'INDEX_DISPLAY_POST_COUNT']
self._GLOBAL_CONTEXT['index_file'] = self.config['INDEX_FILE']
+ self._GLOBAL_CONTEXT['use_base_tag'] = self.config['USE_BASE_TAG']
self._GLOBAL_CONTEXT['use_bundles'] = self.config['USE_BUNDLES']
self._GLOBAL_CONTEXT['use_cdn'] = self.config.get("USE_CDN")
+ self._GLOBAL_CONTEXT['theme_color'] = self.config.get("THEME_COLOR")
self._GLOBAL_CONTEXT['favicons'] = self.config['FAVICONS']
self._GLOBAL_CONTEXT['date_format'] = self.config.get('DATE_FORMAT')
self._GLOBAL_CONTEXT['blog_author'] = self.config.get('BLOG_AUTHOR')
@@ -842,6 +937,8 @@ class Nikola(object):
self._GLOBAL_CONTEXT['show_blog_title'] = self.config.get('SHOW_BLOG_TITLE')
self._GLOBAL_CONTEXT['logo_url'] = self.config.get('LOGO_URL')
self._GLOBAL_CONTEXT['blog_description'] = self.config.get('BLOG_DESCRIPTION')
+ self._GLOBAL_CONTEXT['color_hsl_adjust_hex'] = utils.color_hsl_adjust_hex
+ self._GLOBAL_CONTEXT['colorize_str_from_base_color'] = utils.colorize_str_from_base_color
# TODO: remove in v8
self._GLOBAL_CONTEXT['blog_desc'] = self.config.get('BLOG_DESCRIPTION')
@@ -858,6 +955,7 @@ class Nikola(object):
self._GLOBAL_CONTEXT['site_has_comments'] = bool(self.config.get('COMMENT_SYSTEM'))
self._GLOBAL_CONTEXT['mathjax_config'] = self.config.get(
'MATHJAX_CONFIG')
+ self._GLOBAL_CONTEXT['use_katex'] = self.config.get('USE_KATEX')
self._GLOBAL_CONTEXT['subtheme'] = self.config.get('THEME_REVEAL_CONFIG_SUBTHEME')
self._GLOBAL_CONTEXT['transition'] = self.config.get('THEME_REVEAL_CONFIG_TRANSITION')
self._GLOBAL_CONTEXT['content_footer'] = self.config.get(
@@ -879,12 +977,20 @@ class Nikola(object):
'SHOW_SOURCELINK')
self._GLOBAL_CONTEXT['extra_head_data'] = self.config.get('EXTRA_HEAD_DATA')
self._GLOBAL_CONTEXT['date_fanciness'] = self.config.get('DATE_FANCINESS')
- self._GLOBAL_CONTEXT['js_date_format'] = json.dumps(self.config.get('JS_DATE_FORMAT'))
+ self._GLOBAL_CONTEXT['js_date_format'] = self.config.get('JS_DATE_FORMAT')
self._GLOBAL_CONTEXT['colorbox_locales'] = LEGAL_VALUES['COLORBOX_LOCALES']
self._GLOBAL_CONTEXT['momentjs_locales'] = LEGAL_VALUES['MOMENTJS_LOCALES']
self._GLOBAL_CONTEXT['hidden_tags'] = self.config.get('HIDDEN_TAGS')
self._GLOBAL_CONTEXT['hidden_categories'] = self.config.get('HIDDEN_CATEGORIES')
+ self._GLOBAL_CONTEXT['hidden_authors'] = self.config.get('HIDDEN_AUTHORS')
self._GLOBAL_CONTEXT['url_replacer'] = self.url_replacer
+ self._GLOBAL_CONTEXT['posts_sections'] = self.config.get('POSTS_SECTIONS')
+ self._GLOBAL_CONTEXT['posts_section_are_indexes'] = self.config.get('POSTS_SECTION_ARE_INDEXES')
+ self._GLOBAL_CONTEXT['posts_section_colors'] = self.config.get('POSTS_SECTION_COLORS')
+ self._GLOBAL_CONTEXT['posts_section_descriptions'] = self.config.get('POSTS_SECTION_DESCRIPTIONS')
+ self._GLOBAL_CONTEXT['posts_section_from_meta'] = self.config.get('POSTS_SECTION_FROM_META')
+ self._GLOBAL_CONTEXT['posts_section_name'] = self.config.get('POSTS_SECTION_NAME')
+ self._GLOBAL_CONTEXT['posts_section_title'] = self.config.get('POSTS_SECTION_TITLE')
# IPython theme configuration. If a website has ipynb enabled in post_pages
# we should enable the IPython CSS (leaving that up to the theme itself).
@@ -1064,7 +1170,7 @@ class Nikola(object):
doc.rewrite_links(lambda dst: self.url_replacer(src, dst, lang), resolve_base_href=False)
# lxml ignores srcset in img and source elements, so do that by hand
- objs = list(doc.findall('*//img')) + list(doc.findall('*//source'))
+ objs = list(doc.xpath('(*//img|*//source)'))
for obj in objs:
if 'srcset' in obj.attrib:
urls = [u.strip() for u in obj.attrib['srcset'].split(',')]
@@ -1192,7 +1298,7 @@ class Nikola(object):
"""Take all necessary data, and render a RSS feed in output_path."""
rss_obj = utils.ExtendedRSS2(
title=title,
- link=link,
+ link=utils.encodelink(link),
description=description,
lastBuildDate=datetime.datetime.utcnow(),
generator='https://getnikola.com/',
@@ -1213,10 +1319,12 @@ class Nikola(object):
for post in timeline[:feed_length]:
data = post.text(lang, teaser_only=rss_teasers, strip_html=rss_plain,
- rss_read_more_link=True, rss_links_append_query=feed_append_query)
+ feed_read_more_link=True, feed_links_append_query=feed_append_query)
if feed_url is not None and data:
# Massage the post's HTML (unless plain)
if not rss_plain:
+ if self.config["FEED_PREVIEWIMAGE"] and 'previewimage' in post.meta[lang] and post.meta[lang]['previewimage'] not in data:
+ data = "<figure><img src=\"{}\"></figure> {}".format(post.meta[lang]['previewimage'], data)
# FIXME: this is duplicated with code in Post.text()
try:
doc = lxml.html.document_fromstring(data)
@@ -1308,7 +1416,6 @@ class Nikola(object):
try:
path = self.path_handlers[kind](name, lang)
path = [os.path.normpath(p) for p in path if p != '.'] # Fix Issue #1028
-
if is_link:
link = '/' + ('/'.join(path))
index_len = len(self.config['INDEX_FILE'])
@@ -1324,13 +1431,25 @@ class Nikola(object):
return ""
def post_path(self, name, lang):
- """Handle post_path paths."""
+ """Link to the destination of an element in the POSTS/PAGES settings.
+
+ Example:
+
+ link://post_path/posts => /blog
+ """
return [_f for _f in [self.config['TRANSLATIONS'][lang],
os.path.dirname(name),
self.config['INDEX_FILE']] if _f]
def root_path(self, name, lang):
- """Handle root_path paths."""
+ """Link to the current language's root.
+
+ Example:
+
+ link://root_path => /
+
+ link://root_path => /translations/spanish/
+ """
d = self.config['TRANSLATIONS'][lang]
if d:
return [d, '']
@@ -1338,7 +1457,12 @@ class Nikola(object):
return []
def slug_path(self, name, lang):
- """Handle slug paths."""
+ """A link to a post with given slug, if not ambiguous.
+
+ Example:
+
+ links://slug/yellow-camaro => /posts/cars/awful/yellow-camaro/index.html
+ """
results = [p for p in self.timeline if p.meta('slug') == name]
if not results:
utils.LOGGER.warning("Cannot resolve path request for slug: {0}".format(name))
@@ -1348,7 +1472,12 @@ class Nikola(object):
return [_f for _f in results[0].permalink(lang).split('/') if _f]
def filename_path(self, name, lang):
- """Handle filename paths."""
+ """Link to post or story by source filename.
+
+ Example:
+
+ link://filename/manual.txt => /docs/handbook.html
+ """
results = [p for p in self.timeline if p.source_path == name]
if not results:
utils.LOGGER.warning("Cannot resolve path request for filename: {0}".format(name))
@@ -1366,7 +1495,9 @@ class Nikola(object):
def link(self, *args):
"""Create a link."""
- return self.path(*args, is_link=True)
+ url = self.path(*args, is_link=True)
+ url = utils.encodelink(url)
+ return url
def abs_link(self, dst, protocol_relative=False):
"""Get an absolute link."""
@@ -1378,6 +1509,7 @@ class Nikola(object):
url = urlparse(dst).geturl()
if protocol_relative:
url = url.split(":", 1)[1]
+ url = utils.encodelink(url)
return url
def rel_link(self, src, dst):
@@ -1392,7 +1524,7 @@ class Nikola(object):
parsed_src = urlsplit(src)
parsed_dst = urlsplit(dst)
if parsed_src[:2] != parsed_dst[:2]:
- return dst
+ return utils.encodelink(dst)
# Now both paths are on the same site and absolute
src_elems = parsed_src.path.split('/')[1:]
dst_elems = parsed_dst.path.split('/')[1:]
@@ -1403,7 +1535,9 @@ class Nikola(object):
else:
i += 1
# Now i is the longest common prefix
- return '/'.join(['..'] * (len(src_elems) - i - 1) + dst_elems[i:])
+ url = '/'.join(['..'] * (len(src_elems) - i - 1) + dst_elems[i:])
+ url = utils.encodelink(url)
+ return url
def file_exists(self, path, not_empty=False):
"""Check if the file exists. If not_empty is True, it also must not be empty."""
@@ -1554,7 +1688,7 @@ class Nikola(object):
utils.LOGGER.error('Tag {0} is used in: {1}'.format(other_tag, ', '.join([p.source_path for p in self.posts_per_tag[other_tag]])))
quit = True
else:
- slugged_tags.add(utils.slugify(tag, force=True))
+ slugged_tags.add(utils.slugify(tag))
self.posts_per_tag[tag].append(post)
for lang in self.config['TRANSLATIONS'].keys():
self.tags_per_language[lang].extend(post.tags_for_language(lang))
@@ -1606,6 +1740,7 @@ class Nikola(object):
def generic_page_renderer(self, lang, post, filters, context=None):
"""Render post fragments to final HTML pages."""
+ utils.LocaleBorg().set_locale(lang)
context = context.copy() if context else {}
deps = post.deps(lang) + \
self.template_system.template_deps(post.template_name)
@@ -1711,9 +1846,10 @@ class Nikola(object):
link = lxml.etree.Element("link")
link.set("rel", link_rel)
link.set("type", link_type)
- link.set("href", link_href)
+ link.set("href", utils.encodelink(link_href))
return link
+ utils.LocaleBorg().set_locale(lang)
deps = []
uptodate_deps = []
for post in posts:
@@ -1739,15 +1875,13 @@ class Nikola(object):
deps_context['navigation_links'] = deps_context['global']['navigation_links'](lang)
nslist = {}
- if context["is_feed_stale"] or (not context["feedpagenum"] == context["feedpagecount"] - 1 and not context["feedpagenum"] == 0):
+ if context["is_feed_stale"] or "feedpagenum" in context and (not context["feedpagenum"] == context["feedpagecount"] - 1 and not context["feedpagenum"] == 0):
nslist["fh"] = "http://purl.org/syndication/history/1.0"
- if not self.config["RSS_TEASERS"]:
- nslist["xh"] = "http://www.w3.org/1999/xhtml"
feed_xsl_link = self.abs_link("/assets/xml/atom.xsl")
feed_root = lxml.etree.Element("feed", nsmap=nslist)
feed_root.addprevious(lxml.etree.ProcessingInstruction(
"xml-stylesheet",
- 'href="' + feed_xsl_link + '" type="text/xsl media="all"'))
+ 'href="' + utils.encodelink(feed_xsl_link) + '" type="text/xsl media="all"'))
feed_root.set("{http://www.w3.org/XML/1998/namespace}lang", lang)
feed_root.set("xmlns", "http://www.w3.org/2005/Atom")
feed_title = lxml.etree.SubElement(feed_root, "title")
@@ -1755,7 +1889,7 @@ class Nikola(object):
feed_id = lxml.etree.SubElement(feed_root, "id")
feed_id.text = self.abs_link(context["feedlink"])
feed_updated = lxml.etree.SubElement(feed_root, "updated")
- feed_updated.text = post.formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
+ feed_updated.text = utils.LocaleBorg().formatted_date('webiso', datetime.datetime.now(tz=dateutil.tz.tzutc()))
feed_author = lxml.etree.SubElement(feed_root, "author")
feed_author_name = lxml.etree.SubElement(feed_author, "name")
feed_author_name.text = self.config["BLOG_AUTHOR"](lang)
@@ -1768,50 +1902,64 @@ class Nikola(object):
if "prevfeedlink" in context:
feed_root.append(atom_link("previous", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
- if context["is_feed_stale"] or not context["feedpagenum"] == 0:
+ if context["is_feed_stale"] or "feedpagenum" in context and not context["feedpagenum"] == 0:
feed_root.append(atom_link("current", "application/atom+xml",
self.abs_link(context["currentfeedlink"])))
# Older is "prev-archive" and newer is "next-archive" in archived feeds (opposite of paginated)
- if "prevfeedlink" in context and (context["is_feed_stale"] or not context["feedpagenum"] == context["feedpagecount"] - 1):
+ if "prevfeedlink" in context and (context["is_feed_stale"] or "feedpagenum" in context and not context["feedpagenum"] == context["feedpagecount"] - 1):
feed_root.append(atom_link("next-archive", "application/atom+xml",
self.abs_link(context["prevfeedlink"])))
if "nextfeedlink" in context:
feed_root.append(atom_link("prev-archive", "application/atom+xml",
self.abs_link(context["nextfeedlink"])))
- if context["is_feed_stale"] or not context["feedpagenum"] == context["feedpagecount"] - 1:
+ if context["is_feed_stale"] or "feedpagenum" and not context["feedpagenum"] == context["feedpagecount"] - 1:
lxml.etree.SubElement(feed_root, "{http://purl.org/syndication/history/1.0}archive")
feed_root.append(atom_link("alternate", "text/html",
self.abs_link(context["permalink"])))
feed_generator = lxml.etree.SubElement(feed_root, "generator")
- feed_generator.set("uri", "http://getnikola.com/")
+ feed_generator.set("uri", "https://getnikola.com/")
feed_generator.text = "Nikola"
feed_append_query = None
- if self.config["RSS_LINKS_APPEND_QUERY"]:
- feed_append_query = self.config["RSS_LINKS_APPEND_QUERY"].format(
+ if self.config["FEED_LINKS_APPEND_QUERY"]:
+ feed_append_query = self.config["FEED_LINKS_APPEND_QUERY"].format(
feedRelUri=context["feedlink"],
feedFormat="atom")
- for post in posts:
- data = post.text(lang, teaser_only=self.config["RSS_TEASERS"], strip_html=self.config["RSS_TEASERS"],
- rss_read_more_link=True, rss_links_append_query=feed_append_query)
- if not self.config["RSS_TEASERS"]:
+ def atom_post_text(post, text):
+ if not self.config["FEED_PLAIN"]:
+ if self.config["FEED_PREVIEWIMAGE"] and 'previewimage' in post.meta[lang] and post.meta[lang]['previewimage'] not in text:
+ text = "<figure><img src=\"{}\"></figure> {}".format(post.meta[lang]['previewimage'], text)
+
# FIXME: this is duplicated with code in Post.text() and generic_rss_renderer
try:
- doc = lxml.html.document_fromstring(data)
- doc.rewrite_links(lambda dst: self.url_replacer(post.permalink(), dst, lang, 'absolute'))
+ doc = lxml.html.document_fromstring(text)
+ doc.rewrite_links(lambda dst: self.url_replacer(post.permalink(lang), dst, lang, 'absolute'))
try:
body = doc.body
- data = (body.text or '') + ''.join(
+ text = (body.text or '') + ''.join(
[lxml.html.tostring(child, encoding='unicode')
for child in body.iterchildren()])
except IndexError: # No body there, it happens sometimes
- data = ''
+ text = ''
except lxml.etree.ParserError as e:
if str(e) == "Document is empty":
- data = ""
+ text = ""
else: # let other errors raise
raise(e)
+ return text.strip()
+
+ for post in posts:
+ summary = atom_post_text(post, post.text(lang, teaser_only=True,
+ strip_html=self.config["FEED_PLAIN"],
+ feed_read_more_link=True,
+ feed_links_append_query=feed_append_query))
+ content = None
+ if not self.config["FEED_TEASERS"]:
+ content = atom_post_text(post, post.text(lang, teaser_only=self.config["FEED_TEASERS"],
+ strip_html=self.config["FEED_PLAIN"],
+ feed_read_more_link=True,
+ feed_links_append_query=feed_append_query))
entry_root = lxml.etree.SubElement(feed_root, "entry")
entry_title = lxml.etree.SubElement(entry_root, "title")
@@ -1828,15 +1976,20 @@ class Nikola(object):
entry_root.append(atom_link("alternate", "text/html",
post.permalink(lang, absolute=True,
query=feed_append_query)))
- if self.config["RSS_TEASERS"]:
- entry_summary = lxml.etree.SubElement(entry_root, "summary")
- entry_summary.text = data
+ entry_summary = lxml.etree.SubElement(entry_root, "summary")
+ if not self.config["FEED_PLAIN"]:
+ entry_summary.set("type", "html")
else:
+ entry_summary.set("type", "text")
+ entry_summary.text = summary
+ if content:
entry_content = lxml.etree.SubElement(entry_root, "content")
- entry_content.set("type", "xhtml")
- entry_content_nsdiv = lxml.etree.SubElement(entry_content, "{http://www.w3.org/1999/xhtml}div")
- entry_content_nsdiv.text = data
- for category in post.tags:
+ if not self.config["FEED_PLAIN"]:
+ entry_content.set("type", "html")
+ else:
+ entry_content.set("type", "text")
+ entry_content.text = content
+ for category in post.tags_for_language(lang):
entry_category = lxml.etree.SubElement(entry_root, "category")
entry_category.set("term", utils.slugify(category))
entry_category.set("label", category)
@@ -1886,8 +2039,7 @@ class Nikola(object):
kw['indexes_prety_page_url'] = self.config["INDEXES_PRETTY_PAGE_URL"]
kw['demote_headers'] = self.config['DEMOTE_HEADERS']
kw['generate_atom'] = self.config["GENERATE_ATOM"]
- kw['feed_link_append_query'] = self.config["RSS_LINKS_APPEND_QUERY"]
- kw['feed_teasers'] = self.config["RSS_TEASERS"]
+ kw['feed_link_append_query'] = self.config["FEED_LINKS_APPEND_QUERY"]
kw['currentfeed'] = None
# Split in smaller lists
@@ -1978,6 +2130,9 @@ class Nikola(object):
context["currentfeedlink"] = kw["currentfeed"]
context["feedpagenum"] = i
context["feedpagecount"] = num_pages
+ kw['feed_teasers'] = self.config['FEED_TEASERS']
+ kw['feed_plain'] = self.config['FEED_PLAIN']
+ kw['feed_previewimage'] = self.config['FEED_PREVIEWIMAGE']
atom_task = {
"basename": basename,
"name": atom_output_name,
@@ -2105,7 +2260,7 @@ def valid_locale_fallback(desired_locale=None):
"""
# Whenever fallbacks change, adjust test TestHarcodedFallbacksWork
candidates_windows = [str('English'), str('C')]
- candidates_posix = [str('en_US.utf8'), str('C')]
+ candidates_posix = [str('en_US.UTF-8'), str('C')]
candidates = candidates_windows if sys.platform == 'win32' else candidates_posix
if desired_locale:
candidates = list(candidates)
@@ -2139,7 +2294,7 @@ def guess_locale_from_lang_posix(lang):
locale_n = str(lang)
else:
# this works in Travis when locale support set by Travis suggestion
- locale_n = str((locale.normalize(lang).split('.')[0]) + '.utf8')
+ locale_n = str((locale.normalize(lang).split('.')[0]) + '.UTF-8')
if not is_valid_locale(locale_n):
# http://thread.gmane.org/gmane.comp.web.nikola/337/focus=343
locale_n = str((locale.normalize(lang).split('.')[0]))
diff --git a/nikola/plugin_categories.py b/nikola/plugin_categories.py
index ecbbb82..b96de4f 100644
--- a/nikola/plugin_categories.py
+++ b/nikola/plugin_categories.py
@@ -52,7 +52,6 @@ __all__ = (
class BasePlugin(IPlugin):
-
"""Base plugin class."""
def set_site(self, site):
@@ -84,7 +83,6 @@ class BasePlugin(IPlugin):
class PostScanner(BasePlugin):
-
"""The scan method of these plugins is called by Nikola.scan_posts."""
def scan(self):
@@ -93,7 +91,6 @@ class PostScanner(BasePlugin):
class Command(BasePlugin, DoitCommand):
-
"""Doit command implementation."""
name = "dummy_command"
@@ -156,7 +153,6 @@ DoitCommand.help = help
class BaseTask(BasePlugin):
-
"""Base for task generators."""
name = "dummy_task"
@@ -179,21 +175,18 @@ class BaseTask(BasePlugin):
class Task(BaseTask):
-
"""Task generator."""
name = "dummy_task"
class LateTask(BaseTask):
-
"""Late task generator (plugin executed after all Task plugins)."""
name = "dummy_latetask"
class TemplateSystem(BasePlugin):
-
"""Provide support for templating systems."""
name = "dummy_templates"
@@ -224,7 +217,6 @@ class TemplateSystem(BasePlugin):
class TaskMultiplier(BasePlugin):
-
"""Take a task and return *more* tasks."""
name = "dummy multiplier"
@@ -235,7 +227,6 @@ class TaskMultiplier(BasePlugin):
class PageCompiler(BasePlugin):
-
"""Compile text files into HTML."""
name = "dummy_compiler"
@@ -300,7 +291,6 @@ class PageCompiler(BasePlugin):
class CompilerExtension(BasePlugin):
-
"""An extension for a Nikola compiler.
If you intend to implement those in your own compiler, you can:
@@ -319,7 +309,6 @@ class CompilerExtension(BasePlugin):
class RestExtension(CompilerExtension):
-
"""Extensions for reStructuredText."""
name = "dummy_rest_extension"
@@ -327,7 +316,6 @@ class RestExtension(CompilerExtension):
class MarkdownExtension(CompilerExtension):
-
"""Extensions for Markdown."""
name = "dummy_markdown_extension"
@@ -335,21 +323,18 @@ class MarkdownExtension(CompilerExtension):
class SignalHandler(BasePlugin):
-
"""Signal handlers."""
name = "dummy_signal_handler"
class ConfigPlugin(BasePlugin):
-
"""A plugin that can edit config (or modify the site) on-the-fly."""
name = "dummy_config_plugin"
class Importer(Command):
-
"""Basic structure for importing data into Nikola.
The flow is:
diff --git a/nikola/plugins/basic_import.py b/nikola/plugins/basic_import.py
index 073a539..04f1091 100644
--- a/nikola/plugins/basic_import.py
+++ b/nikola/plugins/basic_import.py
@@ -48,7 +48,6 @@ links = {}
class ImportMixin(object):
-
"""Mixin with common used methods."""
name = "import_mixin"
diff --git a/nikola/plugins/command/auto.plugin b/nikola/plugins/command/auto.plugin
index 3e2b17d..1081c78 100644
--- a/nikola/plugins/command/auto.plugin
+++ b/nikola/plugins/command/auto.plugin
@@ -5,7 +5,7 @@ module = auto
[Documentation]
author = Roberto Alsina
version = 2.1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Automatically detect site changes, rebuild and optionally refresh a browser.
[Nikola]
diff --git a/nikola/plugins/command/auto/__init__.py b/nikola/plugins/command/auto/__init__.py
index 71f9624..e339c06 100644
--- a/nikola/plugins/command/auto/__init__.py
+++ b/nikola/plugins/command/auto/__init__.py
@@ -63,7 +63,7 @@ except ImportError:
from nikola.plugin_categories import Command
-from nikola.utils import req_missing, get_logger, get_theme_path, STDERR_HANDLER
+from nikola.utils import dns_sd, req_missing, get_logger, get_theme_path, STDERR_HANDLER
LRJS_PATH = os.path.join(os.path.dirname(__file__), 'livereload.js')
error_signal = signal('error')
refresh_signal = signal('refresh')
@@ -79,13 +79,14 @@ ERROR {}
class CommandAuto(Command):
-
"""Automatic rebuilds for Nikola."""
name = "auto"
logger = None
has_server = True
doc_purpose = "builds and serves a site; automatically detects site changes, rebuilds, and optionally refreshes a browser"
+ dns_sd = None
+
cmd_options = [
{
'name': 'port',
@@ -156,7 +157,7 @@ class CommandAuto(Command):
# Do not duplicate entries -- otherwise, multiple rebuilds are triggered
watched = set([
- 'templates/',
+ 'templates/', 'plugins/',
] + [get_theme_path(name) for name in self.site.THEMES])
for item in self.site.config['post_pages']:
watched.add(os.path.dirname(item[0]))
@@ -208,7 +209,6 @@ class CommandAuto(Command):
parent = self
class Mixed(WebSocketWSGIApplication):
-
"""A class that supports WS and HTTP protocols on the same port."""
def __call__(self, environ, start_response):
@@ -235,9 +235,12 @@ class CommandAuto(Command):
webbrowser.open('http://{0}:{1}'.format(host, port))
try:
+ self.dns_sd = dns_sd(port, (options['ipv6'] or '::' in host))
ws.serve_forever()
except KeyboardInterrupt:
self.logger.info("Server is shutting down.")
+ if self.dns_sd:
+ self.dns_sd.Reset()
# This is a hack, but something is locking up in a futex
# and exit() doesn't work.
os.kill(os.getpid(), 15)
@@ -262,6 +265,8 @@ class CommandAuto(Command):
fname = os.path.basename(event_path)
if (fname.endswith('~') or
fname.startswith('.') or
+ '__pycache__' in event_path or
+ event_path.endswith(('.pyc', '.pyo', '.pyd')) or
os.path.isdir(event_path)): # Skip on folders, these are usually duplicates
return
self.logger.info('REBUILDING SITE (from {0})'.format(event_path))
@@ -300,11 +305,14 @@ class CommandAuto(Command):
mimetype = 'text/html'
if p_uri.path == '/robots.txt':
- start_response('200 OK', [('Content-type', 'text/plain')])
+ start_response('200 OK', [('Content-type', 'text/plain; charset=UTF-8')])
return ['User-Agent: *\nDisallow: /\n'.encode('utf-8')]
elif os.path.isfile(f_path):
with open(f_path, 'rb') as fd:
- start_response('200 OK', [('Content-type', mimetype)])
+ if mimetype.startswith('text/') or mimetype.endswith('+xml'):
+ start_response('200 OK', [('Content-type', "{0}; charset=UTF-8".format(mimetype))])
+ else:
+ start_response('200 OK', [('Content-type', mimetype)])
return [self.file_filter(mimetype, fd.read())]
elif p_uri.path == '/livereload.js':
with open(LRJS_PATH, 'rb') as fd:
@@ -337,7 +345,6 @@ pending = []
class LRSocket(WebSocket):
-
"""Speak Livereload protocol."""
def __init__(self, *a, **kw):
@@ -410,7 +417,6 @@ class LRSocket(WebSocket):
class OurWatchHandler(FileSystemEventHandler):
-
"""A Nikola-specific handler for Watchdog."""
def __init__(self, function):
@@ -424,7 +430,6 @@ class OurWatchHandler(FileSystemEventHandler):
class ConfigWatchHandler(FileSystemEventHandler):
-
"""A Nikola-specific handler for Watchdog that handles the config file (as a workaround)."""
def __init__(self, configuration_filename, function):
diff --git a/nikola/plugins/command/bootswatch_theme.plugin b/nikola/plugins/command/bootswatch_theme.plugin
index fc25045..51e6718 100644
--- a/nikola/plugins/command/bootswatch_theme.plugin
+++ b/nikola/plugins/command/bootswatch_theme.plugin
@@ -5,7 +5,7 @@ module = bootswatch_theme
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Given a swatch name and a parent theme, creates a custom theme.
[Nikola]
diff --git a/nikola/plugins/command/bootswatch_theme.py b/nikola/plugins/command/bootswatch_theme.py
index b5644a1..afd15af 100644
--- a/nikola/plugins/command/bootswatch_theme.py
+++ b/nikola/plugins/command/bootswatch_theme.py
@@ -37,7 +37,6 @@ LOGGER = utils.get_logger('bootswatch_theme', utils.STDERR_HANDLER)
class CommandBootswatchTheme(Command):
-
"""Given a swatch name from bootswatch.com and a parent theme, creates a custom theme."""
name = "bootswatch_theme"
@@ -91,12 +90,16 @@ class CommandBootswatchTheme(Command):
LOGGER.info("Creating '{0}' theme from '{1}' and '{2}'".format(name, swatch, parent))
utils.makedirs(os.path.join('themes', name, 'assets', 'css'))
for fname in ('bootstrap.min.css', 'bootstrap.css'):
- url = 'http://bootswatch.com'
+ url = 'https://bootswatch.com'
if version:
url += '/' + version
url = '/'.join((url, swatch, fname))
LOGGER.info("Downloading: " + url)
- data = requests.get(url).text
+ r = requests.get(url)
+ if r.status_code > 299:
+ LOGGER.error('Error {} getting {}', r.status_code, url)
+ exit(1)
+ data = r.text
with open(os.path.join('themes', name, 'assets', 'css', fname),
'wb+') as output:
output.write(data.encode('utf-8'))
diff --git a/nikola/plugins/command/check.plugin b/nikola/plugins/command/check.plugin
index e380e64..6d2df82 100644
--- a/nikola/plugins/command/check.plugin
+++ b/nikola/plugins/command/check.plugin
@@ -5,7 +5,7 @@ module = check
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Check the generated site
[Nikola]
diff --git a/nikola/plugins/command/check.py b/nikola/plugins/command/check.py
index abf183e..bfc6ee2 100644
--- a/nikola/plugins/command/check.py
+++ b/nikola/plugins/command/check.py
@@ -46,7 +46,10 @@ from nikola.plugin_categories import Command
from nikola.utils import get_logger, STDERR_HANDLER
-def _call_nikola_list(site):
+def _call_nikola_list(site, cache=None):
+ if cache is not None:
+ if 'files' in cache and 'deps' in cache:
+ return cache['files'], cache['deps']
files = []
deps = defaultdict(list)
for task in generate_tasks('render_site', site.gen_tasks('render_site', "Task", '')):
@@ -57,16 +60,19 @@ def _call_nikola_list(site):
files.extend(task.targets)
for target in task.targets:
deps[target].extend(task.file_dep)
+ if cache is not None:
+ cache['files'] = files
+ cache['deps'] = deps
return files, deps
-def real_scan_files(site):
+def real_scan_files(site, cache=None):
"""Scan for files."""
task_fnames = set([])
real_fnames = set([])
output_folder = site.config['OUTPUT_FOLDER']
# First check that all targets are generated in the right places
- for fname in _call_nikola_list(site)[0]:
+ for fname in _call_nikola_list(site, cache)[0]:
fname = fname.strip()
if fname.startswith(output_folder):
task_fnames.add(fname)
@@ -94,7 +100,6 @@ def fs_relpath_from_url_path(url_path):
class CommandCheck(Command):
-
"""Check the generated site."""
name = "check"
@@ -162,22 +167,25 @@ class CommandCheck(Command):
self.logger.level = 1
else:
self.logger.level = 4
+ failure = False
if options['links']:
- failure = self.scan_links(options['find_sources'], options['remote'])
+ failure |= self.scan_links(options['find_sources'], options['remote'])
if options['files']:
- failure = self.scan_files()
+ failure |= self.scan_files()
if options['clean']:
- failure = self.clean_files()
+ failure |= self.clean_files()
if failure:
return 1
existing_targets = set([])
checked_remote_targets = {}
+ cache = {}
def analyze(self, fname, find_sources=False, check_remote=False):
"""Analyze links on a page."""
rv = False
self.whitelist = [re.compile(x) for x in self.site.config['LINK_CHECK_WHITELIST']]
+ self.internal_redirects = [urljoin('/', _[0]) for _ in self.site.config['REDIRECTIONS']]
base_url = urlparse(self.site.config['BASE_URL'])
self.existing_targets.add(self.site.config['SITE_URL'])
self.existing_targets.add(self.site.config['BASE_URL'])
@@ -185,7 +193,7 @@ class CommandCheck(Command):
deps = {}
if find_sources:
- deps = _call_nikola_list(self.site)[1]
+ deps = _call_nikola_list(self.site, self.cache)[1]
if url_type in ('absolute', 'full_path'):
url_netloc_to_root = urlparse(self.site.config['BASE_URL']).path
@@ -203,31 +211,70 @@ class CommandCheck(Command):
# Quietly ignore files that don’t exist; use `nikola check -f` instead (Issue #1831)
return False
- d = lxml.html.fromstring(open(filename, 'rb').read())
- for l in d.iterlinks():
+ if '.html' == fname[-5:]:
+ d = lxml.html.fromstring(open(filename, 'rb').read())
+ extra_objs = lxml.html.fromstring('<html/>')
+
+ # Turn elements with a srcset attribute into individual img elements with src attributes
+ for obj in list(d.xpath('(*//img|*//source)')):
+ if 'srcset' in obj.attrib:
+ for srcset_item in obj.attrib['srcset'].split(','):
+ extra_objs.append(lxml.etree.Element('img', src=srcset_item.strip().split(' ')[0]))
+ link_elements = list(d.iterlinks()) + list(extra_objs.iterlinks())
+ # Extract links from XML formats to minimal HTML, allowing those to go through the link checks
+ elif '.atom' == filename[-5:]:
+ d = lxml.etree.parse(filename)
+ link_elements = lxml.html.fromstring('<html/>')
+ for elm in d.findall('*//{http://www.w3.org/2005/Atom}link'):
+ feed_link = elm.attrib['href'].split('?')[0].strip() # strip FEED_LINKS_APPEND_QUERY
+ link_elements.append(lxml.etree.Element('a', href=feed_link))
+ link_elements = list(link_elements.iterlinks())
+ elif filename.endswith('sitemap.xml') or filename.endswith('sitemapindex.xml'):
+ d = lxml.etree.parse(filename)
+ link_elements = lxml.html.fromstring('<html/>')
+ for elm in d.getroot().findall("*//{http://www.sitemaps.org/schemas/sitemap/0.9}loc"):
+ link_elements.append(lxml.etree.Element('a', href=elm.text.strip()))
+ link_elements = list(link_elements.iterlinks())
+ else: # unsupported file type
+ return False
+
+ for l in link_elements:
target = l[2]
if target == "#":
continue
- target, _ = urldefrag(target)
+ target = urldefrag(target)[0]
+
+ if any([urlparse(target).netloc.endswith(_) for _ in ['example.com', 'example.net', 'example.org']]):
+ self.logger.info("Not testing example address \"{0}\".".format(target))
+ continue
+
+ # absolute URL to root-relative
+ if target.startswith(base_url.geturl()):
+ target = target.replace(base_url.geturl(), '/')
+
parsed = urlparse(target)
# Warn about links from https to http (mixed-security)
if base_url.netloc == parsed.netloc and base_url.scheme == "https" and parsed.scheme == "http":
self.logger.warn("Mixed-content security for link in {0}: {1}".format(filename, target))
+ # Link to an internal REDIRECTIONS page
+ if target in self.internal_redirects:
+ redir_status_code = 301
+ redir_target = [_dest for _target, _dest in self.site.config['REDIRECTIONS'] if urljoin('/', _target) == target][0]
+ self.logger.warn("Remote link moved PERMANENTLY to \"{0}\" and should be updated in {1}: {2} [HTTP: 301]".format(redir_target, filename, target))
+
# Absolute links to other domains, skip
# Absolute links when using only paths, skip.
if ((parsed.scheme or target.startswith('//')) and parsed.netloc != base_url.netloc) or \
((parsed.scheme or target.startswith('//')) and url_type in ('rel_path', 'full_path')):
if not check_remote or parsed.scheme not in ["http", "https"]:
continue
- if parsed.netloc == base_url.netloc: # absolute URL to self.site
- continue
if target in self.checked_remote_targets: # already checked this exact target
- if self.checked_remote_targets[target] in [301, 307]:
+ if self.checked_remote_targets[target] in [301, 308]:
self.logger.warn("Remote link PERMANENTLY redirected in {0}: {1} [Error {2}]".format(filename, target, self.checked_remote_targets[target]))
- elif self.checked_remote_targets[target] in [302, 308]:
- self.logger.info("Remote link temporarily redirected in {1}: {2} [HTTP: {3}]".format(filename, target, self.checked_remote_targets[target]))
+ elif self.checked_remote_targets[target] in [302, 307]:
+ self.logger.notice("Remote link temporarily redirected in {1}: {2} [HTTP: {3}]".format(filename, target, self.checked_remote_targets[target]))
elif self.checked_remote_targets[target] > 399:
self.logger.error("Broken link in {0}: {1} [Error {2}]".format(filename, target, self.checked_remote_targets[target]))
continue
@@ -255,7 +302,7 @@ class CommandCheck(Command):
if redir_status_code in [301, 308]:
self.logger.warn("Remote link moved PERMANENTLY to \"{0}\" and should be updated in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
if redir_status_code in [302, 307]:
- self.logger.info("Remote link temporarily redirected to \"{0}\" in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
+ self.logger.notice("Remote link temporarily redirected to \"{0}\" in {1}: {2} [HTTP: {3}]".format(resp.url, filename, target, redir_status_code))
self.checked_remote_targets[resp.url] = resp.status_code
self.checked_remote_targets[target] = redir_status_code
else:
@@ -275,8 +322,9 @@ class CommandCheck(Command):
target_filename = os.path.abspath(
os.path.join(self.site.config['OUTPUT_FOLDER'], unquote(target.lstrip('/'))))
else: # Relative path
+ unquoted_target = unquote(target).encode('utf-8') if sys.version_info.major >= 3 else unquote(target).decode('utf-8')
target_filename = os.path.abspath(
- os.path.join(os.path.dirname(filename), unquote(target)))
+ os.path.join(os.path.dirname(filename).encode('utf-8'), unquoted_target))
elif url_type in ('full_path', 'absolute'):
if url_type == 'absolute':
@@ -292,9 +340,10 @@ class CommandCheck(Command):
if any(re.search(x, target_filename) for x in self.whitelist):
continue
+
elif target_filename not in self.existing_targets:
if os.path.exists(target_filename):
- self.logger.notice("Good link {0} => {1}".format(target, target_filename))
+ self.logger.info(u"Good link {0} => {1}".format(target, target_filename))
self.existing_targets.add(target_filename)
else:
rv = True
@@ -304,7 +353,7 @@ class CommandCheck(Command):
self.logger.warn("\n".join(deps[filename]))
self.logger.warn("===============================\n")
except Exception as exc:
- self.logger.error("Error with: {0} {1}".format(filename, exc))
+ self.logger.error(u"Error with: {0} {1}".format(filename, exc))
return rv
def scan_links(self, find_sources=False, check_remote=False):
@@ -315,10 +364,21 @@ class CommandCheck(Command):
failure = False
# Maybe we should just examine all HTML files
output_folder = self.site.config['OUTPUT_FOLDER']
- for fname in _call_nikola_list(self.site)[0]:
- if fname.startswith(output_folder) and '.html' == fname[-5:]:
- if self.analyze(fname, find_sources, check_remote):
- failure = True
+
+ if urlparse(self.site.config['BASE_URL']).netloc == 'example.com':
+ self.logger.error("You've not changed the SITE_URL (or BASE_URL) setting from \"example.com\"!")
+
+ for fname in _call_nikola_list(self.site, self.cache)[0]:
+ if fname.startswith(output_folder):
+ if '.html' == fname[-5:]:
+ if self.analyze(fname, find_sources, check_remote):
+ failure = True
+ if '.atom' == fname[-5:]:
+ if self.analyze(fname, find_sources, False):
+ failure = True
+ if fname.endswith('sitemap.xml') or fname.endswith('sitemapindex.xml'):
+ if self.analyze(fname, find_sources, False):
+ failure = True
if not failure:
self.logger.info("All links checked.")
return failure
@@ -328,7 +388,7 @@ class CommandCheck(Command):
failure = False
self.logger.info("Checking Files:")
self.logger.info("===============\n")
- only_on_output, only_on_input = real_scan_files(self.site)
+ only_on_output, only_on_input = real_scan_files(self.site, self.cache)
# Ignore folders
only_on_output = [p for p in only_on_output if not os.path.isdir(p)]
@@ -351,7 +411,7 @@ class CommandCheck(Command):
def clean_files(self):
"""Remove orphaned files."""
- only_on_output, _ = real_scan_files(self.site)
+ only_on_output, _ = real_scan_files(self.site, self.cache)
for f in only_on_output:
self.logger.info('removed: {0}'.format(f))
os.unlink(f)
diff --git a/nikola/plugins/command/console.plugin b/nikola/plugins/command/console.plugin
index 333762c..9bcc909 100644
--- a/nikola/plugins/command/console.plugin
+++ b/nikola/plugins/command/console.plugin
@@ -5,7 +5,7 @@ module = console
[Documentation]
author = Chris Warrick, Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Start a debugging python console
[Nikola]
diff --git a/nikola/plugins/command/console.py b/nikola/plugins/command/console.py
index 539fa08..3d3daab 100644
--- a/nikola/plugins/command/console.py
+++ b/nikola/plugins/command/console.py
@@ -38,7 +38,6 @@ LOGGER = get_logger('console', STDERR_HANDLER)
class CommandConsole(Command):
-
"""Start debugging console."""
name = "console"
diff --git a/nikola/plugins/command/deploy.plugin b/nikola/plugins/command/deploy.plugin
index 4743ca2..8bdc0e2 100644
--- a/nikola/plugins/command/deploy.plugin
+++ b/nikola/plugins/command/deploy.plugin
@@ -5,7 +5,7 @@ module = deploy
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Deploy the site
[Nikola]
diff --git a/nikola/plugins/command/deploy.py b/nikola/plugins/command/deploy.py
index 821ea11..757c0d2 100644
--- a/nikola/plugins/command/deploy.py
+++ b/nikola/plugins/command/deploy.py
@@ -41,7 +41,6 @@ from nikola.utils import get_logger, remove_file, unicode_str, makedirs, STDERR_
class CommandDeploy(Command):
-
"""Deploy site."""
name = "deploy"
diff --git a/nikola/plugins/command/github_deploy.plugin b/nikola/plugins/command/github_deploy.plugin
index e793548..21e246c 100644
--- a/nikola/plugins/command/github_deploy.plugin
+++ b/nikola/plugins/command/github_deploy.plugin
@@ -5,7 +5,7 @@ module = github_deploy
[Documentation]
author = Puneeth Chaganti
version = 1,0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Deploy the site to GitHub pages.
[Nikola]
diff --git a/nikola/plugins/command/github_deploy.py b/nikola/plugins/command/github_deploy.py
index 0ab9332..2fe0d4e 100644
--- a/nikola/plugins/command/github_deploy.py
+++ b/nikola/plugins/command/github_deploy.py
@@ -57,7 +57,6 @@ def check_ghp_import_installed():
class CommandGitHubDeploy(Command):
-
"""Deploy site to GitHub Pages."""
name = 'github_deploy'
diff --git a/nikola/plugins/command/import_wordpress.plugin b/nikola/plugins/command/import_wordpress.plugin
index 6c4384e..eab9d17 100644
--- a/nikola/plugins/command/import_wordpress.plugin
+++ b/nikola/plugins/command/import_wordpress.plugin
@@ -5,7 +5,7 @@ module = import_wordpress
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Import a wordpress site from a XML dump (requires markdown).
[Nikola]
diff --git a/nikola/plugins/command/import_wordpress.py b/nikola/plugins/command/import_wordpress.py
index a652ec8..69ef144 100644
--- a/nikola/plugins/command/import_wordpress.py
+++ b/nikola/plugins/command/import_wordpress.py
@@ -50,7 +50,7 @@ except ImportError:
from nikola.plugin_categories import Command
from nikola import utils
-from nikola.utils import req_missing
+from nikola.utils import req_missing, unicode_str
from nikola.plugins.basic_import import ImportMixin, links
from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN
from nikola.plugins.command.init import SAMPLE_CONF, prepare_config, format_default_translations_config
@@ -88,7 +88,6 @@ def install_plugin(site, plugin_name, output_dir=None, show_install_notes=False)
class CommandImportWordpress(Command, ImportMixin):
-
"""Import a WordPress dump."""
name = "import_wordpress"
@@ -191,6 +190,12 @@ class CommandImportWordpress(Command, ImportMixin):
'type': bool,
'help': "Automatically installs the WordPress page compiler (either locally or in the new site) if required by other options.\nWarning: the compiler is GPL software!",
},
+ {
+ 'name': 'tag_saniziting_strategy',
+ 'long': 'tag-saniziting-strategy',
+ 'default': 'first',
+ 'help': 'lower: Convert all tag and category names to lower case\nfirst: Keep first spelling of tag or category name',
+ },
]
all_tags = set([])
@@ -239,6 +244,8 @@ class CommandImportWordpress(Command, ImportMixin):
self.install_wordpress_compiler = options.get('install_wordpress_compiler', False)
self.wordpress_page_compiler = None
+ self.tag_saniziting_strategy = options.get('tag_saniziting_strategy', 'first')
+
self.auth = None
if options.get('download_auth') is not None:
username_password = options.get('download_auth')
@@ -337,7 +344,10 @@ class CommandImportWordpress(Command, ImportMixin):
# Add tag redirects
for tag in self.all_tags:
try:
- tag_str = tag.decode('utf8')
+ if isinstance(tag, utils.bytes_str):
+ tag_str = tag.decode('utf8', 'replace')
+ else:
+ tag_str = tag
except AttributeError:
tag_str = tag
tag = utils.slugify(tag_str)
@@ -604,7 +614,7 @@ class CommandImportWordpress(Command, ImportMixin):
def transform_code(self, content):
"""Transform code blocks."""
- # http://en.support.wordpress.com/code/posting-source-code/. There are
+ # https://en.support.wordpress.com/code/posting-source-code/. There are
# a ton of things not supported here. We only do a basic [code
# lang="x"] -> ```x translation, and remove quoted html entities (<,
# >, &, and ").
@@ -686,7 +696,7 @@ class CommandImportWordpress(Command, ImportMixin):
elif approved == 'spam' or approved == 'trash':
pass
else:
- LOGGER.warn("Unknown comment approved status: " + str(approved))
+ LOGGER.warn("Unknown comment approved status: {0}".format(approved))
parent = int(get_text_tag(comment, "{{{0}}}comment_parent".format(wordpress_namespace), 0))
if parent == 0:
parent = None
@@ -707,7 +717,7 @@ class CommandImportWordpress(Command, ImportMixin):
"""Write comment header line."""
if header_content is None:
return
- header_content = str(header_content).replace('\n', ' ')
+ header_content = unicode_str(header_content).replace('\n', ' ')
line = '.. ' + header_field + ': ' + header_content + '\n'
fd.write(line.encode('utf8'))
@@ -747,6 +757,24 @@ class CommandImportWordpress(Command, ImportMixin):
tags_cats = tags + categories
return tags_cats, other_meta
+ _tag_sanitize_map = {True: {}, False: {}}
+
+ def _sanitize(self, tag, is_category):
+ if self.tag_saniziting_strategy == 'lower':
+ return tag.lower()
+ if tag.lower() not in self._tag_sanitize_map[is_category]:
+ self._tag_sanitize_map[is_category][tag.lower()] = [tag]
+ return tag
+ previous = self._tag_sanitize_map[is_category][tag.lower()]
+ if self.tag_saniziting_strategy == 'first':
+ if tag != previous[0]:
+ LOGGER.warn("Changing spelling of {0} name '{1}' to {2}.".format('category' if is_category else 'tag', tag, previous[0]))
+ return previous[0]
+ else:
+ LOGGER.error("Unknown tag sanitizing strategy '{0}'!".format(self.tag_saniziting_strategy))
+ sys.exit(1)
+ return tag
+
def import_postpage_item(self, item, wordpress_namespace, out_folder=None, attachments=None):
"""Take an item from the feed and creates a post file."""
if out_folder is None:
@@ -760,7 +788,10 @@ class CommandImportWordpress(Command, ImportMixin):
path = unquote(parsed.path.strip('/'))
try:
- path = path.decode('utf8')
+ if isinstance(path, utils.bytes_str):
+ path = path.decode('utf8', 'replace')
+ else:
+ path = path
except AttributeError:
pass
@@ -831,15 +862,24 @@ class CommandImportWordpress(Command, ImportMixin):
type = tag.attrib['domain']
if text == 'Uncategorized' and type == 'category':
continue
- self.all_tags.add(text)
if type == 'category':
- categories.append(type)
+ categories.append(text)
else:
tags.append(text)
if '$latex' in content:
tags.append('mathjax')
+ for i, cat in enumerate(categories[:]):
+ cat = self._sanitize(cat, True)
+ categories[i] = cat
+ self.all_tags.add(cat)
+
+ for i, tag in enumerate(tags[:]):
+ tag = self._sanitize(tag, False)
+ tags[i] = tag
+ self.all_tags.add(tag)
+
# Find post format if it's there
post_format = 'wp'
format_tag = [x for x in item.findall('*//{%s}meta_key' % wordpress_namespace) if x.text == '_tc_post_format']
@@ -905,7 +945,7 @@ class CommandImportWordpress(Command, ImportMixin):
comments.append(comment)
for comment in comments:
- comment_filename = slug + "." + str(comment['id']) + ".wpcomment"
+ comment_filename = "{0}.{1}.wpcomment".format(slug, comment['id'])
self._write_comment(os.path.join(self.output_folder, out_folder, comment_filename), comment)
return (out_folder, slug)
diff --git a/nikola/plugins/command/init.plugin b/nikola/plugins/command/init.plugin
index a5404c4..a8b1523 100644
--- a/nikola/plugins/command/init.plugin
+++ b/nikola/plugins/command/init.plugin
@@ -5,7 +5,7 @@ module = init
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new site.
[Nikola]
diff --git a/nikola/plugins/command/init.py b/nikola/plugins/command/init.py
index 91ccdb4..2dbee43 100644
--- a/nikola/plugins/command/init.py
+++ b/nikola/plugins/command/init.py
@@ -41,7 +41,7 @@ from pkg_resources import resource_filename
import tarfile
import nikola
-from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_RSS_READ_MORE_LINK, LEGAL_VALUES, urlsplit, urlunsplit
+from nikola.nikola import DEFAULT_TRANSLATIONS_PATTERN, DEFAULT_INDEX_READ_MORE_LINK, DEFAULT_FEED_READ_MORE_LINK, LEGAL_VALUES, urlsplit, urlunsplit
from nikola.plugin_categories import Command
from nikola.utils import ask, ask_yesno, get_logger, makedirs, STDERR_HANDLER, load_messages
from nikola.packages.tzlocal import get_localzone
@@ -71,7 +71,7 @@ SAMPLE_CONF = {
'CATEGORY_OUTPUT_FLAT_HIERARCHY': False,
'TRANSLATIONS_PATTERN': DEFAULT_TRANSLATIONS_PATTERN,
'INDEX_READ_MORE_LINK': DEFAULT_INDEX_READ_MORE_LINK,
- 'RSS_READ_MORE_LINK': DEFAULT_RSS_READ_MORE_LINK,
+ 'FEED_READ_MORE_LINK': DEFAULT_FEED_READ_MORE_LINK,
'POSTS': """(
("posts/*.rst", "posts", "post.tmpl"),
("posts/*.txt", "posts", "post.tmpl"),
@@ -210,17 +210,16 @@ def prepare_config(config):
"""Parse sample config with JSON."""
p = config.copy()
p.update({k: json.dumps(v, ensure_ascii=False) for k, v in p.items()
- if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'RSS_READ_MORE_LINK')})
+ if k not in ('POSTS', 'PAGES', 'COMPILERS', 'TRANSLATIONS', 'NAVIGATION_LINKS', '_SUPPORTED_LANGUAGES', '_SUPPORTED_COMMENT_SYSTEMS', 'INDEX_READ_MORE_LINK', 'FEED_READ_MORE_LINK')})
# READ_MORE_LINKs require some special treatment.
p['INDEX_READ_MORE_LINK'] = "'" + p['INDEX_READ_MORE_LINK'].replace("'", "\\'") + "'"
- p['RSS_READ_MORE_LINK'] = "'" + p['RSS_READ_MORE_LINK'].replace("'", "\\'") + "'"
+ p['FEED_READ_MORE_LINK'] = "'" + p['FEED_READ_MORE_LINK'].replace("'", "\\'") + "'"
# fix booleans and None
p.update({k: str(v) for k, v in config.items() if isinstance(v, bool) or v is None})
return p
class CommandInit(Command):
-
"""Create a new site."""
name = "init"
@@ -358,7 +357,7 @@ class CommandInit(Command):
def tzhandler(default, toconf):
print("\nPlease choose the correct time zone for your blog. Nikola uses the tz database.")
print("You can find your time zone here:")
- print("http://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
+ print("https://en.wikipedia.org/wiki/List_of_tz_database_time_zones")
print("")
answered = False
while not answered:
diff --git a/nikola/plugins/command/install_theme.plugin b/nikola/plugins/command/install_theme.plugin
index 8434f2e..aa68773 100644
--- a/nikola/plugins/command/install_theme.plugin
+++ b/nikola/plugins/command/install_theme.plugin
@@ -5,7 +5,7 @@ module = install_theme
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Install a theme into the current site.
[Nikola]
diff --git a/nikola/plugins/command/install_theme.py b/nikola/plugins/command/install_theme.py
index f02252e..bad335c 100644
--- a/nikola/plugins/command/install_theme.py
+++ b/nikola/plugins/command/install_theme.py
@@ -43,7 +43,6 @@ LOGGER = utils.get_logger('install_theme', utils.STDERR_HANDLER)
class CommandInstallTheme(Command):
-
"""Install a theme."""
name = "install_theme"
diff --git a/nikola/plugins/command/new_page.plugin b/nikola/plugins/command/new_page.plugin
index 145a419..3eaecb4 100644
--- a/nikola/plugins/command/new_page.plugin
+++ b/nikola/plugins/command/new_page.plugin
@@ -5,7 +5,7 @@ module = new_page
[Documentation]
author = Roberto Alsina, Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new page.
[Nikola]
diff --git a/nikola/plugins/command/new_page.py b/nikola/plugins/command/new_page.py
index 811e28b..8843421 100644
--- a/nikola/plugins/command/new_page.py
+++ b/nikola/plugins/command/new_page.py
@@ -32,7 +32,6 @@ from nikola.plugin_categories import Command
class CommandNewPage(Command):
-
"""Create a new page."""
name = "new_page"
diff --git a/nikola/plugins/command/new_post.plugin b/nikola/plugins/command/new_post.plugin
index d88469f..e9c3af5 100644
--- a/nikola/plugins/command/new_post.plugin
+++ b/nikola/plugins/command/new_post.plugin
@@ -5,7 +5,7 @@ module = new_post
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create a new post.
[Nikola]
diff --git a/nikola/plugins/command/new_post.py b/nikola/plugins/command/new_post.py
index f9fe3ff..30d009d 100644
--- a/nikola/plugins/command/new_post.py
+++ b/nikola/plugins/command/new_post.py
@@ -114,7 +114,6 @@ def get_date(schedule=False, rule=None, last_date=None, tz=None, iso8601=False):
class CommandNewPost(Command):
-
"""Create a new post."""
name = "new_post"
diff --git a/nikola/plugins/command/orphans.plugin b/nikola/plugins/command/orphans.plugin
index 669429d..d20c539 100644
--- a/nikola/plugins/command/orphans.plugin
+++ b/nikola/plugins/command/orphans.plugin
@@ -5,7 +5,7 @@ module = orphans
[Documentation]
author = Roberto Alsina, Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = List all orphans
[Nikola]
diff --git a/nikola/plugins/command/orphans.py b/nikola/plugins/command/orphans.py
index b12cc67..f061d39 100644
--- a/nikola/plugins/command/orphans.py
+++ b/nikola/plugins/command/orphans.py
@@ -34,7 +34,6 @@ from nikola.plugins.command.check import real_scan_files
class CommandOrphans(Command):
-
"""List all orphans."""
name = "orphans"
diff --git a/nikola/plugins/command/plugin.plugin b/nikola/plugins/command/plugin.plugin
index d44dcf3..016bcaa 100644
--- a/nikola/plugins/command/plugin.plugin
+++ b/nikola/plugins/command/plugin.plugin
@@ -5,7 +5,7 @@ module = plugin
[Documentation]
author = Roberto Alsina and Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Manage Nikola plugins
[Nikola]
diff --git a/nikola/plugins/command/plugin.py b/nikola/plugins/command/plugin.py
index f892ee9..1df7b71 100644
--- a/nikola/plugins/command/plugin.py
+++ b/nikola/plugins/command/plugin.py
@@ -45,7 +45,6 @@ LOGGER = utils.get_logger('plugin', utils.STDERR_HANDLER)
class CommandPlugin(Command):
-
"""Manage plugins."""
json = None
diff --git a/nikola/plugins/command/rst2html.plugin b/nikola/plugins/command/rst2html.plugin
index 02c9276..a095705 100644
--- a/nikola/plugins/command/rst2html.plugin
+++ b/nikola/plugins/command/rst2html.plugin
@@ -5,7 +5,7 @@ module = rst2html
[Documentation]
author = Chris Warrick
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile reStructuredText to HTML using the Nikola architecture
[Nikola]
diff --git a/nikola/plugins/command/rst2html/__init__.py b/nikola/plugins/command/rst2html/__init__.py
index 06afffd..68ea13d 100644
--- a/nikola/plugins/command/rst2html/__init__.py
+++ b/nikola/plugins/command/rst2html/__init__.py
@@ -36,7 +36,6 @@ from nikola.plugin_categories import Command
class CommandRst2Html(Command):
-
"""Compile reStructuredText to HTML, using Nikola architecture."""
name = "rst2html"
@@ -65,7 +64,7 @@ class CommandRst2Html(Command):
parser = lxml.html.HTMLParser(remove_blank_text=True)
doc = lxml.html.document_fromstring(template_output, parser)
html = b'<!DOCTYPE html>\n' + lxml.html.tostring(doc, encoding='utf8', method='html', pretty_print=True)
- print(html)
+ print(html.decode('utf-8'))
if error_level < 3:
return 0
else:
diff --git a/nikola/plugins/command/serve.plugin b/nikola/plugins/command/serve.plugin
index aca71ec..a4a726f 100644
--- a/nikola/plugins/command/serve.plugin
+++ b/nikola/plugins/command/serve.plugin
@@ -5,7 +5,7 @@ module = serve
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Start test server.
[Nikola]
diff --git a/nikola/plugins/command/serve.py b/nikola/plugins/command/serve.py
index 0441c93..b647bb7 100644
--- a/nikola/plugins/command/serve.py
+++ b/nikola/plugins/command/serve.py
@@ -45,24 +45,23 @@ except ImportError:
from nikola.plugin_categories import Command
-from nikola.utils import get_logger, STDERR_HANDLER
+from nikola.utils import dns_sd, get_logger, STDERR_HANDLER
class IPv6Server(HTTPServer):
-
"""An IPv6 HTTPServer."""
address_family = socket.AF_INET6
class CommandServe(Command):
-
"""Start test server."""
name = "serve"
doc_usage = "[options]"
doc_purpose = "start the test webserver"
logger = None
+ dns_sd = None
cmd_options = (
{
@@ -152,14 +151,16 @@ class CommandServe(Command):
raise e
else:
try:
+ self.dns_sd = dns_sd(options['port'], (options['ipv6'] or '::' in options['address']))
httpd.serve_forever()
except KeyboardInterrupt:
self.logger.info("Server is shutting down.")
+ if self.dns_sd:
+ self.dns_sd.Reset()
return 130
class OurHTTPRequestHandler(SimpleHTTPRequestHandler):
-
"""A request handler, modified for Nikola."""
extensions_map = dict(SimpleHTTPRequestHandler.extensions_map)
@@ -242,7 +243,10 @@ class OurHTTPRequestHandler(SimpleHTTPRequestHandler):
f.seek(0)
self.send_response(200)
- self.send_header("Content-type", ctype)
+ if ctype.startswith('text/') or ctype.endswith('+xml'):
+ self.send_header("Content-Type", "{0}; charset=UTF-8".format(ctype))
+ else:
+ self.send_header("Content-Type", ctype)
if os.path.splitext(path)[1] == '.svgz':
# Special handling for svgz to make it work nice with browsers.
self.send_header("Content-Encoding", 'gzip')
diff --git a/nikola/plugins/command/status.py b/nikola/plugins/command/status.py
index 55e7f95..40f4f77 100644
--- a/nikola/plugins/command/status.py
+++ b/nikola/plugins/command/status.py
@@ -36,7 +36,6 @@ from nikola.plugin_categories import Command
class CommandStatus(Command):
-
"""Display site status."""
name = "status"
diff --git a/nikola/plugins/command/version.plugin b/nikola/plugins/command/version.plugin
index 4708bdb..d78b79b 100644
--- a/nikola/plugins/command/version.plugin
+++ b/nikola/plugins/command/version.plugin
@@ -5,7 +5,7 @@ module = version
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Show nikola version
[Nikola]
diff --git a/nikola/plugins/command/version.py b/nikola/plugins/command/version.py
index ad08f64..b83d622 100644
--- a/nikola/plugins/command/version.py
+++ b/nikola/plugins/command/version.py
@@ -38,7 +38,6 @@ URL = 'https://pypi.python.org/pypi?:action=doap&name=Nikola'
class CommandVersion(Command):
-
"""Print Nikola version."""
name = "version"
diff --git a/nikola/plugins/compile/html.plugin b/nikola/plugins/compile/html.plugin
index 53ade61..f95bdd5 100644
--- a/nikola/plugins/compile/html.plugin
+++ b/nikola/plugins/compile/html.plugin
@@ -5,7 +5,7 @@ module = html
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile HTML into HTML (just copy)
[Nikola]
diff --git a/nikola/plugins/compile/html.py b/nikola/plugins/compile/html.py
index 5f8b244..6ff5de8 100644
--- a/nikola/plugins/compile/html.py
+++ b/nikola/plugins/compile/html.py
@@ -36,7 +36,6 @@ from nikola.utils import makedirs, write_metadata
class CompileHtml(PageCompiler):
-
"""Compile HTML into HTML."""
name = "html"
diff --git a/nikola/plugins/compile/ipynb.py b/nikola/plugins/compile/ipynb.py
index a9dedde..1023b31 100644
--- a/nikola/plugins/compile/ipynb.py
+++ b/nikola/plugins/compile/ipynb.py
@@ -53,7 +53,6 @@ from nikola.utils import makedirs, req_missing, get_logger, STDERR_HANDLER
class CompileIPynb(PageCompiler):
-
"""Compile IPynb into HTML."""
name = "ipynb"
diff --git a/nikola/plugins/compile/markdown.plugin b/nikola/plugins/compile/markdown.plugin
index f7d11b1..2607413 100644
--- a/nikola/plugins/compile/markdown.plugin
+++ b/nikola/plugins/compile/markdown.plugin
@@ -5,7 +5,7 @@ module = markdown
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile Markdown into HTML
[Nikola]
diff --git a/nikola/plugins/compile/markdown/__init__.py b/nikola/plugins/compile/markdown/__init__.py
index c1425a1..93438a3 100644
--- a/nikola/plugins/compile/markdown/__init__.py
+++ b/nikola/plugins/compile/markdown/__init__.py
@@ -44,7 +44,6 @@ from nikola.utils import makedirs, req_missing, write_metadata
class CompileMarkdown(PageCompiler):
-
"""Compile Markdown into HTML."""
name = "markdown"
diff --git a/nikola/plugins/compile/markdown/mdx_gist.plugin b/nikola/plugins/compile/markdown/mdx_gist.plugin
index 7fe676c..85b5450 100644
--- a/nikola/plugins/compile/markdown/mdx_gist.plugin
+++ b/nikola/plugins/compile/markdown/mdx_gist.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Extension for embedding gists
diff --git a/nikola/plugins/compile/markdown/mdx_gist.py b/nikola/plugins/compile/markdown/mdx_gist.py
index f439fa2..a930de5 100644
--- a/nikola/plugins/compile/markdown/mdx_gist.py
+++ b/nikola/plugins/compile/markdown/mdx_gist.py
@@ -22,7 +22,7 @@
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Warning: URL formats of "raw" gists are undocummented and subject to change.
-# See also: http://developer.github.com/v3/gists/
+# See also: https://developer.github.com/v3/gists/
#
# Inspired by "[Python] reStructuredText GitHub Gist directive"
# (https://gist.github.com/brianhsu/1407759), public domain by Brian Hsu
@@ -217,7 +217,6 @@ GIST_RST_RE = r'(?m)^\.\.\s*gist::\s*(?P<gist_id>[^\]\s]+)(?:\s*(?P<filename>.+?
class GistFetchException(Exception):
-
"""Raised when attempt to fetch content of a Gist from github.com fails."""
def __init__(self, url, status_code):
@@ -228,7 +227,6 @@ class GistFetchException(Exception):
class GistPattern(Pattern):
-
"""InlinePattern for footnote markers in a document's body text."""
def __init__(self, pattern, configs):
@@ -290,7 +288,6 @@ class GistPattern(Pattern):
class GistExtension(MarkdownExtension, Extension):
-
"""Gist extension for Markdown."""
def __init__(self, configs={}):
diff --git a/nikola/plugins/compile/markdown/mdx_nikola.plugin b/nikola/plugins/compile/markdown/mdx_nikola.plugin
index 12e4fb6..3c5c638 100644
--- a/nikola/plugins/compile/markdown/mdx_nikola.plugin
+++ b/nikola/plugins/compile/markdown/mdx_nikola.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Nikola-specific Markdown extensions
diff --git a/nikola/plugins/compile/markdown/mdx_nikola.py b/nikola/plugins/compile/markdown/mdx_nikola.py
index 54cc18c..7984121 100644
--- a/nikola/plugins/compile/markdown/mdx_nikola.py
+++ b/nikola/plugins/compile/markdown/mdx_nikola.py
@@ -24,25 +24,31 @@
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-"""Markdown Extension for Nikola-specific post-processing."""
+"""Markdown Extension for Nikola.
+
+- Specific post-processing.
+- Strikethrough inline patterns.
+"""
from __future__ import unicode_literals
import re
try:
from markdown.postprocessors import Postprocessor
+ from markdown.inlinepatterns import SimpleTagPattern
from markdown.extensions import Extension
except ImportError:
# No need to catch this, if you try to use this without Markdown,
# the markdown compiler will fail first
- Postprocessor = Extension = object
+ Postprocessor = SimpleTagPattern = Extension = object
from nikola.plugin_categories import MarkdownExtension
+
CODERE = re.compile('<div class="codehilite"><pre>(.*?)</pre></div>', flags=re.MULTILINE | re.DOTALL)
+STRIKE_RE = r"(~{2})(.+?)(~{2})" # ~~strike~~
class NikolaPostProcessor(Postprocessor):
-
"""Nikola-specific post-processing for Markdown."""
def run(self, text):
@@ -57,13 +63,22 @@ class NikolaPostProcessor(Postprocessor):
class NikolaExtension(MarkdownExtension, Extension):
+ """Nikola Markdown extensions."""
- """Extension for injecting the postprocessor."""
-
- def extendMarkdown(self, md, md_globals):
+ def _add_nikola_post_processor(self, md):
"""Extend Markdown with the postprocessor."""
pp = NikolaPostProcessor()
md.postprocessors.add('nikola_post_processor', pp, '_end')
+
+ def _add_strikethrough_inline_pattern(self, md):
+ """Support PHP-Markdown style strikethrough, for example: ``~~strike~~``."""
+ pattern = SimpleTagPattern(STRIKE_RE, 'del')
+ md.inlinePatterns.add('strikethrough', pattern, '_end')
+
+ def extendMarkdown(self, md, md_globals):
+ """Extend markdown to Nikola flavours."""
+ self._add_nikola_post_processor(md)
+ self._add_strikethrough_inline_pattern(md)
md.registerExtension(self)
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.plugin b/nikola/plugins/compile/markdown/mdx_podcast.plugin
index c92a8a0..c4ee7e9 100644
--- a/nikola/plugins/compile/markdown/mdx_podcast.plugin
+++ b/nikola/plugins/compile/markdown/mdx_podcast.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Markdown extensions for embedding podcasts and other audio files
diff --git a/nikola/plugins/compile/markdown/mdx_podcast.py b/nikola/plugins/compile/markdown/mdx_podcast.py
index 61afdbf..0f68e40 100644
--- a/nikola/plugins/compile/markdown/mdx_podcast.py
+++ b/nikola/plugins/compile/markdown/mdx_podcast.py
@@ -30,10 +30,10 @@ Extension to Python Markdown for Embedded Audio.
Basic Example:
>>> import markdown
->>> text = "[podcast]http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3[/podcast]"
+>>> text = "[podcast]https://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3[/podcast]"
>>> html = markdown.markdown(text, [PodcastExtension()])
>>> print(html)
-<p><audio controls=""><source src="http://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3" type="audio/mpeg"></source></audio></p>
+<p><audio controls=""><source src="https://archive.org/download/Rebeldes_Stereotipos/rs20120609_1.mp3" type="audio/mpeg"></source></audio></p>
"""
from __future__ import print_function, unicode_literals
@@ -51,7 +51,6 @@ PODCAST_RE = r'\[podcast\](?P<url>.+)\[/podcast\]'
class PodcastPattern(Pattern):
-
"""InlinePattern for footnote markers in a document's body text."""
def __init__(self, pattern, configs):
@@ -70,7 +69,6 @@ class PodcastPattern(Pattern):
class PodcastExtension(MarkdownExtension, Extension):
-
""""Podcast extension for Markdown."""
def __init__(self, configs={}):
diff --git a/nikola/plugins/compile/pandoc.plugin b/nikola/plugins/compile/pandoc.plugin
index 3ff3668..2a69095 100644
--- a/nikola/plugins/compile/pandoc.plugin
+++ b/nikola/plugins/compile/pandoc.plugin
@@ -5,7 +5,7 @@ module = pandoc
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile markups into HTML using pandoc
[Nikola]
diff --git a/nikola/plugins/compile/pandoc.py b/nikola/plugins/compile/pandoc.py
index 3030626..85e84fc 100644
--- a/nikola/plugins/compile/pandoc.py
+++ b/nikola/plugins/compile/pandoc.py
@@ -40,7 +40,6 @@ from nikola.utils import req_missing, makedirs, write_metadata
class CompilePandoc(PageCompiler):
-
"""Compile markups into HTML using pandoc."""
name = "pandoc"
diff --git a/nikola/plugins/compile/php.plugin b/nikola/plugins/compile/php.plugin
index 151c022..f4fb0c1 100644
--- a/nikola/plugins/compile/php.plugin
+++ b/nikola/plugins/compile/php.plugin
@@ -5,7 +5,7 @@ module = php
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile PHP into HTML (just copy and name the file .php)
[Nikola]
diff --git a/nikola/plugins/compile/php.py b/nikola/plugins/compile/php.py
index 28f4923..a60e31a 100644
--- a/nikola/plugins/compile/php.py
+++ b/nikola/plugins/compile/php.py
@@ -37,7 +37,6 @@ from hashlib import md5
class CompilePhp(PageCompiler):
-
"""Compile PHP into PHP."""
name = "php"
diff --git a/nikola/plugins/compile/rest.plugin b/nikola/plugins/compile/rest.plugin
index cf842c7..4d9041a 100644
--- a/nikola/plugins/compile/rest.plugin
+++ b/nikola/plugins/compile/rest.plugin
@@ -5,7 +5,7 @@ module = rest
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Compile reSt into HTML
[Nikola]
diff --git a/nikola/plugins/compile/rest/__init__.py b/nikola/plugins/compile/rest/__init__.py
index b99e872..4b04958 100644
--- a/nikola/plugins/compile/rest/__init__.py
+++ b/nikola/plugins/compile/rest/__init__.py
@@ -42,7 +42,6 @@ from nikola.utils import unicode_str, get_logger, makedirs, write_metadata, STDE
class CompileRest(PageCompiler):
-
"""Compile reStructuredText into HTML."""
name = "rest"
@@ -172,7 +171,6 @@ def get_observer(settings):
class NikolaReader(docutils.readers.standalone.Reader):
-
"""Nikola-specific docutils reader."""
def __init__(self, *args, **kwargs):
@@ -196,7 +194,7 @@ def add_node(node, visit_function=None, depart_function=None):
"""Register a Docutils node class.
This function is completely optional. It is a same concept as
- `Sphinx add_node function <http://sphinx-doc.org/ext/appapi.html#sphinx.application.Sphinx.add_node>`_.
+ `Sphinx add_node function <http://sphinx-doc.org/extdev/appapi.html#sphinx.application.Sphinx.add_node>`_.
For example::
diff --git a/nikola/plugins/compile/rest/chart.plugin b/nikola/plugins/compile/rest/chart.plugin
index 438abe4..0a7896f 100644
--- a/nikola/plugins/compile/rest/chart.plugin
+++ b/nikola/plugins/compile/rest/chart.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Chart directive based in PyGal
diff --git a/nikola/plugins/compile/rest/chart.py b/nikola/plugins/compile/rest/chart.py
index 88fdff3..ed8a250 100644
--- a/nikola/plugins/compile/rest/chart.py
+++ b/nikola/plugins/compile/rest/chart.py
@@ -43,7 +43,6 @@ _site = None
class Plugin(RestExtension):
-
"""Plugin for chart role."""
name = "rest_chart"
@@ -57,7 +56,6 @@ class Plugin(RestExtension):
class Chart(Directive):
-
"""reStructuredText extension for inserting charts as SVG.
Usage:
@@ -150,15 +148,15 @@ class Chart(Directive):
style = getattr(pygal.style, style_name)
for k, v in self.options.items():
options[k] = literal_eval(v)
-
- chart = getattr(pygal, self.arguments[0])(style=style)
+ chart = pygal
+ for o in self.arguments[0].split('.'):
+ chart = getattr(chart, o)
+ chart = chart(style=style)
+ if _site and _site.invariant:
+ chart.no_prefix = True
chart.config(**options)
for line in self.content:
label, series = literal_eval('({0})'.format(line))
chart.add(label, series)
data = chart.render().decode('utf8')
- if _site and _site.invariant:
- import re
- data = re.sub('id="chart-[a-f0-9\-]+"', 'id="chart-foobar"', data)
- data = re.sub('#chart-[a-f0-9\-]+', '#chart-foobar', data)
return [nodes.raw('', data, format='html')]
diff --git a/nikola/plugins/compile/rest/doc.plugin b/nikola/plugins/compile/rest/doc.plugin
index facdd03..e447eb2 100644
--- a/nikola/plugins/compile/rest/doc.plugin
+++ b/nikola/plugins/compile/rest/doc.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Manuel Kaufmann
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Role to link another page / post from the blog
diff --git a/nikola/plugins/compile/rest/doc.py b/nikola/plugins/compile/rest/doc.py
index 99cce81..578f012 100644
--- a/nikola/plugins/compile/rest/doc.py
+++ b/nikola/plugins/compile/rest/doc.py
@@ -34,7 +34,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for doc role."""
name = 'rest_doc'
diff --git a/nikola/plugins/compile/rest/gist.plugin b/nikola/plugins/compile/rest/gist.plugin
index 9fa2e82..763c1d2 100644
--- a/nikola/plugins/compile/rest/gist.plugin
+++ b/nikola/plugins/compile/rest/gist.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Gist directive
diff --git a/nikola/plugins/compile/rest/gist.py b/nikola/plugins/compile/rest/gist.py
index 736ee37..e40c3b2 100644
--- a/nikola/plugins/compile/rest/gist.py
+++ b/nikola/plugins/compile/rest/gist.py
@@ -11,7 +11,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for gist directive."""
name = "rest_gist"
@@ -24,7 +23,6 @@ class Plugin(RestExtension):
class GitHubGist(Directive):
-
"""Embed GitHub Gist.
Usage:
diff --git a/nikola/plugins/compile/rest/listing.plugin b/nikola/plugins/compile/rest/listing.plugin
index 85c780f..3ebb296 100644
--- a/nikola/plugins/compile/rest/listing.plugin
+++ b/nikola/plugins/compile/rest/listing.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Extension for source listings
diff --git a/nikola/plugins/compile/rest/listing.py b/nikola/plugins/compile/rest/listing.py
index 4871bf3..07f1686 100644
--- a/nikola/plugins/compile/rest/listing.py
+++ b/nikola/plugins/compile/rest/listing.py
@@ -55,7 +55,6 @@ from nikola.plugin_categories import RestExtension
# A sanitized version of docutils.parsers.rst.directives.body.CodeBlock.
class CodeBlock(Directive):
-
"""Parse and mark up content of a code block."""
optional_arguments = 1
@@ -126,7 +125,6 @@ docutils.parsers.rst.directives.misc.CodeBlock = CodeBlock
class Plugin(RestExtension):
-
"""Plugin for listing directive."""
name = "rest_listing"
@@ -152,7 +150,6 @@ listing_spec['linenos'] = directives.unchanged
class Listing(Include):
-
"""Create a highlighted block of code from a file in listings/.
Usage:
@@ -171,7 +168,12 @@ class Listing(Include):
"""Run listing directive."""
_fname = self.arguments.pop(0)
fname = _fname.replace('/', os.sep)
- lang = self.arguments.pop(0)
+ try:
+ lang = self.arguments.pop(0)
+ self.options['code'] = lang
+ except IndexError:
+ self.options['literal'] = True
+
if len(self.folders) == 1:
listings_folder = next(iter(self.folders.keys()))
if fname.startswith(listings_folder):
@@ -181,7 +183,6 @@ class Listing(Include):
else:
fpath = os.path.join(fname) # must be new syntax: specify folder name
self.arguments.insert(0, fpath)
- self.options['code'] = lang
if 'linenos' in self.options:
self.options['number-lines'] = self.options['linenos']
with io.open(fpath, 'r+', encoding='utf8') as fileobject:
diff --git a/nikola/plugins/compile/rest/media.plugin b/nikola/plugins/compile/rest/media.plugin
index 9803c8f..8dfb19c 100644
--- a/nikola/plugins/compile/rest/media.plugin
+++ b/nikola/plugins/compile/rest/media.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Directive to support oembed via micawber
diff --git a/nikola/plugins/compile/rest/media.py b/nikola/plugins/compile/rest/media.py
index 345e331..d075e44 100644
--- a/nikola/plugins/compile/rest/media.py
+++ b/nikola/plugins/compile/rest/media.py
@@ -40,7 +40,6 @@ from nikola.utils import req_missing
class Plugin(RestExtension):
-
"""Plugin for reST media directive."""
name = "rest_media"
@@ -53,7 +52,6 @@ class Plugin(RestExtension):
class Media(Directive):
-
"""reST extension for inserting any sort of media using micawber."""
has_content = False
diff --git a/nikola/plugins/compile/rest/post_list.plugin b/nikola/plugins/compile/rest/post_list.plugin
index 48969bf..1802f2b 100644
--- a/nikola/plugins/compile/rest/post_list.plugin
+++ b/nikola/plugins/compile/rest/post_list.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Udo Spallek
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Includes a list of posts with tag and slide based filters.
diff --git a/nikola/plugins/compile/rest/post_list.py b/nikola/plugins/compile/rest/post_list.py
index a22ee85..df9376b 100644
--- a/nikola/plugins/compile/rest/post_list.py
+++ b/nikola/plugins/compile/rest/post_list.py
@@ -43,7 +43,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for reST post-list directive."""
name = "rest_post_list"
@@ -57,7 +56,6 @@ class Plugin(RestExtension):
class PostList(Directive):
-
"""Provide a reStructuredText directive to create a list of posts.
Post List
@@ -204,8 +202,10 @@ class PostList(Directive):
template_data = {
'lang': lang,
'posts': posts,
- 'date_format': self.site.GLOBAL_CONTEXT.get('date_format'),
+ # Need to provide str, not TranslatableSetting (Issue #2104)
+ 'date_format': self.site.GLOBAL_CONTEXT.get('date_format')[lang],
'post_list_id': post_list_id,
+ 'messages': self.site.MESSAGES,
}
output = self.site.template_system.render_template(
template, None, template_data)
diff --git a/nikola/plugins/compile/rest/slides.plugin b/nikola/plugins/compile/rest/slides.plugin
index 5c05b89..389da39 100644
--- a/nikola/plugins/compile/rest/slides.plugin
+++ b/nikola/plugins/compile/rest/slides.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Slides directive
diff --git a/nikola/plugins/compile/rest/slides.py b/nikola/plugins/compile/rest/slides.py
index 2522e55..eb2cc97 100644
--- a/nikola/plugins/compile/rest/slides.py
+++ b/nikola/plugins/compile/rest/slides.py
@@ -37,7 +37,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for reST slides directive."""
name = "rest_slides"
@@ -51,7 +50,6 @@ class Plugin(RestExtension):
class Slides(Directive):
-
"""reST extension for inserting slideshows."""
has_content = True
diff --git a/nikola/plugins/compile/rest/soundcloud.plugin b/nikola/plugins/compile/rest/soundcloud.plugin
index 75469e4..4e36ea4 100644
--- a/nikola/plugins/compile/rest/soundcloud.plugin
+++ b/nikola/plugins/compile/rest/soundcloud.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Roberto Alsina
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = Soundcloud directive
diff --git a/nikola/plugins/compile/rest/soundcloud.py b/nikola/plugins/compile/rest/soundcloud.py
index 30134a9..2577ff1 100644
--- a/nikola/plugins/compile/rest/soundcloud.py
+++ b/nikola/plugins/compile/rest/soundcloud.py
@@ -10,7 +10,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for soundclound directive."""
name = "rest_soundcloud"
@@ -31,7 +30,6 @@ src="https://w.soundcloud.com/player/?url=http://api.soundcloud.com/{preslug}/""
class SoundCloud(Directive):
-
"""reST extension for inserting SoundCloud embedded music.
Usage:
@@ -70,7 +68,6 @@ class SoundCloud(Directive):
class SoundCloudPlaylist(SoundCloud):
-
"""reST directive for SoundCloud playlists."""
preslug = "playlists"
diff --git a/nikola/plugins/compile/rest/thumbnail.plugin b/nikola/plugins/compile/rest/thumbnail.plugin
index 0084310..3324c31 100644
--- a/nikola/plugins/compile/rest/thumbnail.plugin
+++ b/nikola/plugins/compile/rest/thumbnail.plugin
@@ -9,6 +9,6 @@ plugincategory = CompilerExtension
[Documentation]
author = Pelle Nilsson
version = 0.1
-website = http://getnikola.com
+website = https://getnikola.com/
description = reST directive to facilitate enlargeable images with thumbnails
diff --git a/nikola/plugins/compile/rest/thumbnail.py b/nikola/plugins/compile/rest/thumbnail.py
index 1fae06c..c24134a 100644
--- a/nikola/plugins/compile/rest/thumbnail.py
+++ b/nikola/plugins/compile/rest/thumbnail.py
@@ -35,7 +35,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for thumbnail directive."""
name = "rest_thumbnail"
@@ -48,7 +47,6 @@ class Plugin(RestExtension):
class Thumbnail(Figure):
-
"""Thumbnail directive for reST."""
def align(argument):
@@ -70,8 +68,12 @@ class Thumbnail(Figure):
def run(self):
"""Run the thumbnail directive."""
uri = directives.uri(self.arguments[0])
+ if uri.endswith('.svg'):
+ # the ? at the end makes docutil output an <img> instead of an object for the svg, which colorbox requires
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri)) + '?'
+ else:
+ self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
self.options['target'] = uri
- self.arguments[0] = '.thumbnail'.join(os.path.splitext(uri))
if self.content:
(node,) = Figure.run(self)
else:
diff --git a/nikola/plugins/compile/rest/vimeo.py b/nikola/plugins/compile/rest/vimeo.py
index c694a87..29ce5c1 100644
--- a/nikola/plugins/compile/rest/vimeo.py
+++ b/nikola/plugins/compile/rest/vimeo.py
@@ -37,7 +37,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for vimeo reST directive."""
name = "rest_vimeo"
@@ -60,7 +59,6 @@ VIDEO_DEFAULT_WIDTH = 281
class Vimeo(Directive):
-
"""reST extension for inserting vimeo embedded videos.
Usage:
diff --git a/nikola/plugins/compile/rest/youtube.py b/nikola/plugins/compile/rest/youtube.py
index 6c5c211..b3b84b0 100644
--- a/nikola/plugins/compile/rest/youtube.py
+++ b/nikola/plugins/compile/rest/youtube.py
@@ -34,7 +34,6 @@ from nikola.plugin_categories import RestExtension
class Plugin(RestExtension):
-
"""Plugin for the youtube directive."""
name = "rest_youtube"
@@ -54,7 +53,6 @@ src="//www.youtube.com/embed/{yid}?rel=0&amp;hd=1&amp;wmode=transparent"
class Youtube(Directive):
-
"""reST extension for inserting youtube embedded videos.
Usage:
diff --git a/nikola/plugins/misc/scan_posts.plugin b/nikola/plugins/misc/scan_posts.plugin
index 6d2351f..f4af811 100644
--- a/nikola/plugins/misc/scan_posts.plugin
+++ b/nikola/plugins/misc/scan_posts.plugin
@@ -5,6 +5,6 @@ Module = scan_posts
[Documentation]
Author = Roberto Alsina
Version = 1.0
-Website = http://getnikola.com
+Website = https://getnikola.com/
Description = Scan posts and create timeline
diff --git a/nikola/plugins/misc/scan_posts.py b/nikola/plugins/misc/scan_posts.py
index 1f4f995..9db4533 100644
--- a/nikola/plugins/misc/scan_posts.py
+++ b/nikola/plugins/misc/scan_posts.py
@@ -37,7 +37,6 @@ from nikola.post import Post
class ScanPosts(PostScanner):
-
"""Scan posts in the site."""
name = "scan_posts"
diff --git a/nikola/plugins/task/archive.plugin b/nikola/plugins/task/archive.plugin
index 25f1195..eb079da 100644
--- a/nikola/plugins/task/archive.plugin
+++ b/nikola/plugins/task/archive.plugin
@@ -5,7 +5,7 @@ module = archive
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generates the blog's archive pages.
[Nikola]
diff --git a/nikola/plugins/task/archive.py b/nikola/plugins/task/archive.py
index 126aed4..3cdd33b 100644
--- a/nikola/plugins/task/archive.py
+++ b/nikola/plugins/task/archive.py
@@ -37,7 +37,6 @@ from nikola.utils import config_changed, adjust_name_for_index_path, adjust_name
class Archive(Task):
-
"""Render the post archives."""
name = "render_archive"
@@ -53,7 +52,7 @@ class Archive(Task):
"""Prepare an archive task."""
# name: used to build permalink and destination
# posts, items: posts or items; only one of them should be used,
- # the other be None
+ # the other should be None
# template_name: name of the template to use
# title: the (translated) title for the generated page
# deps_translatable: dependencies (None if not added)
@@ -175,10 +174,10 @@ class Archive(Task):
if not kw["create_monthly_archive"] or kw["create_full_archives"]:
yield self._generate_posts_task(kw, year, lang, posts, title, deps_translatable)
else:
- months = set([(m.split('/')[1], self.site.link("archive", m, lang)) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
+ months = set([(m.split('/')[1], self.site.link("archive", m, lang), len(self.site.posts_per_month[m])) for m in self.site.posts_per_month.keys() if m.startswith(str(year))])
months = sorted(list(months))
months.reverse()
- items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link] for month, link in months]
+ items = [[nikola.utils.LocaleBorg().get_month_name(int(month), lang), link, count] for month, link, count in months]
yield self._prepare_task(kw, year, lang, None, items, "list.tmpl", title, deps_translatable)
if not kw["create_monthly_archive"] and not kw["create_full_archives"] and not kw["create_daily_archive"]:
@@ -219,11 +218,16 @@ class Archive(Task):
years.sort(reverse=True)
kw['years'] = years
for lang in kw["translations"]:
- items = [(y, self.site.link("archive", y, lang)) for y in years]
+ items = [(y, self.site.link("archive", y, lang), len(self.site.posts_per_year[y])) for y in years]
yield self._prepare_task(kw, None, lang, None, items, "list.tmpl", kw["messages"][lang]["Archive"])
def archive_path(self, name, lang, is_feed=False):
- """Return archive paths."""
+ """Link to archive path, name is the year.
+
+ Example:
+
+ link://archive/2013 => /archives/2013/index.html
+ """
if is_feed:
extension = ".atom"
archive_file = os.path.splitext(self.site.config['ARCHIVE_FILENAME'])[0] + extension
@@ -241,5 +245,10 @@ class Archive(Task):
archive_file] if _f]
def archive_atom_path(self, name, lang):
- """Return Atom archive paths."""
+ """Link to atom archive path, name is the year.
+
+ Example:
+
+ link://archive_atom/2013 => /archives/2013/index.atom
+ """
return self.archive_path(name, lang, is_feed=True)
diff --git a/nikola/plugins/task/authors.plugin b/nikola/plugins/task/authors.plugin
new file mode 100644
index 0000000..3fc4ef2
--- /dev/null
+++ b/nikola/plugins/task/authors.plugin
@@ -0,0 +1,10 @@
+[Core]
+Name = render_authors
+Module = authors
+
+[Documentation]
+Author = Juanjo Conti
+Version = 0.1
+Website = http://getnikola.com
+Description = Render the author pages and feeds.
+
diff --git a/nikola/plugins/task/authors.py b/nikola/plugins/task/authors.py
new file mode 100644
index 0000000..081d21d
--- /dev/null
+++ b/nikola/plugins/task/authors.py
@@ -0,0 +1,316 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2015 Juanjo Conti.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""Render the author pages and feeds."""
+
+from __future__ import unicode_literals
+import os
+import natsort
+try:
+ from urlparse import urljoin
+except ImportError:
+ from urllib.parse import urljoin # NOQA
+from collections import defaultdict
+
+from nikola.plugin_categories import Task
+from nikola import utils
+
+
+class RenderAuthors(Task):
+ """Render the author pages and feeds."""
+
+ name = "render_authors"
+ posts_per_author = None
+
+ def set_site(self, site):
+ """Set Nikola site."""
+ if site.config["ENABLE_AUTHOR_PAGES"]:
+ site.register_path_handler('author_index', self.author_index_path)
+ site.register_path_handler('author', self.author_path)
+ site.register_path_handler('author_atom', self.author_atom_path)
+ site.register_path_handler('author_rss', self.author_rss_path)
+ return super(RenderAuthors, self).set_site(site)
+
+ def gen_tasks(self):
+ """Render the author pages and feeds."""
+ kw = {
+ "translations": self.site.config["TRANSLATIONS"],
+ "blog_title": self.site.config["BLOG_TITLE"],
+ "site_url": self.site.config["SITE_URL"],
+ "base_url": self.site.config["BASE_URL"],
+ "messages": self.site.MESSAGES,
+ "output_folder": self.site.config['OUTPUT_FOLDER'],
+ "filters": self.site.config['FILTERS'],
+ 'author_path': self.site.config['AUTHOR_PATH'],
+ "author_pages_are_indexes": self.site.config['AUTHOR_PAGES_ARE_INDEXES'],
+ "generate_rss": self.site.config['GENERATE_RSS'],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
+ "feed_link_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
+ "show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
+ "feed_length": self.site.config['FEED_LENGTH'],
+ "tzinfo": self.site.tzinfo,
+ "pretty_urls": self.site.config['PRETTY_URLS'],
+ "strip_indexes": self.site.config['STRIP_INDEXES'],
+ "index_file": self.site.config['INDEX_FILE'],
+ }
+
+ yield self.group_task()
+ self.site.scan_posts()
+
+ generate_author_pages = self.site.config["ENABLE_AUTHOR_PAGES"] and len(self._posts_per_author()) > 1
+ self.site.GLOBAL_CONTEXT["author_pages_generated"] = generate_author_pages
+ if generate_author_pages:
+ yield self.list_authors_page(kw)
+
+ if not self._posts_per_author(): # this may be self.site.posts_per_author
+ return
+
+ author_list = list(self._posts_per_author().items())
+
+ def render_lists(author, posts):
+ """Render author pages as RSS files and lists/indexes."""
+ post_list = sorted(posts, key=lambda a: a.date)
+ post_list.reverse()
+ for lang in kw["translations"]:
+ if kw["show_untranslated_posts"]:
+ filtered_posts = post_list
+ else:
+ filtered_posts = [x for x in post_list if x.is_translation_available(lang)]
+ if kw["generate_rss"]:
+ yield self.author_rss(author, lang, filtered_posts, kw)
+ # Render HTML
+ if kw['author_pages_are_indexes']:
+ yield self.author_page_as_index(author, lang, filtered_posts, kw)
+ else:
+ yield self.author_page_as_list(author, lang, filtered_posts, kw)
+
+ for author, posts in author_list:
+ for task in render_lists(author, posts):
+ yield task
+
+ def _create_authors_page(self, kw):
+ """Create a global "all authors" page for each language."""
+ template_name = "authors.tmpl"
+ kw = kw.copy()
+ for lang in kw["translations"]:
+ authors = natsort.natsorted([author for author in self._posts_per_author().keys()],
+ alg=natsort.ns.F | natsort.ns.IC)
+ has_authors = (authors != [])
+ kw['authors'] = authors
+ output_name = os.path.join(
+ kw['output_folder'], self.site.path('author_index', None, lang))
+ context = {}
+ if has_authors:
+ context["title"] = kw["messages"][lang]["Authors"]
+ context["items"] = [(author, self.site.link("author", author, lang)) for author
+ in authors]
+ context["description"] = context["title"]
+ else:
+ context["items"] = None
+ context["permalink"] = self.site.link("author_index", None, lang)
+ context["pagekind"] = ["list", "authors_page"]
+ task = self.site.generic_post_list_renderer(
+ lang,
+ [],
+ output_name,
+ template_name,
+ kw['filters'],
+ context,
+ )
+ task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:page')]
+ task['basename'] = str(self.name)
+ yield task
+
+ def list_authors_page(self, kw):
+ """Create a global "all authors" page for each language."""
+ yield self._create_authors_page(kw)
+
+ def _get_title(self, author):
+ return author
+
+ def _get_description(self, author, lang):
+ descriptions = self.site.config['AUTHOR_PAGES_DESCRIPTIONS']
+ return descriptions[lang][author] if lang in descriptions and author in descriptions[lang] else None
+
+ def author_page_as_index(self, author, lang, post_list, kw):
+ """Render a sort of index page collection using only this author's posts."""
+ kind = "author"
+
+ def page_link(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_link(self.site.link(kind + feed, author, lang), i, displayed_i, lang, self.site, force_addition, extension)
+
+ def page_path(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_path(self.site.path(kind + feed, author, lang), i, displayed_i, lang, self.site, force_addition, extension)
+
+ context_source = {}
+ title = self._get_title(author)
+ if kw["generate_rss"]:
+ # On a author page, the feeds include the author's feeds
+ rss_link = ("""<link rel="alternate" type="application/rss+xml" """
+ """title="RSS for author """
+ """{0} ({1})" href="{2}">""".format(
+ title, lang, self.site.link(kind + "_rss", author, lang)))
+ context_source['rss_link'] = rss_link
+ context_source["author"] = title
+ indexes_title = kw["messages"][lang]["Posts by %s"] % title
+ context_source["description"] = self._get_description(author, lang)
+ context_source["pagekind"] = ["index", "author_page"]
+ template_name = "authorindex.tmpl"
+
+ yield self.site.generic_index_renderer(lang, post_list, indexes_title, template_name, context_source, kw, str(self.name), page_link, page_path)
+
+ def author_page_as_list(self, author, lang, post_list, kw):
+ """Render a single flat link list with this author's posts."""
+ kind = "author"
+ template_name = "author.tmpl"
+ output_name = os.path.join(kw['output_folder'], self.site.path(
+ kind, author, lang))
+ context = {}
+ context["lang"] = lang
+ title = self._get_title(author)
+ context["author"] = title
+ context["title"] = kw["messages"][lang]["Posts by %s"] % title
+ context["posts"] = post_list
+ context["permalink"] = self.site.link(kind, author, lang)
+ context["kind"] = kind
+ context["description"] = self._get_description(author, lang)
+ context["pagekind"] = ["list", "author_page"]
+ task = self.site.generic_post_list_renderer(
+ lang,
+ post_list,
+ output_name,
+ template_name,
+ kw['filters'],
+ context,
+ )
+ task['uptodate'] = task['uptodate'] + [utils.config_changed(kw, 'nikola.plugins.task.authors:list')]
+ task['basename'] = str(self.name)
+ yield task
+
+ def author_rss(self, author, lang, posts, kw):
+ """Create a RSS feed for a single author in a given language."""
+ kind = "author"
+ # Render RSS
+ output_name = os.path.normpath(
+ os.path.join(kw['output_folder'],
+ self.site.path(kind + "_rss", author, lang)))
+ feed_url = urljoin(self.site.config['BASE_URL'], self.site.link(kind + "_rss", author, lang).lstrip('/'))
+ deps = []
+ deps_uptodate = []
+ post_list = sorted(posts, key=lambda a: a.date)
+ post_list.reverse()
+ for post in post_list:
+ deps += post.deps(lang)
+ deps_uptodate += post.deps_uptodate(lang)
+ task = {
+ 'basename': str(self.name),
+ 'name': output_name,
+ 'file_dep': deps,
+ 'targets': [output_name],
+ 'actions': [(utils.generic_rss_renderer,
+ (lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(author)),
+ kw["site_url"], None, post_list,
+ output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
+ feed_url, None, kw["feed_link_append_query"]))],
+ 'clean': True,
+ 'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.authors:rss')] + deps_uptodate,
+ 'task_dep': ['render_posts'],
+ }
+ return utils.apply_filters(task, kw['filters'])
+
+ def slugify_author_name(self, name):
+ """Slugify an author name."""
+ if self.site.config['SLUG_AUTHOR_PATH']:
+ name = utils.slugify(name)
+ return name
+
+ def author_index_path(self, name, lang):
+ """Link to the author's index.
+
+ Example:
+
+ link://authors/ => /authors/index.html
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.site.config['INDEX_FILE']] if _f]
+
+ def author_path(self, name, lang):
+ """Link to an author's page.
+
+ Example:
+
+ link://author/joe => /authors/joe.html
+ """
+ if self.site.config['PRETTY_URLS']:
+ return [_f for _f in [
+ self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.slugify_author_name(name),
+ self.site.config['INDEX_FILE']] if _f]
+ else:
+ return [_f for _f in [
+ self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'],
+ self.slugify_author_name(name) + ".html"] if _f]
+
+ def author_atom_path(self, name, lang):
+ """Link to an author's Atom feed.
+
+ Example:
+
+ link://author_atom/joe => /authors/joe.atom
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".atom"] if
+ _f]
+
+ def author_rss_path(self, name, lang):
+ """Link to an author's RSS feed.
+
+ Example:
+
+ link://author_rss/joe => /authors/joe.rss
+ """
+ return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['AUTHOR_PATH'], self.slugify_author_name(name) + ".xml"] if
+ _f]
+
+ def _add_extension(self, path, extension):
+ path[-1] += extension
+ return path
+
+ def _posts_per_author(self):
+ """Return a dict of posts per author."""
+ if self.posts_per_author is None:
+ self.posts_per_author = defaultdict(list)
+ for post in self.site.timeline:
+ if post.is_post:
+ self.posts_per_author[post.author()].append(post)
+ return self.posts_per_author
diff --git a/nikola/plugins/task/bundles.plugin b/nikola/plugins/task/bundles.plugin
index ca997d0..b5bf6e4 100644
--- a/nikola/plugins/task/bundles.plugin
+++ b/nikola/plugins/task/bundles.plugin
@@ -5,7 +5,7 @@ module = bundles
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Theme bundles using WebAssets
[Nikola]
diff --git a/nikola/plugins/task/bundles.py b/nikola/plugins/task/bundles.py
index b9c57b9..e709133 100644
--- a/nikola/plugins/task/bundles.py
+++ b/nikola/plugins/task/bundles.py
@@ -40,7 +40,6 @@ from nikola import utils
class BuildBundles(LateTask):
-
"""Bundle assets using WebAssets."""
name = "create_bundles"
@@ -52,6 +51,7 @@ class BuildBundles(LateTask):
utils.req_missing(['webassets'], 'USE_BUNDLES', optional=True)
self.logger.warn('Setting USE_BUNDLES to False.')
site.config['USE_BUNDLES'] = False
+ site._GLOBAL_CONTEXT['use_bundles'] = False
super(BuildBundles, self).set_site(site)
def gen_tasks(self):
@@ -100,7 +100,11 @@ class BuildBundles(LateTask):
files.append(os.path.join(dname, fname))
file_dep = [os.path.join(kw['output_folder'], fname)
for fname in files if
- utils.get_asset_path(fname, self.site.THEMES, self.site.config['FILES_FOLDERS']) or fname == os.path.join('assets', 'css', 'code.css')]
+ utils.get_asset_path(
+ fname,
+ self.site.THEMES,
+ self.site.config['FILES_FOLDERS'],
+ output_dir=kw['output_folder']) or fname == os.path.join('assets', 'css', 'code.css')]
# code.css will be generated by us if it does not exist in
# FILES_FOLDERS or theme assets. It is guaranteed that the
# generation will happen before this task.
diff --git a/nikola/plugins/task/copy_assets.plugin b/nikola/plugins/task/copy_assets.plugin
index c182150..ddd38df 100644
--- a/nikola/plugins/task/copy_assets.plugin
+++ b/nikola/plugins/task/copy_assets.plugin
@@ -5,7 +5,7 @@ module = copy_assets
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy theme assets into output.
[Nikola]
diff --git a/nikola/plugins/task/copy_assets.py b/nikola/plugins/task/copy_assets.py
index 58521d4..2cab71a 100644
--- a/nikola/plugins/task/copy_assets.py
+++ b/nikola/plugins/task/copy_assets.py
@@ -36,7 +36,6 @@ from nikola import utils
class CopyAssets(Task):
-
"""Copy theme assets into output."""
name = "copy_assets"
@@ -61,10 +60,7 @@ class CopyAssets(Task):
code_css_path = os.path.join(kw['output_folder'], 'assets', 'css', 'code.css')
code_css_input = utils.get_asset_path('assets/css/code.css',
themes=kw['themes'],
- files_folders=kw['files_folders'])
-
- kw["code.css_input"] = code_css_input
-
+ files_folders=kw['files_folders'], output_dir=None)
yield self.group_task()
for theme_name in kw['themes']:
@@ -77,7 +73,9 @@ class CopyAssets(Task):
task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.copy_assets')]
task['basename'] = self.name
if code_css_input:
- task['file_dep'] = [code_css_input]
+ if 'file_dep' not in task:
+ task['file_dep'] = []
+ task['file_dep'].append(code_css_input)
yield utils.apply_filters(task, kw['filters'])
# Check whether or not there is a code.css file around.
diff --git a/nikola/plugins/task/copy_files.plugin b/nikola/plugins/task/copy_files.plugin
index ce8f5d0..e4bb1cf 100644
--- a/nikola/plugins/task/copy_files.plugin
+++ b/nikola/plugins/task/copy_files.plugin
@@ -5,7 +5,7 @@ module = copy_files
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy static files into the output.
[Nikola]
diff --git a/nikola/plugins/task/copy_files.py b/nikola/plugins/task/copy_files.py
index 1232248..0488011 100644
--- a/nikola/plugins/task/copy_files.py
+++ b/nikola/plugins/task/copy_files.py
@@ -33,7 +33,6 @@ from nikola import utils
class CopyFiles(Task):
-
"""Copy static files into the output folder."""
name = "copy_files"
diff --git a/nikola/plugins/task/galleries.plugin b/nikola/plugins/task/galleries.plugin
index 9d3fa28..2064e68 100644
--- a/nikola/plugins/task/galleries.plugin
+++ b/nikola/plugins/task/galleries.plugin
@@ -5,7 +5,7 @@ module = galleries
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create image galleries automatically.
[Nikola]
diff --git a/nikola/plugins/task/galleries.py b/nikola/plugins/task/galleries.py
index c0df4a4..d3f1db7 100644
--- a/nikola/plugins/task/galleries.py
+++ b/nikola/plugins/task/galleries.py
@@ -57,7 +57,6 @@ _image_size_cache = {}
class Galleries(Task, ImageProcessor):
-
"""Render image galleries."""
name = 'render_galleries'
@@ -122,20 +121,45 @@ class Galleries(Task, ImageProcessor):
sys.exit(1)
def gallery_path(self, name, lang):
- """Return a gallery path."""
+ """Link to an image gallery's path.
+
+ It will try to find a gallery with that name if it's not ambiguous
+ or with that path. For example:
+
+ link://gallery/london => /galleries/trips/london/index.html
+
+ link://gallery/trips/london => /galleries/trips/london/index.html
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in [self.site.config['TRANSLATIONS'][lang]] +
gallery_path.split(os.sep) +
[self.site.config['INDEX_FILE']] if _f]
def gallery_global_path(self, name, lang):
- """Return the global gallery path, which contains images."""
+ """Link to the global gallery path, which contains all the images in galleries.
+
+ There is only one copy of an image on multilingual blogs, in the site root.
+
+ link://gallery_global/london => /galleries/trips/london/index.html
+
+ link://gallery_global/trips/london => /galleries/trips/london/index.html
+
+ (a ``gallery`` link could lead to eg. /en/galleries/trips/london/index.html)
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in gallery_path.split(os.sep) +
[self.site.config['INDEX_FILE']] if _f]
def gallery_rss_path(self, name, lang):
- """Return path to the RSS file for a gallery."""
+ """Link to an image gallery's RSS feed.
+
+ It will try to find a gallery with that name if it's not ambiguous
+ or with that path. For example:
+
+ link://gallery_rss/london => /galleries/trips/london/rss.xml
+
+ link://gallery_rss/trips/london => /galleries/trips/london/rss.xml
+ """
gallery_path = self._find_gallery_path(name)
return [_f for _f in [self.site.config['TRANSLATIONS'][lang]] +
gallery_path.split(os.sep) +
@@ -538,9 +562,12 @@ class Galleries(Task, ImageProcessor):
for img, thumb, title in zip(img_list, thumbs, img_titles):
w, h = _image_size_cache.get(thumb, (None, None))
if w is None:
- im = Image.open(thumb)
- w, h = im.size
- _image_size_cache[thumb] = w, h
+ if os.path.splitext(thumb)[1] in ['.svg', '.svgz']:
+ w, h = 200, 200
+ else:
+ im = Image.open(thumb)
+ w, h = im.size
+ _image_size_cache[thumb] = w, h
# Thumbs are files in output, we need URLs
photo_array.append({
'url': url_from_path(img),
@@ -587,7 +614,7 @@ class Galleries(Task, ImageProcessor):
description='',
lastBuildDate=datetime.datetime.utcnow(),
items=items,
- generator='http://getnikola.com/',
+ generator='https://getnikola.com/',
language=lang
)
diff --git a/nikola/plugins/task/gzip.plugin b/nikola/plugins/task/gzip.plugin
index 7834d22..d3a34ee 100644
--- a/nikola/plugins/task/gzip.plugin
+++ b/nikola/plugins/task/gzip.plugin
@@ -5,7 +5,7 @@ module = gzip
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create gzipped copies of files
[Nikola]
diff --git a/nikola/plugins/task/gzip.py b/nikola/plugins/task/gzip.py
index cf16f63..aaa213d 100644
--- a/nikola/plugins/task/gzip.py
+++ b/nikola/plugins/task/gzip.py
@@ -35,7 +35,6 @@ from nikola.plugin_categories import TaskMultiplier
class GzipFiles(TaskMultiplier):
-
"""If appropiate, create tasks to create gzipped versions of files."""
name = "gzip"
diff --git a/nikola/plugins/task/indexes.plugin b/nikola/plugins/task/indexes.plugin
index d9b0e5f..553b5ad 100644
--- a/nikola/plugins/task/indexes.plugin
+++ b/nikola/plugins/task/indexes.plugin
@@ -5,7 +5,7 @@ module = indexes
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generates the blog's index pages.
[Nikola]
diff --git a/nikola/plugins/task/indexes.py b/nikola/plugins/task/indexes.py
index c02818e..2ab97fa 100644
--- a/nikola/plugins/task/indexes.py
+++ b/nikola/plugins/task/indexes.py
@@ -29,23 +29,45 @@
from __future__ import unicode_literals
from collections import defaultdict
import os
+try:
+ from urlparse import urljoin
+except ImportError:
+ from urllib.parse import urljoin # NOQA
from nikola.plugin_categories import Task
from nikola import utils
class Indexes(Task):
-
"""Render the blog indexes."""
name = "render_indexes"
def set_site(self, site):
"""Set Nikola site."""
+ self.number_of_pages = dict()
+ self.number_of_pages_section = {lang: dict() for lang in site.config['TRANSLATIONS']}
site.register_path_handler('index', self.index_path)
site.register_path_handler('index_atom', self.index_atom_path)
+ site.register_path_handler('section_index', self.index_section_path)
+ site.register_path_handler('section_index_atom', self.index_section_atom_path)
return super(Indexes, self).set_site(site)
+ def _get_filtered_posts(self, lang, show_untranslated_posts):
+ """Return a filtered list of all posts for the given language.
+
+ If show_untranslated_posts is True, will only include posts which
+ are translated to the given language. Otherwise, returns all posts.
+ """
+ if show_untranslated_posts:
+ return self.site.posts
+ else:
+ return [x for x in self.site.posts if x.is_translation_available(lang)]
+
+ def _compute_number_of_pages(self, filtered_posts, posts_count):
+ """Given a list of posts and the maximal number of posts per page, computes the number of pages needed."""
+ return min(1, (len(filtered_posts) + posts_count - 1) // posts_count)
+
def gen_tasks(self):
"""Render the blog indexes."""
self.site.scan_posts()
@@ -56,16 +78,16 @@ class Indexes(Task):
"messages": self.site.MESSAGES,
"output_folder": self.site.config['OUTPUT_FOLDER'],
"filters": self.site.config['FILTERS'],
+ "index_file": self.site.config['INDEX_FILE'],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"index_display_post_count": self.site.config['INDEX_DISPLAY_POST_COUNT'],
"indexes_title": self.site.config['INDEXES_TITLE'],
+ "strip_indexes": self.site.config['STRIP_INDEXES'],
"blog_title": self.site.config["BLOG_TITLE"],
"generate_atom": self.site.config["GENERATE_ATOM"],
}
template_name = "index.tmpl"
- posts = self.site.posts
- self.number_of_pages = dict()
for lang in kw["translations"]:
def page_link(i, displayed_i, num_pages, force_addition, extension=None):
feed = "_atom" if extension == ".atom" else ""
@@ -77,19 +99,75 @@ class Indexes(Task):
return utils.adjust_name_for_index_path(self.site.path("index" + feed, None, lang), i, displayed_i,
lang, self.site, force_addition, extension)
- if kw["show_untranslated_posts"]:
- filtered_posts = posts
- else:
- filtered_posts = [x for x in posts if x.is_translation_available(lang)]
+ filtered_posts = self._get_filtered_posts(lang, kw["show_untranslated_posts"])
indexes_title = kw['indexes_title'](lang) or kw['blog_title'](lang)
- self.number_of_pages[lang] = (len(filtered_posts) + kw['index_display_post_count'] - 1) // kw['index_display_post_count']
+ self.number_of_pages[lang] = self._compute_number_of_pages(filtered_posts, kw['index_display_post_count'])
context = {}
- context["pagekind"] = ["index"]
+ context["pagekind"] = ["main_index", "index"]
yield self.site.generic_index_renderer(lang, filtered_posts, indexes_title, template_name, context, kw, 'render_indexes', page_link, page_path)
+ if self.site.config['POSTS_SECTIONS']:
+
+ kw["posts_section_are_indexes"] = self.site.config['POSTS_SECTION_ARE_INDEXES']
+ index_len = len(kw['index_file'])
+
+ groups = defaultdict(list)
+ for p in filtered_posts:
+ groups[p.section_slug(lang)].append(p)
+
+ # don't build sections when there is only one, aka. default setups
+ if not len(groups.items()) > 1:
+ continue
+
+ for section_slug, post_list in groups.items():
+ self.number_of_pages_section[lang][section_slug] = self._compute_number_of_pages(post_list, kw['index_display_post_count'])
+
+ def cat_link(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_link(self.site.link("section_index" + feed, section_slug, lang), i, displayed_i,
+ lang, self.site, force_addition, extension)
+
+ def cat_path(i, displayed_i, num_pages, force_addition, extension=None):
+ feed = "_atom" if extension == ".atom" else ""
+ return utils.adjust_name_for_index_path(self.site.path("section_index" + feed, section_slug, lang), i, displayed_i,
+ lang, self.site, force_addition, extension)
+
+ context = {}
+
+ short_destination = os.path.join(section_slug, kw['index_file'])
+ link = short_destination.replace('\\', '/')
+ if kw['strip_indexes'] and link[-(1 + index_len):] == '/' + kw['index_file']:
+ link = link[:-index_len]
+ context["permalink"] = link
+ context["pagekind"] = ["section_page"]
+ context["description"] = self.site.config['POSTS_SECTION_DESCRIPTIONS'](lang)[section_slug] if section_slug in self.site.config['POSTS_SECTION_DESCRIPTIONS'](lang) else ""
+
+ if kw["posts_section_are_indexes"]:
+ context["pagekind"].append("index")
+ kw["posts_section_title"] = self.site.config['POSTS_SECTION_TITLE'](lang)
+
+ section_title = None
+ if type(kw["posts_section_title"]) is dict:
+ if section_slug in kw["posts_section_title"]:
+ section_title = kw["posts_section_title"][section_slug]
+ elif type(kw["posts_section_title"]) is str:
+ section_title = kw["posts_section_title"]
+ if not section_title:
+ section_title = post_list[0].section_name(lang)
+ section_title = section_title.format(name=post_list[0].section_name(lang))
+
+ task = self.site.generic_index_renderer(lang, post_list, section_title, "sectionindex.tmpl", context, kw, self.name, cat_link, cat_path)
+ else:
+ context["pagekind"].append("list")
+ output_name = os.path.join(kw['output_folder'], section_slug, kw['index_file'])
+ task = self.site.generic_post_list_renderer(lang, post_list, output_name, "list.tmpl", kw['filters'], context)
+ task['uptodate'] = [utils.config_changed(kw, 'nikola.plugins.task.indexes')]
+ task['basename'] = self.name
+ yield task
+
if not self.site.config["STORY_INDEX"]:
return
kw = {
@@ -134,7 +212,8 @@ class Indexes(Task):
should_render = False
else:
context["items"].append((post.title(lang),
- post.permalink(lang)))
+ post.permalink(lang),
+ None))
if should_render:
task = self.site.generic_post_list_renderer(lang, post_list,
@@ -147,22 +226,75 @@ class Indexes(Task):
yield task
def index_path(self, name, lang, is_feed=False):
- """Return path to an index."""
+ """Link to a numbered index.
+
+ Example:
+
+ link://index/3 => /index-3.html
+ """
extension = None
if is_feed:
extension = ".atom"
index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
else:
index_file = self.site.config['INDEX_FILE']
+ if lang in self.number_of_pages:
+ number_of_pages = self.number_of_pages[lang]
+ else:
+ number_of_pages = self._compute_number_of_pages(self._get_filtered_posts(lang, self.site.config['SHOW_UNTRANSLATED_POSTS']), self.site.config['INDEX_DISPLAY_POST_COUNT'])
+ self.number_of_pages[lang] = number_of_pages
return utils.adjust_name_for_index_path_list([_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['INDEX_PATH'],
index_file] if _f],
name,
- utils.get_displayed_page_number(name, self.number_of_pages[lang], self.site),
+ utils.get_displayed_page_number(name, number_of_pages, self.site),
+ lang,
+ self.site,
+ extension=extension)
+
+ def index_section_path(self, name, lang, is_feed=False):
+ """Link to the index for a section.
+
+ Example:
+
+ link://section_index/cars => /cars/index.html
+ """
+ extension = None
+
+ if is_feed:
+ extension = ".atom"
+ index_file = os.path.splitext(self.site.config['INDEX_FILE'])[0] + extension
+ else:
+ index_file = self.site.config['INDEX_FILE']
+ if name in self.number_of_pages_section[lang]:
+ number_of_pages = self.number_of_pages_section[lang][name]
+ else:
+ posts = [post for post in self._get_filtered_posts(lang, self.site.config['SHOW_UNTRANSLATED_POSTS']) if post.section_slug(lang) == name]
+ number_of_pages = self._compute_number_of_pages(posts, self.site.config['INDEX_DISPLAY_POST_COUNT'])
+ self.number_of_pages_section[lang][name] = number_of_pages
+ return utils.adjust_name_for_index_path_list([_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ name,
+ index_file] if _f],
+ None,
+ utils.get_displayed_page_number(None, number_of_pages, self.site),
lang,
self.site,
extension=extension)
def index_atom_path(self, name, lang):
- """Return path to an Atom index."""
+ """Link to a numbered Atom index.
+
+ Example:
+
+ link://index_atom/3 => /index-3.atom
+ """
return self.index_path(name, lang, is_feed=True)
+
+ def index_section_atom_path(self, name, lang):
+ """Link to the Atom index for a section.
+
+ Example:
+
+ link://section_index_atom/cars => /cars/index.atom
+ """
+ return self.index_section_path(name, lang, is_feed=True)
diff --git a/nikola/plugins/task/listings.plugin b/nikola/plugins/task/listings.plugin
index 435234b..8fc2e2d 100644
--- a/nikola/plugins/task/listings.plugin
+++ b/nikola/plugins/task/listings.plugin
@@ -5,7 +5,7 @@ module = listings
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Render code listings into output
[Nikola]
diff --git a/nikola/plugins/task/listings.py b/nikola/plugins/task/listings.py
index 5f79724..891f361 100644
--- a/nikola/plugins/task/listings.py
+++ b/nikola/plugins/task/listings.py
@@ -28,6 +28,7 @@
from __future__ import unicode_literals, print_function
+from collections import defaultdict
import sys
import os
import lxml.html
@@ -41,16 +42,13 @@ from nikola import utils
class Listings(Task):
-
"""Render code listings."""
name = "render_listings"
def register_output_name(self, input_folder, rel_name, rel_output_name):
"""Register proper and improper file mappings."""
- if rel_name not in self.improper_input_file_mapping:
- self.improper_input_file_mapping[rel_name] = []
- self.improper_input_file_mapping[rel_name].append(rel_output_name)
+ self.improper_input_file_mapping[rel_name].add(rel_output_name)
self.proper_input_file_mapping[os.path.join(input_folder, rel_name)] = rel_output_name
self.proper_input_file_mapping[rel_output_name] = rel_output_name
@@ -85,7 +83,7 @@ class Listings(Task):
# a list is needed. This is needed for compatibility to previous Nikola
# versions, where there was no need to specify the input directory name
# when asking for a link via site.link('listing', ...).
- self.improper_input_file_mapping = {}
+ self.improper_input_file_mapping = defaultdict(set)
# proper_input_file_mapping maps relative input file (relative to CWD)
# to a generated output file. Since we don't allow an input directory
@@ -255,7 +253,16 @@ class Listings(Task):
}, self.kw["filters"])
def listing_path(self, namep, lang):
- """Return path to a listing."""
+ """A link to a listing.
+
+ It will try to use the file name if it's not ambiguous, or the file path.
+
+ Example:
+
+ link://listing/hello.py => /listings/tutorial/hello.py.html
+
+ link://listing/tutorial/hello.py => /listings/tutorial/hello.py.html
+ """
namep = namep.replace('/', os.sep)
nameh = namep + '.html'
for name in (namep, nameh):
@@ -271,7 +278,7 @@ class Listings(Task):
sys.exit(1)
if len(self.site.config['LISTINGS_FOLDERS']) > 1:
utils.LOGGER.notice("Using listings names in site.link() without input directory prefix while configuration's LISTINGS_FOLDERS has more than one entry.")
- name = self.improper_input_file_mapping[name][0]
+ name = list(self.improper_input_file_mapping[name])[0]
break
else:
utils.LOGGER.error("Unknown listing name {0}!".format(namep))
diff --git a/nikola/plugins/task/pages.plugin b/nikola/plugins/task/pages.plugin
index 023d41b..1bdc7f4 100644
--- a/nikola/plugins/task/pages.plugin
+++ b/nikola/plugins/task/pages.plugin
@@ -5,7 +5,7 @@ module = pages
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create pages in the output.
[Nikola]
diff --git a/nikola/plugins/task/pages.py b/nikola/plugins/task/pages.py
index e6a8a82..8d41035 100644
--- a/nikola/plugins/task/pages.py
+++ b/nikola/plugins/task/pages.py
@@ -32,7 +32,6 @@ from nikola.utils import config_changed
class RenderPages(Task):
-
"""Render pages into output."""
name = "render_pages"
diff --git a/nikola/plugins/task/posts.plugin b/nikola/plugins/task/posts.plugin
index 79b7c51..c9578bc 100644
--- a/nikola/plugins/task/posts.plugin
+++ b/nikola/plugins/task/posts.plugin
@@ -5,7 +5,7 @@ module = posts
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create HTML fragments out of posts.
[Nikola]
diff --git a/nikola/plugins/task/posts.py b/nikola/plugins/task/posts.py
index a3a8375..8735beb 100644
--- a/nikola/plugins/task/posts.py
+++ b/nikola/plugins/task/posts.py
@@ -44,7 +44,6 @@ def update_deps(post, lang, task):
class RenderPosts(Task):
-
"""Build HTML fragments from metadata and text."""
name = "render_posts"
@@ -77,6 +76,8 @@ class RenderPosts(Task):
deps_dict = copy(kw)
deps_dict.pop('timeline')
for post in kw['timeline']:
+ if not post.is_translation_available(lang) and not self.site.config['SHOW_UNTRANSLATED_POSTS']:
+ continue
# Extra config dependencies picked from config
for p in post.fragment_deps(lang):
if p.startswith('####MAGIC####CONFIG:'):
@@ -114,7 +115,7 @@ class RenderPosts(Task):
pass
else:
flist.append(f)
- yield utils.apply_filters(task, {os.path.splitext(dest): flist})
+ yield utils.apply_filters(task, {os.path.splitext(dest)[-1]: flist})
def dependence_on_timeline(self, post, lang):
"""Check if a post depends on the timeline."""
diff --git a/nikola/plugins/task/py3_switch.plugin b/nikola/plugins/task/py3_switch.plugin
new file mode 100644
index 0000000..b0014e1
--- /dev/null
+++ b/nikola/plugins/task/py3_switch.plugin
@@ -0,0 +1,13 @@
+[Core]
+name = py3_switch
+module = py3_switch
+
+[Documentation]
+author = Roberto Alsina
+version = 1.0
+website = https://getnikola.com/
+description = Beg the user to switch to Python 3
+
+[Nikola]
+plugincategory = Task
+
diff --git a/nikola/plugins/task/py3_switch.py b/nikola/plugins/task/py3_switch.py
new file mode 100644
index 0000000..930c593
--- /dev/null
+++ b/nikola/plugins/task/py3_switch.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# Copyright © 2012-2015 Roberto Alsina and others.
+
+# Permission is hereby granted, free of charge, to any
+# person obtaining a copy of this software and associated
+# documentation files (the "Software"), to deal in the
+# Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the
+# Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice
+# shall be included in all copies or substantial portions of
+# the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
+# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""Beg the user to switch to python 3."""
+
+import datetime
+import os
+import random
+import sys
+
+import doit.tools
+
+from nikola.utils import get_logger, STDERR_HANDLER
+from nikola.plugin_categories import LateTask
+
+PY2_AND_NO_PY3_WARNING = """Nikola is going to deprecate Python 2 support in 2016. Your current
+version will continue to work, but please consider upgrading to Python 3.
+
+Please check http://bit.ly/1FKEsiX for details.
+"""
+PY2_WARNING = """Nikola is going to deprecate Python 2 support in 2016. You already have Python 3
+available in your system. Why not switch?
+
+Please check http://bit.ly/1FKEsiX for details.
+"""
+PY2_BARBS = [
+ "Python 2 has been deprecated for years. Stop clinging to your long gone youth and switch to Python3.",
+ "Python 2 is the safety blanket of languages. Be a big kid and switch to Python 3",
+ "Python 2 is old and busted. Python 3 is the new hotness.",
+ "Nice unicode you have there, would be a shame something happened to it.. switch to python 3!.",
+ "Don’t get in the way of progress! Upgrade to Python 3 and save a developer’s mind today!",
+ "Winners don't use Python 2 -- Signed: The FBI",
+ "Python 2? What year is it?",
+ "I just wanna tell you how I'm feeling\n"
+ "Gotta make you understand\n"
+ "Never gonna give you up [But Python 2 has to go]",
+ "The year 2009 called, and they want their Python 2.7 back.",
+]
+
+
+LOGGER = get_logger('Nikola', STDERR_HANDLER)
+
+
+def has_python_3():
+ """Check if python 3 is available."""
+ if 'win' in sys.platform:
+ py_bin = 'py.exe'
+ else:
+ py_bin = 'python3'
+ for path in os.environ["PATH"].split(os.pathsep):
+ if os.access(os.path.join(path, py_bin), os.X_OK):
+ return True
+ return False
+
+
+class Py3Switch(LateTask):
+ """Beg the user to switch to python 3."""
+
+ name = "_switch to py3"
+
+ def gen_tasks(self):
+ """Beg the user to switch to python 3."""
+ def give_warning():
+ if sys.version_info[0] == 3:
+ return
+ if has_python_3():
+ LOGGER.warn(random.choice(PY2_BARBS))
+ LOGGER.warn(PY2_WARNING)
+ else:
+ LOGGER.warn(PY2_AND_NO_PY3_WARNING)
+
+ task = {
+ 'basename': self.name,
+ 'name': 'please!',
+ 'actions': [give_warning],
+ 'clean': True,
+ 'uptodate': [doit.tools.timeout(datetime.timedelta(days=3))]
+ }
+
+ return task
diff --git a/nikola/plugins/task/redirect.plugin b/nikola/plugins/task/redirect.plugin
index c3137b9..c5a3042 100644
--- a/nikola/plugins/task/redirect.plugin
+++ b/nikola/plugins/task/redirect.plugin
@@ -5,7 +5,7 @@ module = redirect
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create redirect pages.
[Nikola]
diff --git a/nikola/plugins/task/redirect.py b/nikola/plugins/task/redirect.py
index 8530f5e..2d4eba4 100644
--- a/nikola/plugins/task/redirect.py
+++ b/nikola/plugins/task/redirect.py
@@ -35,7 +35,6 @@ from nikola import utils
class Redirect(Task):
-
"""Generate redirections."""
name = "redirect"
diff --git a/nikola/plugins/task/robots.plugin b/nikola/plugins/task/robots.plugin
index 72ce31f..7ae56c6 100644
--- a/nikola/plugins/task/robots.plugin
+++ b/nikola/plugins/task/robots.plugin
@@ -5,7 +5,7 @@ module = robots
[Documentation]
author = Daniel Aleksandersen
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate /robots.txt exclusion file and promote sitemap.
[Nikola]
diff --git a/nikola/plugins/task/robots.py b/nikola/plugins/task/robots.py
index 65254b6..7c7f5df 100644
--- a/nikola/plugins/task/robots.py
+++ b/nikola/plugins/task/robots.py
@@ -39,7 +39,6 @@ from nikola import utils
class RobotsFile(LateTask):
-
"""Generate a robots.txt file."""
name = "robots_file"
@@ -64,14 +63,15 @@ class RobotsFile(LateTask):
with io.open(robots_path, 'w+', encoding='utf8') as outf:
outf.write("Sitemap: {0}\n\n".format(sitemapindex_url))
+ outf.write("User-Agent: *\n")
if kw["robots_exclusions"]:
- outf.write("User-Agent: *\n")
for loc in kw["robots_exclusions"]:
outf.write("Disallow: {0}\n".format(loc))
+ outf.write("Host: {0}\n".format(urlparse(kw["base_url"]).netloc))
yield self.group_task()
- if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"]):
+ if not utils.get_asset_path("robots.txt", [], files_folders=kw["files_folders"], output_dir=False):
yield utils.apply_filters({
"basename": self.name,
"name": robots_path,
@@ -82,6 +82,6 @@ class RobotsFile(LateTask):
"task_dep": ["sitemap"]
}, kw["filters"])
elif kw["robots_exclusions"]:
- utils.LOGGER.warn('Did not generate robots.txt as one already exists in FILES_FOLDERS. ROBOTS_EXCLUSIONS will not have any affect on the copied fie.')
+ utils.LOGGER.warn('Did not generate robots.txt as one already exists in FILES_FOLDERS. ROBOTS_EXCLUSIONS will not have any affect on the copied file.')
else:
utils.LOGGER.debug('Did not generate robots.txt as one already exists in FILES_FOLDERS.')
diff --git a/nikola/plugins/task/rss.plugin b/nikola/plugins/task/rss.plugin
index cf9b7a7..4dd8aba 100644
--- a/nikola/plugins/task/rss.plugin
+++ b/nikola/plugins/task/rss.plugin
@@ -5,7 +5,7 @@ module = rss
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate RSS feeds.
[Nikola]
diff --git a/nikola/plugins/task/rss.py b/nikola/plugins/task/rss.py
index 9020a06..be57f5c 100644
--- a/nikola/plugins/task/rss.py
+++ b/nikola/plugins/task/rss.py
@@ -38,7 +38,6 @@ from nikola.plugin_categories import Task
class GenerateRSS(Task):
-
"""Generate RSS feeds."""
name = "generate_rss"
@@ -58,13 +57,14 @@ class GenerateRSS(Task):
"base_url": self.site.config["BASE_URL"],
"blog_description": self.site.config["BLOG_DESCRIPTION"],
"output_folder": self.site.config["OUTPUT_FOLDER"],
- "rss_teasers": self.site.config["RSS_TEASERS"],
- "rss_plain": self.site.config["RSS_PLAIN"],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
+ "feed_previewimage": self.site.config["FEED_PREVIEWIMAGE"],
"tzinfo": self.site.tzinfo,
- "rss_read_more_link": self.site.config["RSS_READ_MORE_LINK"],
- "rss_links_append_query": self.site.config["RSS_LINKS_APPEND_QUERY"],
+ "feed_read_more_link": self.site.config["FEED_READ_MORE_LINK"],
+ "feed_links_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
}
self.site.scan_posts()
# Check for any changes in the state of use_in_feeds for any post.
@@ -96,8 +96,8 @@ class GenerateRSS(Task):
'actions': [(utils.generic_rss_renderer,
(lang, kw["blog_title"](lang), kw["site_url"],
kw["blog_description"](lang), posts, output_name,
- kw["rss_teasers"], kw["rss_plain"], kw['feed_length'], feed_url,
- None, kw["rss_links_append_query"]))],
+ kw["feed_teasers"], kw["feed_plain"], kw['feed_length'], feed_url,
+ None, kw["feed_links_append_query"]))],
'task_dep': ['render_posts'],
'clean': True,
@@ -106,6 +106,11 @@ class GenerateRSS(Task):
yield utils.apply_filters(task, kw['filters'])
def rss_path(self, name, lang):
- """Return RSS path."""
+ """A link to the RSS feed path.
+
+ Example:
+
+ link://rss => /blog/rss.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
self.site.config['RSS_PATH'], 'rss.xml'] if _f]
diff --git a/nikola/plugins/task/scale_images.plugin b/nikola/plugins/task/scale_images.plugin
index d906b8c..3edd0c6 100644
--- a/nikola/plugins/task/scale_images.plugin
+++ b/nikola/plugins/task/scale_images.plugin
@@ -5,7 +5,7 @@ module = scale_images
[Documentation]
author = Pelle Nilsson
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Create down-scaled images and thumbnails.
[Nikola]
diff --git a/nikola/plugins/task/scale_images.py b/nikola/plugins/task/scale_images.py
index 22ed2ab..e55dc6c 100644
--- a/nikola/plugins/task/scale_images.py
+++ b/nikola/plugins/task/scale_images.py
@@ -34,7 +34,6 @@ from nikola import utils
class ScaleImage(Task, ImageProcessor):
-
"""Resize images and create thumbnails for them."""
name = "scale_images"
diff --git a/nikola/plugins/task/sitemap.plugin b/nikola/plugins/task/sitemap.plugin
index e3c991f..83e72c4 100644
--- a/nikola/plugins/task/sitemap.plugin
+++ b/nikola/plugins/task/sitemap.plugin
@@ -5,7 +5,7 @@ module = sitemap
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Generate google sitemap.
[Nikola]
diff --git a/nikola/plugins/task/sitemap/__init__.py b/nikola/plugins/task/sitemap/__init__.py
index fd781d6..90acdd3 100644
--- a/nikola/plugins/task/sitemap/__init__.py
+++ b/nikola/plugins/task/sitemap/__init__.py
@@ -31,6 +31,7 @@ import io
import datetime
import dateutil.tz
import os
+import sys
try:
from urlparse import urljoin, urlparse
import robotparser as robotparser
@@ -39,7 +40,7 @@ except ImportError:
import urllib.robotparser as robotparser # NOQA
from nikola.plugin_categories import LateTask
-from nikola.utils import config_changed, apply_filters
+from nikola.utils import apply_filters, config_changed, encodelink
urlset_header = """<?xml version="1.0" encoding="UTF-8"?>
@@ -106,7 +107,6 @@ def get_base_path(base):
class Sitemap(LateTask):
-
"""Generate a sitemap."""
name = "sitemap"
@@ -146,7 +146,10 @@ class Sitemap(LateTask):
continue # Totally empty, not on sitemap
path = os.path.relpath(root, output)
# ignore the current directory.
- path = (path.replace(os.sep, '/') + '/').replace('./', '')
+ if path == '.':
+ path = ''
+ else:
+ path = path.replace(os.sep, '/') + '/'
lastmod = self.get_lastmod(root)
loc = urljoin(base_url, base_path + path)
if kw['index_file'] in files and kw['strip_indexes']: # ignore folders when not stripping urls
@@ -157,10 +160,10 @@ class Sitemap(LateTask):
if post:
for lang in kw['translations']:
alt_url = post.permalink(lang=lang, absolute=True)
- if loc == alt_url:
+ if encodelink(loc) == alt_url:
continue
alternates.append(alternates_format.format(lang, alt_url))
- urlset[loc] = loc_format.format(loc, lastmod, ''.join(alternates))
+ urlset[loc] = loc_format.format(encodelink(loc), lastmod, ''.join(alternates))
for fname in files:
if kw['strip_indexes'] and fname == kw['index_file']:
continue # We already mapped the folder
@@ -200,7 +203,7 @@ class Sitemap(LateTask):
path = path.replace(os.sep, '/')
lastmod = self.get_lastmod(real_path)
loc = urljoin(base_url, base_path + path)
- sitemapindex[loc] = sitemap_format.format(loc, lastmod)
+ sitemapindex[loc] = sitemap_format.format(encodelink(loc), lastmod)
continue
else:
continue # ignores all XML files except those presumed to be RSS
@@ -214,18 +217,22 @@ class Sitemap(LateTask):
if post:
for lang in kw['translations']:
alt_url = post.permalink(lang=lang, absolute=True)
- if loc == alt_url:
+ if encodelink(loc) == alt_url:
continue
alternates.append(alternates_format.format(lang, alt_url))
- urlset[loc] = loc_format.format(loc, lastmod, '\n'.join(alternates))
+ urlset[loc] = loc_format.format(encodelink(loc), lastmod, '\n'.join(alternates))
def robot_fetch(path):
"""Check if robots can fetch a file."""
for rule in kw["robots_exclusions"]:
robot = robotparser.RobotFileParser()
robot.parse(["User-Agent: *", "Disallow: {0}".format(rule)])
- if not robot.can_fetch("*", '/' + path):
- return False # not robot food
+ if sys.version_info[0] == 3:
+ if not robot.can_fetch("*", '/' + path):
+ return False # not robot food
+ else:
+ if not robot.can_fetch("*", ('/' + path).encode('utf-8')):
+ return False # not robot food
return True
def write_sitemap():
diff --git a/nikola/plugins/task/sources.plugin b/nikola/plugins/task/sources.plugin
index d232c2b..66856f1 100644
--- a/nikola/plugins/task/sources.plugin
+++ b/nikola/plugins/task/sources.plugin
@@ -5,7 +5,7 @@ module = sources
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Copy page sources into the output.
[Nikola]
diff --git a/nikola/plugins/task/sources.py b/nikola/plugins/task/sources.py
index 87b4ae7..f782ad4 100644
--- a/nikola/plugins/task/sources.py
+++ b/nikola/plugins/task/sources.py
@@ -33,7 +33,6 @@ from nikola import utils
class Sources(Task):
-
"""Copy page sources into the output."""
name = "render_sources"
diff --git a/nikola/plugins/task/tags.plugin b/nikola/plugins/task/tags.plugin
index 283a16a..c3a5be3 100644
--- a/nikola/plugins/task/tags.plugin
+++ b/nikola/plugins/task/tags.plugin
@@ -5,7 +5,7 @@ module = tags
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Render the tag pages and feeds.
[Nikola]
diff --git a/nikola/plugins/task/tags.py b/nikola/plugins/task/tags.py
index 3186636..6d9d495 100644
--- a/nikola/plugins/task/tags.py
+++ b/nikola/plugins/task/tags.py
@@ -41,7 +41,6 @@ from nikola import utils
class RenderTags(Task):
-
"""Render the tag/category pages and feeds."""
name = "render_tags"
@@ -74,9 +73,9 @@ class RenderTags(Task):
'category_prefix': self.site.config['CATEGORY_PREFIX'],
"category_pages_are_indexes": self.site.config['CATEGORY_PAGES_ARE_INDEXES'],
"generate_rss": self.site.config['GENERATE_RSS'],
- "rss_teasers": self.site.config["RSS_TEASERS"],
- "rss_plain": self.site.config["RSS_PLAIN"],
- "rss_link_append_query": self.site.config["RSS_LINKS_APPEND_QUERY"],
+ "feed_teasers": self.site.config["FEED_TEASERS"],
+ "feed_plain": self.site.config["FEED_PLAIN"],
+ "feed_link_append_query": self.site.config["FEED_LINKS_APPEND_QUERY"],
"show_untranslated_posts": self.site.config['SHOW_UNTRANSLATED_POSTS'],
"feed_length": self.site.config['FEED_LENGTH'],
"taglist_minimum_post_count": self.site.config['TAGLIST_MINIMUM_POSTS'],
@@ -84,6 +83,10 @@ class RenderTags(Task):
"pretty_urls": self.site.config['PRETTY_URLS'],
"strip_indexes": self.site.config['STRIP_INDEXES'],
"index_file": self.site.config['INDEX_FILE'],
+ "category_pages_descriptions": self.site.config['CATEGORY_PAGES_DESCRIPTIONS'],
+ "category_pages_titles": self.site.config['CATEGORY_PAGES_TITLES'],
+ "tag_pages_descriptions": self.site.config['TAG_PAGES_DESCRIPTIONS'],
+ "tag_pages_titles": self.site.config['TAG_PAGES_TITLES'],
}
self.site.scan_posts()
@@ -168,7 +171,7 @@ class RenderTags(Task):
"""Write tag data into JSON file, for use in tag clouds."""
utils.makedirs(os.path.dirname(output_name))
with open(output_name, 'w+') as fd:
- json.dump(data, fd)
+ json.dump(data, fd, sort_keys=True)
if self.site.config['WRITE_TAG_CLOUD']:
task = {
@@ -199,7 +202,6 @@ class RenderTags(Task):
kw['tags'] = tags
output_name = os.path.join(
kw['output_folder'], self.site.path('tag_index' if has_tags else 'category_index', None, lang))
- output_name = output_name
context = {}
if has_categories and has_tags:
context["title"] = kw["messages"][lang]["Tags and Categories"]
@@ -251,6 +253,10 @@ class RenderTags(Task):
else:
return tag
+ def _get_indexes_title(self, tag, is_category, lang, messages):
+ titles = self.site.config['CATEGORY_PAGES_TITLES'] if is_category else self.site.config['TAG_PAGES_TITLES']
+ return titles[lang][tag] if lang in titles and tag in titles[lang] else messages[lang]["Posts about %s"] % tag
+
def _get_description(self, tag, is_category, lang):
descriptions = self.site.config['CATEGORY_PAGES_DESCRIPTIONS'] if is_category else self.site.config['TAG_PAGES_DESCRIPTIONS']
return descriptions[lang][tag] if lang in descriptions and tag in descriptions[lang] else None
@@ -276,7 +282,7 @@ class RenderTags(Task):
if kw["generate_rss"]:
# On a tag page, the feeds include the tag's feeds
rss_link = ("""<link rel="alternate" type="application/rss+xml" """
- """type="application/rss+xml" title="RSS for tag """
+ """title="RSS for tag """
"""{0} ({1})" href="{2}">""".format(
title, lang, self.site.link(kind + "_rss", tag, lang)))
context_source['rss_link'] = rss_link
@@ -284,7 +290,7 @@ class RenderTags(Task):
context_source["category"] = tag
context_source["category_path"] = self.site.parse_category_name(tag)
context_source["tag"] = title
- indexes_title = kw["messages"][lang]["Posts about %s"] % title
+ indexes_title = self._get_indexes_title(title, is_category, lang, kw["messages"])
context_source["description"] = self._get_description(tag, is_category, lang)
if is_category:
context_source["subcategories"] = self._get_subcategories(tag)
@@ -306,7 +312,7 @@ class RenderTags(Task):
context["category"] = tag
context["category_path"] = self.site.parse_category_name(tag)
context["tag"] = title
- context["title"] = kw["messages"][lang]["Posts about %s"] % title
+ context["title"] = self._get_indexes_title(title, is_category, lang, kw["messages"])
context["posts"] = post_list
context["permalink"] = self.site.link(kind, tag, lang)
context["kind"] = kind
@@ -326,6 +332,29 @@ class RenderTags(Task):
task['basename'] = str(self.name)
yield task
+ if self.site.config['GENERATE_ATOM']:
+ yield self.atom_feed_list(kind, tag, lang, post_list, context, kw)
+
+ def atom_feed_list(self, kind, tag, lang, post_list, context, kw):
+ """Generate atom feeds for tag lists."""
+ if kind == 'tag':
+ context['feedlink'] = self.site.abs_link(self.site.path('tag_atom', tag, lang))
+ feed_path = os.path.join(kw['output_folder'], self.site.path('tag_atom', tag, lang))
+ elif kind == 'category':
+ context['feedlink'] = self.site.abs_link(self.site.path('category_atom', tag, lang))
+ feed_path = os.path.join(kw['output_folder'], self.site.path('category_atom', tag, lang))
+
+ task = {
+ 'basename': str(self.name),
+ 'name': feed_path,
+ 'targets': [feed_path],
+ 'actions': [(self.site.atom_feed_renderer, (lang, post_list, feed_path, kw['filters'], context))],
+ 'clean': True,
+ 'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.tags:atom')],
+ 'task_dep': ['render_posts'],
+ }
+ return task
+
def tag_rss(self, tag, lang, posts, kw, is_category):
"""Create a RSS feed for a single tag in a given language."""
kind = "category" if is_category else "tag"
@@ -349,8 +378,8 @@ class RenderTags(Task):
'actions': [(utils.generic_rss_renderer,
(lang, "{0} ({1})".format(kw["blog_title"](lang), self._get_title(tag, is_category)),
kw["site_url"], None, post_list,
- output_name, kw["rss_teasers"], kw["rss_plain"], kw['feed_length'],
- feed_url, None, kw["rss_link_append_query"]))],
+ output_name, kw["feed_teasers"], kw["feed_plain"], kw['feed_length'],
+ feed_url, None, kw["feed_link_append_query"]))],
'clean': True,
'uptodate': [utils.config_changed(kw, 'nikola.plugins.task.tags:rss')] + deps_uptodate,
'task_dep': ['render_posts'],
@@ -364,41 +393,71 @@ class RenderTags(Task):
return name
def tag_index_path(self, name, lang):
- """Return path to the tag index."""
- return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
- self.site.config['INDEX_FILE']] if _f]
+ """A link to the tag index.
+
+ Example:
+
+ link://tag_index => /tags/index.html
+ """
+ if self.site.config['TAGS_INDEX_PATH'][lang]:
+ paths = [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['TAGS_INDEX_PATH'][lang]] if _f]
+ else:
+ paths = [_f for _f in [self.site.config['TRANSLATIONS'][lang],
+ self.site.config['TAG_PATH'][lang],
+ self.site.config['INDEX_FILE']] if _f]
+ return paths
def category_index_path(self, name, lang):
- """Return path to the category index."""
+ """A link to the category index.
+
+ Example:
+
+ link://category_index => /categories/index.html
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH'],
+ self.site.config['CATEGORY_PATH'][lang],
self.site.config['INDEX_FILE']] if _f]
def tag_path(self, name, lang):
- """Return path to a tag."""
+ """A link to a tag's page.
+
+ Example:
+
+ link://tag/cats => /tags/cats.html
+ """
if self.site.config['PRETTY_URLS']:
return [_f for _f in [
self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
+ self.site.config['TAG_PATH'][lang],
self.slugify_tag_name(name),
self.site.config['INDEX_FILE']] if _f]
else:
return [_f for _f in [
self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'],
+ self.site.config['TAG_PATH'][lang],
self.slugify_tag_name(name) + ".html"] if _f]
def tag_atom_path(self, name, lang):
- """Return path to a tag Atom feed."""
+ """A link to a tag's Atom feed.
+
+ Example:
+
+ link://tag_atom/cats => /tags/cats.atom
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'], self.slugify_tag_name(name) + ".atom"] if
+ self.site.config['TAG_PATH'][lang], self.slugify_tag_name(name) + ".atom"] if
_f]
def tag_rss_path(self, name, lang):
- """Return path to a tag RSS feed."""
+ """A link to a tag's RSS feed.
+
+ Example:
+
+ link://tag_rss/cats => /tags/cats.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['TAG_PATH'], self.slugify_tag_name(name) + ".xml"] if
+ self.site.config['TAG_PATH'][lang], self.slugify_tag_name(name) + ".xml"] if
_f]
def slugify_category_name(self, name):
@@ -417,24 +476,39 @@ class RenderTags(Task):
return path
def category_path(self, name, lang):
- """Return path to a category."""
+ """A link to a category.
+
+ Example:
+
+ link://category/dogs => /categories/dogs.html
+ """
if self.site.config['PRETTY_URLS']:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self.slugify_category_name(name) + [self.site.config['INDEX_FILE']]
else:
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".html")
def category_atom_path(self, name, lang):
- """Return path to a category Atom feed."""
+ """A link to a category's Atom feed.
+
+ Example:
+
+ link://category_atom/dogs => /categories/dogs.atom
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".atom")
def category_rss_path(self, name, lang):
- """Return path to a category RSS feed."""
+ """A link to a category's RSS feed.
+
+ Example:
+
+ link://category_rss/dogs => /categories/dogs.xml
+ """
return [_f for _f in [self.site.config['TRANSLATIONS'][lang],
- self.site.config['CATEGORY_PATH']] if
+ self.site.config['CATEGORY_PATH'][lang]] if
_f] + self._add_extension(self.slugify_category_name(name), ".xml")
diff --git a/nikola/plugins/template/jinja.plugin b/nikola/plugins/template/jinja.plugin
index cfe9fa8..78fd41b 100644
--- a/nikola/plugins/template/jinja.plugin
+++ b/nikola/plugins/template/jinja.plugin
@@ -5,7 +5,7 @@ module = jinja
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Support for Jinja2 templates.
[Nikola]
diff --git a/nikola/plugins/template/jinja.py b/nikola/plugins/template/jinja.py
index b02d75c..e7df102 100644
--- a/nikola/plugins/template/jinja.py
+++ b/nikola/plugins/template/jinja.py
@@ -42,7 +42,6 @@ from nikola.utils import makedirs, req_missing
class JinjaTemplates(TemplateSystem):
-
"""Support for Jinja2 templates."""
name = "jinja"
diff --git a/nikola/plugins/template/mako.plugin b/nikola/plugins/template/mako.plugin
index d256faf..308d291 100644
--- a/nikola/plugins/template/mako.plugin
+++ b/nikola/plugins/template/mako.plugin
@@ -5,7 +5,7 @@ module = mako
[Documentation]
author = Roberto Alsina
version = 1.0
-website = http://getnikola.com
+website = https://getnikola.com/
description = Support for Mako templates.
[Nikola]
diff --git a/nikola/plugins/template/mako.py b/nikola/plugins/template/mako.py
index aed6596..6da21db 100644
--- a/nikola/plugins/template/mako.py
+++ b/nikola/plugins/template/mako.py
@@ -44,7 +44,6 @@ LOGGER = get_logger('mako', STDERR_HANDLER)
class MakoTemplates(TemplateSystem):
-
"""Support for Mako templates."""
name = "mako"
diff --git a/nikola/post.py b/nikola/post.py
index 7badfc6..f8039e0 100644
--- a/nikola/post.py
+++ b/nikola/post.py
@@ -56,7 +56,6 @@ from math import ceil
# for tearDown with _reload we cannot use 'from import' to get forLocaleBorg
import nikola.utils
from .utils import (
- bytes_str,
current_time,
Functionary,
LOGGER,
@@ -77,7 +76,6 @@ _UPGRADE_METADATA_ADVERTISED = False
class Post(object):
-
"""Represent a blog post or site page."""
def __init__(
@@ -130,7 +128,6 @@ class Post(object):
self._template_name = template_name
self.is_two_file = True
self.newstylemeta = True
- self.hyphenate = self.config['HYPHENATE']
self._reading_time = None
self._remaining_reading_time = None
self._paragraph_count = None
@@ -232,6 +229,11 @@ class Post(object):
# Register potential extra dependencies
self.compiler.register_extra_dependencies(self)
+ def _get_hyphenate(self):
+ return bool(self.config['HYPHENATE'] or self.meta('hyphenate'))
+
+ hyphenate = property(_get_hyphenate)
+
def __repr__(self):
"""Provide a representation of the post object."""
# Calculate a hash that represents most data about the post
@@ -320,23 +322,12 @@ class Post(object):
@property
def template_name(self):
"""Return template name for this post."""
- return self.meta('template') or self._template_name
+ lang = nikola.utils.LocaleBorg().current_lang
+ return self.meta[lang]['template'] or self._template_name
def formatted_date(self, date_format, date=None):
"""Return the formatted date as unicode."""
- date = date if date else self.date
-
- if date_format == 'webiso':
- # Formatted after RFC 3339 (web ISO 8501 profile) with Zulu
- # zone desgignator for times in UTC and no microsecond precision.
- fmt_date = date.replace(microsecond=0).isoformat().replace('+00:00', 'Z')
- else:
- fmt_date = date.strftime(date_format)
-
- # Issue #383, this changes from py2 to py3
- if isinstance(fmt_date, bytes_str):
- fmt_date = fmt_date.decode('utf8')
- return fmt_date
+ return utils.LocaleBorg().formatted_date(date_format, date if date else self.date)
def formatted_updated(self, date_format):
"""Return the updated date as unicode."""
@@ -447,11 +438,16 @@ class Post(object):
if self.default_lang in self.translated_to:
deps.append(self.base_path)
deps.append(self.source_path)
+ if os.path.exists(self.metadata_path):
+ deps.append(self.metadata_path)
if lang != self.default_lang:
cand_1 = get_translation_candidate(self.config, self.source_path, lang)
cand_2 = get_translation_candidate(self.config, self.base_path, lang)
if os.path.exists(cand_1):
deps.extend([cand_1, cand_2])
+ cand_3 = get_translation_candidate(self.config, self.metadata_path, lang)
+ if os.path.exists(cand_3):
+ deps.append(cand_3)
deps += self._get_dependencies(self._dependency_file_page[lang])
deps += self._get_dependencies(self._dependency_file_page[None])
return sorted(deps)
@@ -558,13 +554,13 @@ class Post(object):
return get_translation_candidate(self.config, self.base_path, sorted(self.translated_to)[0])
def text(self, lang=None, teaser_only=False, strip_html=False, show_read_more_link=True,
- rss_read_more_link=False, rss_links_append_query=None):
+ feed_read_more_link=False, feed_links_append_query=None):
"""Read the post file for that language and return its contents.
teaser_only=True breaks at the teaser marker and returns only the teaser.
strip_html=True removes HTML tags
show_read_more_link=False does not add the Read more... link
- rss_read_more_link=True uses RSS_READ_MORE_LINK instead of INDEX_READ_MORE_LINK
+ feed_read_more_link=True uses FEED_READ_MORE_LINK instead of INDEX_READ_MORE_LINK
lang=None uses the last used to set locale
All links in the returned HTML will be relative.
@@ -613,9 +609,9 @@ class Post(object):
teaser_text = teaser_regexp.search(data).groups()[-1]
else:
teaser_text = self.messages[lang]["Read more"]
- l = self.config['RSS_READ_MORE_LINK'](lang) if rss_read_more_link else self.config['INDEX_READ_MORE_LINK'](lang)
+ l = self.config['FEED_READ_MORE_LINK'](lang) if feed_read_more_link else self.config['INDEX_READ_MORE_LINK'](lang)
teaser += l.format(
- link=self.permalink(lang, query=rss_links_append_query),
+ link=self.permalink(lang, query=feed_links_append_query),
read_more=teaser_text,
min_remaining_read=self.messages[lang]["%d min remaining to read"] % (self.remaining_reading_time),
reading_time=self.reading_time,
@@ -715,10 +711,9 @@ class Post(object):
def source_link(self, lang=None):
"""Return absolute link to the post's source."""
ext = self.source_ext(True)
- return "/" + self.destination_path(
- lang=lang,
- extension=ext,
- sep='/')
+ link = "/" + self.destination_path(lang=lang, extension=ext, sep='/')
+ link = utils.encodelink(link)
+ return link
def destination_path(self, lang=None, extension='.html', sep=os.sep):
"""Destination path for this post, relative to output/.
@@ -740,6 +735,61 @@ class Post(object):
path = path[2:]
return path
+ def section_color(self, lang=None):
+ """Return the color of the post's section."""
+ slug = self.section_slug(lang)
+ if slug in self.config['POSTS_SECTION_COLORS'](lang):
+ return self.config['POSTS_SECTION_COLORS'](lang)[slug]
+ base = self.config['THEME_COLOR']
+ return utils.colorize_str_from_base_color(slug, base)
+
+ def section_link(self, lang=None):
+ """Return the link to the post's section (deprecated)."""
+ utils.LOGGER.warning("Post.section_link is deprecated. Please use " +
+ "site.link('section_index', post.section_slug()) instead.")
+ if lang is None:
+ lang = nikola.utils.LocaleBorg().current_lang
+
+ slug = self.section_slug(lang)
+ t = os.path.normpath(self.translations[lang])
+ if t == '.':
+ t = ''
+ link = '/' + '/'.join(i for i in (t, slug) if i) + '/'
+ if not self.pretty_urls:
+ link = urljoin(link, self.index_file)
+ link = utils.encodelink(link)
+ return link
+
+ def section_name(self, lang=None):
+ """Return the name of the post's section."""
+ slug = self.section_slug(lang)
+ if slug in self.config['POSTS_SECTION_NAME'](lang):
+ name = self.config['POSTS_SECTION_NAME'](lang)[slug]
+ else:
+ name = slug.replace('-', ' ').title()
+ return name
+
+ def section_slug(self, lang=None):
+ """Return the slug for the post's section."""
+ if lang is None:
+ lang = nikola.utils.LocaleBorg().current_lang
+
+ if not self.config['POSTS_SECTION_FROM_META']:
+ dest = self.destination_path(lang)
+ if dest[-(1 + len(self.index_file)):] == os.sep + self.index_file:
+ dest = dest[:-(1 + len(self.index_file))]
+ dirname = os.path.dirname(dest)
+ slug = dest.split(os.sep)
+ if not slug or dirname == '.':
+ slug = self.messages[lang]["Uncategorized"]
+ elif lang == slug[0]:
+ slug = slug[1]
+ else:
+ slug = slug[0]
+ else:
+ slug = self.meta[lang]['section'].split(',')[0] if 'section' in self.meta[lang] else self.messages[lang]["Uncategorized"]
+ return utils.slugify(slug)
+
def permalink(self, lang=None, absolute=False, extension='.html', query=None):
"""Return permalink for a post."""
if lang is None:
@@ -764,6 +814,7 @@ class Post(object):
link = link[:-index_len]
if query:
link = link + "?" + query
+ link = utils.encodelink(link)
return link
@property
@@ -842,7 +893,7 @@ def get_metadata_from_file(source_path, config=None, lang=None):
source_path = get_translation_candidate(config, source_path, lang)
elif lang:
source_path += '.' + lang
- with io.open(source_path, "r", encoding="utf8") as meta_file:
+ with io.open(source_path, "r", encoding="utf-8-sig") as meta_file:
meta_data = [x.strip() for x in meta_file.readlines()]
return _get_metadata_from_file(meta_data)
except (UnicodeDecodeError, UnicodeEncodeError):
@@ -851,18 +902,37 @@ def get_metadata_from_file(source_path, config=None, lang=None):
return {}
+re_md_title = re.compile(r'^{0}([^{0}].*)'.format(re.escape('#')))
+# Assuming rst titles are going to be at least 4 chars long
+# otherwise this detects things like ''' wich breaks other markups.
+re_rst_title = re.compile(r'^([{0}]{{4,}})'.format(re.escape(
+ string.punctuation)))
+
+
+def _get_title_from_contents(meta_data):
+ """Extract title from file contents, LAST RESOURCE."""
+ piece = meta_data[:]
+ title = None
+ for i, line in enumerate(piece):
+ if re_rst_title.findall(line) and i > 0:
+ title = meta_data[i - 1].strip()
+ break
+ if (re_rst_title.findall(line) and i >= 0 and
+ re_rst_title.findall(meta_data[i + 2])):
+ title = meta_data[i + 1].strip()
+ break
+ if re_md_title.findall(line):
+ title = re_md_title.findall(line)[0]
+ break
+ return title
+
+
def _get_metadata_from_file(meta_data):
"""Extract metadata from a post's source file."""
meta = {}
if not meta_data:
return meta
- re_md_title = re.compile(r'^{0}([^{0}].*)'.format(re.escape('#')))
- # Assuming rst titles are going to be at least 4 chars long
- # otherwise this detects things like ''' wich breaks other markups.
- re_rst_title = re.compile(r'^([{0}]{{4,}})'.format(re.escape(
- string.punctuation)))
-
# Skip up to one empty line at the beginning (for txt2tags)
if not meta_data[0]:
meta_data = meta_data[1:]
@@ -879,18 +949,9 @@ def _get_metadata_from_file(meta_data):
# If we have no title, try to get it from document
if 'title' not in meta:
- piece = meta_data[:]
- for i, line in enumerate(piece):
- if re_rst_title.findall(line) and i > 0:
- meta['title'] = meta_data[i - 1].strip()
- break
- if (re_rst_title.findall(line) and i >= 0 and
- re_rst_title.findall(meta_data[i + 2])):
- meta['title'] = meta_data[i + 1].strip()
- break
- if re_md_title.findall(line):
- meta['title'] = re_md_title.findall(line)[0]
- break
+ t = _get_title_from_contents(meta_data)
+ if t is not None:
+ meta['title'] = t
return meta
@@ -1015,7 +1076,11 @@ def hyphenate(dom, _lang):
"""Hyphenate a post."""
# circular import prevention
from .nikola import LEGAL_VALUES
- lang = LEGAL_VALUES['PYPHEN_LOCALES'].get(_lang, pyphen.language_fallback(_lang))
+ lang = None
+ if pyphen is not None:
+ lang = LEGAL_VALUES['PYPHEN_LOCALES'].get(_lang, pyphen.language_fallback(_lang))
+ else:
+ utils.req_missing(['pyphen'], 'hyphenate texts', optional=True)
if pyphen is not None and lang is not None:
# If pyphen does exist, we tell the user when configuring the site.
# If it does not support a language, we ignore it quietly.
diff --git a/nikola/utils.py b/nikola/utils.py
index 3a268ff..3359514 100644
--- a/nikola/utils.py
+++ b/nikola/utils.py
@@ -31,6 +31,7 @@ import calendar
import datetime
import dateutil.tz
import hashlib
+import husl
import io
import locale
import logging
@@ -39,20 +40,30 @@ import os
import re
import json
import shutil
+import socket
import subprocess
import sys
import dateutil.parser
import dateutil.tz
import logbook
+try:
+ from urllib import quote as urlquote
+ from urllib import unquote as urlunquote
+ from urlparse import urlparse, urlunparse
+except ImportError:
+ from urllib.parse import quote as urlquote # NOQA
+ from urllib.parse import unquote as urlunquote # NOQA
+ from urllib.parse import urlparse, urlunparse # NOQA
import warnings
import PyRSS2Gen as rss
-from collections import defaultdict, Callable
+from collections import defaultdict, Callable, OrderedDict
from logbook.compat import redirect_logging
from logbook.more import ExceptionHandler, ColorizedStderrHandler
from pygments.formatters import HtmlFormatter
from zipfile import ZipFile as zipf
from doit import tools
from unidecode import unidecode
+from unicodedata import normalize as unicodenormalize
from pkg_resources import resource_filename
from doit.cmdparse import CmdParse
@@ -94,7 +105,6 @@ class ApplicationWarning(Exception):
class ColorfulStderrHandler(ColorizedStderrHandler):
-
"""Stream handler with colors."""
_colorful = False
@@ -116,7 +126,7 @@ def get_logger(name, handlers):
STDERR_HANDLER = [ColorfulStderrHandler(
- level=logbook.INFO if not DEBUG else logbook.DEBUG,
+ level=logbook.NOTICE if not DEBUG else logbook.DEBUG,
format_string=u'[{record.time:%Y-%m-%dT%H:%M:%SZ}] {record.level_name}: {record.channel}: {record.message}'
)]
@@ -228,7 +238,6 @@ def makedirs(path):
class Functionary(defaultdict):
-
"""Class that looks like a function, but is a defaultdict."""
def __init__(self, default, default_lang):
@@ -244,7 +253,6 @@ class Functionary(defaultdict):
class TranslatableSetting(object):
-
"""A setting that can be translated.
You can access it via: SETTING(lang). You can omit lang, in which
@@ -423,15 +431,20 @@ class TranslatableSetting(object):
def __eq__(self, other):
"""Test whether two TranslatableSettings are equal."""
- return self.values == other.values
+ try:
+ return self.values == other.values
+ except AttributeError:
+ return self(self.default_lang) == other
def __ne__(self, other):
"""Test whether two TranslatableSettings are inequal."""
- return self.values != other.values
+ try:
+ return self.values != other.values
+ except AttributeError:
+ return self(self.default_lang) != other
class TemplateHookRegistry(object):
-
r"""A registry for template hooks.
Usage:
@@ -497,7 +510,6 @@ class TemplateHookRegistry(object):
class CustomEncoder(json.JSONEncoder):
-
"""Custom JSON encoder."""
def default(self, obj):
@@ -513,7 +525,6 @@ class CustomEncoder(json.JSONEncoder):
class config_changed(tools.config_changed):
-
"""A copy of doit's config_changed, using pickle instead of serializing manually."""
def __init__(self, config, identifier=None):
@@ -610,7 +621,6 @@ language_incomplete_warned = []
class LanguageNotFoundError(Exception):
-
"""An exception thrown if language is not found."""
def __init__(self, lang, orig):
@@ -724,7 +734,7 @@ def remove_file(source):
elif os.path.isfile(source) or os.path.islink(source):
os.remove(source)
-# slugify is copied from
+# slugify is adopted from
# http://code.activestate.com/recipes/
# 577257-slugify-make-a-string-usable-in-a-url-or-filename/
_slugify_strip_re = re.compile(r'[^+\w\s-]')
@@ -782,11 +792,23 @@ def unslugify(value, discard_numbers=True):
return value
+def encodelink(iri):
+ """Given an encoded or unencoded link string, return an encoded string suitable for use as a link in HTML and XML."""
+ iri = unicodenormalize('NFC', iri)
+ link = OrderedDict(urlparse(iri)._asdict())
+ link['path'] = urlquote(urlunquote(link['path']).encode('utf-8'))
+ try:
+ link['netloc'] = link['netloc'].encode('utf-8').decode('idna').encode('idna').decode('utf-8')
+ except UnicodeDecodeError:
+ link['netloc'] = link['netloc'].encode('idna').decode('utf-8')
+ encoded_link = urlunparse(link.values())
+ return encoded_link
+
# A very slightly safer version of zip.extractall that works on
# python < 2.6
-class UnsafeZipException(Exception):
+class UnsafeZipException(Exception):
"""Exception for unsafe zip files."""
pass
@@ -945,12 +967,14 @@ def get_crumbs(path, is_file=False, index_folder=None):
return list(reversed(_crumbs))
-def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='themes'):
+def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='themes', output_dir='output'):
"""Return the "real", absolute path to the asset.
By default, it checks which theme provides the asset.
If the asset is not provided by a theme, then it will be checked for
in the FILES_FOLDERS.
+ If it's not provided by either, it will be chacked in output, where
+ it may have been created by another plugin.
>>> print(get_asset_path('assets/css/rst.css', ['bootstrap3', 'base']))
/.../nikola/data/themes/base/assets/css/rst.css
@@ -961,9 +985,12 @@ def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='theme
>>> print(get_asset_path('nikola.py', ['bootstrap3', 'base'], {'nikola': ''}))
/.../nikola/nikola.py
- >>> print(get_asset_path('nikola/nikola.py', ['bootstrap3', 'base'], {'nikola':'nikola'}))
+ >>> print(get_asset_path('nikola.py', ['bootstrap3', 'base'], {'nikola': 'nikola'}))
None
+ >>> print(get_asset_path('nikola/nikola.py', ['bootstrap3', 'base'], {'nikola': 'nikola'}))
+ /.../nikola/nikola.py
+
"""
for theme_name in themes:
candidate = os.path.join(
@@ -973,7 +1000,14 @@ def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='theme
if os.path.isfile(candidate):
return candidate
for src, rel_dst in files_folders.items():
- candidate = os.path.abspath(os.path.join(src, path))
+ relpath = os.path.normpath(os.path.relpath(path, rel_dst))
+ if not relpath.startswith('..' + os.path.sep):
+ candidate = os.path.abspath(os.path.join(src, relpath))
+ if os.path.isfile(candidate):
+ return candidate
+
+ if output_dir:
+ candidate = os.path.join(output_dir, path)
if os.path.isfile(candidate):
return candidate
@@ -982,7 +1016,6 @@ def get_asset_path(path, themes, files_folders={'files': ''}, _themes_dir='theme
class LocaleBorgUninitializedException(Exception):
-
"""Exception for unitialized LocaleBorg."""
def __init__(self):
@@ -991,7 +1024,6 @@ class LocaleBorgUninitializedException(Exception):
class LocaleBorg(object):
-
"""Provide locale related services and autoritative current_lang.
current_lang is the last lang for which the locale was set
@@ -1040,6 +1072,8 @@ class LocaleBorg(object):
assert initial_lang is not None and initial_lang in locales
cls.reset()
cls.locales = locales
+ cls.month_name_handlers = []
+ cls.formatted_date_handlers = []
# needed to decode some localized output in py2x
encodings = {}
@@ -1049,25 +1083,71 @@ class LocaleBorg(object):
encodings[lang] = encoding
cls.encodings = encodings
- cls.__shared_state['current_lang'] = initial_lang
+ cls.__initial_lang = initial_lang
cls.initialized = True
+ def __get_shared_state(self):
+ if not self.initialized:
+ raise LocaleBorgUninitializedException()
+ shared_state = getattr(self.__thread_local, 'shared_state', None)
+ if shared_state is None:
+ shared_state = {'current_lang': self.__initial_lang}
+ self.__thread_local.shared_state = shared_state
+ return shared_state
+
@classmethod
def reset(cls):
"""Reset LocaleBorg.
Used in testing to prevent leaking state between tests.
"""
+ import threading
+ cls.__thread_local = threading.local()
+ cls.__thread_lock = threading.Lock()
+
cls.locales = {}
cls.encodings = {}
- cls.__shared_state = {'current_lang': None}
cls.initialized = False
+ cls.month_name_handlers = []
+ cls.formatted_date_handlers = []
+ cls.thread_local = None
+ cls.thread_lock = None
+
+ @classmethod
+ def add_handler(cls, month_name_handler=None, formatted_date_handler=None):
+ """Allow to add month name and formatted date handlers.
+
+ If month_name_handler is not None, it is expected to be a callable
+ which accepts (month_no, lang) and returns either a string or None.
+
+ If formatted_date_handler is not None, it is expected to be a callable
+ which accepts (date_format, date, lang) and returns either a string or
+ None.
+
+ A handler is expected to either return the correct result for the given
+ language and data, or return None to indicate it is not able to do the
+ job. In that case, the next handler is asked, and finally the default
+ implementation is used.
+ """
+ if month_name_handler is not None:
+ cls.month_name_handlers.append(month_name_handler)
+ if formatted_date_handler is not None:
+ cls.formatted_date_handlers.append(formatted_date_handler)
def __init__(self):
"""Initialize."""
if not self.initialized:
raise LocaleBorgUninitializedException()
- self.__dict__ = self.__shared_state
+
+ @property
+ def current_lang(self):
+ """Return the current language."""
+ return self.__get_shared_state()['current_lang']
+
+ def __set_locale(self, lang):
+ """Set the locale for language lang without updating current_lang."""
+ locale_n = self.locales[lang]
+ locale.setlocale(locale.LC_ALL, locale_n)
def set_locale(self, lang):
"""Set the locale for language lang, returns an empty string.
@@ -1076,36 +1156,70 @@ class LocaleBorg(object):
in windows that cannot be guaranted.
In either case, the locale encoding is available in cls.encodings[lang]
"""
- # intentional non try-except: templates must ask locales with a lang,
- # let the code explode here and not hide the point of failure
- # Also, not guarded with an if lang==current_lang because calendar may
- # put that out of sync
- locale_n = self.locales[lang]
- self.__shared_state['current_lang'] = lang
- locale.setlocale(locale.LC_ALL, locale_n)
- return ''
+ with self.__thread_lock:
+ # intentional non try-except: templates must ask locales with a lang,
+ # let the code explode here and not hide the point of failure
+ # Also, not guarded with an if lang==current_lang because calendar may
+ # put that out of sync
+ self.__set_locale(lang)
+ self.__get_shared_state()['current_lang'] = lang
+ return ''
def get_month_name(self, month_no, lang):
"""Return localized month name in an unicode string."""
- if sys.version_info[0] == 3: # Python 3
- with calendar.different_locale(self.locales[lang]):
- s = calendar.month_name[month_no]
- # for py3 s is unicode
- else: # Python 2
- with calendar.TimeEncoding(self.locales[lang]):
- s = calendar.month_name[month_no]
- enc = self.encodings[lang]
- if not enc:
- enc = 'UTF-8'
-
- s = s.decode(enc)
- # paranoid about calendar ending in the wrong locale (windows)
- self.set_locale(self.current_lang)
- return s
+ # For thread-safety
+ with self.__thread_lock:
+ for handler in self.month_name_handlers:
+ res = handler(month_no, lang)
+ if res is not None:
+ return res
+ if sys.version_info[0] == 3: # Python 3
+ with calendar.different_locale(self.locales[lang]):
+ s = calendar.month_name[month_no]
+ # for py3 s is unicode
+ else: # Python 2
+ with calendar.TimeEncoding(self.locales[lang]):
+ s = calendar.month_name[month_no]
+ enc = self.encodings[lang]
+ if not enc:
+ enc = 'UTF-8'
+
+ s = s.decode(enc)
+ # paranoid about calendar ending in the wrong locale (windows)
+ self.__set_locale(self.current_lang)
+ return s
+ def formatted_date(self, date_format, date):
+ """Return the formatted date as unicode."""
+ with self.__thread_lock:
+ current_lang = self.current_lang
+ # For thread-safety
+ self.__set_locale(current_lang)
+ fmt_date = None
+ # Get a string out of a TranslatableSetting
+ if isinstance(date_format, TranslatableSetting):
+ date_format = date_format(current_lang)
+ # First check handlers
+ for handler in self.formatted_date_handlers:
+ fmt_date = handler(date_format, date, current_lang)
+ if fmt_date is not None:
+ break
+ # If no handler was able to format the date, ask Python
+ if fmt_date is None:
+ if date_format == 'webiso':
+ # Formatted after RFC 3339 (web ISO 8501 profile) with Zulu
+ # zone desgignator for times in UTC and no microsecond precision.
+ fmt_date = date.replace(microsecond=0).isoformat().replace('+00:00', 'Z')
+ else:
+ fmt_date = date.strftime(date_format)
-class ExtendedRSS2(rss.RSS2):
+ # Issue #383, this changes from py2 to py3
+ if isinstance(fmt_date, bytes_str):
+ fmt_date = fmt_date.decode('utf8')
+ return fmt_date
+
+class ExtendedRSS2(rss.RSS2):
"""Extended RSS class."""
xsl_stylesheet_href = None
@@ -1129,7 +1243,6 @@ class ExtendedRSS2(rss.RSS2):
class ExtendedItem(rss.RSSItem):
-
"""Extended RSS item."""
def __init__(self, **kw):
@@ -1326,7 +1439,6 @@ def ask_yesno(query, default=None):
class CommandWrapper(object):
-
"""Converts commands into functions."""
def __init__(self, cmd, commands_object):
@@ -1342,7 +1454,6 @@ class CommandWrapper(object):
class Commands(object):
-
"""Nikola Commands.
Sample usage:
@@ -1433,7 +1544,6 @@ def options2docstring(name, options):
class NikolaPygmentsHTML(HtmlFormatter):
-
"""A Nikola-specific modification of Pygments' HtmlFormatter."""
def __init__(self, anchor_ref, classes=None, linenos='table', linenostart=1):
@@ -1540,7 +1650,6 @@ def create_redirect(src, dst):
class TreeNode(object):
-
"""A tree node."""
indent_levels = None # use for formatting comments as tree
@@ -1673,6 +1782,73 @@ def join_hierarchical_category_path(category_path):
return '/'.join([escape(p) for p in category_path])
+def colorize_str_from_base_color(string, base_color):
+ """Find a perceptual similar color from a base color based on the hash of a string.
+
+ Make up to 16 attempts (number of bytes returned by hashing) at picking a
+ hue for our color at least 27 deg removed from the base color, leaving
+ lightness and saturation untouched using HUSL colorspace.
+ """
+ def hash_str(string, pos):
+ return hashlib.md5(string.encode('utf-8')).digest()[pos]
+
+ def degreediff(dega, degb):
+ return min(abs(dega - degb), abs((degb - dega) + 360))
+
+ def husl_similar_from_base(string, base_color):
+ h, s, l = husl.hex_to_husl(base_color)
+ old_h = h
+ idx = 0
+ while degreediff(old_h, h) < 27 and idx < 16:
+ h = 360.0 * (float(hash_str(string, idx)) / 255)
+ idx += 1
+ return husl.husl_to_hex(h, s, l)
+
+ return husl_similar_from_base(string, base_color)
+
+
+def color_hsl_adjust_hex(hexstr, adjust_h=None, adjust_s=None, adjust_l=None):
+ """Adjust a hex color using HSL arguments, adjustments in percentages 1.0 to -1.0. Returns a hex color."""
+ h, s, l = husl.hex_to_husl(hexstr)
+
+ if adjust_h:
+ h = h + (adjust_h * 360.0)
+
+ if adjust_s:
+ s = s + (adjust_s * 100.0)
+
+ if adjust_l:
+ l = l + (adjust_l * 100.0)
+
+ return husl.husl_to_hex(h, s, l)
+
+
+def dns_sd(port, inet6):
+ """Optimistically publish a HTTP service to the local network over DNS-SD.
+
+ Works only on Linux/FreeBSD. Requires the `avahi` and `dbus` modules (symlinks in virtualenvs)
+ """
+ try:
+ import avahi
+ import dbus
+ inet = avahi.PROTO_INET6 if inet6 else avahi.PROTO_INET
+ name = "{0}'s Nikola Server on {1}".format(os.getlogin(), socket.gethostname())
+ bus = dbus.SystemBus()
+ bus_server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
+ avahi.DBUS_PATH_SERVER),
+ avahi.DBUS_INTERFACE_SERVER)
+ bus_group = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
+ bus_server.EntryGroupNew()),
+ avahi.DBUS_INTERFACE_ENTRY_GROUP)
+ bus_group.AddService(avahi.IF_UNSPEC, inet, dbus.UInt32(0),
+ name, '_http._tcp', '', '',
+ dbus.UInt16(port), '')
+ bus_group.Commit()
+ return bus_group # remember to bus_group.Reset() to unpublish
+ except Exception:
+ return None
+
+
# Stolen from textwrap in Python 3.4.3.
def indent(text, prefix, predicate=None):
"""Add 'prefix' to the beginning of selected lines in 'text'.