Commits

Oben Sonne committed 43f18bf Merge

Merge in default

  • Participants
  • Parent commits 09467f6, 625d57a
  • Branches py3

Comments (0)

Files changed (48)

 tests/actual
 tests/errors.diff
 
+# misc
+box/
+SNAPSHOT*
+
 # IDE files:
 .settings
 .project
-syntax: regexp
-^tests/actual$
-^tests/errors.diff$
-\.pyc$
-~$
-^.project$
-^.pydevproject$
+syntax: glob
+tests/actual
+tests/errors.diff
+*.pyc
+*~
+.project
+.pydevproject
+box
+SNAPSHOT*
+.settings
 
     $ mkdir /path/to/site/project
     $ cd /path/to/site/project
-    $ poole.py --init
+    $ poole.py --init --theme minimal
     $ poole.py --build
     $ poole.py --serve
 
 Done. You've just created a website! Browse <http://localhost:8080/> and watch
-the example pages which have been created during initialization.
+the example pages which have been created during initialization. To write your
+own pages, use the example pages in the *input* folder as a starting point.
 
-To write your own pages, use the example pages in the *input* folder as a
-starting point.
+Next to the *miniaml* theme, there are some other [choices available][themes].
 
 Run `poole.py --build` whenever you've made some changes in the *input* folder.
 
 [tgz]: http://bitbucket.org/obensonne/poole/get/default.tar.gz
 [zip3]: https://bitbucket.org/obensonne/poole/get/py3.zip
 [tgz3]: http://bitbucket.org/obensonne/poole/get/py3.tar.gz
+[themes]: https://bitbucket.org/obensonne/poole/wiki/Themes
 
 ## How It Works
 
 
 Currently, there is only one builtin macro available.
 
-`htmlspecialchars(s)`
+`hx(s)`
 
 > Replace the characters that are special within HTML (`&`, `<`, `>` and `"`)
 > with their equivalent character entity (e.g., `&amp;`). This should be
 > called whenever an arbitrary string is inserted into HTML (i.e. use
-> `{{ htmlspecialchars(variable) }}` instead of `{{ variable }}`).
+> `{{ hx(variable) }}` instead of `{{ variable }}`). You do not need this
+> within a markdown context.
 >
 > Note that `"` is not special in most HTML, only within attributes.
 > However, since escaping it does not hurt within normal HTML, it is
 
 UTF8 = 'UTF8'
 
+HERE = os.path.dirname(os.path.realpath(__file__))
+
+THEME_DIR = opj(HERE, 'themes')
+
+THEME_NAMES = ['minimal'] + [
+    os.path.basename(x)
+    for x in glob.glob(opj(THEME_DIR, '*'))
+    if os.path.isdir(x)
+]
+
 # =============================================================================
 # init site
 # =============================================================================
 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
-    <title>poole - {{ htmlspecialchars(page["title"]) }}</title>
-    <meta name="description" content="{{ htmlspecialchars(page.get("description", "a poole site")) }}" />
-    <meta name="keywords" content="{{ htmlspecialchars(page.get("keywords", "poole")) }}" />
-    <link rel="stylesheet" type="text/css" href="poole.css" />
+    <title>poole - {{ hx(page["title"]) }}</title>
+    <meta name="description" content="{{ hx(page.get("description", "a poole site")) }}" />
+    <meta name="keywords" content="{{ hx(page.get("keywords", "poole")) }}" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">
     <div id="header">
          <h1>a poole site</h1>
-         <h2>{{ htmlspecialchars(page["title"]) }}</h2>
+         <h2>{{ hx(page["title"]) }}</h2>
     </div>
     <div id="menu">
     <!--%
         mpages.sort(key=lambda p: int(p["menu-position"]))
         entry = '<span class="%s"><a href="%s">%s</a></span>'
         for p in mpages:
-            style = p["title"] == page["title"] and "current" or ""
-            print(entry % (style, htmlspecialchars(p["url"]), htmlspecialchars(p["title"])))
+            style = "current" if p["title"] == page["title"] else ""
+            print(entry % (style, p["url"], hx(p["title"])))
     %-->
     </div>
     <div id="content">{{ __content__ }}</div>
 menu-position: 3
 ---
 Every page of a poole site is based on *one global template file*, `page.html`.
-All you need to adjust the site layout is to
-
- * edit the page template `page.html` and
- * extend or edit the style file `input/poole.css`.
+All you need to adjust the site layout is to edit the page template
+`page.html`.
 """,
 
 opj("input", "blog.md"): """
 
 # -----------------------------------------------------------------------------
 
-opj("input", "blog.2010-02-22.Doctors_in_my_penguin.md") : """
+opj("input", "blog.2013-04-08.Lorem_Ipsum.md") : """
 
 ---
 ## {{ page["post"] }}
 print(datetime.strptime(page["date"], "%Y-%m-%d").strftime("%B %d, %Y"))
 %-->*
 
-There is a bank in my eel, your argument is invalid.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sed pretium arcu.
+Nullam eu leo ut justo egestas condimentum sed id dolor. In suscipit est eu
+tellus lacinia congue. Nunc tincidunt posuere nibh vitae accumsan. Suspendisse
+quis justo quis nulla rhoncus venenatis. Cum sociis natoque penatibus et magnis
+dis parturient montes, nascetur ridiculus mus. Suspendisse potenti.
 
