+:Date: 2011-09-15 09:05
+:Category: Blog
+:Tags: Linux, Python, Pelican
+
+== Used for pelican test
+
+The quick brown fox jumped over the lazy dog's back.
diff --git a/plugins/asciidoc_reader/test_data/article_with_asc_options.asc b/plugins/asciidoc_reader/test_data/article_with_asc_options.asc
new file mode 100644
index 0000000..620abba
--- /dev/null
+++ b/plugins/asciidoc_reader/test_data/article_with_asc_options.asc
@@ -0,0 +1,7 @@
+= Test AsciiDoc File Header
+
+== Used for pelican test
+
+version {revision}
+
+The quick brown fox jumped over the lazy dog's back.
diff --git a/plugins/assets/Readme.rst b/plugins/assets/Readme.rst
new file mode 100644
index 0000000..42091cb
--- /dev/null
+++ b/plugins/assets/Readme.rst
@@ -0,0 +1,106 @@
+Asset management
+----------------
+
+This plugin allows you to use the `Webassets`_ module to manage assets such as
+CSS and JS files. The module must first be installed::
+
+ pip install webassets
+
+The Webassets module allows you to perform a number of useful asset management
+functions, including:
+
+* CSS minifier (``cssmin``, ``yui_css``, ...)
+* CSS compiler (``less``, ``sass``, ...)
+* JS minifier (``uglifyjs``, ``yui_js``, ``closure``, ...)
+
+Others filters include CSS URL rewriting, integration of images in CSS via data
+URIs, and more. Webassets can also append a version identifier to your asset
+URL to convince browsers to download new versions of your assets when you use
+far-future expires headers. Please refer to the `Webassets documentation`_ for
+more information.
+
+When used with Pelican, Webassets is configured to process assets in the
+``OUTPUT_PATH/theme`` directory. You can use Webassets in your templates by
+including one or more template tags. The Jinja variable ``{{ ASSET_URL }}`` can
+be used in templates and is relative to the ``theme/`` url. The
+``{{ ASSET_URL }}`` variable should be used in conjunction with the
+``{{ SITEURL }}`` variable in order to generate URLs properly. For example:
+
+.. code-block:: jinja
+
+ {% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %}
+
+ {% endassets %}
+
+... will produce a minified css file with a version identifier that looks like:
+
+.. code-block:: html
+
+
+
+These filters can be combined. Here is an example that uses the SASS compiler
+and minifies the output:
+
+.. code-block:: jinja
+
+ {% assets filters="sass,cssmin", output="css/style.min.css", "css/style.scss" %}
+
+ {% endassets %}
+
+Another example for Javascript:
+
+.. code-block:: jinja
+
+ {% assets filters="uglifyjs", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %}
+
+ {% endassets %}
+
+The above will produce a minified JS file:
+
+.. code-block:: html
+
+
+
+Pelican's debug mode is propagated to Webassets to disable asset packaging
+and instead work with the uncompressed assets.
+
+If you need to create named bundles (for example, if you need to compile SASS
+files before minifying with other CSS files), you can use the ``ASSET_BUNDLES``
+variable in your settings file. This is an ordered sequence of 3-tuples, where
+the 3-tuple is defined as ``(name, args, kwargs)``. This tuple is passed to the
+`environment's register() method`_. The following will compile two SCSS files
+into a named bundle, using the ``pyscss`` filter:
+
+.. code-block:: python
+
+ ASSET_BUNDLES = (
+ ('scss', ['colors.scss', 'main.scss'], {'filters': 'pyscss'}),
+ )
+
+Many of Webasset's available compilers have additional configuration options
+(i.e. 'Less', 'Sass', 'Stylus', 'Closure_js'). You can pass these options to
+Webassets using the ``ASSET_CONFIG`` in your settings file.
+
+The following will handle Google Closure's compilation level and locate
+LessCSS's binary:
+
+.. code-block:: python
+
+ ASSET_CONFIG = (('closure_compressor_optimization', 'WHITESPACE_ONLY'),
+ ('less_bin', 'lessc.cmd'), )
+
+If you wish to place your assets in locations other than the theme output
+directory, you can use ``ASSET_SOURCE_PATHS`` in your settings file to provide
+webassets with a list of additional directories to search, relative to the
+theme's top-level directory:
+
+.. code-block:: python
+
+ ASSET_SOURCE_PATHS = [
+ 'vendor/css',
+ 'scss',
+ ]
+
+.. _Webassets: https://github.com/miracle2k/webassets
+.. _Webassets documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html
+.. _environment's register() method: http://webassets.readthedocs.org/en/latest/environment.html#registering-bundles
diff --git a/plugins/assets/__init__.py b/plugins/assets/__init__.py
new file mode 100644
index 0000000..67b75dd
--- /dev/null
+++ b/plugins/assets/__init__.py
@@ -0,0 +1 @@
+from .assets import *
diff --git a/plugins/assets/assets.py b/plugins/assets/assets.py
new file mode 100644
index 0000000..e204dd6
--- /dev/null
+++ b/plugins/assets/assets.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+"""
+Asset management plugin for Pelican
+===================================
+
+This plugin allows you to use the `webassets`_ module to manage assets such as
+CSS and JS files.
+
+The ASSET_URL is set to a relative url to honor Pelican's RELATIVE_URLS
+setting. This requires the use of SITEURL in the templates::
+
+
+
+.. _webassets: https://webassets.readthedocs.org/
+
+"""
+from __future__ import unicode_literals
+
+import os
+import logging
+
+from pelican import signals
+logger = logging.getLogger(__name__)
+
+try:
+ import webassets
+ from webassets import Environment
+ from webassets.ext.jinja2 import AssetsExtension
+except ImportError:
+ webassets = None
+
+def add_jinja2_ext(pelican):
+ """Add Webassets to Jinja2 extensions in Pelican settings."""
+
+ if 'JINJA_ENVIRONMENT' in pelican.settings: # pelican 3.7+
+ pelican.settings['JINJA_ENVIRONMENT']['extensions'].append(AssetsExtension)
+ else:
+ pelican.settings['JINJA_EXTENSIONS'].append(AssetsExtension)
+
+
+def create_assets_env(generator):
+ """Define the assets environment and pass it to the generator."""
+
+ theme_static_dir = generator.settings['THEME_STATIC_DIR']
+ assets_destination = os.path.join(generator.output_path, theme_static_dir)
+ generator.env.assets_environment = Environment(
+ assets_destination, theme_static_dir)
+
+ if 'ASSET_CONFIG' in generator.settings:
+ for item in generator.settings['ASSET_CONFIG']:
+ generator.env.assets_environment.config[item[0]] = item[1]
+
+ if 'ASSET_BUNDLES' in generator.settings:
+ for name, args, kwargs in generator.settings['ASSET_BUNDLES']:
+ generator.env.assets_environment.register(name, *args, **kwargs)
+
+ if 'ASSET_DEBUG' in generator.settings:
+ generator.env.assets_environment.debug = generator.settings['ASSET_DEBUG']
+ elif logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG":
+ generator.env.assets_environment.debug = True
+
+ for path in (generator.settings['THEME_STATIC_PATHS'] +
+ generator.settings.get('ASSET_SOURCE_PATHS', [])):
+ full_path = os.path.join(generator.theme, path)
+ generator.env.assets_environment.append_path(full_path)
+
+
+def register():
+ """Plugin registration."""
+ if webassets:
+ signals.initialized.connect(add_jinja2_ext)
+ signals.generator_init.connect(create_assets_env)
+ else:
+ logger.warning('`assets` failed to load dependency `webassets`.'
+ '`assets` plugin not loaded.')
diff --git a/plugins/assets/test_assets.py b/plugins/assets/test_assets.py
new file mode 100644
index 0000000..6eed987
--- /dev/null
+++ b/plugins/assets/test_assets.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+# from __future__ import unicode_literals
+
+import hashlib
+import locale
+import os
+from codecs import open
+from tempfile import mkdtemp
+from shutil import rmtree
+import unittest
+import subprocess
+
+from pelican import Pelican
+from pelican.settings import read_settings
+from pelican.tests.support import mute, skipIfNoExecutable, module_exists
+
+CUR_DIR = os.path.dirname(__file__)
+THEME_DIR = os.path.join(CUR_DIR, 'test_data')
+CSS_REF = open(os.path.join(THEME_DIR, 'static', 'css',
+ 'style.min.css')).read()
+CSS_HASH = hashlib.md5(CSS_REF).hexdigest()[0:8]
+
+
+@unittest.skipUnless(module_exists('webassets'), "webassets isn't installed")
+@skipIfNoExecutable(['scss', '-v'])
+@skipIfNoExecutable(['cssmin', '--version'])
+class TestWebAssets(unittest.TestCase):
+ """Base class for testing webassets."""
+
+ def setUp(self, override=None):
+ import assets
+ self.temp_path = mkdtemp(prefix='pelicantests.')
+ settings = {
+ 'PATH': os.path.join(os.path.dirname(CUR_DIR), 'test_data', 'content'),
+ 'OUTPUT_PATH': self.temp_path,
+ 'PLUGINS': [assets],
+ 'THEME': THEME_DIR,
+ 'LOCALE': locale.normalize('en_US'),
+ 'CACHE_CONTENT': False
+ }
+ if override:
+ settings.update(override)
+
+ self.settings = read_settings(override=settings)
+ pelican = Pelican(settings=self.settings)
+ mute(True)(pelican.run)()
+
+ def tearDown(self):
+ rmtree(self.temp_path)
+
+ def check_link_tag(self, css_file, html_file):
+ """Check the presence of `css_file` in `html_file`."""
+
+ link_tag = (''
+ .format(css_file=css_file))
+ html = open(html_file).read()
+ self.assertRegexpMatches(html, link_tag)
+
+
+class TestWebAssetsRelativeURLS(TestWebAssets):
+ """Test pelican with relative urls."""
+
+
+ def setUp(self):
+ TestWebAssets.setUp(self, override={'RELATIVE_URLS': True})
+
+ def test_jinja2_ext(self):
+ # Test that the Jinja2 extension was correctly added.
+
+ from webassets.ext.jinja2 import AssetsExtension
+ self.assertIn(AssetsExtension, self.settings['JINJA_ENVIRONMENT']['extensions'])
+
+ def test_compilation(self):
+ # Compare the compiled css with the reference.
+
+ gen_file = os.path.join(self.temp_path, 'theme', 'gen',
+ 'style.{0}.min.css'.format(CSS_HASH))
+ self.assertTrue(os.path.isfile(gen_file))
+
+ css_new = open(gen_file).read()
+ self.assertEqual(css_new, CSS_REF)
+
+ def test_template(self):
+ # Look in the output files for the link tag.
+
+ css_file = './theme/gen/style.{0}.min.css'.format(CSS_HASH)
+ html_files = ['index.html', 'archives.html',
+ 'this-is-a-super-article.html']
+ for f in html_files:
+ self.check_link_tag(css_file, os.path.join(self.temp_path, f))
+
+ self.check_link_tag(
+ '../theme/gen/style.{0}.min.css'.format(CSS_HASH),
+ os.path.join(self.temp_path, 'category/yeah.html'))
+
+
+class TestWebAssetsAbsoluteURLS(TestWebAssets):
+ """Test pelican with absolute urls."""
+
+ def setUp(self):
+ TestWebAssets.setUp(self, override={'RELATIVE_URLS': False,
+ 'SITEURL': 'http://localhost'})
+
+ def test_absolute_url(self):
+ # Look in the output files for the link tag with absolute url.
+
+ css_file = ('http://localhost/theme/gen/style.{0}.min.css'
+ .format(CSS_HASH))
+ html_files = ['index.html', 'archives.html',
+ 'this-is-a-super-article.html']
+ for f in html_files:
+ self.check_link_tag(css_file, os.path.join(self.temp_path, f))
diff --git a/plugins/assets/test_data/static/css/style.min.css b/plugins/assets/test_data/static/css/style.min.css
new file mode 100644
index 0000000..daf9c3c
--- /dev/null
+++ b/plugins/assets/test_data/static/css/style.min.css
@@ -0,0 +1 @@
+body{font:14px/1.5 "Droid Sans",sans-serif;background-color:#e4e4e4;color:#242424}a{color:red}a:hover{color:orange}
\ No newline at end of file
diff --git a/plugins/assets/test_data/static/css/style.scss b/plugins/assets/test_data/static/css/style.scss
new file mode 100644
index 0000000..10cd05b
--- /dev/null
+++ b/plugins/assets/test_data/static/css/style.scss
@@ -0,0 +1,19 @@
+/* -*- scss-compile-at-save: nil -*- */
+
+$baseFontFamily : "Droid Sans", sans-serif;
+$textColor : #242424;
+$bodyBackground : #e4e4e4;
+
+body {
+ font: 14px/1.5 $baseFontFamily;
+ background-color: $bodyBackground;
+ color: $textColor;
+}
+
+a {
+ color: red;
+
+ &:hover {
+ color: orange;
+ }
+}
diff --git a/plugins/assets/test_data/templates/base.html b/plugins/assets/test_data/templates/base.html
new file mode 100644
index 0000000..05a32d0
--- /dev/null
+++ b/plugins/assets/test_data/templates/base.html
@@ -0,0 +1,7 @@
+{% extends "!simple/base.html" %}
+
+{% block head %}
+ {% assets filters="scss,cssmin", output="gen/style.%(version)s.min.css", "css/style.scss" %}
+
+ {% endassets %}
+{% endblock %}
diff --git a/plugins/author_images/README.md b/plugins/author_images/README.md
new file mode 100644
index 0000000..f4d6811
--- /dev/null
+++ b/plugins/author_images/README.md
@@ -0,0 +1,55 @@
+# author_images
+
+This Pelican plugin adds support for author images and avatars. You may choose
+to display one or the other.
+
+## Configuration
+
+Add the directory to the base plugins directory to `PLUGIN_PATHS` in
+`pelicanconf.py`, and then add `author_images` to the `PLUGINS` list. For example,
+
+ PLUGIN_PATHS = ["../git/pelican-plugins"]
+ PLUGINS = ['author_images']
+
+You can also configure the directory for the author images and avatars. Note
+that both of these directories should exist in your theme, inside the static
+directory. This feels like the best way to approach this.
+
+ AUTHOR_AVATARS = 'images/author_avatars'
+ AUTHOR_IMAGES = 'images/author_images'
+
+### Adding images
+
+Now you can place images and avatars into the correct places. The location for
+these is `THEME / THEME_STATIC_DIR / AUTHOR_AVATARS`. For instance,
+`strudel/static/images/author_avatars` for my particular setup. Note that in
+this case, `strudel` is my theme.
+
+### Naming images
+
+Images have to named correctly for the plugin to find them. Currently, this
+means you need to take a `sha256` of the authors name. The extension of
+the file can be one of `svg`, `jpg`, `jpeg` or `png`. For instance, my name is
+William Pettersson, so I can run
+
+ python -c 'import hashlib; print hashlib.sha256("William Pettersson").hexdigest()'
+
+to get the hash sum of my name. Then I just rename my images or avatars to have
+that name, but with the appropriate extension. For simplicity, there is a
+`generate_hashsum.py` which can also be used as follows
+
+ python generate_hashsum.py "William Pettersson"
+
+which prints out
+`a40249517dfaf4e83264ced7d802c9fe9b811c8425b1ce1b3e8b9e236b52fa3e`. This means
+my files have to be named
+`a40249517dfaf4e83264ced7d802c9fe9b811c8425b1ce1b3e8b9e236b52fa3e.png`, or
+`a40249517dfaf4e83264ced7d802c9fe9b811c8425b1ce1b3e8b9e236b52fa3e.jpg` or
+similar.
+
+
+### Using in themes
+
+These images and avatars are made available to themes through the
+`author.avatar` and `author.image` variables.
+
diff --git a/plugins/author_images/__init__.py b/plugins/author_images/__init__.py
new file mode 100644
index 0000000..b3ebd91
--- /dev/null
+++ b/plugins/author_images/__init__.py
@@ -0,0 +1 @@
+from .author_images import *
diff --git a/plugins/author_images/author_images.py b/plugins/author_images/author_images.py
new file mode 100644
index 0000000..380e852
--- /dev/null
+++ b/plugins/author_images/author_images.py
@@ -0,0 +1,47 @@
+"""
+Author images plugin for Pelican
+===========================
+
+This plugin assigns the ``author.avatar`` and ``author.image`` variables to the
+avatar and image of the author in question. Authors are identified by email
+address, and avatars are images are stored in directories configured by
+AUTHOR_AVATARS and AUTHOR_IMAGES.
+"""
+
+from pelican import signals
+from hashlib import sha256
+from os.path import exists
+
+EXTENSIONS = ['jpg', 'png', 'svg']
+
+
+def add_author_image(author, generator):
+ hashsum = sha256(author.name).hexdigest()
+ static = generator.settings['THEME'] + '/static/'
+ if 'AUTHOR_AVATARS' in generator.settings.keys():
+ avatar = generator.settings['AUTHOR_AVATARS'] + '/' + hashsum
+ for ext in EXTENSIONS:
+ if exists('%s%s.%s' % (static, avatar, ext)):
+ author.avatar = '%s/%s.%s' % \
+ (generator.settings['THEME_STATIC_DIR'], avatar, ext)
+ break
+
+ if 'AUTHOR_IMAGES' in generator.settings.keys():
+ image = generator.settings['AUTHOR_IMAGES'] + '/' + hashsum
+ for ext in EXTENSIONS:
+ if exists('%s%s.%s' % (static, image, ext)):
+ author.image = '%s/%s.%s' % \
+ (generator.settings['THEME_STATIC_DIR'], image, ext)
+ break
+
+
+def add_author_images(generator):
+ for article in generator.articles:
+ for author in article.authors:
+ add_author_image(author, generator)
+ for author, _ in generator.authors:
+ add_author_image(author, generator)
+
+
+def register():
+ signals.article_generator_finalized.connect(add_author_images)
diff --git a/plugins/author_images/generate_hashsum.py b/plugins/author_images/generate_hashsum.py
new file mode 100755
index 0000000..5d57270
--- /dev/null
+++ b/plugins/author_images/generate_hashsum.py
@@ -0,0 +1,7 @@
+#!/usr/bin/env python2
+
+from __future__ import print_function
+import hashlib
+import sys
+
+print(hashlib.sha256(sys.argv[1]).hexdigest())
diff --git a/plugins/autopages/LICENSE b/plugins/autopages/LICENSE
new file mode 100644
index 0000000..44364d3
--- /dev/null
+++ b/plugins/autopages/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2015, Magnetic Media Online, Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/plugins/autopages/README.md b/plugins/autopages/README.md
new file mode 100644
index 0000000..b43acac
--- /dev/null
+++ b/plugins/autopages/README.md
@@ -0,0 +1,21 @@
+# Auto Pages
+
+This plugin adds an attribute `page` to the author, category, and tag
+objects which can be used in templates by themes. The page is processed as
+an ordinary Pelican page, so it can be Markdown, reStructuredText, etc.
+
+## Configuration
+
+| Setting | Default | Notes |
+|----------------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `AUTHOR_PAGE_PATH` | `authors` | The location, relative to the project root where author pages can be found. The filename of the author page minus the extension must match the Author's slug. |
+| `CATEGORY_PAGE_PATH` | `categories` | The location, relative to the project root where category pages can be found. The filename of the category page minus the extension must match the Category's slug. |
+| `TAG_PAGE_PATH` | `tags` | The location, relative to the project root where tag pages can be found. The filename of the tag page minus the extension must match the Tag's slug. |
+
+## Template Variables
+
+| Variable | Notes |
+|-----------------|--------------------------------------------|
+| `author.page` | The rendered content of the author page. |
+| `category.page` | The rendered content of the category page. |
+| `tag.page` | The rendered content of the tag page. |
diff --git a/plugins/autopages/__init__.py b/plugins/autopages/__init__.py
new file mode 100644
index 0000000..b562ddc
--- /dev/null
+++ b/plugins/autopages/__init__.py
@@ -0,0 +1 @@
+from .autopages import *
diff --git a/plugins/autopages/autopages.py b/plugins/autopages/autopages.py
new file mode 100644
index 0000000..ea8220d
--- /dev/null
+++ b/plugins/autopages/autopages.py
@@ -0,0 +1,64 @@
+import logging
+import os
+import os.path
+
+from pelican import signals
+from pelican.contents import Page
+
+
+logger = logging.getLogger("autopages")
+
+def yield_files(root):
+ root = os.path.realpath(os.path.abspath(root))
+ for dirpath, dirnames, filenames in os.walk(root):
+ for dirname in list(dirnames):
+ try:
+ if dirname.startswith("."):
+ dirnames.remove(dirname)
+ except IndexError:
+ # duplicate already removed?
+ pass
+ for filename in filenames:
+ if filename.startswith("."):
+ continue
+ yield os.path.join(dirpath, filename)
+
+def make_page(readers, context, filename):
+ base_path, filename = os.path.split(filename)
+ page = readers.read_file(base_path, filename, Page, None, context)
+ slug, _ = os.path.splitext(filename)
+ return slug, page
+
+def make_pages(readers, context, path):
+ pages = {}
+ for filename in yield_files(path):
+ try:
+ slug, page = make_page(readers, context, filename)
+ except Exception:
+ logger.exception("Could not make autopage for %r", filename)
+ continue
+ pages[slug] = page
+ return pages
+
+def create_autopages(article_generator):
+ settings = article_generator.settings
+ readers = article_generator.readers
+ context = article_generator.context
+
+ authors_path = settings.get("AUTHOR_PAGE_PATH", "authors")
+ categories_path = settings.get("CATEGORY_PAGE_PATH", "categories")
+ tags_path = settings.get("TAG_PAGE_PATH", "tags")
+
+ author_pages = make_pages(readers, context, authors_path)
+ category_pages = make_pages(readers, context, categories_path)
+ tag_pages = make_pages(readers, context, tags_path)
+
+ for author, _ in article_generator.authors:
+ author.page = author_pages.get(author.slug, "")
+ for category, _ in article_generator.categories:
+ category.page = category_pages.get(category.slug, "")
+ for tag in article_generator.tags:
+ tag.page = tag_pages.get(tag.slug, "")
+
+def register():
+ signals.article_generator_finalized.connect(create_autopages)
diff --git a/plugins/better_codeblock_line_numbering/Readme.md b/plugins/better_codeblock_line_numbering/Readme.md
new file mode 100644
index 0000000..cd9eeca
--- /dev/null
+++ b/plugins/better_codeblock_line_numbering/Readme.md
@@ -0,0 +1,125 @@
+# Better Code Line Numbering Plugin
+
+## Copyright, Contact, and Acknowledgements
+
+This plugin is copyright 2014 Jacob Levernier
+It is released under the BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause). This basically means that you can do whatever you want with the code, provided that you include this copyright and license notice.
+
+Some of this code is modified from my YouTube Privacy Enhancer plugin for Pelican (https://github.com/getpelican/pelican-plugins/pull/183).
+
+
+### To contact the author:
+
+* jleverni at uoregon dot edu
+* http://AdUnumDatum.org
+* BitBucket: https://bitbucket.org/jlev_uo/
+* Github: https://github.com/publicus
+
+This is the second plugin that I've written for Pelican, and it was intended as a training project for learning Pelican as well as Python better. I would be very happy to hear constructive feedback on the plugin and for suggestions for making it more efficient and/or expandable. Also, I've heavily annotated all of the Python code in order to make it easier to understand for others looking to learn more, like I was when I wrote the plugin.
+
+### Acknowledgements
+
+I'm grateful to the authors of the plugins in the pelican-plugins repo; being able to look over other plugins' authors' code helped me immensely in learning more about how Pelican's [signals](http://docs.getpelican.com/en/3.3.0/plugins.html#how-to-create-plugins "Pelican documentation on creating plugins") system works.
+
+
+## Explanation and Rationale
+
+Pelican uses Python's built-in code highlighting extension when processing Markdown. This extension, called Code HiLite (https://pythonhosted.org/Markdown/extensions/code_hilite.html), can add line numbers to any code that is enclosed in triple backticks (and, by default, has a shebang as a first line), like this:
+
+```
+#!python
+
+code goes here
+
+more code goes here
+```
+
+This works well, except for one problem: If the lines of code are long (or if the page template is narrow), the code will run off of the page, requiring that the user scroll sideways to read it. This can be annoying in some circumstances (e.g., if the code block scrollbar is at the very bottom of a long block of code). The Code HiLite Python extension creates line numbers by making a table with all of the line numbers in one column (as a big line of text, not separated into different table rows) and the code in the second column, like this:
+
+Column 1 | Column 2
+--------- | -------------
+1 | Code line 1 goes here, and maybe is very very long.
+2 | Code line 2 goes here.
+
+It is possible to use CSS to get this code to wrap, but the line numbers can become mis-matched with the code to which they're supposed to refer, like this:
+
+Column 1 | Column 2
+--------- | -------------
+1 | Code line 1 goes here, and
+2 | maybe is very very long.
+ | Code line 2 goes here.
+
+This plugin enables the use of a CSS technique from http://bililite.com/blog/2012/08/05/line-numbering-in-pre-elements/ . All that this plugin does is wrap every individual line of a code block with .... When you combine this with the CSS that's included in the setup instructions below, your code blocks will word-wrap and have nicely formatted line numbers. Since they're added with CSS, the line numbers will not be highlighted when a user wants to copy and paste the contents of the code block, making it easier for the user to benefit from what you've written.
+
+
+## Usage
+
+**After you set up the plugin (by following the steps below), any code written in triple backticks will have line numbers added to it.** Thus, to avoid line numbers, you can use a single backtick to include code `like this`, and can add line numbers by using three backticks
+
+```
+like this
+```
+
+That's all there is to it!
+
+Since this plugin builds on the Code HiLite plugin, you can change syntax highlighting by using one of two methods:
+
+```{python}
+This code will highlight as python
+```
+
+```
+#!python
+This code will also highlight as python
+```
+
+
+**In order for this plugin to work optimally, you need to do just a few things:**
+
+1. Enable the plugin in pelicanconf.py (see http://docs.getpelican.com/en/3.3.0/plugins.html for documentation):
+ PLUGIN_PATH = "/pelican-plugins"
+ PLUGINS = ["better_codeblock_line_numbering"]
+
+2. Add the following to your pelicanconf.py file:
+```
+MD_EXTENSIONS = [
+ 'codehilite(css_class=highlight,linenums=False)',
+ 'extra'
+ ]
+```
+This sets python's CodeHiLite Markdown extension (http://pythonhosted.org/Markdown/extensions/code_hilite.html) so that it never assigns line numbers (since we're taking care of those ourselves now), and to wrap code blocks in a div with class="highlight". As is the default for Pelican (see http://docs.getpelican.com/en/3.1.1/settings.html, under "MD_EXTENSIONS"), this also keeps the 'extra' extension (http://pythonhosted.org/Markdown/extensions/extra.html) active.
+
+3. Add the following code to your CSS file:
+```
+/* For use with the code_line-number_word-wrap_switcher_jquery.js Pelican plugin */
+code {
+ overflow: auto;
+ /* This uses `white-space: pre-wrap` to get elements within tags to wrap. Python, for code chunks within three backticks (```), doesn't wordwrap code lines by default, because they're within tags, which don't wrap by default. See https://github.com/github/markup/issues/168 , which is specifically about this parsing issue, even though that link's discussion is talking about GitHub. */
+ white-space: pre-wrap; /* css-3 */
+ white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+/* Following http://bililite.com/blog/2012/08/05/line-numbering-in-pre-elements/, use CSS to add line numbers to all spans that have the class 'code-line' */
+
+.highlight pre {
+ counter-reset: linecounter;
+ padding-left: 2em;
+}
+.highlight pre span.code-line {
+ counter-increment: linecounter;
+ padding-left: 1em;
+ text-indent: -1em;
+ display: inline-block;
+}
+.highlight pre span.code-line:before {
+ content: counter(linecounter);
+ padding-right: 1em;
+ display: inline-block;
+ color: grey;
+ text-align: right;
+}
+```
+
diff --git a/plugins/better_codeblock_line_numbering/__init__.py b/plugins/better_codeblock_line_numbering/__init__.py
new file mode 100644
index 0000000..fe59e18
--- /dev/null
+++ b/plugins/better_codeblock_line_numbering/__init__.py
@@ -0,0 +1 @@
+from .better_codeblock_line_numbering import *
diff --git a/plugins/better_codeblock_line_numbering/better_codeblock_line_numbering.py b/plugins/better_codeblock_line_numbering/better_codeblock_line_numbering.py
new file mode 100644
index 0000000..2cfd7b0
--- /dev/null
+++ b/plugins/better_codeblock_line_numbering/better_codeblock_line_numbering.py
@@ -0,0 +1,47 @@
+"""
+Better Code-Block Line Numbering Plugin
+--------------------------
+
+Authored by Jacob Levernier, 2014
+Released under the BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
+
+For more information on this plugin, please see the attached Readme.md file.
+"""
+
+from pelican import signals # For making this plugin work with Pelican.
+
+import os.path # For checking whether files are present in the filesystem.
+
+import re # For using regular expressions.
+
+def add_line_wrappers(data_passed_from_pelican):
+ """A function to read through each page and post as it comes through from Pelican, find all instances of triple-backtick (```...```) code blocks, and add an HTML wrapper to each line of each of those code blocks"""
+
+ if data_passed_from_pelican._content: # If the item passed from Pelican has a "content" attribute (i.e., if it's not an image file or something else like that). NOTE: data_passed_from_pelican.content (without an underscore in front of 'content') seems to be read-only, whereas data_passed_from_pelican._content is able to be overwritten. This is somewhat explained in an IRC log from 2013-02-03 from user alexis to user webdesignhero_ at https://botbot.me/freenode/pelican/2013-02-01/?tz=America/Los_Angeles.
+ full_content_of_page_or_post = data_passed_from_pelican._content
+ else:
+ return # Exit the function, essentially passing over the (non-text) file.
+
+ all_instances_of_pre_elements = re.findall('.*?
', full_content_of_page_or_post, re.DOTALL) # Use a regular expression to find every instance of '' followed by anything up to the first matching '
'. re.DOTALL puts python's regular expression engine ('re') into a mode where a dot ('.') matches absolutely anything, including newline characters.
+
+ if(len(all_instances_of_pre_elements) > 0): # If the article/page HAS any ...
elements, go on. Otherwise, don't (to do so would inadvertantly wipe out the output content for that article/page).
+ updated_full_content_of_page_or_post = full_content_of_page_or_post # This just gives this an initial value before going into the loop below.
+
+ # Go through each element instance that we found above, and parse it:
+ for pre_element_to_parse in all_instances_of_pre_elements:
+
+ # Wrap each line of the ...
section with ..., following http://bililite.com/blog/2012/08/05/line-numbering-in-pre-elements/. We'll use these to add line numbers using CSS later.
+ # Note that below, '^' is the beginning of a string, '$' is the end of a string, and '\n' is a newline.
+ replacement_text_with_beginning_of_each_line_wrapped_in_span = re.sub(r'(|\n(?!
))','\\1',pre_element_to_parse) # The (?!...) here is a Negative Lookahead (cf. http://www.regular-expressions.info/lookaround.html). This full regular expression says "Give me all code snippets that start with or start with a newline (\n), but NOT if the newline is followed immediately with '
'. Take whatever you find, and replace it with what you found (\1) followed immediately by ''.
+ # http://stackoverflow.com/a/14625628 explains why we need to escape the backslash in the capture group reference (the '\1'). In short, python will recognize it as "\x01" if it's not escaped.
+ replacement_text_with_full_line_wrapped_in_span = re.sub(r'((?)$|(?)\n)','\\1',replacement_text_with_beginning_of_each_line_wrapped_in_span) # This regular expression says "Give me all code snippets that are the end of a string or a newline (but not preceeded by "
" (this is a 'negative lookahead,' '(?<)'), and replace whatever you found with ' followed by whatever you found (\1).
+
+ updated_full_content_of_page_or_post = updated_full_content_of_page_or_post.replace(pre_element_to_parse,replacement_text_with_full_line_wrapped_in_span)
+
+ # Replace the content of the page or post with our now-updated content (having gone through all instances of elements and updated them all, exiting the loop above.
+ data_passed_from_pelican._content = updated_full_content_of_page_or_post
+
+
+# Make Pelican work (see http://docs.getpelican.com/en/3.3.0/plugins.html#how-to-create-plugins):
+def register():
+ signals.content_object_init.connect(add_line_wrappers)
diff --git a/plugins/better_figures_and_images/README.rst b/plugins/better_figures_and_images/README.rst
new file mode 100644
index 0000000..119ca2f
--- /dev/null
+++ b/plugins/better_figures_and_images/README.rst
@@ -0,0 +1,54 @@
+Requirements
+------------
+
+* pip install pillow beautifulsoup4
+
+Summary
+=======
+
+This plug-in:
+
+- Adds a ``style="width: ???px; height: auto;"`` attribute to any ```` tags in the content, by checking the dimensions of the image file and adding the appropriate ``style="width: ???px; height: auto;"`` to the ```` tag.
+
+- Also finds any ``div class="figures"`` tags in the content, that contain images and adds the same style to them too.
+
+- If ``RESPONSIVE_IMAGES`` setting is true, it adds ``style="width: ???px; max-width: 100%; height: auto;"`` instead.
+
+- Corrects Alt text: If an img ``alt`` attribute equals the image filename, it sets it to ""
+
+
+Assuming that the image is 250px wide, it turns this::
+
+
+
+into this::
+
+
+
+or this, if ``RESPONSIVE_IMAGES = True``::
+
+
diff --git a/plugins/better_figures_and_images/__init__.py b/plugins/better_figures_and_images/__init__.py
new file mode 100644
index 0000000..b8fefc4
--- /dev/null
+++ b/plugins/better_figures_and_images/__init__.py
@@ -0,0 +1 @@
+from .better_figures_and_images import *
diff --git a/plugins/better_figures_and_images/better_figures_and_images.py b/plugins/better_figures_and_images/better_figures_and_images.py
new file mode 100644
index 0000000..9364184
--- /dev/null
+++ b/plugins/better_figures_and_images/better_figures_and_images.py
@@ -0,0 +1,123 @@
+"""
+Better Figures & Images
+------------------------
+
+This plugin:
+
+- Adds a style="width: ???px; height: auto;" to each image in the content
+- Also adds the width of the contained image to any parent div.figures.
+ - If RESPONSIVE_IMAGES == True, also adds style="max-width: 100%;"
+- Corrects alt text: if alt == image filename, set alt = ''
+
+TODO: Need to add a test.py for this plugin.
+
+"""
+
+from __future__ import unicode_literals
+from os import path, access, R_OK
+import os
+
+from pelican import signals
+
+from bs4 import BeautifulSoup
+from PIL import Image
+import pysvg.parser
+
+import logging
+logger = logging.getLogger(__name__)
+
+def content_object_init(instance):
+
+ if instance._content is not None:
+ content = instance._content
+ soup = BeautifulSoup(content, 'html.parser')
+
+ for img in soup(['img', 'object']):
+ logger.debug('Better Fig. PATH: %s', instance.settings['PATH'])
+ if img.name == 'img':
+ logger.debug('Better Fig. img.src: %s', img['src'])
+ img_path, img_filename = path.split(img['src'])
+ else:
+ logger.debug('Better Fig. img.data: %s', img['data'])
+ img_path, img_filename = path.split(img['data'])
+ logger.debug('Better Fig. img_path: %s', img_path)
+ logger.debug('Better Fig. img_fname: %s', img_filename)
+
+ # Pelican 3.5+ supports {attach} macro for auto copy, in this use case the content does not exist in output
+ # due to the fact it has not been copied, hence we take it from the source (same as current document)
+ if img_filename.startswith('{attach}'):
+ img_path = os.path.dirname(instance.source_path)
+ img_filename = img_filename[8:]
+ src = os.path.join(img_path, img_filename)
+ else:
+ # Strip off {filename}, |filename| or /static
+ if img_path.startswith(('{filename}', '|filename|')):
+ img_path = img_path[10:]
+ elif img_path.startswith('/static'):
+ img_path = img_path[7:]
+ elif img_path.startswith('data:image'):
+ # Image is encoded in-line (not a file).
+ continue
+ else:
+ logger.warning('Better Fig. Error: img_path should start with either {filename}, |filename| or /static')
+
+ # search src path list
+ # 1. Build the source image filename from PATH
+ # 2. Build the source image filename from STATIC_PATHS
+
+ # if img_path start with '/', remove it.
+ img_path = os.path.sep.join([el for el in img_path.split("/") if len(el) > 0])
+
+ # style: {filename}/static/foo/bar.png
+ src = os.path.join(instance.settings['PATH'], img_path, img_filename)
+ src_candidates = [src]
+
+ # style: {filename}../static/foo/bar.png
+ src_candidates += [os.path.join(instance.settings['PATH'], static_path, img_path, img_filename) for static_path in instance.settings['STATIC_PATHS']]
+
+ src_candidates = [f for f in src_candidates if path.isfile(f) and access(f, R_OK)]
+
+ if not src_candidates:
+ logger.error('Better Fig. Error: image not found: %s', src)
+ logger.debug('Better Fig. Skip src: %s', img_path + '/' + img_filename)
+ continue
+
+ src = src_candidates[0]
+ logger.debug('Better Fig. src: %s', src)
+
+ # Open the source image and query dimensions; build style string
+ try:
+ if img.name == 'img':
+ im = Image.open(src)
+ extra_style = 'width: {}px; height: auto;'.format(im.size[0])
+ else:
+ svg = pysvg.parser.parse(src)
+ extra_style = 'width: {}px; height: auto;'.format(svg.get_width())
+ except IOError as e:
+ logger.debug('Better Fig. Failed to open: %s', src)
+ extra_style = 'width: 100%; height: auto;'
+
+ if 'RESPONSIVE_IMAGES' in instance.settings and instance.settings['RESPONSIVE_IMAGES']:
+ extra_style += ' max-width: 100%;'
+
+ if img.get('style'):
+ img['style'] += extra_style
+ else:
+ img['style'] = extra_style
+
+ if img.name == 'img':
+ if img['alt'] == img['src']:
+ img['alt'] = ''
+
+ fig = img.find_parent('div', 'figure')
+ if fig:
+ if fig.get('style'):
+ fig['style'] += extra_style
+ else:
+ fig['style'] = extra_style
+
+ instance._content = soup.decode()
+
+
+def register():
+ signals.content_object_init.connect(content_object_init)
diff --git a/plugins/better_figures_and_images/test_data/dummy-200x200.png b/plugins/better_figures_and_images/test_data/dummy-200x200.png
new file mode 100644
index 0000000..598d754
Binary files /dev/null and b/plugins/better_figures_and_images/test_data/dummy-200x200.png differ
diff --git a/plugins/better_figures_and_images/test_data/dummy-250x300.png b/plugins/better_figures_and_images/test_data/dummy-250x300.png
new file mode 100644
index 0000000..f21336a
Binary files /dev/null and b/plugins/better_figures_and_images/test_data/dummy-250x300.png differ
diff --git a/plugins/better_figures_and_images/test_data/dummy-800x300.png b/plugins/better_figures_and_images/test_data/dummy-800x300.png
new file mode 100644
index 0000000..4122c88
Binary files /dev/null and b/plugins/better_figures_and_images/test_data/dummy-800x300.png differ
diff --git a/plugins/better_figures_and_images/test_data/images-test.html b/plugins/better_figures_and_images/test_data/images-test.html
new file mode 100644
index 0000000..98a8e64
--- /dev/null
+++ b/plugins/better_figures_and_images/test_data/images-test.html
@@ -0,0 +1,44 @@
+
+
+
+
+ Better Figures & Images Test
+
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+
+
\ No newline at end of file
diff --git a/plugins/better_figures_and_images/test_data/images-test.rst b/plugins/better_figures_and_images/test_data/images-test.rst
new file mode 100644
index 0000000..b1104ba
--- /dev/null
+++ b/plugins/better_figures_and_images/test_data/images-test.rst
@@ -0,0 +1,75 @@
+:title: Images Test
+:slug: images-test
+:date: 2013-04-23 15:59:39
+:tags: images, test
+
+.. figure:: /static/images/dummy-800x300.png
+
+ This is the caption of the figure (a simple paragraph).
+
+ The legend consists of all elements after the caption. In this
+ case, the legend consists of this paragraph.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+.. figure:: /static/images/dummy-200x200.png
+ :alt: map to buried treasure
+
+ This is the caption of the figure (a simple paragraph).
+
+ The legend consists of all elements after the caption. In this
+ case, the legend consists of this paragraph.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+.. figure:: /static/images/dummy-250x300.png
+ :alt: map to buried treasure 2
+ :align: right
+
+ This is the second image caption.
+
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+.. image:: /static/images/dummy-200x200.png
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+
+.. image:: /static/images/dummy-250x300.png
+ :align: right
+
+Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
+tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
+cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
+proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
\ No newline at end of file
diff --git a/plugins/better_tables/LICENSE b/plugins/better_tables/LICENSE
new file mode 100644
index 0000000..e41460a
--- /dev/null
+++ b/plugins/better_tables/LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2015 Alex Waite
+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.
diff --git a/plugins/better_tables/README.md b/plugins/better_tables/README.md
new file mode 100644
index 0000000..7c456f4
--- /dev/null
+++ b/plugins/better_tables/README.md
@@ -0,0 +1,38 @@
+# Better Tables
+
+This Pelican plugin removes the excess attributes and elements in the HTML
+tables generated from reST. Trimming this fat allows them to pass HTML5
+validation. Hopefully `rst2html5` will be merged into Pelican at some point, but
+until then, this hacky approach is needed.
+
+This approach has the advantage of restoring sanity to tables, and allows their
+column width to flow normally. All styling is default and must be styled by CSS
+rather than in HTML attributes.
+
+I make no claim that **all** HTML table crimes generated are corrected — merely
+the ones that I have stumbled across.
+
+## Requirements
+
+* Beautiful Soup 4
+
+## What does it do?
+
+At the moment, the following is stripped from tables (though when in doubt,
+check the source as it may be updated and out-of-sync with this document).
+
+* `` element (and its evil `` children)
+* `table` > `border` attribute
+* `` and `` > `valign` attribute
+
+## Usage
+
+Enable the plugin in your pelicanconf.py:
+
+ PLUGINS = [
+ # ...
+ 'better_tables',
+ # ...
+ ]
+
+And that's it. Life's simple like that sometimes.
diff --git a/plugins/better_tables/__init__.py b/plugins/better_tables/__init__.py
new file mode 100644
index 0000000..f752acf
--- /dev/null
+++ b/plugins/better_tables/__init__.py
@@ -0,0 +1,31 @@
+# Copyright (c) 2015 Alex Waite
+# 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.
+
+# -*- coding: utf-8 -*-
+__title__ = 'better-tables'
+__version__ = '0.1.0'
+__author__ = 'Alex Waite'
+__credits__ = ["Alex Waite"]
+__maintainer__ = "Alex Waite"
+__email__ = "Alexqw85@gmail.com"
+__status__ = "Stable"
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2015'
+
+from .better_tables import *
diff --git a/plugins/better_tables/better_tables.py b/plugins/better_tables/better_tables.py
new file mode 100644
index 0000000..1611249
--- /dev/null
+++ b/plugins/better_tables/better_tables.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2015 Alex Waite
+# 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.
+
+''' Better Tables: Restore sanity to rst->html tables
+
+This pelican plugin removes the excess attributes and elements in the HTML
+tables generated from RST. Trimming this fat allows them to pass HTML5
+validation. Hopefully rst2html5 will be merged into pelican at some point, but
+until then, this hacky approach is needed.
+
+This approach has the advantage of restoring sanity to tables, and allows their
+column with to flow normally. All styling is default and must be styled by CSS
+rather than in HTML attributes.
+
+I make no claim that /all/ HTML table crimes generated are corrected, merely
+the ones which I have stumbled across.
+
+Usage:
+ Enable the plugin in your pelicanconf.py
+
+ PLUGINS = [
+ # ...
+ 'better_tables',
+ # ...
+ ]
+
+ And that's it. Life's simple like that sometimes.
+'''
+
+from pelican import signals, contents
+from bs4 import BeautifulSoup
+
+def better_tables(content):
+ if isinstance(content, contents.Static):
+ return
+
+ soup = BeautifulSoup(content._content, 'html.parser')
+
+ for table in soup.findAll('table'):
+ # table's "border" is so 1996
+ del(table['border'])
+
+ # col widths. not only /infuriating/ it's also not in HTML5
+ for tag in table.findAll('colgroup'):
+ tag.extract()
+
+ # tbody and thead's valign
+ for tag in table.findAll(['tbody', 'thead']):
+ del(tag['valign'])
+
+ soup.renderContents()
+ content._content = soup.decode()
+
+def register():
+ signals.content_object_init.connect(better_tables)
diff --git a/plugins/bootstrap-rst/140x140.png b/plugins/bootstrap-rst/140x140.png
new file mode 100644
index 0000000..79e8992
Binary files /dev/null and b/plugins/bootstrap-rst/140x140.png differ
diff --git a/plugins/bootstrap-rst/171x180.png b/plugins/bootstrap-rst/171x180.png
new file mode 100644
index 0000000..9067b5c
Binary files /dev/null and b/plugins/bootstrap-rst/171x180.png differ
diff --git a/plugins/bootstrap-rst/300x200.png b/plugins/bootstrap-rst/300x200.png
new file mode 100644
index 0000000..866c674
Binary files /dev/null and b/plugins/bootstrap-rst/300x200.png differ
diff --git a/plugins/bootstrap-rst/LICENSE b/plugins/bootstrap-rst/LICENSE
new file mode 100644
index 0000000..4fa4e7b
--- /dev/null
+++ b/plugins/bootstrap-rst/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Nicolas P. Rougier
+
+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.
diff --git a/plugins/bootstrap-rst/Makefile b/plugins/bootstrap-rst/Makefile
new file mode 100644
index 0000000..5cc5dea
--- /dev/null
+++ b/plugins/bootstrap-rst/Makefile
@@ -0,0 +1,32 @@
+MAKE = /usr/bin/make
+RST2HTML = ./bootstrap.py
+STYLESHEET =
+RST2HTML_OPTIONS = --strip-comments \
+ --report=3 \
+ --no-doc-title \
+ --traceback \
+ --compact-lists \
+ --no-toc-backlinks \
+ --syntax-highlight=short \
+ --template=page.tmpl \
+ --cloak-email-addresses \
+ --stylesheet=$(STYLESHEET) \
+ --link-stylesheet
+
+SOURCES = $(wildcard doc/*.rst)
+TMP = $(subst .rst,.html, $(SOURCES))
+OBJECTS = $(subst doc/,, $(TMP))
+
+all:$(OBJECTS)
+
+%.html: doc/%.rst
+ @echo " - $@"
+ @$(RST2HTML) $(RST2HTML_OPTIONS) $< $@
+
+clean:
+ @-rm -f $(OBJECTS)
+
+distclean: clean
+ @-rm -f `find . -name "*~"`
+
+.PHONY: all clean distclean
diff --git a/plugins/bootstrap-rst/README.rst b/plugins/bootstrap-rst/README.rst
new file mode 100644
index 0000000..bb34b12
--- /dev/null
+++ b/plugins/bootstrap-rst/README.rst
@@ -0,0 +1,44 @@
+Bootstrap RST for Pelican
+=========================
+
+This plugin merely adds what little glue is needed to make bootstrap-rst play
+nicely with Pelican. All credit goes to **Nicolas P. Rougier**.
+
+It is much more featureful than the 'twitter_bootstrap_rst_directives' plugin.
+
+Usage
+-----
+Enable the plugin in your `pelicanconf.py`
+
+ PLUGINS = [
+ 'bootstrap-rst'
+ ]
+
+And then use any of the many fine directives made available. Peruse the `doc`
+folder for more information.
+
+Bootstrap RST
+=============
+
+Bootstrap RST offers an easy access to the `bootstrap `_
+framework using the `reStructuredText `_
+markup language. Bootstrap RST provides a set of new directives and roles (row,
+column, button, list, etc.) that allow seamless integration of the bootstrap
+framework. Have a look at the source of this page for example and see below for
+what is available so far.
+
+See demo at: `http://rougier.github.io/bootstrap-rst/ `_.
+
+Creators
+========
+
+**Nicolas P. Rougier** :
+
+* `http://www.labri.fr/perso/nrougier/ `_
+* `https://github.com/rougier `_
+
+Copyright and License
+=====================
+
+Code and documentation copyright 2014 Nicolas P. Rougier.
+Code released under the MIT license. Docs released under CC BY 3.0.
diff --git a/plugins/bootstrap-rst/__init__.py b/plugins/bootstrap-rst/__init__.py
new file mode 100644
index 0000000..ac086b7
--- /dev/null
+++ b/plugins/bootstrap-rst/__init__.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+__title__ = 'bootstrap-rst'
+__version__ = '0.1.1'
+__author__ = 'Nicolas P. Rougier'
+__credits__ = ['Nicolas P. Rougier', 'Alex Waite', 'Trevor Morgan']
+__maintainer__ = "Alex Waite"
+__email__ = "alex@waite.eu"
+__status__ = "Development"
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2014'
+
+from .bootstrap import *
diff --git a/plugins/bootstrap-rst/bootstrap.py b/plugins/bootstrap-rst/bootstrap.py
new file mode 100755
index 0000000..c1bf8f1
--- /dev/null
+++ b/plugins/bootstrap-rst/bootstrap.py
@@ -0,0 +1,310 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# -----------------------------------------------------------------------------
+# Bootstrap RST
+# Copyright (c) 2014, Nicolas P. Rougier
+# Distributed under the (new) BSD License. See LICENSE.txt for more info.
+# -----------------------------------------------------------------------------
+import sys, os, re
+from docutils import nodes, utils
+from docutils.parsers.rst.directives import images
+from docutils.transforms import TransformError, Transform, parts
+from docutils.parsers.rst import Directive, directives, states, roles
+from docutils.nodes import fully_normalize_name, whitespace_normalize_name
+from docutils.parsers.rst.roles import set_classes
+
+from docutils.io import StringOutput
+from docutils.core import Publisher
+
+from pelican import signals
+from pelican.readers import RstReader, PelicanHTMLTranslator
+
+from .roles import *
+from .directives import *
+
+
+class HTMLTranslator(PelicanHTMLTranslator):
+ """
+ This is a translator class for the docutils system.
+ """
+
+ def visit_h1(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_h2(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_h3(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_h4(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_h5(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_h6(self, node):
+ self.body.append('%s
' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_default(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_primary(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_success(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_info(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_warning(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_label_danger(self, node):
+ self.body.append(
+ '%s' % node.children[0])
+ raise nodes.SkipNode
+
+ def visit_page_row(self, node):
+ self.body.append(self.starttag(node,'div'))
+
+ def depart_page_row(self, node):
+ self.body.append('\n')
+
+ def visit_page_column(self, node):
+ self.body.append(self.starttag(node,'div'))
+
+ def depart_page_column(self, node):
+ self.body.append('\n')
+
+
+ def visit_button(self, node):
+ btn_classes = { 'primary' : 'btn-primary', 'success' : 'btn-success',
+ 'info' : 'btn-info', 'warning' : 'btn-warning',
+ 'danger' : 'btn-danger', 'link' : 'btn-link',
+ 'outline' : 'btn-outline', 'tiny' : 'btn-xs',
+ 'small' : 'btn-sm', 'large' : 'btn-lg',
+ 'block' : 'btn-block', 'active' : 'btn-active' }
+
+ classes = 'btn '
+ flag = False
+ for node_class in node['classes']:
+ if node_class in ['primary', 'success', 'warning'
+ 'info', 'link', 'danger', 'outline']:
+ flag = True
+ btn_class = btn_classes.get(node_class, None)
+ if btn_class:
+ classes += btn_class + ' '
+ if flag == False:
+ classes += 'btn-default'
+
+ target = node['target']
+ properties = ''
+
+ # Disabled
+ if 'disabled' in node['classes']:
+ if target:
+ properties += ' disabled="disabled"'
+ else:
+ classes += ' disabled'
+
+ # Data toggle
+ if 'toggle' in node['classes']:
+ classes += ' dropdown-toggle '
+ properties += ' data-toggle="dropdown"'
+ if target:
+ properties += ' role="button"'
+ anchor = '' % (target,classes,properties)
+ self.body.append(anchor)
+ else:
+ properties += ' type="button"'
+ button = '\n')
+ else:
+ self.body.append('\n')
+
+
+ def visit_progress(self, node):
+ prg_classes = { 'success' : 'progress-bar-success',
+ 'info' : 'progress-bar-info',
+ 'warning' : 'progress-bar-warning',
+ 'danger' : 'progress-bar-danger' }
+
+ label = node['label']
+ classes = 'progress-bar'
+ flag = False
+ for nodeclass in node['classes']:
+ flag = True
+ classes += ' ' + prg_classes.get(nodeclass, '')
+ if flag == False:
+ classes += ' progress-bar-default'
+ properties = 'role="progress-bar"'
+ properties += ' aria-valuenow="%d"' % int(node['value'])
+ properties += ' aria-valuemin="%d"' % int(node['value_min'])
+ properties += ' aria-valuemax="%d"' % int(node['value_max'])
+ properties += ' style="width: %d%%";' % int(node['value'])
+ if 'active' in node['classes']:
+ self.body.append('')
+ elif 'striped' in node['classes']:
+ self.body.append('
')
+ else:
+ self.body.append('
')
+ self.body.append(
+ '
%s
' % (classes,properties,label))
+ self.body.append('
')
+ raise nodes.SkipNode
+
+ def visit_alert(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='alert'))
+ if node.dismissable:
+ self.body.append(
+ u"""
""")
+
+ def depart_alert(self, node):
+ self.body.append('
\n')
+
+ def visit_callout(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='bs-callout'))
+
+ def depart_callout(self, node):
+ self.body.append('
\n')
+
+
+
+ # overwritten
+ def visit_definition_list(self, node):
+ list_class = node.parent.get('list-class', [])
+ list_class.append('docutils')
+ list_class = ' '.join(list_class)
+ self.body.append(self.starttag(node, 'dl', CLASS=list_class))
+
+ # overwritten
+ def visit_sidebar(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS='col-md-3 col-md-push-9'))
+ self.body.append(self.starttag(node, 'div', CLASS='bs-docs-sidebar hidden-print affix-top'))
+ self.body.append(self.starttag(node, 'div', CLASS='sidebar'))
+ self.set_first_last(node)
+ self.in_sidebar = True
+
+ # overwritten
+ def depart_sidebar(self, node):
+ self.body.append('\n')
+ self.body.append('\n')
+ self.body.append('\n')
+ # Opening tag for body
+ self.body.append(self.starttag(node, 'div', CLASS='col-md-9 col-md-pull-3'))
+ self.in_sidebar = False
+
+ # overwritten : removed compact paragraph
+ # def visit_paragraph(self, node):
+ # if self.should_be_compact_paragraph(node):
+ # self.context.append('')
+ # else:
+ # self.body.append(self.starttag(node, 'p', ''))
+ # self.context.append('\n')
+
+ # overwritten: remove border=1, replace docutils/table class
+ def visit_table(self, node):
+ self.context.append(self.compact_p)
+ self.compact_p = True
+ #classes = ' '.join(['docutils', self.settings.table_style]).strip()
+ classes = ' '.join(['table', self.settings.table_style]).strip()
+ self.body.append(self.starttag(node, 'table', CLASS=classes))
+
+ # overwritten : removed 'container' class
+ def visit_container(self, node):
+ self.body.append(self.starttag(node, 'div', CLASS=''))
+
+ # overwritten: get rid of
tag
+ def depart_header(self, node):
+ start = self.context.pop()
+ header = [self.starttag(node, 'div', CLASS='header')]
+ header.extend(self.body[start:])
+ header.append('\n\n')
+ self.body_prefix.extend(header)
+ self.header.extend(header)
+ del self.body[start:]
+
+ # overwritten: get rid of
tag
+ def depart_footer(self, node):
+ start = self.context.pop()
+ footer = [self.starttag(node, 'div', CLASS='footer')]
+ footer.extend(self.body[start:])
+ footer.append('\n\n')
+ self.footer.extend(footer)
+ self.body_suffix[:0] = footer
+ del self.body[start:]
+
+ # overwritten
+ def depart_document(self, node):
+ self.head_prefix.extend([self.doctype,
+ self.head_prefix_template %
+ {'lang': self.settings.language_code}])
+ self.html_prolog.append(self.doctype)
+ self.meta.insert(0, self.content_type % self.settings.output_encoding)
+ self.head.insert(0, self.content_type % self.settings.output_encoding)
+ if self.math_header:
+ self.head.append(self.math_header)
+ # skip content-type meta tag with interpolated charset value:
+ self.html_head.extend(self.head[1:])
+ # self.body_prefix.append(self.starttag(node, 'div', CLASS='document'))
+ self.body_prefix.append(self.starttag(node, 'div', CLASS='container'))
+ # self.body_suffix.insert(0, '\n')
+ self.fragment.extend(self.body) # self.fragment is the "naked" body
+ self.html_body.extend(self.body_prefix[1:] + self.body_pre_docinfo
+ + self.docinfo + self.body
+ + self.body_suffix[:-1])
+ assert not self.context, 'len(context) = %s' % len(self.context)
+
+
+# -----------------------------------------------------------------------------
+class RSTReader(RstReader):
+ """
+ A custom RST reader that behaves exactly like its parent class RstReader
+ with the difference that it uses our HTMLTranslator
+ """
+
+ def _get_publisher(self, source_path):
+ extra_params = {'initial_header_level': '2',
+ 'syntax_highlight': 'short',
+ 'input_encoding': 'utf-8'}
+ user_params = self.settings.get('DOCUTILS_SETTINGS')
+ if user_params:
+ extra_params.update(user_params)
+
+ pub = Publisher(destination_class=StringOutput)
+ pub.set_components('standalone', 'restructuredtext', 'html')
+ pub.writer.translator_class = HTMLTranslator
+ pub.process_programmatic_settings(None, extra_params, None)
+ pub.set_source(source_path=source_path)
+ pub.publish()
+ return pub
+
+
+def add_reader(readers):
+ readers.reader_classes['rst'] = RSTReader
+
+def register():
+ signals.readers_init.connect(add_reader)
diff --git a/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css b/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css
new file mode 100644
index 0000000..a406992
--- /dev/null
+++ b/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css
@@ -0,0 +1,347 @@
+/*!
+ * Bootstrap v3.1.1 (http://getbootstrap.com)
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ */
+
+.btn-default,
+.btn-primary,
+.btn-success,
+.btn-info,
+.btn-warning,
+.btn-danger {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
+}
+.btn-default:active,
+.btn-primary:active,
+.btn-success:active,
+.btn-info:active,
+.btn-warning:active,
+.btn-danger:active,
+.btn-default.active,
+.btn-primary.active,
+.btn-success.active,
+.btn-info.active,
+.btn-warning.active,
+.btn-danger.active {
+ -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+ box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
+}
+.btn:active,
+.btn.active {
+ background-image: none;
+}
+.btn-default {
+ text-shadow: 0 1px 0 #fff;
+ background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
+ background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #dbdbdb;
+ border-color: #ccc;
+}
+.btn-default:hover,
+.btn-default:focus {
+ background-color: #e0e0e0;
+ background-position: 0 -15px;
+}
+.btn-default:active,
+.btn-default.active {
+ background-color: #e0e0e0;
+ border-color: #dbdbdb;
+}
+.btn-primary {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #2b669a;
+}
+.btn-primary:hover,
+.btn-primary:focus {
+ background-color: #2d6ca2;
+ background-position: 0 -15px;
+}
+.btn-primary:active,
+.btn-primary.active {
+ background-color: #2d6ca2;
+ border-color: #2b669a;
+}
+.btn-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #3e8f3e;
+}
+.btn-success:hover,
+.btn-success:focus {
+ background-color: #419641;
+ background-position: 0 -15px;
+}
+.btn-success:active,
+.btn-success.active {
+ background-color: #419641;
+ border-color: #3e8f3e;
+}
+.btn-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #28a4c9;
+}
+.btn-info:hover,
+.btn-info:focus {
+ background-color: #2aabd2;
+ background-position: 0 -15px;
+}
+.btn-info:active,
+.btn-info.active {
+ background-color: #2aabd2;
+ border-color: #28a4c9;
+}
+.btn-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #e38d13;
+}
+.btn-warning:hover,
+.btn-warning:focus {
+ background-color: #eb9316;
+ background-position: 0 -15px;
+}
+.btn-warning:active,
+.btn-warning.active {
+ background-color: #eb9316;
+ border-color: #e38d13;
+}
+.btn-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-color: #b92c28;
+}
+.btn-danger:hover,
+.btn-danger:focus {
+ background-color: #c12e2a;
+ background-position: 0 -15px;
+}
+.btn-danger:active,
+.btn-danger.active {
+ background-color: #c12e2a;
+ border-color: #b92c28;
+}
+.thumbnail,
+.img-thumbnail {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.dropdown-menu > li > a:hover,
+.dropdown-menu > li > a:focus {
+ background-color: #e8e8e8;
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.dropdown-menu > .active > a,
+.dropdown-menu > .active > a:hover,
+.dropdown-menu > .active > a:focus {
+ background-color: #357ebd;
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+ background-repeat: repeat-x;
+}
+.navbar-default {
+ background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
+ background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
+}
+.navbar-default .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
+}
+.navbar-brand,
+.navbar-nav > li > a {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
+}
+.navbar-inverse {
+ background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
+ background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
+ filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
+ background-repeat: repeat-x;
+}
+.navbar-inverse .navbar-nav > .active > a {
+ background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
+ background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
+ background-repeat: repeat-x;
+ -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+ box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
+}
+.navbar-inverse .navbar-brand,
+.navbar-inverse .navbar-nav > li > a {
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
+}
+.navbar-static-top,
+.navbar-fixed-top,
+.navbar-fixed-bottom {
+ border-radius: 0;
+}
+.alert {
+ text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
+}
+.alert-success {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #b2dba1;
+}
+.alert-info {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #9acfea;
+}
+.alert-warning {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #f5e79e;
+}
+.alert-danger {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
+ background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dca7a7;
+}
+.progress {
+ background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
+ background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-success {
+ background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
+ background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-info {
+ background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
+ background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-warning {
+ background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
+ background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
+ background-repeat: repeat-x;
+}
+.progress-bar-danger {
+ background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
+ background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
+ background-repeat: repeat-x;
+}
+.list-group {
+ border-radius: 4px;
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
+}
+.list-group-item.active,
+.list-group-item.active:hover,
+.list-group-item.active:focus {
+ text-shadow: 0 -1px 0 #3071a9;
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #3278b3;
+}
+.panel {
+ -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+ box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
+}
+.panel-default > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
+ background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-primary > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
+ background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-success > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
+ background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-info > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
+ background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-warning > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
+ background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.panel-danger > .panel-heading {
+ background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
+ background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
+ background-repeat: repeat-x;
+}
+.well {
+ background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
+ background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
+ background-repeat: repeat-x;
+ border-color: #dcdcdc;
+ -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
+}
+/*# sourceMappingURL=bootstrap-theme.css.map */
diff --git a/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css.map b/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css.map
new file mode 100644
index 0000000..b36fc9a
--- /dev/null
+++ b/plugins/bootstrap-rst/bootstrap/css/bootstrap-theme.css.map
@@ -0,0 +1 @@
+{"version":3,"sources":["less/theme.less","less/mixins.less"],"names":[],"mappings":"AAeA;AACA;AACA;AACA;AACA;AACA;EACE,wCAAA;ECoGA,2FAAA;EACQ,mFAAA;;ADhGR,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;AACD,YAAC;AAAD,YAAC;AAAD,YAAC;AAAD,SAAC;AAAD,YAAC;AAAD,WAAC;EC8FD,wDAAA;EACQ,gDAAA;;ADnER,IAAC;AACD,IAAC;EACC,sBAAA;;AAKJ;EC4PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;EAyB2C,yBAAA;EAA2B,kBAAA;;AAvBtE,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAeJ;EC2PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAgBJ;EC0PI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAiBJ;ECyPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,SAAC;AACD,SAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,SAAC;AACD,SAAC;EACC,yBAAA;EACA,qBAAA;;AAkBJ;ECwPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,YAAC;AACD,YAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,YAAC;AACD,YAAC;EACC,yBAAA;EACA,qBAAA;;AAmBJ;ECuPI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EAEA,sHAAA;EAoCF,mEAAA;ED7TA,2BAAA;EACA,qBAAA;;AAEA,WAAC;AACD,WAAC;EACC,yBAAA;EACA,4BAAA;;AAGF,WAAC;AACD,WAAC;EACC,yBAAA;EACA,qBAAA;;AA2BJ;AACA;EC6CE,kDAAA;EACQ,0CAAA;;ADpCV,cAAe,KAAK,IAAG;AACvB,cAAe,KAAK,IAAG;ECmOnB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EDpOF,yBAAA;;AAEF,cAAe,UAAU;AACzB,cAAe,UAAU,IAAG;AAC5B,cAAe,UAAU,IAAG;EC6NxB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED9NF,yBAAA;;AAUF;ECiNI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;EDrPA,kBAAA;ECaA,2FAAA;EACQ,mFAAA;;ADjBV,eAOE,YAAY,UAAU;EC0MpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,wDAAA;EACQ,gDAAA;;ADLV;AACA,WAAY,KAAK;EACf,8CAAA;;AAIF;EC+LI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EAoCF,mEAAA;;ADtOF,eAIE,YAAY,UAAU;EC2LpB,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;EApMF,uDAAA;EACQ,+CAAA;;ADCV,eASE;AATF,eAUE,YAAY,KAAK;EACf,yCAAA;;AAKJ;AACA;AACA;EACE,gBAAA;;AAUF;EACE,6CAAA;EChCA,0FAAA;EACQ,kFAAA;;AD2CV;ECqJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAKF;ECoJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAMF;ECmJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAOF;ECkJI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED5JF,qBAAA;;AAgBF;ECyII,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADlIJ;EC+HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADjIJ;EC8HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADhIJ;EC6HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD/HJ;EC4HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD9HJ;EC2HI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtHJ;EACE,kBAAA;EC/EA,kDAAA;EACQ,0CAAA;;ADiFV,gBAAgB;AAChB,gBAAgB,OAAO;AACvB,gBAAgB,OAAO;EACrB,6BAAA;EC4GE,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED7GF,qBAAA;;AAUF;ECjGE,iDAAA;EACQ,yCAAA;;AD0GV,cAAe;ECsFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADxFJ,cAAe;ECqFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADvFJ,cAAe;ECoFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADtFJ,WAAY;ECmFR,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADrFJ,cAAe;ECkFX,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;ADpFJ,aAAc;ECiFV,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;;AD5EJ;ECyEI,kBAAkB,sDAAlB;EACA,kBAAkB,oDAAlB;EACA,2BAAA;EACA,sHAAA;ED1EF,qBAAA;EC1HA,yFAAA;EACQ,iFAAA","sourcesContent":["\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-bg, 5%); @end-color: darken(@navbar-default-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-bg; @end-color: lighten(@navbar-inverse-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n}\n\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","//\n// Mixins\n// --------------------------------------------------\n\n\n// Utilities\n// -------------------------\n\n// Clearfix\n// Source: http://nicolasgallagher.com/micro-clearfix-hack/\n//\n// For modern browsers\n// 1. The space content is one way to avoid an Opera bug when the\n// contenteditable attribute is included anywhere else in the document.\n// Otherwise it causes space to appear at the top and bottom of elements\n// that are clearfixed.\n// 2. The use of `table` rather than `block` is only necessary if using\n// `:before` to contain the top-margins of child elements.\n.clearfix() {\n &:before,\n &:after {\n content: \" \"; // 1\n display: table; // 2\n }\n &:after {\n clear: both;\n }\n}\n\n// WebKit-style focus\n.tab-focus() {\n // Default\n outline: thin dotted;\n // WebKit\n outline: 5px auto -webkit-focus-ring-color;\n outline-offset: -2px;\n}\n\n// Center-align a block level element\n.center-block() {\n display: block;\n margin-left: auto;\n margin-right: auto;\n}\n\n// Sizing shortcuts\n.size(@width; @height) {\n width: @width;\n height: @height;\n}\n.square(@size) {\n .size(@size; @size);\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n &::-moz-placeholder { color: @color; // Firefox\n opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Text overflow\n// Requires inline-block or block for proper styling\n.text-overflow() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n// CSS image replacement\n//\n// Heads up! v3 launched with with only `.hide-text()`, but per our pattern for\n// mixins being reused as classes with the same name, this doesn't hold up. As\n// of v3.0.1 we have added `.text-hide()` and deprecated `.hide-text()`. Note\n// that we cannot chain the mixins together in Less, so they are repeated.\n//\n// Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757\n\n// Deprecated as of v3.0.1 (will be removed in v4)\n.hide-text() {\n font: ~\"0/0\" a;\n color: transparent;\n text-shadow: none;\n background-color: transparent;\n border: 0;\n}\n// New mixin to use as of v3.0.1\n.text-hide() {\n .hide-text();\n}\n\n\n\n// CSS3 PROPERTIES\n// --------------------------------------------------\n\n// Single side border-radius\n.border-top-radius(@radius) {\n border-top-right-radius: @radius;\n border-top-left-radius: @radius;\n}\n.border-right-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-top-right-radius: @radius;\n}\n.border-bottom-radius(@radius) {\n border-bottom-right-radius: @radius;\n border-bottom-left-radius: @radius;\n}\n.border-left-radius(@radius) {\n border-bottom-left-radius: @radius;\n border-top-left-radius: @radius;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support the\n// standard `box-shadow` property.\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Transitions\n.transition(@transition) {\n -webkit-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n// Transformations\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n transform: rotate(@degrees);\n}\n.scale(@ratio; @ratio-y...) {\n -webkit-transform: scale(@ratio, @ratio-y);\n -ms-transform: scale(@ratio, @ratio-y); // IE9 only\n transform: scale(@ratio, @ratio-y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n transform: translate(@x, @y);\n}\n.skew(@x; @y) {\n -webkit-transform: skew(@x, @y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n transform: skew(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n.backface-visibility(@visibility){\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// User select\n// For selecting text on the page\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n\n// Resize anything\n.resizable(@direction) {\n resize: @direction; // Options: horizontal, vertical, both\n overflow: auto; // Safari fix\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Opacity\n.opacity(@opacity) {\n opacity: @opacity;\n // IE8 filter\n @opacity-ie: (@opacity * 100);\n filter: ~\"alpha(opacity=@{opacity-ie})\";\n}\n\n\n\n// GRADIENTS\n// --------------------------------------------------\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, color-stop(@start-color @start-percent), color-stop(@end-color @end-percent)); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n\n// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n\n\n\n// Retina images\n//\n// Short retina mixin for setting background-image and -size\n\n.img-retina(@file-1x; @file-2x; @width-1x; @height-1x) {\n background-image: url(\"@{file-1x}\");\n\n @media\n only screen and (-webkit-min-device-pixel-ratio: 2),\n only screen and ( min--moz-device-pixel-ratio: 2),\n only screen and ( -o-min-device-pixel-ratio: 2/1),\n only screen and ( min-device-pixel-ratio: 2),\n only screen and ( min-resolution: 192dpi),\n only screen and ( min-resolution: 2dppx) {\n background-image: url(\"@{file-2x}\");\n background-size: @width-1x @height-1x;\n }\n}\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n.img-responsive(@display: block) {\n display: @display;\n max-width: 100%; // Part 1: Set a maximum relative to the parent\n height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching\n}\n\n\n// COMPONENT MIXINS\n// --------------------------------------------------\n\n// Horizontal dividers\n// -------------------------\n// Dividers (basically an hr) within dropdowns and nav lists\n.nav-divider(@color: #e5e5e5) {\n height: 1px;\n margin: ((@line-height-computed / 2) - 1) 0;\n overflow: hidden;\n background-color: @color;\n}\n\n// Panels\n// -------------------------\n.panel-variant(@border; @heading-text-color; @heading-bg-color; @heading-border) {\n border-color: @border;\n\n & > .panel-heading {\n color: @heading-text-color;\n background-color: @heading-bg-color;\n border-color: @heading-border;\n\n + .panel-collapse .panel-body {\n border-top-color: @border;\n }\n }\n & > .panel-footer {\n + .panel-collapse .panel-body {\n border-bottom-color: @border;\n }\n }\n}\n\n// Alerts\n// -------------------------\n.alert-variant(@background; @border; @text-color) {\n background-color: @background;\n border-color: @border;\n color: @text-color;\n\n hr {\n border-top-color: darken(@border, 5%);\n }\n .alert-link {\n color: darken(@text-color, 10%);\n }\n}\n\n// Tables\n// -------------------------\n.table-row-variant(@state; @background) {\n // Exact selectors below required to override `.table-striped` and prevent\n // inheritance to nested tables.\n .table > thead > tr,\n .table > tbody > tr,\n .table > tfoot > tr {\n > td.@{state},\n > th.@{state},\n &.@{state} > td,\n &.@{state} > th {\n background-color: @background;\n }\n }\n\n // Hover states for `.table-hover`\n // Note: this is not available for cells or rows within `thead` or `tfoot`.\n .table-hover > tbody > tr {\n > td.@{state}:hover,\n > th.@{state}:hover,\n &.@{state}:hover > td,\n &.@{state}:hover > th {\n background-color: darken(@background, 5%);\n }\n }\n}\n\n// List Groups\n// -------------------------\n.list-group-item-variant(@state; @background; @color) {\n .list-group-item-@{state} {\n color: @color;\n background-color: @background;\n\n a& {\n color: @color;\n\n .list-group-item-heading { color: inherit; }\n\n &:hover,\n &:focus {\n color: @color;\n background-color: darken(@background, 5%);\n }\n &.active,\n &.active:hover,\n &.active:focus {\n color: #fff;\n background-color: @color;\n border-color: @color;\n }\n }\n }\n}\n\n// Button variants\n// -------------------------\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n.button-variant(@color; @background; @border) {\n color: @color;\n background-color: @background;\n border-color: @border;\n\n &:hover,\n &:focus,\n &:active,\n &.active,\n .open .dropdown-toggle& {\n color: @color;\n background-color: darken(@background, 8%);\n border-color: darken(@border, 12%);\n }\n &:active,\n &.active,\n .open .dropdown-toggle& {\n background-image: none;\n }\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &:active,\n &.active {\n background-color: @background;\n border-color: @border;\n }\n }\n\n .badge {\n color: @background;\n background-color: @color;\n }\n}\n\n// Button sizes\n// -------------------------\n.button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n line-height: @line-height;\n border-radius: @border-radius;\n}\n\n// Pagination\n// -------------------------\n.pagination-size(@padding-vertical; @padding-horizontal; @font-size; @border-radius) {\n > li {\n > a,\n > span {\n padding: @padding-vertical @padding-horizontal;\n font-size: @font-size;\n }\n &:first-child {\n > a,\n > span {\n .border-left-radius(@border-radius);\n }\n }\n &:last-child {\n > a,\n > span {\n .border-right-radius(@border-radius);\n }\n }\n }\n}\n\n// Labels\n// -------------------------\n.label-variant(@color) {\n background-color: @color;\n &[href] {\n &:hover,\n &:focus {\n background-color: darken(@color, 10%);\n }\n }\n}\n\n// Contextual backgrounds\n// -------------------------\n.bg-variant(@color) {\n background-color: @color;\n a&:hover {\n background-color: darken(@color, 10%);\n }\n}\n\n// Typography\n// -------------------------\n.text-emphasis-variant(@color) {\n color: @color;\n a&:hover {\n color: darken(@color, 10%);\n }\n}\n\n// Navbar vertical align\n// -------------------------\n// Vertically center elements in the navbar.\n// Example: an element has a height of 30px, so write out `.navbar-vertical-align(30px);` to calculate the appropriate top margin.\n.navbar-vertical-align(@element-height) {\n margin-top: ((@navbar-height - @element-height) / 2);\n margin-bottom: ((@navbar-height - @element-height) / 2);\n}\n\n// Progress bars\n// -------------------------\n.progress-bar-variant(@color) {\n background-color: @color;\n .progress-striped & {\n #gradient > .striped();\n }\n}\n\n// Responsive utilities\n// -------------------------\n// More easily include all the states for responsive-utilities.less.\n.responsive-visibility() {\n display: block !important;\n table& { display: table; }\n tr& { display: table-row !important; }\n th&,\n td& { display: table-cell !important; }\n}\n\n.responsive-invisibility() {\n display: none !important;\n}\n\n\n// Grid System\n// -----------\n\n// Centered container element\n.container-fixed() {\n margin-right: auto;\n margin-left: auto;\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n &:extend(.clearfix all);\n}\n\n// Creates a wrapper for a series of columns\n.make-row(@gutter: @grid-gutter-width) {\n margin-left: (@gutter / -2);\n margin-right: (@gutter / -2);\n &:extend(.clearfix all);\n}\n\n// Generate the extra small columns\n.make-xs-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n float: left;\n width: percentage((@columns / @grid-columns));\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n}\n.make-xs-column-offset(@columns) {\n @media (min-width: @screen-xs-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-push(@columns) {\n @media (min-width: @screen-xs-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-xs-column-pull(@columns) {\n @media (min-width: @screen-xs-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the small columns\n.make-sm-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-sm-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-offset(@columns) {\n @media (min-width: @screen-sm-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-push(@columns) {\n @media (min-width: @screen-sm-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-sm-column-pull(@columns) {\n @media (min-width: @screen-sm-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the medium columns\n.make-md-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-md-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-offset(@columns) {\n @media (min-width: @screen-md-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-push(@columns) {\n @media (min-width: @screen-md-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-md-column-pull(@columns) {\n @media (min-width: @screen-md-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Generate the large columns\n.make-lg-column(@columns; @gutter: @grid-gutter-width) {\n position: relative;\n min-height: 1px;\n padding-left: (@gutter / 2);\n padding-right: (@gutter / 2);\n\n @media (min-width: @screen-lg-min) {\n float: left;\n width: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-offset(@columns) {\n @media (min-width: @screen-lg-min) {\n margin-left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-push(@columns) {\n @media (min-width: @screen-lg-min) {\n left: percentage((@columns / @grid-columns));\n }\n}\n.make-lg-column-pull(@columns) {\n @media (min-width: @screen-lg-min) {\n right: percentage((@columns / @grid-columns));\n }\n}\n\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `@grid-columns`.\n\n.make-grid-columns() {\n // Common styles for all sizes of grid columns, widths 1-12\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general; \"=<\" isn't a typo\n @item: ~\".col-xs-@{index}, .col-sm-@{index}, .col-md-@{index}, .col-lg-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n position: relative;\n // Prevent columns from collapsing when empty\n min-height: 1px;\n // Inner gutter via padding\n padding-left: (@grid-gutter-width / 2);\n padding-right: (@grid-gutter-width / 2);\n }\n }\n .col(1); // kickstart it\n}\n\n.float-grid-columns(@class) {\n .col(@index) when (@index = 1) { // initial\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), @item);\n }\n .col(@index, @list) when (@index =< @grid-columns) { // general\n @item: ~\".col-@{class}-@{index}\";\n .col((@index + 1), ~\"@{list}, @{item}\");\n }\n .col(@index, @list) when (@index > @grid-columns) { // terminal\n @{list} {\n float: left;\n }\n }\n .col(1); // kickstart it\n}\n\n.calc-grid-column(@index, @class, @type) when (@type = width) and (@index > 0) {\n .col-@{class}-@{index} {\n width: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = push) {\n .col-@{class}-push-@{index} {\n left: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = pull) {\n .col-@{class}-pull-@{index} {\n right: percentage((@index / @grid-columns));\n }\n}\n.calc-grid-column(@index, @class, @type) when (@type = offset) {\n .col-@{class}-offset-@{index} {\n margin-left: percentage((@index / @grid-columns));\n }\n}\n\n// Basic looping in LESS\n.loop-grid-columns(@index, @class, @type) when (@index >= 0) {\n .calc-grid-column(@index, @class, @type);\n // next iteration\n .loop-grid-columns((@index - 1), @class, @type);\n}\n\n// Create grid for specific class\n.make-grid(@class) {\n .float-grid-columns(@class);\n .loop-grid-columns(@grid-columns, @class, width);\n .loop-grid-columns(@grid-columns, @class, pull);\n .loop-grid-columns(@grid-columns, @class, push);\n .loop-grid-columns(@grid-columns, @class, offset);\n}\n\n// Form validation states\n//\n// Used in forms.less to generate the form validation CSS for warnings, errors,\n// and successes.\n\n.form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) {\n // Color the label and help text\n .help-block,\n .control-label,\n .radio,\n .checkbox,\n .radio-inline,\n .checkbox-inline {\n color: @text-color;\n }\n // Set the border and box shadow on specific inputs to match\n .form-control {\n border-color: @border-color;\n .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work\n &:focus {\n border-color: darken(@border-color, 10%);\n @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%);\n .box-shadow(@shadow);\n }\n }\n // Set validation states also for addons\n .input-group-addon {\n color: @text-color;\n border-color: @border-color;\n background-color: @background-color;\n }\n // Optional feedback icon\n .form-control-feedback {\n color: @text-color;\n }\n}\n\n// Form control focus state\n//\n// Generate a customized focus state and for any input with the specified color,\n// which defaults to the `@input-focus-border` variable.\n//\n// We highly encourage you to not customize the default value, but instead use\n// this to tweak colors on an as-needed basis. This aesthetic change is based on\n// WebKit's default styles, but applicable to a wider range of browsers. Its\n// usability and accessibility should be taken into account with any change.\n//\n// Example usage: change the default blue border and shadow to white for better\n// contrast against a dark gray background.\n\n.form-control-focus(@color: @input-border-focus) {\n @color-rgba: rgba(red(@color), green(@color), blue(@color), .6);\n &:focus {\n border-color: @color;\n outline: 0;\n .box-shadow(~\"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}\");\n }\n}\n\n// Form control sizing\n//\n// Relative text size, padding, and border-radii changes for form controls. For\n// horizontal sizing, wrap controls in the predefined grid classes. `