shithub: hugo

Download patch

ref: 6e16449e5fca5df192de04430af26a46ea9ceb2d
parent: 50a1d6f3f155ab837310e00ffb309a9199773c73
author: spf13 <[email protected]>
date: Thu Jul 4 07:32:55 EDT 2013

adding hugo

--- /dev/null
+++ b/LICENSE.md
@@ -1,0 +1,67 @@
+Simple Public License (SimPL-2.0)
+=================================
+
+Preamble
+--------
+
+This Simple Public License 2.0 (SimPL-2.0 for short) is a plain language
+implementation of GPL 2.0.  The words are different, but the goal is the
+same - to guarantee for all users the freedom to share and change
+software.  If anyone wonders about the meaning of the SimPL, they should
+interpret it as consistent with GPL 2.0.
+
+
+Simple Public License (SimPL) 2.0
+=================================
+
+The SimPL applies to the software's source and object code and comes
+with any rights that I have in it (other than trademarks). You agree to
+the SimPL by copying, distributing, or making a derivative work of the
+software.
+
+ You get the royalty free right to:
+
+-   Use the software for any purpose;
+-   Make derivative works of it (this is called a "Derived Work");
+-   Copy and distribute it and any Derived Work.
+
+If you distribute the software or a Derived Work, you must give back to
+the community by:
+
+-   Prominently noting the date of any changes you make;
+-   Leaving other people's copyright notices, warranty disclaimers, and
+    license terms in place;
+-   Providing the source code, build scripts, installation scripts, and
+    interface definitions in a form that is easy to get and best to
+    modify;
+-   Licensing it to everyone under SimPL, or substantially similar terms
+    (such as GPL 2.0), without adding further restrictions to the rights
+    provided;
+-   Conspicuously announcing that it is available under that license.
+
+There are some things that you must shoulder:
+
+-   You get NO WARRANTIES. None of any kind;
+-   If the software damages you in any way, you may only recover direct
+    damages up to the amount you paid for it (that is zero if you did
+    not pay anything). You may not recover any other damages, including
+    those called "consequential damages." (The state or country where
+    you live may not allow you to limit your liability in this way, so
+    this may not apply to you);
+
+The SimPL continues perpetually, except that your license rights end
+automatically if:
+
+-   You do not abide by the "give back to the community" terms (your
+    licensees get to keep their rights if they abide);
+-   Anyone prevents you from distributing the software under the terms
+    of the SimPL.
+
+License for the License
+-----------------------
+
+You may do anything that you want with the SimPL text; it's a license
+form to use in any way that you find helpful.  To avoid confusion,
+however, if you change the terms in any way then you may not call your
+license the Simple Public License or the SimPL (but feel free to
+acknowledge that your license is "based on the Simple Public License").
--- /dev/null
+++ b/docs/config.json
@@ -1,0 +1,4 @@
+{
+    "Indexes" : {"tag": "tags"},
+    "BaseUrl"    : "http://localhost"
+}
--- /dev/null
+++ b/docs/content/doc/configuration.md
@@ -1,0 +1,19 @@
+{
+    "title": "Configuring Hugo",
+    "Pubdate": "2013-07-01"
+}
+
+The directory structure and templates provide the majority of the
+configuration for a site. In fact a config file isn't even needed for many websites
+since the defaults used follow commonly used patterns.
+
+The following is an example of a config file with the default values
+
+    {
+        "SourceDir" : "content",
+        "LayoutDir" : "layouts",
+        "PublishDir" : "public",
+        "BuildDrafts" : false,
+        "Tags" : { "category" : "categories", "tag" : "tags" },
+        "BaseUrl"    : "http://yourSite.com/"
+    }
--- /dev/null
+++ b/docs/content/doc/contributing.md
@@ -1,0 +1,10 @@
+{
+    "title": "Contributing to Hugo",
+    "Pubdate": "2013-07-01"
+}
+
+1. Fork it from https://github.com/spf13/hugo
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
--- /dev/null
+++ b/docs/content/doc/contributors.md
@@ -1,0 +1,9 @@
+{
+    "title": "Contributors",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo was built with love and golang by:
+
+* [spf13](https://github.com/spf13)
+
--- /dev/null
+++ b/docs/content/doc/example.md
@@ -1,0 +1,40 @@
+{
+    "title": "Example Content File",
+    "Pubdate": "2013-07-01"
+}
+
+Somethings are better shown than explained. The following is a very basic example of a content file:
+
+**mysite/project/nitro.md  <- http://mysite.com/project/nitro.html**
+
+    {
+        "Title": "Nitro : A quick and simple profiler for golang",
+        "Description": "",
+        "Keywords": [ "Development", "golang", "profiling" ],
+        "Tags": [ "Development", "golang", "profiling" ],
+        "Pubdate": "2013-06-19",
+        "Topics": [ "Development", "GoLang" ],
+        "Slug": "nitro",
+        "project_url": "http://github.com/spf13/nitro"
+    }
+
+    # Nitro
+
+    Quick and easy performance analyzer library for golang.
+
+    ## Overview
+
+    Nitro is a quick and easy performance analyzer library for golang.
+    It is useful for comparing A/B against different drafts of functions
+    or different functions.
+
+    ## Implementing Nitro
+
+    Using Nitro is simple. First use go get to install the latest version
+    of the library.
+
+        $ go get github.com/spf13/nitro
+
+    Next include nitro in your application.
+
+
--- /dev/null
+++ b/docs/content/doc/front-matter.md
@@ -1,0 +1,38 @@
+{
+    "title": "Front Matter",
+    "Pubdate": "2013-07-01"
+}
+
+The front matter is one of the features that gives Hugo it's strength. It enables
+you to include the meta data of the content right with it. Hugo supports a few 
+different formats. The main format supported is JSON. Here is an example:
+
+    {
+        "Title": "spf13-vim 3.0 release and new website",
+        "Description": "spf13-vim is a cross platform distribution of vim plugins and resources for Vim.",
+        "Tags": [ ".vimrc", "plugins", "spf13-vim", "vim" ],
+        "Pubdate": "2012-04-06",
+        "Categories": [ "Development", "VIM" ],
+        "Slug": "spf13-vim-3-0-release-and-new-website"
+    }
+
+### Variables
+There are a few predefined variables that Hugo is aware of and utilizes. The user can also create
+any variable they want to. These will be placed into the `.Params` variable available to the templates.
+
+#### Required
+
+**Title**  The title for the content. <br>
+**Description** The description for the content.<br>
+**Pubdate** The date the content will be sorted by.<br>
+**Indexes** These will use the field name of the plural form of the index (see tags and categories above)
+
+#### Optional
+
+**Draft** If true the content will not be rendered unless `hugo` is called with -d<br>
+**Type** The type of the content (will be derived from the directory automatically if unset).<br>
+**Slug** The token to appear in the tail of the url.<br>
+  *or*<br>
+**Url** The full path to the content from the web root.<br>
+*If neither is present the filename will be used.*
+
--- /dev/null
+++ b/docs/content/doc/installing.md
@@ -1,0 +1,18 @@
+{
+    "title": "Installing Hugo",
+    "Pubdate": "2013-07-01"
+}
+
+Installation is very easy. Simply download the appropriate version for your
+platform. 
+
+Hugo is written in GoLang with support for Windows, Linux and OSX.
+
+<div class="alert alert-info">
+Please make sure that you place the executable in your path. `/usr/local/bin` 
+is the most probable location.
+</div>
+
+
+Hugo doesn't have any external dependencies, but can benefit from external
+programs.
--- /dev/null
+++ b/docs/content/doc/license.md
@@ -1,0 +1,75 @@
+{
+    "title": "License",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo is released under the Simple Public License.
+
+
+Simple Public License (SimPL-2.0)
+=================================
+
+Preamble
+--------
+
+This Simple Public License 2.0 (SimPL-2.0 for short) is a plain language
+implementation of GPL 2.0.  The words are different, but the goal is the
+same - to guarantee for all users the freedom to share and change
+software.  If anyone wonders about the meaning of the SimPL, they should
+interpret it as consistent with GPL 2.0.
+
+
+Simple Public License (SimPL) 2.0
+=================================
+
+The SimPL applies to the software's source and object code and comes
+with any rights that I have in it (other than trademarks). You agree to
+the SimPL by copying, distributing, or making a derivative work of the
+software.
+
+ You get the royalty free right to:
+
+-   Use the software for any purpose;
+-   Make derivative works of it (this is called a "Derived Work");
+-   Copy and distribute it and any Derived Work.
+
+If you distribute the software or a Derived Work, you must give back to
+the community by:
+
+-   Prominently noting the date of any changes you make;
+-   Leaving other people's copyright notices, warranty disclaimers, and
+    license terms in place;
+-   Providing the source code, build scripts, installation scripts, and
+    interface definitions in a form that is easy to get and best to
+    modify;
+-   Licensing it to everyone under SimPL, or substantially similar terms
+    (such as GPL 2.0), without adding further restrictions to the rights
+    provided;
+-   Conspicuously announcing that it is available under that license.
+
+There are some things that you must shoulder:
+
+-   You get NO WARRANTIES. None of any kind;
+-   If the software damages you in any way, you may only recover direct
+    damages up to the amount you paid for it (that is zero if you did
+    not pay anything). You may not recover any other damages, including
+    those called "consequential damages." (The state or country where
+    you live may not allow you to limit your liability in this way, so
+    this may not apply to you);
+
+The SimPL continues perpetually, except that your license rights end
+automatically if:
+
+-   You do not abide by the "give back to the community" terms (your
+    licensees get to keep their rights if they abide);
+-   Anyone prevents you from distributing the software under the terms
+    of the SimPL.
+
+License for the License
+-----------------------
+
+You may do anything that you want with the SimPL text; it's a license
+form to use in any way that you find helpful.  To avoid confusion,
+however, if you change the terms in any way then you may not call your
+license the Simple Public License or the SimPL (but feel free to
+acknowledge that your license is "based on the Simple Public License").
--- /dev/null
+++ b/docs/content/doc/organization.md
@@ -1,0 +1,22 @@
+{
+    "title": "Organization",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo uses markdown files with headers commonly called the front matter. Hugo respects the organization
+that you provide for your content to minimize any extra configuration, though this can be overridden
+by additional configuration in the front matter.
+
+## Organization
+In Hugo the content should be arranged in the same way they are intended for the rendered website.
+Without any additional configuration the following will just work.
+
+    .
+    └── content
+        ├── post
+        |   ├── firstpost.md   // <- http://site.com/post/firstpost.html
+        |   └── secondpost.md  // <- http://site.com/post/secondpost.html
+        └── quote
+            ├── first.md       // <- http://site.com/quote/first.html
+            └── second.md      // <- http://site.com/quote/second.html
+
--- /dev/null
+++ b/docs/content/doc/release-notes.md
@@ -1,0 +1,14 @@
+{
+    "title": "Release Notes",
+    "Pubdate": "2013-07-01"
+
+}
+
+* **0.7.0** July 4, 2013
+  * Hugo now includes a simple server
+  * First public release
+* **0.6.0** July 2, 2013
+  * Hugo includes an example documentation site which it builds
+* **0.5.0** June 25, 2013
+  * Hugo is quite usable and able to build spf13.com
+
--- /dev/null
+++ b/docs/content/doc/roadmap.md
@@ -1,0 +1,18 @@
+{
+    "title": "Roadmap",
+    "Pubdate": "2013-07-01"
+}
+
+In no particular order, here is what I'm working on:
+
+ * Pagination
+ * Support for top level pages (other than homepage)
+ * Series support
+ * Syntax highlighting
+ * Previous & Next
+ * Related Posts
+ * Support for TOML front matter
+ * Proper YAML support for front matter
+ * Support for other formats
+
+
--- /dev/null
+++ b/docs/content/doc/shortcodes.md
@@ -1,0 +1,76 @@
+{
+    "title": "Shortcodes",
+    "Pubdate": "2013-07-01"
+}
+
+Because Hugo uses markdown for it's content format, it was clear that there's a lot of things that 
+markdown doesn't support well. This is good, the simple nature of markdown is exactly why we chose it.
+
+However we cannot accept being constrained by our simple format. Also unacceptable is writing raw
+html in our markdown every time we want to include unsupported content such as a video. To do 
+so is in complete opposition to the intent of using a bare bones format for our content and 
+utilizing templates to apply styling for display.
+
+To avoid both of these limitations Hugo has full support for shortcodes.
+
+### What is a shortcode?
+A shortcode is a simple snippet inside a markdown file that Hugo will render using a template.
+
+Short codes are designated by the opening and closing characters of '{{&#37;' and '%}}' respectively.
+Short codes are space delimited. The first word is always the name of the shortcode.  Following the 
+name are the parameters. The author of the shortcode can choose if the short code
+will use positional parameters or named parameters (but not both). A good rule of thumb is that if a
+short code has a single required value in the case of the youtube example below then positional
+works very well. For more complex layouts with optional parameters named parameters work best.
+
+The format for named parameters models that of html with the format name="value"
+
+### Example: youtube
+*Example has an extra space so Hugo doesn't actually render it*
+
+    {{ % youtube 09jf3ow9jfw %}}
+
+This would be rendered as 
+
+    <div class="embed video-player">
+    <iframe class="youtube-player" type="text/html"
+        width="640" height="385" 
+        src="http://www.youtube.com/embed/09jf3ow9jfw"
+        allowfullscreen frameborder="0">
+    </iframe>
+    </div>
+
+### Example: image with caption
+*Example has an extra space so Hugo doesn't actually render it*
+
+    {{ % img src="/media/spf13.jpg" title="Steve Francia" %}}
+
+Would be rendered as:
+
+    <figure >
+        <img src="/media/spf13.jpg"  />
+        <figcaption>
+            <h4>Steve Francia</h4>
+        </figcaption>
+    </figure>
+
+
+### Creating a shortcode
+
+All that you need to do to create a shortcode is place a template in the layouts/shortcodes directory.
+
+The template name will be the name of the shortcode.
+
+**Inside the template**
+
+To access a parameter by either position or name the index method can be used.
+
+    {{ index .Params 0 }}
+    or
+    {{ index .Params "class" }}
+
+To check if a parameter has been provided use the isset method provided by Hugo.
+
+    {{ if isset .Params "class"}} class="{{ index .Params "class"}}" {{ end }}
+
+
--- /dev/null
+++ b/docs/content/doc/source-directory.md
@@ -1,0 +1,54 @@
+{
+    "title": "Source Directory Organization",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo takes a single directory and uses it as the input for creating a complete website.
+
+Hugo has a very small amount of configuration, while remaining highly customizable. 
+It accomplishes by assuming that you will only provide templates with the intent of
+using them.
+
+An example directory may look like:
+
+    .
+    ├── config.json
+    ├── content
+    |   ├── post
+    |   |   ├── firstpost.md
+    |   |   └── secondpost.md
+    |   └── quote
+    |   |   ├── first.md
+    |   |   └── second.md
+    ├── layouts
+    |   ├── chrome
+    |   |   ├── header.html
+    |   |   └── footer.html
+    |   ├── indexes
+    |   |   ├── category.html
+    |   |   ├── post.html
+    |   |   ├── quote.html
+    |   |   └── tag.html
+    |   ├── post
+    |   |   ├── li.html
+    |   |   ├── single.html
+    |   |   └── summary.html
+    |   ├── quote
+    |   |   ├── li.html
+    |   |   ├── single.html
+    |   |   └── summary.html
+    |   ├── shortcodes
+    |   |   ├── img.html
+    |   |   ├── vimeo.html
+    |   |   └── youtube.html
+    |   ├── index.html
+    |   └── rss.xml
+    └── public
+
+This directory structure tells us a lot about this site:
+
+1. the website intends to have two different types of content, posts and quotes.
+2. It will also apply two different indexes to that content, categories and tags.
+3. It will be displaying content in 3 different views, a list, a summary and a full page view.
+
+Included with the repository is an this example site ready to be rendered.
--- /dev/null
+++ b/docs/content/doc/templates.md
@@ -1,0 +1,66 @@
+{
+    "title": "Templates",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo uses the excellent golang html/template library for it's template engine. It is an extremely
+lightweight engine that provides a very small amount of logic. In our 
+experience that it is just the right amount of logic to be able to create a good static website
+
+This document will not cover how to use golang templates, but the [golang docs](http://golang.org/pkg/html/template/)
+provide a good introduction.
+
+### Template roles
+
+There are 5 different kinds of templates that Hugo works with.
+
+#### index.html
+This file must exist in the layouts directory. It is the template used to render the 
+homepage of your site.
+
+#### rss.xml
+This file must exist in the layouts directory. It will be used to render all rss documents.
+The one provided in the example application will generate an ATOM format. 
+
+*Important: Hugo will automatically add the following header line to this file.*
+
+    <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+
+#### Indexes
+An index is a page that list multiple pieces of content. If you think of a typical blog, the tag 
+pages are good examples of indexes.
+
+
+#### Content Type(s)
+Hugo supports multiple types of content. Another way of looking at this is that Hugo has the ability
+to render content in a variety of ways as determined by the type.
+
+#### Chrome
+Chrome is simply the decoration of your site. It's not a requirement to have this, but in practice
+it's very convenient. Hugo doesn't know anything about Chrome, it's simply a convention that you may
+likely find beneficial. As you create the rest of your templates you will include templates from the 
+/layout/chrome directory. I've found it helpful to include a header and footer template 
+in Chrome so I can include those in the other full page layouts (index.html, indexes/ type/single.html).
+
+### Adding a new content type
+
+Adding a type is easy.
+
+**Step 1:**
+Create a directory with the name of the type in layouts.Type is always singular.  *Eg /layouts/post*.
+
+**Step 2:**
+Create a file called single.html inside your directory. *Eg /layouts/post/single.html*.
+
+**Step 3:**
+Create a file with the same name as your directory in /layouts/indexes/. *Eg /layouts/index/post.html*.
+
+**Step 4:**
+Many sites support rendering content in a few different ways, for instance a single page view and a 
+summary view to be used when displaying a list of contents on a single page. Hugo makes no assumptions
+here about how you want to display your content, and will support as many different views of a content
+type as your site requires. All that is required for these additional views is that a template
+exists in each layout/type directory with the same name.
+
+For these, reviewing this example site will be very helpful in order to understand how these types work.
+
--- /dev/null
+++ b/docs/content/doc/usage.md
@@ -1,0 +1,52 @@
+{
+    "title": "Using Hugo",
+    "Pubdate": "2013-07-01"
+}
+
+Make sure either hugo is in your path or provide a path to it.
+
+    $ hugo --help
+    usage: hugo [flags] []
+      -b="": hostname (and path) to the root eg. http://spf13.com/
+      -c="config.json": config file (default is path/config.json)
+      -d=false: include content marked as draft
+      -h=false: show this help
+      -k=false: analyze content and provide feedback
+      -p="": filesystem path to read files relative from
+      -w=false: watch filesystem for changes and recreate as needed
+      -s=false: a (very) simple webserver
+      -p="1313": port for webserver to run on
+
+## Common Usage Example:
+
+The most common use is probably to run hugo with your current 
+directory being the input directory.
+
+
+    $ hugo
+    > X pages created
+    > Y indicies created
+
+
+If you are working on things and want to see the changes 
+immediately, tell Hugo to watch for changes. 
+<br>
+**It will 
+recreate the site faster than you can tab over to 
+your browser to view the changes.**
+
+    $ hugo -p ~/mysite -w
+       Watching for changes. Press ctrl+c to stop
+       15 pages created
+       0 tags created
+
+Hugo can even run a server and create your site at the same time!
+
+    $hugo -p ~/mysite -w -s
+       Watching for changes. Press ctrl+c to stop
+       15 pages created
+       0 tags created
+       Web Server is available at http://localhost:1313
+       Press ctrl+c to stop
+
+
--- /dev/null
+++ b/docs/content/doc/variables.md
@@ -1,0 +1,29 @@
+{
+    "title": "Variables",
+    "Pubdate": "2013-07-01"
+}
+
+Hugo makes a set of values available to the templates. Go templates are context based. The following
+are available in the context for the templates.
+
+**.Title**  The title for the content. <br>
+**.Description** The description for the content.<br>
+**.Keywords** The meta keywords for this content.<br>
+**.Date** The date the content is published on.<br>
+**.Indexes** These will use the field name of the plural form of the index (see tags and categories above)<br>
+**.Permalink** The Permanent link for this page.<br>
+**.FuzzyWordCount** The approximate number of words in the content.<br>
+**.RSSLink** Link to the indexes' rss link <br>
+
+Any value defined in the front matter, including indexes will be made available under `.Params`. 
+Take for example I'm using tags and categories as my indexes. The following would be how I would access them:
+
+**.Params.Tags** <br> 
+**.Params.Categories** <br> 
+
+Also available is `.Site` which has the following:
+
+**.Site.BaseUrl** The base URL for the site as defined in the config.json file.<br>
+**.Site.Indexes** The names of the indexes of the site.<br>
+**.Site.LastChange** The date of the last change of the most recent content.<br>
+**.Site.Recent** Array of all content ordered by Date, newest first<br>
--- /dev/null
+++ b/docs/layouts/chrome/footer.html
@@ -1,0 +1,12 @@
+        </div>
+      </div>
+      <hr>
+      <footer id="footer">
+            <p class="pull-right"><a href="#top">Back to top</a></p>
+            Made by <a href="http://spf13.com">Steve Francia</a>.<br>
+            Code licensed under the <a href="https://github.com/spf13/hugo/blob/master/LICENSE.md">Simple Public License 2.0</a>.<br>
+      </footer>
+    </div>
+  </body>
+
+</html>
--- /dev/null
+++ b/docs/layouts/chrome/header.html
@@ -1,0 +1,20 @@
+<!doctype html>
+<html>
+  <head>
+  <title>{{ .Title }}</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
+    {{ template "chrome/includes.html" . }}
+  </head>
+  <body>
+    <div class="navbar"></div>
+    <div class="container-fluid">
+      <div class="row-fluid">
+        <div class="span3">
+          <div class="well" style="background-color: #222; color: #ccc;">
+            <h1>Hugo</h1>
+            <p>A Fast and Flexible Static Site Generator built with love by <a href="http://spf13.com">spf13</a> in GO</p>
+          </div>
+        {{ template "chrome/menu.html" . }}
+        </div>
+        <div class="span9">
--- /dev/null
+++ b/docs/layouts/chrome/includes.html
@@ -1,0 +1,2 @@
+    <link rel="stylesheet" href="/static/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/static/css/bootstrap-responsive.css">
--- /dev/null
+++ b/docs/layouts/chrome/menu.html
@@ -1,0 +1,28 @@
+          <ul class="nav nav-list">
+            <li> <a href="/">Home</a> </li>
+            <li class="divider"></li>
+            <li class="nav-header">Getting Started</li>
+            <li> <a href="/doc/installing.html">Installing Hugo</a> </li>
+            <li> <a href="/doc/usage.html">Usage</a> </li>
+            <li> <a href="/doc/configuration.html">Configuration</a> </li>
+            <li> <a href="/doc/source-directory.html">Input Directory Layout</a> </li>
+            <li class="divider"></li>
+            <li class="nav-header">Layout</li>
+            <li> <a href="/doc/templates.html">Templates</a> </li>
+            <li> <a href="/doc/variables.html">Variables</a> </li>
+            <li class="divider"></li>
+            <li class="nav-header">Content</li>
+            <li> <a href="/doc/organization.html">Organization</a> </li>
+            <li> <a href="/doc/front-matter.html">Front Matter</a> </li>
+            <li> <a href="/doc/example.html">Example</a> </li>
+            <li class="divider"></li>
+            <li class="nav-header">Extras</li>
+            <li> <a href="/doc/shortcodes.html">ShortCodes</a> </li>
+            <li class="divider"></li>
+            <li class="nav-header">Meta</li>
+            <li> <a href="/doc/release-notes.html">Release Notes</a> </li>
+            <li> <a href="/doc/roadmap.html">Roadmap</a> </li>
+            <li> <a href="/doc/contributing.html">Contributing</a> </li>
+            <li> <a href="/doc/contributors.html">Contributors</a> </li>
+            <li> <a href="/doc/license.html">License</a> </li>
+          </ul>
--- /dev/null
+++ b/docs/layouts/doc/single.html
@@ -1,0 +1,4 @@
+{{ template "chrome/header.html" . }}
+          <h1>{{ .Title }}</h1>
+          {{ .Content }}
+{{ template "chrome/footer.html" . }}
--- /dev/null
+++ b/docs/layouts/index.html
@@ -1,0 +1,46 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Hugo Static Site Generator written in GO lang</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
+    {{ template "chrome/includes.html" . }}
+  </head>
+  <body>
+    <div class="navbar"></div>
+    <div class="container-fluid">
+      <div class="row-fluid">
+        <div class="span3">
+        {{ template "chrome/menu.html" . }}
+        </div>
+        <div class="span9">
+
+          <div class="hero-unit" style="background-color: #222; color: #ccc;">
+            <h1>Hugo</h1>
+            <p>A Fast and Flexible Static Site Generator built with love by <a href="http://spf13.com">spf13</a> in GO</p>
+            <p>
+              <a class="btn btn-large btn-success" href="/doc/installing.html">Get Started</a> 
+            </p>
+          </div>
+          <div class="row-fluid">
+            <div class="span4">
+              <h2>Fast
+                <br> 
+              </h2>
+              <p>Written in GoLang for speed, Hugo is significantly faster than other
+              static site generators. It's so fast that it will render the site in 
+              less time than it takes to switch to your browser and reload.</p>
+            </div>
+            <div class="span4">
+              <h2>Flexible</h2>
+              <p>Hugo is made to be very flexible. Define your own content types. Define
+              your own indexes. Build your own templates, shortcodes and more.</p>
+            </div>
+            <div class="span4">
+              <h2>Fun</h2>
+              <p>Hugo is more fun than you can shake a stick at. Hugo removes all 
+              the cruft of building a site allowing you to focus on creating the 
+              best site possible.</p>
+            </div>
+          </div>
+{{ template "chrome/footer.html" }}
binary files /dev/null b/docs/public/static/.DS_Store differ
--- /dev/null
+++ b/docs/public/static/css/bootstrap-responsive.css
@@ -1,0 +1,1109 @@
+/*!
+ * Bootstrap Responsive v2.3.1
+ *
+ * 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%;
+    *margin-left: 19.783119783707537%;
+  }
+  .row-fluid .offset2:first-child {
+    margin-left: 17.12707182320442%;
+    *margin-left: 17.02068884448102%;
+  }
+  .row-fluid .offset1 {
+    margin-left: 11.32596685082873%;
+    *margin-left: 11.219583872105325%;
+  }
+  .row-fluid .offset1:first-child {
+    margin-left: 8.56353591160221%;
+    *margin-left: 8.457152932878806%;
+  }
+  input,
+  textarea,
+  .uneditable-input {
+    margin-left: 0;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 20px;
+  }
+  input.span12,
+  textarea.span12,
+  .uneditable-input.span12 {
+    width: 710px;
+  }
+  input.span11,
+  textarea.span11,
+  .uneditable-input.span11 {
+    width: 648px;
+  }
+  input.span10,
+  textarea.span10,
+  .uneditable-input.span10 {
+    width: 586px;
+  }
+  input.span9,
+  textarea.span9,
+  .uneditable-input.span9 {
+    width: 524px;
+  }
+  input.span8,
+  textarea.span8,
+  .uneditable-input.span8 {
+    width: 462px;
+  }
+  input.span7,
+  textarea.span7,
+  .uneditable-input.span7 {
+    width: 400px;
+  }
+  input.span6,
+  textarea.span6,
+  .uneditable-input.span6 {
+    width: 338px;
+  }
+  input.span5,
+  textarea.span5,
+  .uneditable-input.span5 {
+    width: 276px;
+  }
+  input.span4,
+  textarea.span4,
+  .uneditable-input.span4 {
+    width: 214px;
+  }
+  input.span3,
+  textarea.span3,
+  .uneditable-input.span3 {
+    width: 152px;
+  }
+  input.span2,
+  textarea.span2,
+  .uneditable-input.span2 {
+    width: 90px;
+  }
+  input.span1,
+  textarea.span1,
+  .uneditable-input.span1 {
+    width: 28px;
+  }
+}
+
+@media (max-width: 767px) {
+  body {
+    padding-right: 20px;
+    padding-left: 20px;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom,
+  .navbar-static-top {
+    margin-right: -20px;
+    margin-left: -20px;
+  }
+  .container-fluid {
+    padding: 0;
+  }
+  .dl-horizontal dt {
+    float: none;
+    width: auto;
+    clear: none;
+    text-align: left;
+  }
+  .dl-horizontal dd {
+    margin-left: 0;
+  }
+  .container {
+    width: auto;
+  }
+  .row-fluid {
+    width: 100%;
+  }
+  .row,
+  .thumbnails {
+    margin-left: 0;
+  }
+  .thumbnails > li {
+    float: none;
+    margin-left: 0;
+  }
+  [class*="span"],
+  .uneditable-input[class*="span"],
+  .row-fluid [class*="span"] {
+    display: block;
+    float: none;
+    width: 100%;
+    margin-left: 0;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .span12,
+  .row-fluid .span12 {
+    width: 100%;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .row-fluid [class*="offset"]:first-child {
+    margin-left: 0;
+  }
+  .input-large,
+  .input-xlarge,
+  .input-xxlarge,
+  input[class*="span"],
+  select[class*="span"],
+  textarea[class*="span"],
+  .uneditable-input {
+    display: block;
+    width: 100%;
+    min-height: 30px;
+    -webkit-box-sizing: border-box;
+       -moz-box-sizing: border-box;
+            box-sizing: border-box;
+  }
+  .input-prepend input,
+  .input-append input,
+  .input-prepend input[class*="span"],
+  .input-append input[class*="span"] {
+    display: inline-block;
+    width: auto;
+  }
+  .controls-row [class*="span"] + [class*="span"] {
+    margin-left: 0;
+  }
+  .modal {
+    position: fixed;
+    top: 20px;
+    right: 20px;
+    left: 20px;
+    width: auto;
+    margin: 0;
+  }
+  .modal.fade {
+    top: -100px;
+  }
+  .modal.fade.in {
+    top: 20px;
+  }
+}
+
+@media (max-width: 480px) {
+  .nav-collapse {
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+  .page-header h1 small {
+    display: block;
+    line-height: 20px;
+  }
+  input[type="checkbox"],
+  input[type="radio"] {
+    border: 1px solid #ccc;
+  }
+  .form-horizontal .control-label {
+    float: none;
+    width: auto;
+    padding-top: 0;
+    text-align: left;
+  }
+  .form-horizontal .controls {
+    margin-left: 0;
+  }
+  .form-horizontal .control-list {
+    padding-top: 0;
+  }
+  .form-horizontal .form-actions {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+  .media .pull-left,
+  .media .pull-right {
+    display: block;
+    float: none;
+    margin-bottom: 10px;
+  }
+  .media-object {
+    margin-right: 0;
+    margin-left: 0;
+  }
+  .modal {
+    top: 10px;
+    right: 10px;
+    left: 10px;
+  }
+  .modal-header .close {
+    padding: 10px;
+    margin: -10px;
+  }
+  .carousel-caption {
+    position: static;
+  }
+}
+
+@media (max-width: 979px) {
+  body {
+    padding-top: 0;
+  }
+  .navbar-fixed-top,
+  .navbar-fixed-bottom {
+    position: static;
+  }
+  .navbar-fixed-top {
+    margin-bottom: 20px;
+  }
+  .navbar-fixed-bottom {
+    margin-top: 20px;
+  }
+  .navbar-fixed-top .navbar-inner,
+  .navbar-fixed-bottom .navbar-inner {
+    padding: 5px;
+  }
+  .navbar .container {
+    width: auto;
+    padding: 0;
+  }
+  .navbar .brand {
+    padding-right: 10px;
+    padding-left: 10px;
+    margin: 0 0 0 -5px;
+  }
+  .nav-collapse {
+    clear: both;
+  }
+  .nav-collapse .nav {
+    float: none;
+    margin: 0 0 10px;
+  }
+  .nav-collapse .nav > li {
+    float: none;
+  }
+  .nav-collapse .nav > li > a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > .divider-vertical {
+    display: none;
+  }
+  .nav-collapse .nav .nav-header {
+    color: #777777;
+    text-shadow: none;
+  }
+  .nav-collapse .nav > li > a,
+  .nav-collapse .dropdown-menu a {
+    padding: 9px 15px;
+    font-weight: bold;
+    color: #777777;
+    -webkit-border-radius: 3px;
+       -moz-border-radius: 3px;
+            border-radius: 3px;
+  }
+  .nav-collapse .btn {
+    padding: 4px 10px 4px;
+    font-weight: normal;
+    -webkit-border-radius: 4px;
+       -moz-border-radius: 4px;
+            border-radius: 4px;
+  }
+  .nav-collapse .dropdown-menu li + li a {
+    margin-bottom: 2px;
+  }
+  .nav-collapse .nav > li > a:hover,
+  .nav-collapse .nav > li > a:focus,
+  .nav-collapse .dropdown-menu a:hover,
+  .nav-collapse .dropdown-menu a:focus {
+    background-color: #f2f2f2;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a,
+  .navbar-inverse .nav-collapse .dropdown-menu a {
+    color: #999999;
+  }
+  .navbar-inverse .nav-collapse .nav > li > a:hover,
+  .navbar-inverse .nav-collapse .nav > li > a:focus,
+  .navbar-inverse .nav-collapse .dropdown-menu a:hover,
+  .navbar-inverse .nav-collapse .dropdown-menu a:focus {
+    background-color: #111111;
+  }
+  .nav-collapse.in .btn-group {
+    padding: 0;
+    margin-top: 5px;
+  }
+  .nav-collapse .dropdown-menu {
+    position: static;
+    top: auto;
+    left: auto;
+    display: none;
+    float: none;
+    max-width: none;
+    padding: 0;
+    margin: 0 15px;
+    background-color: transparent;
+    border: none;
+    -webkit-border-radius: 0;
+       -moz-border-radius: 0;
+            border-radius: 0;
+    -webkit-box-shadow: none;
+       -moz-box-shadow: none;
+            box-shadow: none;
+  }
+  .nav-collapse .open > .dropdown-menu {
+    display: block;
+  }
+  .nav-collapse .dropdown-menu:before,
+  .nav-collapse .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .dropdown-menu .divider {
+    display: none;
+  }
+  .nav-collapse .nav > li > .dropdown-menu:before,
+  .nav-collapse .nav > li > .dropdown-menu:after {
+    display: none;
+  }
+  .nav-collapse .navbar-form,
+  .nav-collapse .navbar-search {
+    float: none;
+    padding: 10px 15px;
+    margin: 10px 0;
+    border-top: 1px solid #f2f2f2;
+    border-bottom: 1px solid #f2f2f2;
+    -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+       -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+            box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1);
+  }
+  .navbar-inverse .nav-collapse .navbar-form,
+  .navbar-inverse .nav-collapse .navbar-search {
+    border-top-color: #111111;
+    border-bottom-color: #111111;
+  }
+  .navbar .nav-collapse .nav.pull-right {
+    float: none;
+    margin-left: 0;
+  }
+  .nav-collapse,
+  .nav-collapse.collapse {
+    height: 0;
+    overflow: hidden;
+  }
+  .navbar .btn-navbar {
+    display: block;
+  }
+  .navbar-static .navbar-inner {
+    padding-right: 10px;
+    padding-left: 10px;
+  }
+}
+
+@media (min-width: 980px) {
+  .nav-collapse.collapse {
+    height: auto !important;
+    overflow: visible !important;
+  }
+}
\ No newline at end of file
--- /dev/null
+++ b/docs/public/static/css/bootstrap.min.css
@@ -1,0 +1,9 @@
+@import url("http://fonts.googleapis.com/css?family=Lato:400,700,900,400italic");/*!
+ * Bootstrap v2.3.2
+ *
+ * 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}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Lato","Helvetica Neue",Helvetica,Arial,sans-serif;font-size:15px;line-height:20px;color:#2c3e50;background-color:#fff}a{color:#1abc9c;text-decoration:none}a:hover,a:focus{color:#1dd2af;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.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:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.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.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:bo
\ No newline at end of file
--- /dev/null
+++ b/hugolib/config.go
@@ -1,0 +1,143 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"path/filepath"
+)
+
+// config file items
+type Config struct {
+	SourceDir, PublishDir, BaseUrl, StaticDir string
+	Path, CacheDir, LayoutDir, DefaultLayout  string
+	Indexes                                   map[string]string // singular, plural
+	ProcessFilters                            map[string][]string
+	BuildDrafts                               bool
+}
+
+var c Config
+
+// Read cfgfile or setup defaults.
+func SetupConfig(cfgfile *string, path *string) *Config {
+	c.setPath(*path)
+
+	configPath, err := c.findConfigFile(*cfgfile)
+
+	if err != nil {
+		fmt.Printf("%v", err)
+		fmt.Println(" using defaults instead")
+	}
+
+	// set defaults
+
+	c.SourceDir = "content"
+	c.LayoutDir = "layouts"
+	c.PublishDir = "public"
+	c.StaticDir = "static"
+	c.DefaultLayout = "post"
+	c.BuildDrafts = false
+
+	file, err := ioutil.ReadFile(configPath)
+	if err == nil {
+		if err := json.Unmarshal(file, &c); err != nil {
+			fmt.Printf("Error parsing config: %s", err)
+			os.Exit(1)
+		}
+	}
+
+	// set index defaults if none provided
+	if len(c.Indexes) == 0 {
+		c.Indexes = make(map[string]string)
+		c.Indexes["tag"] = "tags"
+		c.Indexes["category"] = "categories"
+	}
+	return &c
+}
+
+func (c *Config) setPath(p string) {
+	if p == "" {
+		path, err := FindPath()
+		if err != nil {
+			fmt.Printf("Error finding path: %s", err)
+		}
+		c.Path = path
+	} else {
+		path, err := filepath.Abs(p)
+		if err != nil {
+			fmt.Printf("Error finding path: %s", err)
+		}
+		c.Path = path
+	}
+}
+
+func (c *Config) GetPath() string {
+	if c.Path == "" {
+		c.setPath("")
+	}
+	return c.Path
+}
+
+func FindPath() (string, error) {
+	serverFile, err := filepath.Abs(os.Args[0])
+
+	if err != nil {
+		return "", fmt.Errorf("Can't get absolute path for executable: %v", err)
+	}
+
+	path := filepath.Dir(serverFile)
+	realFile, err := filepath.EvalSymlinks(serverFile)
+
+	if err != nil {
+		if _, err = os.Stat(serverFile + ".exe"); err == nil {
+			realFile = filepath.Clean(serverFile + ".exe")
+		}
+	}
+
+	if err == nil && realFile != serverFile {
+		path = filepath.Dir(realFile)
+	}
+
+	return path, nil
+}
+
+func (c *Config) GetAbsPath(name string) string {
+	if path.IsAbs(name) {
+		return name
+	}
+
+	p := filepath.Join(c.GetPath(), name)
+	return p
+}
+
+func (c *Config) findConfigFile(configFileName string) (string, error) {
+	// If the full path is given, just use that
+	if path.IsAbs(configFileName) {
+		return configFileName, nil
+	}
+
+	// Else check the local directory
+	t := c.GetAbsPath(configFileName)
+	if b, _ := exists(t); b {
+		return t, nil
+	} else {
+		return "", fmt.Errorf("config file not found at: %s", t)
+	}
+
+	return "", nil // This line won't ever happen.. looking forward to go 1.1 when I don't need it
+}
--- /dev/null
+++ b/hugolib/helpers.go
@@ -1,0 +1,309 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"bytes"
+	"fmt"
+	"github.com/kr/pretty"
+	"os"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var sanitizeRegexp = regexp.MustCompile("[^a-zA-Z0-9/_-]")
+
+// TODO: Make these wrappers private
+// Wrapper around Fprintf taking verbose flag in account.
+func Printvf(format string, a ...interface{}) {
+	//if *verbose {
+	fmt.Fprintf(os.Stderr, format, a...)
+	//}
+}
+
+func Printer(x interface{}) {
+	fmt.Printf("%#v", pretty.Formatter(x))
+	fmt.Println("")
+}
+
+// Wrapper around Fprintln taking verbose flag in account.
+func Printvln(a ...interface{}) {
+	//if *verbose {
+	fmt.Fprintln(os.Stderr, a...)
+	//}
+}
+
+func FatalErr(str string) {
+	fmt.Println(str)
+	os.Exit(1)
+}
+
+func PrintErr(str string, a ...interface{}) {
+	fmt.Fprintln(os.Stderr, str, a)
+}
+
+func Error(str string, a ...interface{}) {
+	fmt.Fprintln(os.Stderr, str, a)
+}
+
+func interfaceToStringToDate(i interface{}) time.Time {
+	s := interfaceToString(i)
+	d, e := time.Parse("02 Jan 06 15:04 MST", s)
+
+	if e != nil {
+		d, e = time.Parse("2006-01-02", s)
+	}
+
+	if e != nil {
+		d, e = time.Parse("02 Jan 06", s)
+	}
+
+	return d
+
+}
+
+func interfaceToBool(i interface{}) bool {
+	switch b := i.(type) {
+	case bool:
+		return b
+	default:
+		Error("Only Boolean values are supported for this JSON key")
+	}
+
+	return false
+
+}
+
+func interfaceArrayToStringArray(i interface{}) []string {
+	var a []string
+
+	switch vv := i.(type) {
+	case []interface{}:
+		for _, u := range vv {
+			a = append(a, interfaceToString(u))
+		}
+	}
+
+	return a
+}
+
+func interfaceToString(i interface{}) string {
+	switch s := i.(type) {
+	case string:
+		return s
+	default:
+		Error("Only Strings are supported for this JSON key")
+	}
+
+	return ""
+}
+
+// Check if Exists && is Directory
+func dirExists(path string) (bool, error) {
+	fi, err := os.Stat(path)
+	if err == nil && fi.IsDir() {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+// Check if File / Directory Exists
+func exists(path string) (bool, error) {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true, nil
+	}
+	if os.IsNotExist(err) {
+		return false, nil
+	}
+	return false, err
+}
+
+func mkdirIf(path string) {
+	err := os.Mkdir(path, 0777)
+	if err != nil && os.IsNotExist(err) {
+		fmt.Println(err)
+	}
+}
+
+func Urlize(url string) string {
+	return Sanitize(strings.ToLower(strings.Replace(strings.TrimSpace(url), " ", "-", -1)))
+}
+
+func Gt(a interface{}, b interface{}) bool {
+	var left, right int64
+	av := reflect.ValueOf(a)
+
+	switch av.Kind() {
+	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+		left = int64(av.Len())
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		left = av.Int()
+	case reflect.String:
+		left, _ = strconv.ParseInt(av.String(), 10, 64)
+	}
+
+	bv := reflect.ValueOf(b)
+
+	switch bv.Kind() {
+	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
+		right = int64(bv.Len())
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		right = bv.Int()
+	case reflect.String:
+		right, _ = strconv.ParseInt(bv.String(), 10, 64)
+	}
+
+	return left > right
+}
+
+func IsSet(a interface{}, key interface{}) bool {
+	av := reflect.ValueOf(a)
+	kv := reflect.ValueOf(key)
+
+	switch av.Kind() {
+	case reflect.Array, reflect.Chan, reflect.Slice:
+		if int64(av.Len()) > kv.Int() {
+			return true
+		}
+	case reflect.Map:
+		if kv.Type() == av.Type().Key() {
+			return av.MapIndex(kv).IsValid()
+		}
+	}
+
+	return false
+}
+
+func ReturnWhenSet(a interface{}, index int) interface{} {
+	av := reflect.ValueOf(a)
+
+	switch av.Kind() {
+	case reflect.Array, reflect.Slice:
+		if av.Len() > index {
+
+			avv := av.Index(index)
+			switch avv.Kind() {
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				return avv.Int()
+			case reflect.String:
+				return avv.String()
+			}
+		}
+	}
+
+	return ""
+}
+
+func Sanitize(s string) string {
+	return sanitizeRegexp.ReplaceAllString(s, "")
+}
+
+func fileExt(path string) (file, ext string) {
+	if strings.Contains(path, ".") {
+		i := len(path) - 1
+		for path[i] != '.' {
+			i--
+		}
+		return path[:i], path[i+1:]
+	}
+	return path, ""
+}
+
+func replaceExtension(path string, newExt string) string {
+	f, _ := fileExt(path)
+	return f + "." + newExt
+}
+
+func TotalWords(s string) int {
+	return len(strings.Fields(s))
+}
+
+func WordCount(s string) map[string]int {
+	m := make(map[string]int)
+	for _, f := range strings.Fields(s) {
+		m[f] += 1
+	}
+
+	return m
+}
+
+func StripHTML(s string) string {
+	output := ""
+
+	// Shortcut strings with no tags in them
+	if !strings.ContainsAny(s, "<>") {
+		output = s
+	} else {
+		s = strings.Replace(s, "\n", " ", -1)
+		s = strings.Replace(s, "</p>", " \n", -1)
+		s = strings.Replace(s, "<br>", " \n", -1)
+		s = strings.Replace(s, "</br>", " \n", -1)
+
+		// Walk through the string removing all tags
+		b := new(bytes.Buffer)
+		inTag := false
+		for _, r := range s {
+			switch r {
+			case '<':
+				inTag = true
+			case '>':
+				inTag = false
+			default:
+				if !inTag {
+					b.WriteRune(r)
+				}
+			}
+		}
+		output = b.String()
+	}
+	return output
+}
+
+func TruncateWords(s string, max int) string {
+	words := strings.Fields(s)
+	if max > len(words) {
+		return strings.Join(words, " ")
+	}
+
+	return strings.Join(words[:max], " ")
+}
+
+func TruncateWordsToWholeSentence(s string, max int) string {
+	words := strings.Fields(s)
+	if max > len(words) {
+		return strings.Join(words, " ")
+	}
+
+	for counter, word := range words[max:] {
+		if strings.HasSuffix(word, ".") ||
+			strings.HasSuffix(word, "?") ||
+			strings.HasSuffix(word, ".\"") ||
+			strings.HasSuffix(word, "!") {
+			return strings.Join(words[:max+counter+1], " ")
+		}
+	}
+
+	return strings.Join(words[:max], " ")
+}
+
+func MakePermalink(domain string, path string) string {
+	return strings.TrimRight(domain, "/") + "/" + strings.TrimLeft(path, "/")
+}
--- /dev/null
+++ b/hugolib/index.go
@@ -1,0 +1,58 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"sort"
+)
+
+type Index map[string]Pages
+type IndexList map[string]Index
+
+type OrderedIndex []*Pages
+type OrderedIndexList map[string]OrderedIndex
+
+// KeyPrep... Indexes should be case insensitive. Can make it easily conditional later.
+func kp(in string) string {
+	return Urlize(in)
+}
+
+func (i Index) Get(key string) Pages { return i[kp(key)] }
+func (i Index) Count(key string) int { return len(i[kp(key)]) }
+func (i Index) Add(key string, p *Page) {
+	key = kp(key)
+	i[key] = append(i[key], p)
+}
+
+func (l IndexList) BuildOrderedIndexList() *OrderedIndexList {
+	oil := make(OrderedIndexList, len(l))
+	for idx_name, index := range l {
+		i := 0
+		oi := make(OrderedIndex, len(index))
+		for _, e := range index {
+			oi[i] = &e
+			i++
+		}
+		oi.Sort()
+		oil[idx_name] = oi
+	}
+	return &oil
+}
+
+func (idx OrderedIndex) Len() int { return len(idx) }
+
+func (idx OrderedIndex) Less(i, j int) bool       { return len(*idx[i]) < len(*idx[j]) }
+func (idx OrderedIndex) Swap(i, j int)            { idx[i], idx[j] = idx[j], idx[i] }
+func (idx OrderedIndex) Sort()                    { sort.Sort(idx) }
+func (idx OrderedIndex) Limit(n int) OrderedIndex { return idx[0:n] }
--- /dev/null
+++ b/hugolib/node.go
@@ -1,0 +1,43 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"html/template"
+	"time"
+)
+
+type Node struct {
+	Url         string
+	Permalink   template.HTML
+	RSSlink     template.HTML
+	Site        SiteInfo
+	layout      string
+	Data        map[string]interface{}
+	Section     string
+	Slug        string
+	Title       string
+	Description string
+	Keywords    []string
+	Date        time.Time
+}
+
+func (n *Node) GetSection() string {
+	s := ""
+	if n.Section != "" {
+		s = n.Section
+	}
+
+	return s
+}
--- /dev/null
+++ b/hugolib/page.go
@@ -1,0 +1,381 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/theplant/blackfriday"
+	"html/template"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+	"time"
+)
+
+var _ = filepath.Base("")
+
+type Page struct {
+	Status          string
+	Images          []string
+	Content         template.HTML
+	Summary         template.HTML
+	RawMarkdown     string // TODO should be []byte
+	Params          map[string]interface{}
+	RenderedContent *bytes.Buffer
+	contentType     string
+	Draft           bool
+	Tmpl            *template.Template
+	PageMeta
+	File
+	Position
+	Node
+}
+
+const summaryLength = 70
+
+type File struct {
+	FileName, OutFile, Extension string
+}
+
+type PageMeta struct {
+	WordCount      int
+	FuzzyWordCount int
+}
+
+type Position struct {
+	Prev *Page
+	Next *Page
+}
+
+type Pages []*Page
+
+func (p Pages) Len() int           { return len(p) }
+func (p Pages) Less(i, j int) bool { return p[i].Date.Unix() > p[j].Date.Unix() }
+func (p Pages) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// TODO eliminate unnecessary things
+func (p Pages) Sort()             { sort.Sort(p) }
+func (p Pages) Limit(n int) Pages { return p[0:n] }
+
+func initializePage(filename string) (page Page) {
+	page = Page{}
+	page.Date, _ = time.Parse("20060102", "20080101")
+	page.FileName = filename
+	page.contentType = ""
+	page.Extension = "html"
+	page.Params = make(map[string]interface{})
+	page.Keywords = make([]string, 10, 30)
+	page.setSection()
+
+	return page
+}
+
+func (p *Page) setSection() {
+	x := strings.Split(p.FileName, "/")
+
+	if section := x[len(x)-2]; section != "content" {
+		p.Section = section
+	}
+}
+
+func (page *Page) Type() string {
+	if page.contentType != "" {
+		return page.contentType
+	}
+
+	if x := page.GetSection(); x != "" {
+		return x
+	}
+
+	return "page"
+}
+
+func (page *Page) Layout(l ...string) string {
+	layout := ""
+	if len(l) == 0 {
+		layout = "single"
+	} else {
+		layout = l[0]
+	}
+
+	if x := page.layout; x != "" {
+		return x
+	}
+
+	return strings.ToLower(page.Type()) + "/" + layout + ".html"
+}
+
+// TODO should return errors as well
+// TODO new page should return just a page
+// TODO initalize separately... load from reader (file, or []byte)
+func NewPage(filename string) *Page {
+	p := initializePage(filename)
+	if err := p.buildPageFromFile(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	p.analyzePage()
+
+	return &p
+}
+
+func (p *Page) analyzePage() {
+	p.WordCount = TotalWords(p.RawMarkdown)
+	p.FuzzyWordCount = int((p.WordCount+100)/100) * 100
+}
+
+// TODO //rewrite to use byte methods instead
+func (page *Page) parseJsonMetaData(data []byte) ([]string, error) {
+	var err error
+
+	lines := strings.Split(string(data), "\n")
+	datum := lines[0:]
+
+	// go through content parse between "{" and "}"
+	// must be on their own lines (for now)
+	var found = 0
+	for i, line := range lines {
+		line = strings.TrimSpace(line)
+
+		if line == "{" {
+			found += 1
+		}
+
+		if line == "}" {
+			found -= 1
+		}
+
+		if found == 0 {
+			datum = lines[0 : i+1]
+			lines = lines[i+1:]
+			break
+		}
+	}
+
+	err = page.handleJsonMetaData([]byte(strings.Join(datum, "\n")))
+
+	return lines, err
+}
+
+func (p *Page) Permalink() template.HTML {
+	if len(strings.TrimSpace(p.Slug)) > 0 {
+		return template.HTML(MakePermalink(string(p.Site.BaseUrl), strings.TrimSpace(p.Section)+"/"+p.Slug))
+	} else if len(strings.TrimSpace(p.Url)) > 2 {
+		return template.HTML(MakePermalink(string(p.Site.BaseUrl), strings.TrimSpace(p.Url)))
+	} else {
+		_, t := filepath.Split(p.FileName)
+		x := replaceExtension(strings.TrimSpace(t), p.Extension)
+		return template.HTML(MakePermalink(string(p.Site.BaseUrl), strings.TrimSpace(p.Section)+"/"+x))
+	}
+}
+
+func (page *Page) handleJsonMetaData(datum []byte) error {
+	var f interface{}
+	if err := json.Unmarshal(datum, &f); err != nil {
+		return fmt.Errorf("Invalide JSON in $v \nError parsing page meta data: %s", page.FileName, err)
+	}
+
+	m := f.(map[string]interface{})
+
+	for k, v := range m {
+		switch strings.ToLower(k) {
+		case "title":
+			page.Title = interfaceToString(v)
+		case "description":
+			page.Description = interfaceToString(v)
+		case "slug":
+			page.Slug = Urlize(interfaceToString(v))
+		case "url":
+			if url := interfaceToString(v); strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
+				return fmt.Errorf("Only relative urls are supported, %v provided", url)
+			}
+			page.Url = Urlize(interfaceToString(v))
+		case "type":
+			page.contentType = interfaceToString(v)
+		case "keywords":
+			page.Keywords = interfaceArrayToStringArray(v)
+		case "date", "pubdate":
+			page.Date = interfaceToStringToDate(v)
+		case "draft":
+			page.Draft = interfaceToBool(v)
+		case "layout":
+			page.layout = interfaceToString(v)
+		case "status":
+			page.Status = interfaceToString(v)
+		default:
+			// If not one of the explicit values, store in Params
+			//fmt.Println(strings.ToLower(k))
+			switch vv := v.(type) {
+			case string: // handle string values
+				page.Params[strings.ToLower(k)] = vv
+			default: // handle array of strings as well
+				switch vvv := vv.(type) {
+				case []interface{}:
+					var a = make([]string, len(vvv))
+					for i, u := range vvv {
+						a[i] = interfaceToString(u)
+					}
+					page.Params[strings.ToLower(k)] = a
+				}
+			}
+		}
+	}
+	//Printer(page.Params)
+	return nil
+}
+
+func (page *Page) GetParam(key string) interface{} {
+	v := page.Params[strings.ToLower(key)]
+
+	if v == nil {
+		return nil
+	}
+
+	switch v.(type) {
+	case string:
+		return interfaceToString(v)
+	case []string:
+		return v
+	}
+	return nil
+}
+
+func (page *Page) parseFileMetaData(data []byte) ([]string, error) {
+	lines := strings.Split(string(data), "\n")
+
+	// go through content parse from --- to ---
+	var found = 0
+	for i, line := range lines {
+		line = strings.TrimSpace(line)
+
+		if found == 1 {
+			// parse line for param
+			colonIndex := strings.Index(line, ":")
+			if colonIndex > 0 {
+				key := strings.TrimSpace(line[:colonIndex])
+				value := strings.TrimSpace(line[colonIndex+1:])
+				value = strings.Trim(value, "\"") //remove quotes
+				switch key {
+				case "title":
+					page.Title = value
+				case "layout":
+					page.layout = value
+				case "extension":
+					page.Extension = "." + value
+				default:
+					page.Params[key] = value
+				}
+			}
+
+		} else if found >= 2 {
+			// params over
+			lines = lines[i:]
+			break
+		}
+
+		if line == "---" {
+			found += 1
+		}
+	}
+
+	return lines, nil
+}
+
+func (page *Page) Err(message string) {
+	fmt.Println(page.FileName + " : " + message)
+}
+
+// TODO return error on last line instead of nil
+func (page *Page) parseFileHeading(data []byte) ([]string, error) {
+	if len(data) == 0 {
+		page.Err("Empty File, skipping")
+	} else {
+		if data[0] == '-' {
+			return page.parseFileMetaData(data)
+		}
+		return page.parseJsonMetaData(data)
+	}
+	return nil, nil
+}
+
+func (p *Page) Render(layout ...string) template.HTML {
+	curLayout := ""
+
+	if len(layout) > 0 {
+		curLayout = layout[0]
+	}
+
+	return template.HTML(string(p.ExecuteTemplate(curLayout).Bytes()))
+}
+
+func (p *Page) ExecuteTemplate(layout string) *bytes.Buffer {
+	l := p.Layout(layout)
+	buffer := new(bytes.Buffer)
+	p.Tmpl.ExecuteTemplate(buffer, l, p)
+	return buffer
+}
+
+func (page *Page) readFile() []byte {
+	var data, err = ioutil.ReadFile(page.FileName)
+	if err != nil {
+		PrintErr("Error Reading: " + page.FileName)
+		return nil
+	}
+	return data
+}
+
+func (page *Page) buildPageFromFile() error {
+	data := page.readFile()
+
+	content, err := page.parseFileHeading(data)
+	if err != nil {
+		return err
+	}
+
+	if err := page.setOutFile(); err != nil {
+		return err
+	}
+
+	page.convertMarkdown(content)
+	return nil
+}
+
+func (p *Page) setOutFile() error {
+	if len(strings.TrimSpace(p.Slug)) > 0 {
+		// Use Slug if provided
+		p.OutFile = strings.TrimSpace(p.Slug + "." + p.Extension)
+	} else if len(strings.TrimSpace(p.Url)) > 2 {
+		// Use Url if provided & Slug missing
+		p.OutFile = strings.TrimSpace(p.Url)
+	} else {
+		// Fall back to filename
+		_, t := filepath.Split(p.FileName)
+		p.OutFile = replaceExtension(strings.TrimSpace(t), p.Extension)
+	}
+
+	return nil
+}
+
+func (page *Page) convertMarkdown(lines []string) {
+
+	page.RawMarkdown = strings.Join(lines, "\n")
+	content := string(blackfriday.MarkdownCommon([]byte(page.RawMarkdown)))
+	page.Content = template.HTML(content)
+	page.Summary = template.HTML(TruncateWordsToWholeSentence(StripHTML(StripShortcodes(content)), summaryLength))
+}
--- /dev/null
+++ b/hugolib/shortcode.go
@@ -1,0 +1,131 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"bytes"
+	"fmt"
+	"html/template"
+	"strings"
+	"unicode"
+)
+
+var _ = fmt.Println
+
+type ShortcodeFunc func([]string) string
+
+type Shortcode struct {
+	Name string
+	Func ShortcodeFunc
+}
+
+type ShortcodeWithPage struct {
+	Params interface{}
+	Page   *Page
+}
+
+type Shortcodes map[string]ShortcodeFunc
+
+func ShortcodesHandle(stringToParse string, p *Page, t *template.Template) string {
+	posStart := strings.Index(stringToParse, "{{%")
+	if posStart > 0 {
+		posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart
+		if posEnd > posStart {
+			name, par := SplitParams(stringToParse[posStart+3 : posEnd])
+			params := Tokenize(par)
+			var data = &ShortcodeWithPage{Params: params, Page: p}
+			newString := stringToParse[:posStart] + ShortcodeRender(name, data, t) + ShortcodesHandle(stringToParse[posEnd+3:], p, t)
+			return newString
+		}
+	}
+	return stringToParse
+}
+
+func StripShortcodes(stringToParse string) string {
+	posStart := strings.Index(stringToParse, "{{%")
+	if posStart > 0 {
+		posEnd := strings.Index(stringToParse[posStart:], "%}}") + posStart
+		if posEnd > posStart {
+			newString := stringToParse[:posStart] + StripShortcodes(stringToParse[posEnd+3:])
+			return newString
+		}
+	}
+	return stringToParse
+}
+
+func Tokenize(in string) interface{} {
+	first := strings.Fields(in)
+	var final = make([]string, 0)
+	var keys = make([]string, 0)
+	inQuote := false
+	start := 0
+
+	for i, v := range first {
+		index := strings.Index(v, "=")
+
+		if !inQuote {
+			if index > 1 {
+				keys = append(keys, v[:index])
+				v = v[index+1:]
+			}
+		}
+
+		if !strings.HasPrefix(v, "&ldquo;") && !inQuote {
+			final = append(final, v)
+		} else if inQuote && strings.HasSuffix(v, "&rdquo;") && !strings.HasSuffix(v, "\\\"") {
+			first[i] = v[:len(v)-7]
+			final = append(final, strings.Join(first[start:i+1], " "))
+			inQuote = false
+		} else if strings.HasPrefix(v, "&ldquo;") && !inQuote {
+			if strings.HasSuffix(v, "&rdquo;") {
+				final = append(final, v[7:len(v)-7])
+			} else {
+				start = i
+				first[i] = v[7:]
+				inQuote = true
+			}
+		}
+
+		// No closing "... just make remainder the final token
+		if inQuote && i == len(first) {
+			final = append(final, first[start:len(first)]...)
+		}
+	}
+
+	if len(keys) > 0 {
+		var m = make(map[string]string)
+		for i, k := range keys {
+			m[k] = final[i]
+		}
+
+		return m
+	}
+
+	return final
+}
+
+func SplitParams(in string) (name string, par2 string) {
+	i := strings.IndexFunc(strings.TrimSpace(in), unicode.IsSpace)
+	if i < 1 {
+		return strings.TrimSpace(in), ""
+	}
+
+	return strings.TrimSpace(in[:i+1]), strings.TrimSpace(in[i+1:])
+}
+
+func ShortcodeRender(name string, data *ShortcodeWithPage, t *template.Template) string {
+	buffer := new(bytes.Buffer)
+	t.ExecuteTemplate(buffer, "shortcodes/"+name+".html", data)
+	return buffer.String()
+}
--- /dev/null
+++ b/hugolib/site.go
@@ -1,0 +1,362 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package hugolib
+
+import (
+	"bitbucket.org/pkg/inflect"
+	"bytes"
+	"fmt"
+	"github.com/spf13/nitro"
+	"html/template"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+	"time"
+	//"sync"
+)
+
+type Site struct {
+	c           Config
+	Pages       Pages
+	Tmpl        *template.Template
+	Indexes     IndexList
+	Files       []string
+	Directories []string
+	Sections    Index
+	Info        SiteInfo
+	Shortcodes  map[string]ShortcodeFunc
+	timer       *nitro.B
+}
+
+type SiteInfo struct {
+	BaseUrl    template.URL
+	Indexes    *OrderedIndexList
+	Recent     *Pages
+	LastChange time.Time
+}
+
+func (s *Site) getFromIndex(kind string, name string) Pages {
+	return s.Indexes[kind][name]
+}
+
+func NewSite(config *Config) *Site {
+	return &Site{c: *config, timer: nitro.Initalize()}
+}
+
+func (site *Site) Build() {
+	site.Process()
+	site.Render()
+	site.Write()
+}
+
+func (site *Site) Analyze() {
+	site.Process()
+	site.checkDescriptions()
+}
+
+func (site *Site) Process() {
+	site.initialize()
+	site.prepTemplates()
+	site.timer.Step("initialize & template prep")
+	site.CreatePages()
+	site.timer.Step("import pages")
+	site.BuildSiteMeta()
+	site.timer.Step("build indexes")
+}
+
+func (site *Site) Render() {
+	site.RenderIndexes()
+	site.timer.Step("render and write indexes")
+	site.RenderLists()
+	site.timer.Step("render and write lists")
+	site.RenderPages()
+	site.timer.Step("render pages")
+	site.ProcessShortcodes()
+	site.timer.Step("render shortcodes")
+	site.RenderHomePage()
+	site.timer.Step("render and write homepage")
+}
+
+func (site *Site) Write() {
+	site.WritePages()
+	site.timer.Step("write pages")
+}
+
+func (site *Site) checkDescriptions() {
+	for _, p := range site.Pages {
+		if len(p.Description) < 60 {
+			fmt.Print(p.FileName + " ")
+		}
+	}
+}
+
+func (s *Site) prepTemplates() {
+	var templates = template.New("")
+
+	funcMap := template.FuncMap{
+		"urlize":    Urlize,
+		"gt":        Gt,
+		"isset":     IsSet,
+		"echoParam": ReturnWhenSet,
+	}
+
+	templates.Funcs(funcMap)
+
+	walker := func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			PrintErr("Walker: ", err)
+			return nil
+		}
+
+		if !fi.IsDir() {
+			filetext, err := ioutil.ReadFile(path)
+			if err != nil {
+				return err
+			}
+			text := string(filetext)
+			name := path[len(s.c.GetAbsPath(s.c.LayoutDir))+1:]
+			t := templates.New(name)
+			template.Must(t.Parse(text))
+		}
+		return nil
+	}
+
+	filepath.Walk(s.c.GetAbsPath(s.c.LayoutDir), walker)
+
+	s.Tmpl = templates
+}
+
+func (s *Site) initialize() {
+	site := s
+
+	s.checkDirectories()
+
+	walker := func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			PrintErr("Walker: ", err)
+			return nil
+		}
+
+		if fi.IsDir() {
+			site.Directories = append(site.Directories, path)
+			return nil
+		} else {
+			site.Files = append(site.Files, path)
+			return nil
+		}
+		return nil
+	}
+
+	filepath.Walk(s.c.GetAbsPath(s.c.SourceDir), walker)
+
+	s.Info = SiteInfo{BaseUrl: template.URL(s.c.BaseUrl)}
+
+	s.Shortcodes = make(map[string]ShortcodeFunc)
+}
+
+func (s *Site) checkDirectories() {
+	if b, _ := dirExists(s.c.GetAbsPath(s.c.LayoutDir)); !b {
+		FatalErr("No layout directory found, expecting to find it at " + s.c.GetAbsPath(s.c.LayoutDir))
+	}
+	if b, _ := dirExists(s.c.GetAbsPath(s.c.SourceDir)); !b {
+		FatalErr("No source directory found, expecting to find it at " + s.c.GetAbsPath(s.c.SourceDir))
+	}
+	mkdirIf(s.c.GetAbsPath(s.c.PublishDir))
+}
+
+func (s *Site) ProcessShortcodes() {
+	for i, _ := range s.Pages {
+		var bb bytes.Buffer
+		bb.WriteString(ShortcodesHandle(s.Pages[i].RenderedContent.String(), s.Pages[i], s.Tmpl))
+		s.Pages[i].RenderedContent = &bb
+	}
+}
+
+func (s *Site) CreatePages() {
+	for _, fileName := range s.Files {
+		page := NewPage(fileName)
+		page.Site = s.Info
+		page.Tmpl = s.Tmpl
+		if s.c.BuildDrafts || !page.Draft {
+			s.Pages = append(s.Pages, page)
+		}
+	}
+
+	s.Pages.Sort()
+}
+
+func (s *Site) BuildSiteMeta() {
+	s.Indexes = make(IndexList)
+	s.Sections = make(Index)
+
+	for _, plural := range s.c.Indexes {
+		s.Indexes[plural] = make(Index)
+		for i, p := range s.Pages {
+			vals := p.GetParam(plural)
+
+			if vals != nil {
+				for _, idx := range vals.([]string) {
+					s.Indexes[plural].Add(idx, s.Pages[i])
+				}
+			}
+		}
+		for k, _ := range s.Indexes[plural] {
+			s.Indexes[plural][k].Sort()
+		}
+	}
+
+	for i, p := range s.Pages {
+		sect := p.GetSection()
+		s.Sections.Add(sect, s.Pages[i])
+	}
+
+	for k, _ := range s.Sections {
+		s.Sections[k].Sort()
+	}
+
+	s.Info.Indexes = s.Indexes.BuildOrderedIndexList()
+
+	s.Info.LastChange = s.Pages[0].Date
+}
+
+func (s *Site) RenderPages() {
+	for i, _ := range s.Pages {
+		s.Pages[i].RenderedContent = s.RenderThing(s.Pages[i], s.Pages[i].Layout())
+	}
+}
+
+func (s *Site) WritePages() {
+	for _, p := range s.Pages {
+		s.WritePublic(p.Section, p.OutFile, p.RenderedContent.Bytes())
+	}
+}
+
+func (s *Site) RenderIndexes() {
+	for singular, plural := range s.c.Indexes {
+		for k, o := range s.Indexes[plural] {
+			n := s.NewNode()
+			n.Title = strings.Title(k)
+			url := Urlize(plural + "/" + k)
+			n.Url = url + ".html"
+			n.Permalink = template.HTML(MakePermalink(string(n.Site.BaseUrl), string(n.Url)))
+			n.RSSlink = template.HTML(MakePermalink(string(n.Site.BaseUrl), string(url+".xml")))
+			n.Date = o[0].Date
+			n.Data[singular] = o
+			n.Data["Pages"] = o
+			layout := "indexes/" + singular + ".html"
+
+			x := s.RenderThing(n, layout)
+			s.WritePublic(plural, k+".html", x.Bytes())
+
+			if a := s.Tmpl.Lookup("rss.xml"); a != nil {
+				// XML Feed
+				y := s.NewXMLBuffer()
+				n.Url = Urlize(plural + "/" + k + ".xml")
+				s.Tmpl.ExecuteTemplate(y, "rss.xml", n)
+				s.WritePublic(plural, k+".xml", y.Bytes())
+			}
+		}
+	}
+}
+
+func (s *Site) RenderLists() {
+	for section, data := range s.Sections {
+		n := s.NewNode()
+		n.Title = strings.Title(inflect.Pluralize(section))
+		n.Url = Urlize(section + "/index.html")
+		n.Permalink = template.HTML(MakePermalink(string(n.Site.BaseUrl), string(n.Url)))
+		n.RSSlink = template.HTML(MakePermalink(string(n.Site.BaseUrl), string(section+"/index.xml")))
+		n.Date = data[0].Date
+		n.Data["Pages"] = data
+		layout := "indexes/" + section + ".html"
+
+		x := s.RenderThing(n, layout)
+		s.WritePublic(section, "index.html", x.Bytes())
+
+		if a := s.Tmpl.Lookup("rss.xml"); a != nil {
+			// XML Feed
+			n.Url = Urlize(section + "/index.xml")
+			y := s.NewXMLBuffer()
+			s.Tmpl.ExecuteTemplate(y, "rss.xml", n)
+			s.WritePublic(section, "index.xml", y.Bytes())
+		}
+	}
+}
+
+func (s *Site) RenderHomePage() {
+	n := s.NewNode()
+	n.Title = ""
+	n.Url = Urlize(string(n.Site.BaseUrl))
+	n.RSSlink = template.HTML(MakePermalink(string(n.Site.BaseUrl), string("/index.xml")))
+	n.Permalink = template.HTML(string(n.Site.BaseUrl))
+	n.Date = s.Pages[0].Date
+	if len(s.Pages) < 9 {
+		n.Data["Pages"] = s.Pages
+	} else {
+		n.Data["Pages"] = s.Pages[:9]
+	}
+	x := s.RenderThing(n, "index.html")
+	s.WritePublic("", "index.html", x.Bytes())
+
+	if a := s.Tmpl.Lookup("rss.xml"); a != nil {
+		// XML Feed
+		n.Url = Urlize("index.xml")
+		y := s.NewXMLBuffer()
+		s.Tmpl.ExecuteTemplate(y, "rss.xml", n)
+		s.WritePublic("", "index.xml", y.Bytes())
+	}
+}
+
+func (s *Site) Stats() {
+	fmt.Printf("%d pages created \n", len(s.Pages))
+	for _, pl := range s.c.Indexes {
+		fmt.Printf("%d %s created\n", len(s.Indexes[pl]), pl)
+	}
+}
+
+func (s *Site) NewNode() Node {
+	var y Node
+	y.Data = make(map[string]interface{})
+	y.Site = s.Info
+
+	return y
+}
+
+func (s *Site) RenderThing(d interface{}, layout string) *bytes.Buffer {
+	buffer := new(bytes.Buffer)
+	s.Tmpl.ExecuteTemplate(buffer, layout, d)
+	return buffer
+}
+
+func (s *Site) NewXMLBuffer() *bytes.Buffer {
+	header := "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\" ?>\n"
+	return bytes.NewBufferString(header)
+}
+
+func (s *Site) WritePublic(path string, filename string, content []byte) {
+	AbsPath := ""
+	if path != "" {
+		// TODO double check the following line.. calling GetAbsPath 2x seems wrong
+		mkdirIf(s.c.GetAbsPath(filepath.Join(s.c.GetAbsPath(s.c.PublishDir), path)))
+		AbsPath = filepath.Join(s.c.GetAbsPath(s.c.PublishDir), path, filename)
+	} else {
+		AbsPath = filepath.Join(s.c.GetAbsPath(s.c.PublishDir), filename)
+	}
+
+	file, _ := os.Create(AbsPath)
+	defer file.Close()
+
+	file.Write(content)
+}
--- /dev/null
+++ b/main.go
@@ -1,0 +1,190 @@
+// Copyright © 2013 Steve Francia <[email protected]>.
+//
+// Licensed under the Simple Public License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://opensource.org/licenses/Simple-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"github.com/howeyc/fsnotify"
+	"github.com/spf13/hugo/hugolib"
+	"net/http"
+	"os"
+	"path/filepath"
+	"runtime/pprof"
+	"sync"
+)
+
+const (
+	cfgFiledefault = "config.json"
+)
+
+var (
+	baseUrl    = flag.String("b", "", "hostname (and path) to the root eg. http://spf13.com/")
+	cfgfile    = flag.String("c", cfgFiledefault, "config file (default is path/config.json)")
+	checkMode  = flag.Bool("k", false, "analyze content and provide feedback")
+	draft      = flag.Bool("d", false, "include content marked as draft")
+	help       = flag.Bool("h", false, "show this help")
+	path       = flag.String("p", "", "filesystem path to read files relative from")
+	verbose    = flag.Bool("v", false, "verbose output")
+	cpuprofile = flag.Int("cpuprofile", 0, "Number of times to create the site and profile it")
+	watchMode  = flag.Bool("w", false, "watch filesystem for changes and recreate as needed")
+	server     = flag.Bool("s", false, "run a (very) simple web server")
+	port       = flag.String("port", "1313", "port to run web server on, default :1313")
+)
+
+func usage() {
+	PrintErr("usage: hugo [flags]", "")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func main() {
+
+	flag.Usage = usage
+	flag.Parse()
+
+	if *help {
+		usage()
+	}
+
+	config := hugolib.SetupConfig(cfgfile, path)
+	config.BuildDrafts = *draft
+
+	if *baseUrl != "" {
+		config.BaseUrl = *baseUrl
+	}
+
+	if *cpuprofile != 0 {
+		f, err := os.Create("/tmp/hugo-cpuprofile")
+
+		if err != nil {
+			panic(err)
+		}
+
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+
+		for i := 0; i < *cpuprofile; i++ {
+			_ = buildSite(config)
+		}
+	}
+
+	if *checkMode {
+		site := hugolib.NewSite(config)
+		site.Analyze()
+		os.Exit(2)
+	}
+
+	if *watchMode {
+		fmt.Println("Watching for changes. Press ctrl+c to stop")
+		_ = buildSite(config)
+		err := NewWatcher(config, *port, *server)
+
+		if err != nil {
+			fmt.Println(err)
+		}
+	}
+
+	_ = buildSite(config)
+
+	if *server {
+		serve(*port, config)
+	}
+
+}
+
+func serve(port string, config *hugolib.Config) {
+	fmt.Println("Web Server is available at http://localhost:" + port)
+	fmt.Println("Press ctrl+c to stop")
+	panic(http.ListenAndServe(":"+port, http.FileServer(http.Dir(config.PublishDir))))
+}
+
+func buildSite(config *hugolib.Config) *hugolib.Site {
+	site := hugolib.NewSite(config)
+	site.Build()
+
+	site.Stats()
+
+	return site
+}
+
+func watchChange(c *hugolib.Config) {
+	fmt.Println("Change detected, rebuilding site\n")
+	buildSite(c)
+}
+
+func NewWatcher(c *hugolib.Config, port string, server bool) error {
+	watcher, err := fsnotify.NewWatcher()
+	var wg sync.WaitGroup
+
+	if err != nil {
+		return err
+		fmt.Println(err)
+	}
+
+	defer watcher.Close()
+
+	wg.Add(1)
+	go func() {
+		for {
+			select {
+			case ev := <-watcher.Event:
+				var _ = ev
+				watchChange(c)
+				// TODO add newly created directories to the watch list
+			case err := <-watcher.Error:
+				if err != nil {
+					fmt.Println("error:", err)
+				}
+			}
+		}
+	}()
+
+	for _, d := range getDirList(c) {
+		if d != "" {
+			_ = watcher.Watch(d)
+		}
+	}
+
+	if server {
+		go serve(port, c)
+	}
+
+	wg.Wait()
+	return nil
+}
+
+func getDirList(c *hugolib.Config) []string {
+	var a []string
+	walker := func(path string, fi os.FileInfo, err error) error {
+		if err != nil {
+			PrintErr("Walker: ", err)
+			return nil
+		}
+
+		if fi.IsDir() {
+			a = append(a, path)
+		}
+		return nil
+	}
+
+	filepath.Walk(c.GetAbsPath(c.SourceDir), walker)
+	filepath.Walk(c.GetAbsPath(c.LayoutDir), walker)
+
+	return a
+}
+
+func PrintErr(str string, a ...interface{}) {
+	fmt.Fprintln(os.Stderr, str, a)
+}