-More nonsense at <http://automeme.net/>.
+Nullam luctus tortor ac libero eleifend interdum nec eget dolor. Aliquam quis
+massa metus, id fringilla odio. Fusce lobortis sollicitudin gravida. Donec
+porttitor metus aliquam diam consectetur vitae tristique ligula aliquet. Nulla
+facilisi. Mauris eleifend erat id velit eleifend facilisis. Proin orci lacus,
+imperdiet eu mollis ac, cursus sit amet ligula. Ut id neque urna, sed dignissim
+urna. Cras sit amet sodales orci. In at lacus dui. Duis mi neque, posuere ut
+congue non, ornare a magna. Fusce massa ligula, vestibulum sed vulputate quis,
+sodales at massa.
 
 No-ASCII characters like `öäüß` are no problems as long as input files are
 encoded in UTF8.
 
 # -----------------------------------------------------------------------------
 
-opj("input", "blog.2010-03-01.I_ate_all the pokemans.md"): """
+opj("input", "blog.2013-04-01.Holy_Grail.md"): """
 
 ## {{ page["post"] }}
 
 *Posted at <!--{ page["date"] }-->.*
 
-What *are* interior crocodile alligators? We just don't know.
+Knights of Ni, we are but simple travelers who seek the enchanter who lives
+beyond these woods. A newt? Did you dress her up like this? On second thoughts,
+let's not go there. It is a silly place. You don't vote for kings. Knights of
+Ni, we are but simple travelers who seek the enchanter who lives beyond these
+woods.
 
-More nonsense at <http://automeme.net/>.
-""",
+### Bridgekeeper ###
 
-# -----------------------------------------------------------------------------
+Camelot! What do you mean? And this isn't my nose. This is a false one. Ah, now
+we see the violence inherent in the system!
 
-opj("input", "poole.css"): """
-body {
-    font-family: sans;
-    width: 800px;
-    margin: 1em auto;
-    color: #2e3436;
-}
-div#box {
-    border: solid #2e3436 1px;
-}
-div#header, div#menu, div#content, div#footer {
-    padding: 1em;
-}
-div#menu {
-    background-color: #2e3436;
-    padding: 0.6em 0 0.6em 0;
-}
-#menu span {
-    background-color: #2e3436;
-    font-weight: bold;
-    padding: 0.6em;
-}
-#menu span.current {
-    background-color: #555753;
-}
-#menu a {
-    color: #fefefc;
-    text-decoration: none;
-}
-div#footer {
-    color: gray;
-    text-align: center;
-    font-size: small;
-}
-div#footer a {
-    color: gray;
-    text-decoration: none;
-}
-pre {
-    border: dotted black 1px;
-    background: #eeeeec;
-    font-size: small;
-    padding: 1em;
-}
+You don't frighten us, English pig-dogs! Go and boil your bottoms, sons of a
+silly person! I blow my nose at you, so-called Ah-thoor Keeng, you and all your
+silly English K-n-n-n-n-n-n-n-niggits! I don't want to talk to you no more, you
+empty-headed animal food trough water! I fart in your general direction! Your
+mother was a hamster and your father smelt of elderberries! Now leave before I
+am forced to taunt you a second time! Shh! Knights, I bid you welcome to your
+new home. Let us ride to Camelot! Now, look here, my good man.
 
+### What a strange ###
+
+She looks like one. Why do you think that she is a witch? Look, my liege! Bring
+her forward!
+
+[Ni!](http://chrisvalleskey.com/fillerama/)
 """
 }
 
-def init(project):
+def init(project, theme):
     """Initialize a site project."""
 
     if not opx(project):
         print("abort  : project dir %s is not empty" % project)
         sys.exit(1)
 
-    os.mkdir(opj(project, "input"))
-    os.mkdir(opj(project, "output"))
+    dir_in = opj(project, "input")
+    dir_out = opj(project, "output")
+
+    os.mkdir(dir_in)
+    os.mkdir(dir_out)
 
     for fname, content in EXAMPLE_FILES.items():
+        print('info: create example %r' % fname)
         with open(opj(project, fname), 'w') as fp:
             fp.write(content)
 
+    if theme != 'minimal':
+        shutil.copy(opj(THEME_DIR, theme, 'page.html'), project)
+        for fname in glob.glob(opj(THEME_DIR, theme, '*')):
+            print('info: copy theme data %r' % fname)
+            if os.path.basename(fname) == 'page.html':
+                continue
+            if os.path.isdir(fname):
+                shutil.copytree(fname, opj(dir_in, os.path.basename(fname)))
+            else:
+                shutil.copy(fname, dir_in)
+
     print("success: initialized project")
 
 # =============================================================================
 
 MKD_PATT = r'\.(?:md|mkd|mdown|markdown)$'
 
+def hx(s):
+    """
+    Replace the characters that are special within HTML (&, <, > and ")
+    with their equivalent character entity (e.g., &amp;). This should be
+    called whenever an arbitrary string is inserted into HTML (so in most
+    places where you use {{ variable }} in your templates).
+
+    Note that " is not special in most HTML, only within attributes.
+    However, since escaping it does not hurt within normal HTML, it is
+    just escaped unconditionally.
+    """
+    if getattr(s, 'escaped', False):
+        return s
+
+    escape = {
+        "&": "&amp;",
+        '"': "&quot;",
+        ">": "&gt;",
+        "<": "&lt;",
+    }
+    return ''.join(escape.get(c, c) for c in s)
+
 class Page(dict):
     """Abstraction of a source page."""
 
     macros["input"] = dir_in
     macros["output"] = dir_out
 
-    # "builtin" functions for use in macros and templates
-    macros["htmlspecialchars"] = htmlspecialchars
+    # "builtin" items for use in macros and templates
+    macros["hx"] = hx
+    macros["htmlspecialchars"] = hx # legacy name of `htmlx` function
     macros["Page"] = Page
 
     # -------------------------------------------------------------------------
 def options():
     """Parse and validate command line arguments."""
 
-    usage = ("Usage: %prog --init [path/to/project]\n"
+    usage = ("Usage: %prog --init  [OPTIONS] [path/to/project]\n"
              "       %prog --build [OPTIONS] [path/to/project]\n"
              "       %prog --serve [OPTIONS] [path/to/project]\n"
              "\n"
     op.add_option("-s" , "--serve", action="store_true", default=False,
                   help="serve project")
 
+    og = optparse.OptionGroup(op, "Init options")
+    og.add_option("", "--theme", type="choice", default="minimal",
+                  choices=THEME_NAMES,
+                  help="theme for a new project (choices: %s)" % ', '.join(THEME_NAMES))
+    op.add_option_group(og)
+
     og = optparse.OptionGroup(op, "Build options")
     og.add_option("", "--base-url", default="/", metavar="URL",
                   help="base url for relative links (default: /)")
     return opts
 
 # =============================================================================
-# template helper functions
-# =============================================================================
-
-def htmlspecialchars(s):
-    """
-    Replace the characters that are special within HTML (&, <, > and ")
-    with their equivalent character entity (e.g., &amp;). This should be
-    called whenever an arbitrary string is inserted into HTML (so in most
-    places where you use {{ variable }} in your templates).
-
-    Note that " is not special in most HTML, only within attributes.
-    However, since escaping it does not hurt within normal HTML, it is
-    just escaped unconditionally.
-    """
-    escape = {
-        "&": "&amp;",
-        '"': "&quot;",
-        ">": "&gt;",
-        "<": "&lt;",
-    }
-
-    # Look up the translation for every character in s (defaulting to
-    # the character itself if no translation is available).
-    return ''.join([escape.get(c,c) for c in s])
-
-# =============================================================================
 # main
 # =============================================================================
 
     opts = options()
 
     if opts.init:
-        init(opts.project)
+        init(opts.project, opts.theme)
     if opts.build:
         build(opts.project, opts)
     if opts.serve:

File tests/expected/input/blog.2010-02-22.Doctors_in_my_penguin.md

-
-
----
-## {{ page["post"] }}
-
-*Posted at
-<!--%
-from datetime import datetime
-print(datetime.strptime(page["date"], "%Y-%m-%d").strftime("%B %d, %Y"))
-%-->*
-
-There is a bank in my eel, your argument is invalid.
-
-More nonsense at <http://automeme.net/>.
-
-No-ASCII characters like `öäüß` are no problems as long as input files are
-encoded in UTF8.

File tests/expected/input/blog.2010-03-01.I_ate_all the pokemans.md

-
-
-## {{ page["post"] }}
-
-*Posted at <!--{ page["date"] }-->.*
-
-What *are* interior crocodile alligators? We just don't know.
-
-More nonsense at <http://automeme.net/>.

File tests/expected/input/blog.2013-04-01.Holy_Grail.md

+
+
+## {{ page["post"] }}
+
+*Posted at <!--{ page["date"] }-->.*
+
+Knights of Ni, we are but simple travelers who seek the enchanter who lives
+beyond these woods. A newt? Did you dress her up like this? On second thoughts,
+let's not go there. It is a silly place. You don't vote for kings. Knights of
+Ni, we are but simple travelers who seek the enchanter who lives beyond these
+woods.
+
+### Bridgekeeper ###
+
+Camelot! What do you mean? And this isn't my nose. This is a false one. Ah, now
+we see the violence inherent in the system!
+
+You don't frighten us, English pig-dogs! Go and boil your bottoms, sons of a
+silly person! I blow my nose at you, so-called Ah-thoor Keeng, you and all your
+silly English K-n-n-n-n-n-n-n-niggits! I don't want to talk to you no more, you
+empty-headed animal food trough water! I fart in your general direction! Your
+mother was a hamster and your father smelt of elderberries! Now leave before I
+am forced to taunt you a second time! Shh! Knights, I bid you welcome to your
+new home. Let us ride to Camelot! Now, look here, my good man.
+
+### What a strange ###
+
+She looks like one. Why do you think that she is a witch? Look, my liege! Bring
+her forward!
+
+[Ni!](http://chrisvalleskey.com/fillerama/)

File tests/expected/input/blog.2013-04-08.Lorem_Ipsum.md

+
+
+---
+## {{ page["post"] }}
+
+*Posted at
+<!--%
+from datetime import datetime
+print(datetime.strptime(page["date"], "%Y-%m-%d").strftime("%B %d, %Y"))
+%-->*
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sed pretium arcu.
+Nullam eu leo ut justo egestas condimentum sed id dolor. In suscipit est eu
+tellus lacinia congue. Nunc tincidunt posuere nibh vitae accumsan. Suspendisse
+quis justo quis nulla rhoncus venenatis. Cum sociis natoque penatibus et magnis
+dis parturient montes, nascetur ridiculus mus. Suspendisse potenti.
+
+Nullam luctus tortor ac libero eleifend interdum nec eget dolor. Aliquam quis
+massa metus, id fringilla odio. Fusce lobortis sollicitudin gravida. Donec
+porttitor metus aliquam diam consectetur vitae tristique ligula aliquet. Nulla
+facilisi. Mauris eleifend erat id velit eleifend facilisis. Proin orci lacus,
+imperdiet eu mollis ac, cursus sit amet ligula. Ut id neque urna, sed dignissim
+urna. Cras sit amet sodales orci. In at lacus dui. Duis mi neque, posuere ut
+congue non, ornare a magna. Fusce massa ligula, vestibulum sed vulputate quis,
+sodales at massa.
+
+No-ASCII characters like `öäüß` are no problems as long as input files are
+encoded in UTF8.

File tests/expected/input/layout.md

 menu-position: 3
 ---
 Every page of a poole site is based on *one global template file*, `page.html`.
-All you need to adjust the site layout is to
-
- * edit the page template `page.html` and
- * extend or edit the style file `input/poole.css`.
+All you need to adjust the site layout is to edit the page template
+`page.html`.

File tests/expected/input/poole.css

-
-body {
-    font-family: sans;
-    width: 800px;
-    margin: 1em auto;
-    color: #2e3436;
-}
-div#box {
-    border: solid #2e3436 1px;
-}
-div#header, div#menu, div#content, div#footer {
-    padding: 1em;
-}
-div#menu {
-    background-color: #2e3436;
-    padding: 0.6em 0 0.6em 0;
-}
-#menu span {
-    background-color: #2e3436;
-    font-weight: bold;
-    padding: 0.6em;
-}
-#menu span.current {
-    background-color: #555753;
-}
-#menu a {
-    color: #fefefc;
-    text-decoration: none;
-}
-div#footer {
-    color: gray;
-    text-align: center;
-    font-size: small;
-}
-div#footer a {
-    color: gray;
-    text-decoration: none;
-}
-pre {
-    border: dotted black 1px;
-    background: #eeeeec;
-    font-size: small;
-    padding: 1em;
-}
-

File tests/expected/output/blog.2010-02-22.Doctors_in_my_penguin.html

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
-<head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
-    <title>poole - blog</title>
-    <meta name="description" content="a poole site" />
-    <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
-</head>
-<body>
-    <div id="box">
-    <div id="header">
-         <h1>a poole site</h1>
-         <h2>blog</h2>
-    </div>
-    <div id="menu">
-    <span class=""><a href="/index.html">home</a></span>
-<span class=""><a href="/layout.html">layout</a></span>
-<span class=""><a href="/logic.html">logic</a></span>
-<span class="current"><a href="/blog.html">blog</a></span>
-    </div>
-    <div id="content"><h2>Doctors in my penguin</h2>
-<p><em>Posted at
-February 22, 2010</em></p>
-<p>There is a bank in my eel, your argument is invalid.</p>
-<p>More nonsense at <a href="http://automeme.net/">http://automeme.net/</a>.</p>
-<p>No-ASCII characters like <code>öäüß</code> are no problems as long as input files are
-encoded in UTF8.</p></div>
-    </div>
-    <div id="footer">
-        Built with <a href="http://bitbucket.org/obensonne/poole">Poole</a>
-        &middot;
-        Licensed as <a href="http://creativecommons.org/licenses/by-sa/3.0">CC-SA</a>
-        &middot;
-        <a href="http://validator.w3.org/check?uri=referer">Validate me</a>
-    </div>
-</body>
-</html>

File tests/expected/output/blog.2010-03-01.I_ate_all the pokemans.html

-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
-<head>
-    <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
-    <title>poole - blog</title>
-    <meta name="description" content="a poole site" />
-    <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
-</head>
-<body>
-    <div id="box">
-    <div id="header">
-         <h1>a poole site</h1>
-         <h2>blog</h2>
-    </div>
-    <div id="menu">
-    <span class=""><a href="/index.html">home</a></span>
-<span class=""><a href="/layout.html">layout</a></span>
-<span class=""><a href="/logic.html">logic</a></span>
-<span class="current"><a href="/blog.html">blog</a></span>
-    </div>
-    <div id="content"><h2>I ate all the pokemans</h2>
-<p><em>Posted at 2010-03-01.</em></p>
-<p>What <em>are</em> interior crocodile alligators? We just don't know.</p>
-<p>More nonsense at <a href="http://automeme.net/">http://automeme.net/</a>.</p></div>
-    </div>
-    <div id="footer">
-        Built with <a href="http://bitbucket.org/obensonne/poole">Poole</a>
-        &middot;
-        Licensed as <a href="http://creativecommons.org/licenses/by-sa/3.0">CC-SA</a>
-        &middot;
-        <a href="http://validator.w3.org/check?uri=referer">Validate me</a>
-    </div>
-</body>
-</html>

File tests/expected/output/blog.2013-04-01.Holy_Grail.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
+    <title>poole - blog</title>
+    <meta name="description" content="a poole site" />
+    <meta name="keywords" content="poole" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
+</head>
+<body>
+    <div id="box">
+    <div id="header">
+         <h1>a poole site</h1>
+         <h2>blog</h2>
+    </div>
+    <div id="menu">
+    <span class=""><a href="/index.html">home</a></span>
+<span class=""><a href="/layout.html">layout</a></span>
+<span class=""><a href="/logic.html">logic</a></span>
+<span class="current"><a href="/blog.html">blog</a></span>
+    </div>
+    <div id="content"><h2>Holy Grail</h2>
+<p><em>Posted at 2013-04-01.</em></p>
+<p>Knights of Ni, we are but simple travelers who seek the enchanter who lives
+beyond these woods. A newt? Did you dress her up like this? On second thoughts,
+let's not go there. It is a silly place. You don't vote for kings. Knights of
+Ni, we are but simple travelers who seek the enchanter who lives beyond these
+woods.</p>
+<h3>Bridgekeeper</h3>
+<p>Camelot! What do you mean? And this isn't my nose. This is a false one. Ah, now
+we see the violence inherent in the system!</p>
+<p>You don't frighten us, English pig-dogs! Go and boil your bottoms, sons of a
+silly person! I blow my nose at you, so-called Ah-thoor Keeng, you and all your
+silly English K-n-n-n-n-n-n-n-niggits! I don't want to talk to you no more, you
+empty-headed animal food trough water! I fart in your general direction! Your
+mother was a hamster and your father smelt of elderberries! Now leave before I
+am forced to taunt you a second time! Shh! Knights, I bid you welcome to your
+new home. Let us ride to Camelot! Now, look here, my good man.</p>
+<h3>What a strange</h3>
+<p>She looks like one. Why do you think that she is a witch? Look, my liege! Bring
+her forward!</p>
+<p><a href="http://chrisvalleskey.com/fillerama/">Ni!</a></p></div>
+    </div>
+    <div id="footer">
+        Built with <a href="http://bitbucket.org/obensonne/poole">Poole</a>
+        &middot;
+        Licensed as <a href="http://creativecommons.org/licenses/by-sa/3.0">CC-SA</a>
+        &middot;
+        <a href="http://validator.w3.org/check?uri=referer">Validate me</a>
+    </div>
+</body>
+</html>

File tests/expected/output/blog.2013-04-08.Lorem_Ipsum.html

+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+<head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
+    <title>poole - blog</title>
+    <meta name="description" content="a poole site" />
+    <meta name="keywords" content="poole" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
+</head>
+<body>
+    <div id="box">
+    <div id="header">
+         <h1>a poole site</h1>
+         <h2>blog</h2>
+    </div>
+    <div id="menu">
+    <span class=""><a href="/index.html">home</a></span>
+<span class=""><a href="/layout.html">layout</a></span>
+<span class=""><a href="/logic.html">logic</a></span>
+<span class="current"><a href="/blog.html">blog</a></span>
+    </div>
+    <div id="content"><h2>Lorem Ipsum</h2>
+<p><em>Posted at
+April 08, 2013</em></p>
+<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed sed pretium arcu.
+Nullam eu leo ut justo egestas condimentum sed id dolor. In suscipit est eu
+tellus lacinia congue. Nunc tincidunt posuere nibh vitae accumsan. Suspendisse
+quis justo quis nulla rhoncus venenatis. Cum sociis natoque penatibus et magnis
+dis parturient montes, nascetur ridiculus mus. Suspendisse potenti.</p>
+<p>Nullam luctus tortor ac libero eleifend interdum nec eget dolor. Aliquam quis
+massa metus, id fringilla odio. Fusce lobortis sollicitudin gravida. Donec
+porttitor metus aliquam diam consectetur vitae tristique ligula aliquet. Nulla
+facilisi. Mauris eleifend erat id velit eleifend facilisis. Proin orci lacus,
+imperdiet eu mollis ac, cursus sit amet ligula. Ut id neque urna, sed dignissim
+urna. Cras sit amet sodales orci. In at lacus dui. Duis mi neque, posuere ut
+congue non, ornare a magna. Fusce massa ligula, vestibulum sed vulputate quis,
+sodales at massa.</p>
+<p>No-ASCII characters like <code>öäüß</code> are no problems as long as input files are
+encoded in UTF8.</p></div>
+    </div>
+    <div id="footer">
+        Built with <a href="http://bitbucket.org/obensonne/poole">Poole</a>
+        &middot;
+        Licensed as <a href="http://creativecommons.org/licenses/by-sa/3.0">CC-SA</a>
+        &middot;
+        <a href="http://validator.w3.org/check?uri=referer">Validate me</a>
+    </div>
+</body>
+</html>

File tests/expected/output/blog.html

     <title>poole - blog</title>
     <meta name="description" content="a poole site" />
     <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">
 Poole recognizes the date and post title and sets them as attributes of the
 page. These attributes can then be used to generate a list of blog posts:</p>
 <ul>
-<li><strong><a href="/blog.2010-03-01.I_ate_all%20the%20pokemans.html">I ate all the pokemans</a></strong> - March 01, 2010</li>
-<li><strong><a href="/blog.2010-02-22.Doctors_in_my_penguin.html">Doctors in my penguin</a></strong> - February 22, 2010</li>
+<li><strong><a href="/blog.2013-04-08.Lorem_Ipsum.html">Lorem Ipsum</a></strong> - April 08, 2013</li>
+<li><strong><a href="/blog.2013-04-01.Holy_Grail.html">Holy Grail</a></strong> - April 01, 2013</li>
 </ul>
 <p>Have a look into <code>input/blog.md</code> to see how it works. Feel free to adjust it
 to your needs.</p></div>

File tests/expected/output/index.html

     <title>poole - home</title>
     <meta name="description" content="a poole site" />
     <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">

File tests/expected/output/layout.html

     <title>poole - layout</title>
     <meta name="description" content="a poole site" />
     <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">
 <span class=""><a href="/blog.html">blog</a></span>
     </div>
     <div id="content"><p>Every page of a poole site is based on <em>one global template file</em>, <code>page.html</code>.
-All you need to adjust the site layout is to</p>
-<ul>
-<li>edit the page template <code>page.html</code> and</li>
-<li>extend or edit the style file <code>input/poole.css</code>.</li>
-</ul></div>
+All you need to adjust the site layout is to edit the page template
+<code>page.html</code>.</p></div>
     </div>
     <div id="footer">
         Built with <a href="http://bitbucket.org/obensonne/poole">Poole</a>

File tests/expected/output/logic.html

     <title>poole - logic</title>
     <meta name="description" content="a poole site" />
     <meta name="keywords" content="poole" />
-    <link rel="stylesheet" type="text/css" href="/poole.css" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">

File tests/expected/output/poole.css

-
-body {
-    font-family: sans;
-    width: 800px;
-    margin: 1em auto;
-    color: #2e3436;
-}
-div#box {
-    border: solid #2e3436 1px;
-}
-div#header, div#menu, div#content, div#footer {
-    padding: 1em;
-}
-div#menu {
-    background-color: #2e3436;
-    padding: 0.6em 0 0.6em 0;
-}
-#menu span {
-    background-color: #2e3436;
-    font-weight: bold;
-    padding: 0.6em;
-}
-#menu span.current {
-    background-color: #555753;
-}
-#menu a {
-    color: #fefefc;
-    text-decoration: none;
-}
-div#footer {
-    color: gray;
-    text-align: center;
-    font-size: small;
-}
-div#footer a {
-    color: gray;
-    text-decoration: none;
-}
-pre {
-    border: dotted black 1px;
-    background: #eeeeec;
-    font-size: small;
-    padding: 1em;
-}
-

File tests/expected/page.html

 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
 <head>
     <meta http-equiv="Content-Type" content="text/html; charset=utf8" />
-    <title>poole - {{ htmlspecialchars(page["title"]) }}</title>
-    <meta name="description" content="{{ htmlspecialchars(page.get("description", "a poole site")) }}" />
-    <meta name="keywords" content="{{ htmlspecialchars(page.get("keywords", "poole")) }}" />
-    <link rel="stylesheet" type="text/css" href="poole.css" />
+    <title>poole - {{ hx(page["title"]) }}</title>
+    <meta name="description" content="{{ hx(page.get("description", "a poole site")) }}" />
+    <meta name="keywords" content="{{ hx(page.get("keywords", "poole")) }}" />
+    <style type="text/css">
+        body {
+            font-family: sans;
+            width: 800px;
+            margin: 1em auto;
+            color: #2e3436;
+        }
+        div#box {
+        }
+        div#header, div#menu, div#content, div#footer {
+            padding: 1em;
+        }
+        div#menu {
+            background-color: #eeeeec;
+            padding: 0.6em 0 0.6em 0;
+        }
+        #menu span {
+            font-weight: bold;
+            padding: 0.6em;
+        }
+        #menu span.current {
+            background-color: #ffffff;
+            border: 1px solid #eeeeec;
+        }
+        #menu a {
+            color: #000000;
+            text-decoration: none;
+        }
+        div#footer {
+            color: gray;
+            text-align: center;
+            font-size: small;
+        }
+        div#footer a {
+            color: gray;
+            text-decoration: none;
+        }
+        pre {
+            border: dotted black 1px;
+            background: #eeeeec;
+            font-size: small;
+            padding: 1em;
+        }
+    </style>
 </head>
 <body>
     <div id="box">
     <div id="header">
          <h1>a poole site</h1>
-         <h2>{{ htmlspecialchars(page["title"]) }}</h2>
+         <h2>{{ hx(page["title"]) }}</h2>
     </div>
     <div id="menu">
     <!--%
         mpages.sort(key=lambda p: int(p["menu-position"]))
         entry = '<span class="%s"><a href="%s">%s</a></span>'
         for p in mpages:
-            style = p["title"] == page["title"] and "current" or ""
-            print(entry % (style, htmlspecialchars(p["url"]), htmlspecialchars(p["title"])))
+            style = "current" if p["title"] == page["title"] else ""
+            print(entry % (style, p["url"], hx(p["title"])))
     %-->
     </div>
     <div id="content">{{ __content__ }}</div>

File themes/bootstrap/css/bootstrap-responsive.css

+/*!
+ * Bootstrap Responsive v2.3.0
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */
+
+.clearfix {
+  *zoom: 1;
+}
+
+.clearfix:before,
+.clearfix:after {
+  display: table;
+  line-height: 0;
+  content: "";
+}
+
+.clearfix:after {
+  clear: both;
+}
+
+.hide-text {
+  font: 0/0 a;
+  color: transparent;
+  text-shadow: none;
+  background-color: transparent;
+  border: 0;
+}
+
+.input-block-level {
+  display: block;
+  width: 100%;
+  min-height: 30px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+@-ms-viewport {
+  width: device-width;
+}
+
+.hidden {
+  display: none;
+  visibility: hidden;
+}
+
+.visible-phone {
+  display: none !important;
+}
+
+.visible-tablet {
+  display: none !important;
+}
+
+.hidden-desktop {
+  display: none !important;
+}
+
+.visible-desktop {
+  display: inherit !important;
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important ;
+  }
+  .visible-tablet {
+    display: inherit !important;
+  }
+  .hidden-tablet {
+    display: none !important;
+  }
+}
+
+@media (max-width: 767px) {
+  .hidden-desktop {
+    display: inherit !important;
+  }
+  .visible-desktop {
+    display: none !important;
+  }
+  .visible-phone {
+    display: inherit !important;
+  }
+  .hidden-phone {
+    display: none !important;
+  }
+}
+
+.visible-print {
+  display: none !important;
+}
+
+@media print {
+  .visible-print {
+    display: inherit !important;
+  }
+  .hidden-print {
+    display: none !important;
+  }
+}
+
+@media (min-width: 1200px) {
+  .row {
+    margin-left: -30px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 30px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 1170px;
+  }
+  .span12 {
+    width: 1170px;
+  }
+  .span11 {
+    width: 1070px;
+  }
+  .span10 {
+    width: 970px;
+  }
+  .span9 {
+    width: 870px;
+  }
+  .span8 {
+    width: 770px;
+  }
+  .span7 {
+    width: 670px;
+  }
+  .span6 {
+    width: 570px;
+  }
+  .span5 {
+    width: 470px;
+  }
+  .span4 {
+    width: 370px;
+  }
+  .span3 {
+    width: 270px;
+  }
+  .span2 {
+    width: 170px;
+  }
+  .span1 {
+    width: 70px;
+  }
+  .offset12 {
+    margin-left: 1230px;
+  }
+  .offset11 {
+    margin-left: 1130px;
+  }
+  .offset10 {
+    margin-left: 1030px;
+  }
+  .offset9 {
+    margin-left: 930px;
+  }
+  .offset8 {
+    margin-left: 830px;
+  }
+  .offset7 {
+    margin-left: 730px;
+  }
+  .offset6 {
+    margin-left: 630px;
+  }
+  .offset5 {
+    margin-left: 530px;
+  }
+  .offset4 {
+    margin-left: 430px;
+  }
+  .offset3 {
+    margin-left: 330px;
+  }
+  .offset2 {
+    margin-left: 230px;
+  }
+  .offset1 {
+    margin-left: 130px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.564102564102564%;
+    *margin-left: 2.5109110747408616%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.564102564102564%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.45299145299145%;
+    *width: 91.39979996362975%;
+  }
+  .row-fluid .span10 {
+    width: 82.90598290598291%;
+    *width: 82.8527914166212%;
+  }
+  .row-fluid .span9 {
+    width: 74.35897435897436%;
+    *width: 74.30578286961266%;
+  }
+  .row-fluid .span8 {
+    width: 65.81196581196582%;
+    *width: 65.75877432260411%;
+  }
+  .row-fluid .span7 {
+    width: 57.26495726495726%;
+    *width: 57.21176577559556%;
+  }
+  .row-fluid .span6 {
+    width: 48.717948717948715%;
+    *width: 48.664757228587014%;
+  }
+  .row-fluid .span5 {
+    width: 40.17094017094017%;
+    *width: 40.11774868157847%;
+  }
+  .row-fluid .span4 {
+    width: 31.623931623931625%;
+    *width: 31.570740134569924%;
+  }
+  .row-fluid .span3 {
+    width: 23.076923076923077%;
+    *width: 23.023731587561375%;
+  }
+  .row-fluid .span2 {
+    width: 14.52991452991453%;
+    *width: 14.476723040552828%;
+  }
+  .row-fluid .span1 {
+    width: 5.982905982905983%;
+    *width: 5.929714493544281%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.12820512820512%;
+    *margin-left: 105.02182214948171%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.56410256410257%;
+    *margin-left: 102.45771958537915%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.58119658119658%;
+    *margin-left: 96.47481360247316%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.01709401709402%;
+    *margin-left: 93.91071103837061%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.03418803418803%;
+    *margin-left: 87.92780505546462%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.47008547008548%;
+    *margin-left: 85.36370249136206%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.48717948717949%;
+    *margin-left: 79.38079650845607%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 76.92307692307693%;
+    *margin-left: 76.81669394435352%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 70.94017094017094%;
+    *margin-left: 70.83378796144753%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.37606837606839%;
+    *margin-left: 68.26968539734497%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.393162393162385%;
+    *margin-left: 62.28677941443899%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.82905982905982%;
+    *margin-left: 59.72267685033642%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 53.84615384615384%;
+    *margin-left: 53.739770867430444%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.28205128205128%;
+    *margin-left: 51.175668303327875%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.299145299145295%;
+    *margin-left: 45.1927623204219%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.73504273504273%;
+    *margin-left: 42.62865975631933%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 36.75213675213675%;
+    *margin-left: 36.645753773413354%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.18803418803419%;
+    *margin-left: 34.081651209310785%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.205128205128204%;
+    *margin-left: 28.0987452264048%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.641025641025642%;
+    *margin-left: 25.53464266230224%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.65811965811966%;
+    *margin-left: 19.551736679396257%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.094017094017094%;
+    *margin-left: 16.98763411529369%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.11111111111111%;
+    *margin-left: 11.004728132387708%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.547008547008547%;
+    *margin-left: 8.440625568285142%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 30px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 1156px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 1056px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 956px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 856px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 756px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 656px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 556px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 456px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 356px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 256px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 156px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 56px;
+  }
+  .thumbnails {
+    margin-left: -30px;
+  }
+  .thumbnails > li {
+    margin-left: 30px;
+  }
+  .row-fluid .thumbnails {
+    margin-left: 0;
+  }
+}
+
+@media (min-width: 768px) and (max-width: 979px) {
+  .row {
+    margin-left: -20px;
+    *zoom: 1;
+  }
+  .row:before,
+  .row:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row:after {
+    clear: both;
+  }
+  [class*="span"] {
+    float: left;
+    min-height: 1px;
+    margin-left: 20px;
+  }
+  .container,
+  .navbar-static-top .container,
+  .navbar-fixed-top .container,
+  .navbar-fixed-bottom .container {
+    width: 724px;
+  }
+  .span12 {
+    width: 724px;
+  }
+  .span11 {
+    width: 662px;
+  }
+  .span10 {
+    width: 600px;
+  }
+  .span9 {
+    width: 538px;
+  }
+  .span8 {
+    width: 476px;
+  }
+  .span7 {
+    width: 414px;
+  }
+  .span6 {
+    width: 352px;
+  }
+  .span5 {
+    width: 290px;
+  }
+  .span4 {
+    width: 228px;
+  }
+  .span3 {
+    width: 166px;
+  }
+  .span2 {
+    width: 104px;
+  }
+  .span1 {
+    width: 42px;
+  }
+  .offset12 {
+    margin-left: 764px;
+  }
+  .offset11 {
+    margin-left: 702px;
+  }
+  .offset10 {
+    margin-left: 640px;
+  }
+  .offset9 {
+    margin-left: 578px;
+  }
+  .offset8 {
+    margin-left: 516px;
+  }
+  .offset7 {
+    margin-left: 454px;
+  }
+  .offset6 {
+    margin-left: 392px;
+  }
+  .offset5 {
+    margin-left: 330px;
+  }
+  .offset4 {
+    margin-left: 268px;
+  }
+  .offset3 {
+    margin-left: 206px;
+  }
+  .offset2 {
+    margin-left: 144px;
+  }
+  .offset1 {
+    margin-left: 82px;
+  }
+  .row-fluid {
+    width: 100%;
+    *zoom: 1;
+  }
+  .row-fluid:before,
+  .row-fluid:after {
+    display: table;
+    line-height: 0;
+    content: "";
+  }
+  .row-fluid:after {
+    clear: both;
+  }
+  .row-fluid [class*="span"] {
+    display: block;
+    float: left;
+    width: 100%;
+    min-height: 30px;
+    margin-left: 2.7624309392265194%;
+    *margin-left: 2.709239449864817%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="span"]:first-child {
+    margin-left: 0;
+  }
+  .row-fluid .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 2.7624309392265194%;
+  }
+  .row-fluid .span12 {
+    width: 100%;
+    *width: 99.94680851063829%;
+  }
+  .row-fluid .span11 {
+    width: 91.43646408839778%;
+    *width: 91.38327259903608%;
+  }
+  .row-fluid .span10 {
+    width: 82.87292817679558%;
+    *width: 82.81973668743387%;
+  }
+  .row-fluid .span9 {
+    width: 74.30939226519337%;
+    *width: 74.25620077583166%;
+  }
+  .row-fluid .span8 {
+    width: 65.74585635359117%;
+    *width: 65.69266486422946%;
+  }
+  .row-fluid .span7 {
+    width: 57.18232044198895%;
+    *width: 57.12912895262725%;
+  }
+  .row-fluid .span6 {
+    width: 48.61878453038674%;
+    *width: 48.56559304102504%;
+  }
+  .row-fluid .span5 {
+    width: 40.05524861878453%;
+    *width: 40.00205712942283%;
+  }
+  .row-fluid .span4 {
+    width: 31.491712707182323%;
+    *width: 31.43852121782062%;
+  }
+  .row-fluid .span3 {
+    width: 22.92817679558011%;
+    *width: 22.87498530621841%;
+  }
+  .row-fluid .span2 {
+    width: 14.3646408839779%;
+    *width: 14.311449394616199%;
+  }
+  .row-fluid .span1 {
+    width: 5.801104972375691%;
+    *width: 5.747913483013988%;
+  }
+  .row-fluid .offset12 {
+    margin-left: 105.52486187845304%;
+    *margin-left: 105.41847889972962%;
+  }
+  .row-fluid .offset12:first-child {
+    margin-left: 102.76243093922652%;
+    *margin-left: 102.6560479605031%;
+  }
+  .row-fluid .offset11 {
+    margin-left: 96.96132596685082%;
+    *margin-left: 96.8549429881274%;
+  }
+  .row-fluid .offset11:first-child {
+    margin-left: 94.1988950276243%;
+    *margin-left: 94.09251204890089%;
+  }
+  .row-fluid .offset10 {
+    margin-left: 88.39779005524862%;
+    *margin-left: 88.2914070765252%;
+  }
+  .row-fluid .offset10:first-child {
+    margin-left: 85.6353591160221%;
+    *margin-left: 85.52897613729868%;
+  }
+  .row-fluid .offset9 {
+    margin-left: 79.8342541436464%;
+    *margin-left: 79.72787116492299%;
+  }
+  .row-fluid .offset9:first-child {
+    margin-left: 77.07182320441989%;
+    *margin-left: 76.96544022569647%;
+  }
+  .row-fluid .offset8 {
+    margin-left: 71.2707182320442%;
+    *margin-left: 71.16433525332079%;
+  }
+  .row-fluid .offset8:first-child {
+    margin-left: 68.50828729281768%;
+    *margin-left: 68.40190431409427%;
+  }
+  .row-fluid .offset7 {
+    margin-left: 62.70718232044199%;
+    *margin-left: 62.600799341718584%;
+  }
+  .row-fluid .offset7:first-child {
+    margin-left: 59.94475138121547%;
+    *margin-left: 59.838368402492065%;
+  }
+  .row-fluid .offset6 {
+    margin-left: 54.14364640883978%;
+    *margin-left: 54.037263430116376%;
+  }
+  .row-fluid .offset6:first-child {
+    margin-left: 51.38121546961326%;
+    *margin-left: 51.27483249088986%;
+  }
+  .row-fluid .offset5 {
+    margin-left: 45.58011049723757%;
+    *margin-left: 45.47372751851417%;
+  }
+  .row-fluid .offset5:first-child {
+    margin-left: 42.81767955801105%;
+    *margin-left: 42.71129657928765%;
+  }
+  .row-fluid .offset4 {
+    margin-left: 37.01657458563536%;
+    *margin-left: 36.91019160691196%;
+  }
+  .row-fluid .offset4:first-child {
+    margin-left: 34.25414364640884%;
+    *margin-left: 34.14776066768544%;
+  }
+  .row-fluid .offset3 {
+    margin-left: 28.45303867403315%;
+    *margin-left: 28.346655695309746%;
+  }
+  .row-fluid .offset3:first-child {
+    margin-left: 25.69060773480663%;
+    *margin-left: 25.584224756083227%;
+  }
+  .row-fluid .offset2 {
+    margin-left: 19.88950276243094%;