[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = space\nindent_size = 4\nend_of_line = lf\ncharset = utf-8\n\n[*.md]\nindent_style = tab\n\n[*.yml]\nindent_style = space\nindent_size = 2\n"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n    \"env\": {\n        \"node\": true\n    },\n    \"extends\": \"eslint:recommended\",\n    \"rules\": {\n        \"indent\": [\n            \"error\",\n            4,\n            {\n                \"SwitchCase\": 1\n            }\n        ],\n        \"linebreak-style\": [\n            \"error\",\n            \"unix\"\n        ],\n        \"quotes\": [\n            \"error\",\n            \"double\"\n        ],\n        \"semi\": [\n            \"error\",\n            \"always\"\n        ],\n        \"no-console\": [\n            \"error\", {\n                \"allow\": [\"info\", \"warn\", \"error\"]\n            }\n        ]\n    },\n    \"globals\": {\n        \"process\": false,\n        \"it\": false,\n        \"afterEach\": false,\n        \"beforeEach\": false,\n        \"after\": false,\n        \"describe\": false,\n        \"before\": false\n    }\n}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules/\ncoverage/\n*.log\n.vscode/\n.idea/\n.tmp/\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nnode_js:\n  - \"6.9\"\n  - \"4.7\"\nbefore_script:\n  - npm install -g gulp\nscript: gulp test-ci\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Change log\n\n## v0.4.1 (2017-08-27)\n\n**Fixes**\n\n* Fix `gulp-mocha` to v3.0.1 to ensure `istanbul` coverage is generated\n\n## v0.4.0 (2017-08-27)\n\n**Features**\n\n* Replace livereload with browser-sync [#35]\n* Replace uncss with sass in develop task [#35]\n* Uplift npm packages\n\n## v0.3.2 (2017-02-24)\n\n**Fixes**\n\n* Fix update script to ignore installing `content/template.md` if missing\n\n## v0.3.1 (2017-02-23)\n\n**Features**\n\n* Open browser in development task\n* Open browser in server task\n\n## v0.3.0 (2017-02-23)\n\n**Features**\n\n* Change tasks for development - run specific tasks on changes\n* Draft posts/pages are compiled by default in development\n* Uplift npm packages\n* Add editorconfig to installed files\n* Update gitignore\n* Code cleanup\n\n## v0.2.2 (2017-02-09)\n\n**Fixes**\n\n* Added eslint [#28]\n* New lines for some files [#28]\n* Changed .editorconfig to use utf-8 [#28]\n\n## v0.2.1 (2017-01-24)\n\n**Features**\n\n* Removed comma in getTagsAsLinks [#27]\n\n## v0.2.0 (2017-01-11)\n\n**Features**\n\n* Refactor compilation [#26]\n* Uplift npm packages\n* Remove temp files\n* Code cleanup\n* Fix image npm module versions\n\n## v0.1.29 (2017-01-11)\n\n**Features**\n\n* Add cssIgnore configuration option\n\n## v0.1.28 (2016-11-11)\n\n**Fixes**\n\n* Fix livereload race condition + HBS watch [#24]\n\n## v0.1.27 (2016-01-03)\n\n**Fixes**\n\n* Fix issue with Handlebars date helper and the wrong format.\n\n## v0.1.26 (2016-01-03)\n\n**Fixes**\n\n* Fix issue with missing node modules after running update script.\n\n## v0.1.25 (2016-01-02)\n\n**Features**\n\n* Add image compression setting to site.json. If set to false, no image compression is performed.\n\n## v0.1.24 (2015-12-30)\n\n**Features**\n\n* Add update script for easy node module upgrades. Readme edited with info on how to update.\n* Refactor install script\n* Code cleanup\n\n## v0.1.23 (2015-12-29)\n\n**Features**\n\n* Update install script to modify package.json dependencies\n* Uplift node modules\n\n**Fixes**\n\n* Update Travis CI build config\n\n## v0.1.22 (2015-12-29)\n\n**Features**\n\n* Support leaving out the initial --- for front-matter [#12]\n* Support tags defined as an array as well as a string [#13]\n\n**Fixes**\n\n* Fix automatically generated slug doesn't link correctly [#11]\n* Fix post sorting is not correct [#10]\n\n## v0.1.21 (2015-12-16)\n\n**Fixes**\n\n* Fix missing pagination partial from the install script\n\n## v0.1.20 (2015-11-11)\n\n**Features**\n\n* Add site data to individual pages or posts\n\n**Fixes**\n\n* Fix issue with pagination on home, date and tag pages\n\n## v0.1.19 (2015-10-09)\n\n**Fixes**\n\n* Fix sidebar dates and tags\n\n## v0.1.18 (2015-10-09)\n\n**Features**\n\n* Update readme and add help task\n\n## v0.1.17 (2015-10-06)\n\n**Fixes**\n\n* Fix develop task to watch files in `src` and run default task\n\n## v0.1.16 (2015-09-23)\n\n**Fixes**\n\n* Add auto-generated changelog\n\n## v0.1.15 (2015-09-23)\n\n**Fixes**\n\n* Fix compile rss tests\n\n## v0.1.14 (2015-09-22)\n\n**Features**\n\n* Replace imagemin-jpegoptim with imagemin-mozjpeg\n* Uplift node modules\n\n**Breaking changes**\n\n* If installed as a sub-module, you'll need to update your package.json in the root of your project as several node modules have been updated\n\n\n## v0.1.13 (2015-07-29)\n\n**Features**\n\n* Add slug as optional page or post variable.\n\n**Breaking changes**\n\n* If installed as a sub-module, you'll need to update your package.json in the root of your project as several node modules have been updated\n\n\n## v0.1.12 (2015-07-11)\n\n**Notes**\n\n* Uplift node modules\n\n\n## v0.1.11 (2015-02-26)\n\n**Fixes**\n\n* Fix an issue where date pages were skipped if tags exist\n\n\n## v0.1.10 (2015-02-26)\n\n**Fixes**\n\n* Fix example handlebars templates\n\n\n## v0.1.9 (2015-02-26)\n\n**Fixes**\n\n* Fix issue with pagination paths in tests\n\n\n## v0.1.8 (2015-02-26)\n\n**Fixes**\n\n* Fixed an issue with promises on tests\n* Fixed an issue with incorrect URLs on originated pages\n\n**Breaking changes**\n\nNew npm dev module `gulp-coveralls`\nNew npm module `mout`\n\n\n## v0.1.7 (2015-02-25)\n\n*  Update to generate full paginated pages\n*  Update so pages/posts can be stored anywhere in src/content\n*  Update README to include coveralls badge\n*  Add coveralls coverage\n*  Update node version for travis ci\n*  Add pages array to handlebars template data\n\n\n## v0.1.5 (2015-02-19)\n\n*  Add RSS feed feature to readme\n*  Add install sample files\n\n\n## v0.1.4 (2015-02-18)\n\n*  Improve test coverage\n*  Update readme for install script\n*  Implement install script\n\n\n## v0.1.3 (2015-02-17)\n\n*  Add minify css to copy-css task\n\n\n## v0.1.2 (2015-02-17)\n\n*  Fix error handling on no content\n\n\n## v0.1.1 (2015-02-17)\n\n*  Update copy tasks to remove dependencies\n\n\n## v0.1.0 (2015-02-17)\n\n*  Initial commit\n"
  },
  {
    "path": "README.md",
    "content": "# Static site generator using Gulp\n\n[![Build Status](https://travis-ci.org/ducksoupdev/gulp-site-generator.svg?branch=master)](https://travis-ci.org/ducksoupdev/gulp-site-generator)\n[![Coverage Status](https://coveralls.io/repos/ducksoupdev/gulp-site-generator/badge.svg?branch=master)](https://coveralls.io/r/ducksoupdev/gulp-site-generator?branch=master)\n\nThis is a simple static site generator which is perfect for a personal, blog or documentation site.\n\nIt is similar to other static site generators in that it takes your Markdown content, renders it, optimises it and creates a production-ready site that can be served by Nginx, Apache or another web server.\n\n## Features\n\n* Convert Markdown files to static HTML\n* [Handlebars](http://handlebarsjs.com) templates and partials\n* Sass compiling and minification\n* Css reducing (Uncss)\n* Javascript concatenating and minification\n* Asset copying\n* Image compression\n* HTML compression\n* RSS feed creation\n* Server for viewing built site\n* Clobber for cleaning build directory\n* Save content as draft\n* Convert draft templates\n* Creates a `build/` directory with built content and assets\n\n## Installation\n\nThis project is ideal when used as a Git sub-module or installed along-side your site so you can update it when new releases are made.\n\n### Getting the generator\n\n#### Git sub-module\n\n    $ mkdir my-static-site\n    $ cd my-static-site\n    $ git init\n    $ git submodule add https://github.com/ducksoupdev/gulp-site-generator.git tools\n\n#### Straightforward checkout\n\n    $ mkdir my-static-site\n    $ cd my-static-site\n    $ git clone https://github.com/ducksoupdev/gulp-site-generator.git tools\n\n### Installing the dependencies\n\nThe generator requires Gulp to be installed globally. If you don't have it you can install it using:\n\n    $ npm install -g gulp\n\nThe generator has some dependencies that need to be installed using the following script:\n\n    $ node tools/install\n\nThe script creates the following files in the root of your site:\n\n* `package.json` - the node modules required by the generator\n* `gulpfile.js` - the gulp file for all the generator tasks\n* `site.json` - the metadata for your site\n* `src/content` - the content folder for the markdown files including some sample ones\n* `src/images` - a sample image\n* `src/sass` - a sample sass file\n* `src/templates` - a set of Handlebar templates for creating pages and posts\n\nOnce created, the next thing is to install the required node modules:\n\n    $ npm install\n\nFinally, you can run the generator to create the sample site:\n\n    $ gulp\n\nThe generator will create a `build/` folder with the compiled and optimised site ready to be deployed to your web server.\n\nSo putting it all together, the installation steps are:\n\n    $ mkdir my-static-site\n    $ cd my-static-site\n    $ git init\n    $ git submodule add https://github.com/ducksoupdev/gulp-site-generator.git tools\n    $ npm install -g gulp\n    $ node tools/install\n    $ npm install\n    $ gulp\n\n## Updating\n\nUpdating the generator submodule to the latest version can be done using git:\n\n    $ cd tools\n    $ git remote update\n    $ git pull\n    $ cd ..\n\nThe generator has an update script that can then be run:\n\n    $ node tools/update\n\nThe script updates the `package.json` in the root of your site and updates any dependencies to the latest versions.\n\n## Tasks\n\nWhen you have created templates, content and assets, the default task will run the generator:\n\n    $ gulp\n\nThe following tasks can also be run individually:\n\n* **develop** - a live-reload task for developing your site where changes are reloaded automatically including draft posts and pages - view at http://localhost:8080\n* **sass** - converts sass files to css\n* **clobber** - removes the `build/` directory\n* **server** - view your built site locally at http://localhost:8080\n* **help** - lists available tasks\n\n## Configuration\n\nThe metadata file `site.json` contains all configuration required by your site. The following properties are used by the generator.\nYou are free to add properties to this file for use in your Handlebars templates.\n\n* title (string) (required) - the title of your site\n* description (string) (required) - a description of your site\n* url (string) (required) - the URL of your site\n* rss (string) (required) - the RSS feed XML file\n* maxItems (number) (optional) - the number to use for pagination\n* authors (object) (optional) - an map of authors with metadata\n* concatJs (array) (optional) - a list of javascript files to combine and minify\n* styleSheet (string) (optional) - the name of your main CSS file created by the sass task\n* imageCompression (boolean) (optional) - a boolean value to enable/disable image compresssion on build\n* uncssIgnore (array) (optional) - a list of selectors that uncss should ignore (for example \".container\" or \"#my-element\")\n\n## Content\n\nContent must be added to the `src/content` directory.\n\n### Pages and posts\n\nPages and posts must created in the `src/content/pages` and `src/content/posts` directories.\n\nPages and posts are Markdown files with a YAML front-matter block. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:\n\n    ---\n    title: Home\n    template: index.hbs\n    ---\n\n    The rest of the template goes here as markdown text.\n\nBetween these triple-dashed lines, you can set predefined variables (see below). These variables will then be available to you in any Handlebars templates or includes that the page or post in question relies on.\n\n* title (required) - the title of the page or post\n* template (required) - the Handlebars template to use to compile the page or post\n* slug (optional) - the URL slug which is used as the directory name when the page or post is built\n* date (optional) - used for posts and in the format YYYY-MM-DD\n* author (optional) - used for posts and the author key in the `site.json` file\n* status (optional) - set to 'draft' to ignore the page or post when running the generator\n\n### Assets\n\nImages, javascripts, fonts etc can all be added to the `src/` directory. You are free to create directories for these and name them accordingly.\n\nContent is created in the `src/content/pages` or `src/content/posts`.\n\nThe generator is opinionated in that it expects certain files in particular directories.\nTo help with this, [an example site](https://github.com/ducksoupdev/gulp-site-generator-example) is available that shows you how to structure your site with the generator.\n\n### Templates\n\nHandlebars is used for rendering templates. Partials located in `src/templates/partials` are automatically available to your Handlebar templates.\n\nHelpers are available to your Handlebar templates and partials, these are:\n\n* date - format a date in a particular format (uses Moment)\n\n    `{{date format=\"MMM Do, YYYY\"}}`\n\n* excerpt - returns an excerpt of the text of your content, use 'words' or 'characters' to set the length\n\n    `{{excerpt words=\"50\"}}`\n\n* content - returns an excerpt of content and is tag aware, use 'words' or 'characters' to set the length\n\n    `{{content words=\"50\"}}`\n\n* resolve - resolves the path to an asset relative to the site root\n\n    `{{resolve \"/favicon.ico\"}}`\n\n## Further information\n\nThe [example site](https://github.com/ducksoupdev/gulp-site-generator-example) is a good place to start and shows a basic structure of a site with templates and content.\n\nIf you encounter any issues or have any feedback, please [send me a tweet](http://twitter.com/ducksoupdev) or raise a bug on the issue tracker.\n"
  },
  {
    "path": "gulp/lib/compile-dates.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    Promise = require(\"bluebird\"),\n    compileHandlebars = require(\"gulp-compile-handlebars\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\"),\n    glob = require(\"glob\"),\n    moment = require(\"moment\"),\n    _ = require(\"lodash\"),\n    compileOptions = require(\"../lib/compile-options\"),\n    tags = require(\"../lib/tags\"),\n    dates = require(\"../lib/dates\"),\n    resolvePaths = require(\"../lib/paths\"),\n    compileDrafts = require(\"../lib/drafts\"),\n    promiseList = require(\"../lib/promises\");\n\nmodule.exports = function (rootPath) {\n    return new Promise(function(resolve, reject) {\n        var siteData = JSON.parse(fs.readFileSync(rootPath + \"/site.json\", \"utf8\"));\n        var gulpVersion = require(\"gulp/package\").version;\n        var compileOptionsObj = compileOptions(rootPath);\n\n        glob(rootPath + \"/build/content/**/*.json\", {\n            cwd: \".\"\n        }, function (err, files) {\n            if (err) {\n                reject(err);\n            } else {\n                var datePosts = {},\n                    posts = [],\n                    allPosts = [];\n\n                files.forEach(function (file) {\n                    var fileData = JSON.parse(fs.readFileSync(file, \"utf8\"));\n\n                    if (fileData.status && fileData.status === \"draft\" && !compileDrafts()) {\n                        return;\n                    }\n\n                    if (!fileData.date || !fileData.template) {\n                        return;\n                    }\n\n                    // check and fill-in missing file meta data\n                    fileData = compileOptionsObj.checkContent(fileData);\n\n                    var metaData = {\n                        title: fileData.title,\n                        description: resolvePaths.resolve(fileData.body, \"../..\"),\n                        url: \"../../\" + fileData.slug + \"/\",\n                        tagStr: fileData.tags,\n                        tags: (fileData.tags ? tags.getTagsAsLinks(\"../..\", fileData.tags) : undefined),\n                        date: fileData.date,\n                        post_class: \"post\" + (fileData.tags ? tags.getTagClasses(fileData.tags) : fileData.slug),\n                        meta: fileData\n                    };\n\n                    if (fileData.date && fileData.template === \"post.hbs\") {\n                        posts.push(metaData);\n                    }\n\n                    if (fileData.date) {\n                        var dateMonth = fileData.date.substr(0, 7); //2014-12\n                        if (datePosts[dateMonth]) {\n                            datePosts[dateMonth].push(metaData);\n                        } else {\n                            datePosts[dateMonth] = [metaData];\n                        }\n                    }\n                });\n\n                if (_.size(datePosts)) {\n                    var promises = [];\n                    posts.sort(dates.sortFunc);\n                    allPosts = _.cloneDeep(posts);\n\n                    for (var dateMonth in datePosts) {\n                        // sort the dateMonth posts\n                        datePosts[dateMonth].sort(dates.sortFunc);\n\n                        var templateData = {\n                            date: moment().format(\"YYYY-MM-DD\"),\n                            resourcePath: \"../..\",\n                            generator: \"Gulp \" + gulpVersion,\n                            meta_title: siteData.title,\n                            url: \"../..\",\n                            site: siteData,\n                            posts: datePosts[dateMonth],\n                            body_class: \"home-template\",\n                            rss: \"../..\" + siteData.rss,\n                            dateStr: moment(dateMonth, \"YYYY-MM\").format(\"MMMM YYYY\")\n                        };\n\n                        if (siteData.maxItems && datePosts[dateMonth].length > siteData.maxItems) {\n                            // how many pages do we need to create?\n                            var totalPages = Math.ceil(datePosts[dateMonth].length / siteData.maxItems);\n\n                            // shorten posts\n                            var paginatedPosts = datePosts[dateMonth].splice(siteData.maxItems);\n\n                            for (var i = 1; i < totalPages; i++) {\n                                var pageNumber = i + 1;\n                                var nextPosts = paginatedPosts.splice(0, siteData.maxItems);\n\n                                // update the resource paths\n                                nextPosts.forEach(function (post) {\n                                    post.description = resolvePaths.resolve(post.meta.body, \"../../../..\");\n                                    post.url = \"../../../../\" + post.meta.slug;\n                                });\n\n                                // create custom template data for this paginated page\n                                var pageTemplateData = _.cloneDeep(templateData);\n                                _.extend(pageTemplateData, {\n                                    posts: nextPosts,\n                                    resourcePath: \"../../../..\",\n                                    url: \"../../../..\",\n                                    rss: \"../../../..\" + siteData.rss,\n                                    allDates: dates.getAllDatesAsLinks(\"../../../..\", allPosts),\n                                    allTags: tags.getAllTagsAsLinks(\"../../../..\", allPosts)\n                                });\n                                delete pageTemplateData.pages;\n\n                                // add pagination data\n                                if (pageNumber === 2) {\n                                    pageTemplateData.prevUrl = \"../../\";\n                                } else {\n                                    pageTemplateData.prevUrl = \"../\" + (pageNumber - 1);\n                                }\n\n                                if (pageNumber < totalPages) {\n                                    pageTemplateData.nextUrl = \"../\" + (pageNumber + 1);\n                                }\n\n                                pageTemplateData.totalPages = totalPages;\n\n                                promises.push(new Promise(function (resolve, reject) {\n                                    gulp.src(rootPath + \"/src/templates/index.hbs\")\n                                        .pipe(compileHandlebars(pageTemplateData, compileOptionsObj))\n                                        .pipe(rename(\"index.html\"))\n                                        .pipe(gulp.dest(rootPath + \"/build/date/\" + dateMonth + \"/page/\" + pageNumber))\n                                        .on(\"error\", reject)\n                                        .on(\"end\", resolve);\n                                }));\n                            }\n\n                            templateData.nextUrl = \"../../date/\" + dateMonth + \"/page/2\";\n                            templateData.totalPages = totalPages;\n                        }\n\n                        // update template\n                        _.extend(templateData, {\n                            allDates: dates.getAllDatesAsLinks(\"../..\", allPosts),\n                            allTags: tags.getAllTagsAsLinks(\"../..\", allPosts)\n                        });\n\n                        promises.unshift(new Promise(function (resolve, reject) {\n                            gulp.src(rootPath + \"/src/templates/index.hbs\")\n                                .pipe(compileHandlebars(templateData, compileOptionsObj))\n                                .pipe(rename(\"index.html\"))\n                                .pipe(gulp.dest(rootPath + \"/build/date/\" + dateMonth))\n                                .on(\"error\", reject)\n                                .on(\"end\", resolve);\n                        }));\n                    }\n\n                    Promise.all(promiseList.filter(promises))\n                        .then(function () {\n                            resolve();\n                        }, function (err) {\n                            reject(err);\n                        });\n                } else {\n                    resolve();\n                }\n            }\n        });\n    });\n};\n"
  },
  {
    "path": "gulp/lib/compile-home.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    Promise = require(\"bluebird\"),\n    compileHandlebars = require(\"gulp-compile-handlebars\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\"),\n    glob = require(\"glob\"),\n    moment = require(\"moment\"),\n    _ = require(\"lodash\"),\n    compileOptions = require(\"../lib/compile-options\"),\n    tags = require(\"../lib/tags\"),\n    dates = require(\"../lib/dates\"),\n    resolvePaths = require(\"../lib/paths\"),\n    compileDrafts = require(\"../lib/drafts\"),\n    promiseList = require(\"../lib/promises\");\n\nmodule.exports = function (rootPath) {\n    return new Promise(function(resolve, reject) {\n        var siteData = JSON.parse(fs.readFileSync(rootPath + \"/site.json\", \"utf8\"));\n        var gulpVersion = require(\"gulp/package\").version;\n        var compileOptionsObj = compileOptions(rootPath);\n\n        glob(rootPath + \"/build/content/**/*.json\", {\n            cwd: \".\"\n        }, function (err, files) {\n            if (err) {\n                reject(err);\n            } else {\n                var posts = [],\n                    allPosts = [],\n                    pages = [];\n\n                files.forEach(function (file) {\n                    var fileData = JSON.parse(fs.readFileSync(file, \"utf8\"));\n\n                    if (fileData.status && fileData.status === \"draft\" && !compileDrafts()) {\n                        return;\n                    }\n\n                    // check and fill-in missing file meta data\n                    fileData = compileOptionsObj.checkContent(fileData);\n\n                    var metaData = {\n                        title: fileData.title,\n                        description: resolvePaths.resolve(fileData.body, \"\"),\n                        url: fileData.slug + \"/\",\n                        tagStr: fileData.tags,\n                        tags: (fileData.tags ? tags.getTagsAsLinks(\"\", fileData.tags) : undefined),\n                        date: fileData.date,\n                        post_class: \"post \" + (fileData.template === \"page.hbs\" ? \"page \" : \"\") + (fileData.tags ? tags.getTagClasses(fileData.tags) : fileData.slug),\n                        meta: fileData\n                    };\n\n                    if (fileData.date && fileData.template === \"post.hbs\") {\n                        posts.push(metaData);\n                    } else {\n                        pages.push(metaData);\n                    }\n                });\n\n                if (posts.length || pages.length) {\n                    posts.sort(dates.sortFunc);\n                    allPosts = _.cloneDeep(posts);\n\n                    var templateData = {\n                        date: moment().format(\"YYYY-MM-DD\"),\n                        resourcePath: \"\",\n                        generator: \"Gulp \" + gulpVersion,\n                        meta_title: siteData.title,\n                        url: \"\",\n                        site: siteData,\n                        posts: posts,\n                        pages: pages,\n                        body_class: \"home-template\",\n                        rss: siteData.rss,\n                        allDates: dates.getAllDatesAsLinks(\"\", allPosts),\n                        allTags: tags.getAllTagsAsLinks(\"\", allPosts)\n                    };\n\n                    var promises = [];\n\n                    if (siteData.maxItems && posts.length > siteData.maxItems) {\n                        // how many pages do we need to create?\n                        var totalPages = Math.ceil(posts.length / siteData.maxItems);\n\n                        // shorten posts\n                        var paginatedPosts = posts.splice(siteData.maxItems);\n\n                        for (var i = 1; i < totalPages; i++) {\n                            var pageNumber = i + 1;\n                            var nextPosts = paginatedPosts.splice(0, siteData.maxItems);\n\n                            // update the resource paths\n                            nextPosts.forEach(function (post) {\n                                post.description = resolvePaths.resolve(post.meta.body, \"../..\");\n                                post.url = \"../../\" + post.meta.slug;\n                            });\n\n                            // create custom template data for this paginated page\n\n                            var pageTemplateData = _.cloneDeep(templateData);\n                            _.extend(pageTemplateData, {\n                                posts: nextPosts,\n                                resourcePath: \"../..\",\n                                url: \"../..\",\n                                rss: \"../..\" + siteData.rss,\n                                allDates: dates.getAllDatesAsLinks(\"../..\", allPosts),\n                                allTags: tags.getAllTagsAsLinks(\"../..\", allPosts)\n                            });\n                            delete pageTemplateData.pages;\n\n                            // add pagination data\n                            if (pageNumber === 2) {\n                                pageTemplateData.prevUrl = \"../../\";\n                            } else {\n                                pageTemplateData.prevUrl = \"../\" + (pageNumber - 1);\n                            }\n\n                            if (pageNumber < totalPages) {\n                                pageTemplateData.nextUrl = \"../\" + (pageNumber + 1);\n                            }\n\n                            pageTemplateData.totalPages = totalPages;\n\n                            promises.push(new Promise(function (resolve, reject) {\n                                gulp.src(rootPath + \"/src/templates/index.hbs\")\n                                    .pipe(compileHandlebars(pageTemplateData, compileOptionsObj))\n                                    .pipe(rename(\"index.html\"))\n                                    .pipe(gulp.dest(rootPath + \"/build/page/\" + pageNumber))\n                                    .on(\"error\", reject)\n                                    .on(\"end\", function () {\n                                        resolve();\n                                    });\n                            }));\n                        }\n\n                        // update template\n                        templateData.nextUrl = \"page/2\";\n                        templateData.totalPages = totalPages;\n                    }\n\n                    promises.unshift(new Promise(function (resolve, reject) {\n                        gulp.src(rootPath + \"/src/templates/index.hbs\")\n                            .pipe(compileHandlebars(templateData, compileOptionsObj))\n                            .pipe(rename(\"index.html\"))\n                            .pipe(gulp.dest(rootPath + \"/build\"))\n                            .on(\"error\", reject)\n                            .on(\"end\", resolve);\n                    }));\n\n                    Promise.all(promiseList.filter(promises))\n                        .then(function () {\n                            resolve();\n                        }, function (err) {\n                            reject(err);\n                        });\n                } else {\n                    resolve();\n                }\n            }\n        });\n    });\n};\n"
  },
  {
    "path": "gulp/lib/compile-options.js",
    "content": "\"use strict\";\n\nvar moment = require(\"moment\"),\n    _ = require(\"lodash\"),\n    downsize = require(\"downsize\"),\n    downzero = require(\"./downzero\"),\n    stringUtils = require(\"mout/string\");\n\nmodule.exports = function (rootPath) {\n    return {\n        batch: [rootPath + \"/src/templates/partials\"],\n        checkContent: function (fileData) {\n            var excerpt = stringUtils.stripHtmlTags(fileData.body);\n            excerpt = excerpt.replace(/(\\r\\n|\\n|\\r)+/gm, \" \");\n            var title = downsize(excerpt, { words: 10 });\n\n            if (!fileData.title) {\n                fileData.title = title;\n            }\n\n            if (!fileData.slug) {\n                fileData.slug = stringUtils.slugify(fileData.title, \"-\");\n            }\n\n            if (!fileData.template && !fileData.date) {\n                fileData.template = \"page.hbs\";\n            } else if (fileData.date && !fileData.template) {\n                fileData.template = \"post.hbs\";\n            }\n\n            return fileData;\n        },\n        helpers: {\n            date: function (context, options) {\n                if (!options && context.hasOwnProperty(\"hash\")) {\n                    options = context;\n                    context = undefined;\n\n                    // set to published_at by default, if it\"s available\n                    // otherwise, this will print the current date\n                    if (this.date) {\n                        context = this.date;\n                    }\n                }\n\n                // ensure that context is undefined, not null, as that can cause errors\n                context = context === null ? undefined : context;\n\n                var format = options.hash.format || \"MMM Do, YYYY\";\n                var date = moment(context, \"YYYY-MM-DD\").format(format);\n\n                return date;\n            },\n            excerpt: function (options) {\n                var truncateOptions = (options || {}).hash || {},\n                    excerpt;\n\n                truncateOptions = _.pick(truncateOptions, [\"words\", \"characters\"]);\n                _.keys(truncateOptions).map(function (key) {\n                    truncateOptions[key] = parseInt(truncateOptions[key], 10);\n                });\n\n                excerpt = stringUtils.stripHtmlTags(this.description);\n                excerpt = excerpt.replace(/(\\r\\n|\\n|\\r)+/gm, \" \");\n\n                if (!truncateOptions.words && !truncateOptions.characters) {\n                    truncateOptions.words = 50;\n                }\n\n                return downsize(excerpt, truncateOptions);\n            },\n            content: function (options) {\n                var truncateOptions = (options || {}).hash || {};\n                truncateOptions = _.pick(truncateOptions, [\"words\", \"characters\"]);\n                _.keys(truncateOptions).map(function (key) {\n                    truncateOptions[key] = parseInt(truncateOptions[key], 10);\n                });\n\n                if (truncateOptions.hasOwnProperty(\"words\") || truncateOptions.hasOwnProperty(\"characters\")) {\n                    // Legacy function: {{content words=\"0\"}} should return leading tags.\n                    if (truncateOptions.hasOwnProperty(\"words\") && truncateOptions.words === 0) {\n                        return downzero(this.description);\n                    }\n\n                    return downsize(this.description, truncateOptions);\n                }\n\n                return this.description;\n            },\n            resolve: function (path) {\n                if (path && this.resourcePath && this.resourcePath !== \"\") {\n                    return this.resourcePath + path;\n                }\n                if (/^\\//.test(path)) {\n                    path = path.substring(1);\n                }\n                return \"\" + path;\n            },\n            or: function (v1, v2) {\n                return v1 || v2;\n            }\n        }\n    };\n};\n"
  },
  {
    "path": "gulp/lib/compile-pages.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    Promise = require(\"bluebird\"),\n    compileHandlebars = require(\"gulp-compile-handlebars\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\"),\n    path = require(\"path\"),\n    glob = require(\"glob\"),\n    moment = require(\"moment\"),\n    _ = require(\"lodash\"),\n    compileOptions = require(\"../lib/compile-options\"),\n    tags = require(\"../lib/tags\"),\n    dates = require(\"../lib/dates\"),\n    resolvePaths = require(\"../lib/paths\"),\n    compileDrafts = require(\"../lib/drafts\"),\n    promiseList = require(\"../lib/promises\");\n\nmodule.exports = function (rootPath) {\n    return new Promise(function(resolve, reject) {\n        var siteData = JSON.parse(fs.readFileSync(rootPath + \"/site.json\", \"utf8\"));\n        var gulpVersion = require(\"gulp/package\").version;\n        var compileOptionsObj = compileOptions(rootPath);\n\n        glob(rootPath + \"/build/content/**/*.json\", {\n            cwd: \".\"\n        }, function (err, files) {\n            if (err) {\n                reject(err);\n            } else {\n                var templatesToCreate = [],\n                    posts = [];\n\n                files.forEach(function (file) {\n                    var fileData = JSON.parse(fs.readFileSync(file, \"utf8\"));\n\n                    if (fileData.status && fileData.status === \"draft\" && !compileDrafts()) {\n                        return;\n                    }\n\n                    // check and fill-in missing file meta data\n                    fileData = compileOptionsObj.checkContent(fileData);\n\n                    var tagClasses = tags.getTagClasses(fileData.tags);\n\n                    var metaData = {\n                        title: fileData.title,\n                        body: resolvePaths.resolve(fileData.body, \"..\"),\n                        url: \"../\" + fileData.slug + \"/\",\n                        tagStr: fileData.tags,\n                        tags: (fileData.tags ? tags.getTagsAsLinks(\"..\", fileData.tags) : undefined),\n                        date: fileData.date,\n                        post_class: \"post \" + (fileData.template === \"page.hbs\" ? \"page \" : \"\") + (fileData.tags ? tagClasses : fileData.slug),\n                        author: (fileData.author ? siteData.authors[fileData.author] : \"\"),\n                        meta: fileData\n                    };\n\n                    if (fileData.date && fileData.template === \"post.hbs\") {\n                        posts.push(metaData);\n                    }\n\n                    // post class\n                    var bodyClass = \"post-template\";\n                    if (fileData.template === \"page.hbs\") {\n                        bodyClass += \" page-template page\";\n                    }\n\n                    // tags\n                    if (fileData.tags) {\n                        bodyClass += tagClasses;\n                    }\n\n                    var templateData = {\n                        date: moment().format(\"YYYY-MM-DD\"),\n                        resourcePath: \"..\",\n                        generator: \"Gulp \" + gulpVersion,\n                        meta_title: fileData.title,\n                        url: \"..\",\n                        site: siteData,\n                        post: metaData,\n                        body_class: bodyClass,\n                        rss: \"..\" + siteData.rss\n                    };\n\n                    var outDir = rootPath + \"/build/\" + path.basename(file).replace(/\\.[^/.]+$/, \"\");\n\n                    templatesToCreate.push({\n                        outDir: outDir,\n                        templateSrc: rootPath + \"/src/templates/\" + fileData.template,\n                        templateData: templateData\n                    });\n\n                });\n\n                if (templatesToCreate.length) {\n                    var promises = [];\n                    templatesToCreate.forEach(function (templateToCreate) {\n                        _.extend(templateToCreate.templateData.post, {\n                            site: siteData,\n                            allDates: dates.getAllDatesAsLinks(\"..\", posts),\n                            allTags: tags.getAllTagsAsLinks(\"..\", posts)\n                        });\n\n                        promises.push(new Promise(function (resolve, reject) {\n                            gulp.src(templateToCreate.templateSrc)\n                                .pipe(compileHandlebars(templateToCreate.templateData, compileOptionsObj))\n                                .pipe(rename(\"index.html\"))\n                                .pipe(gulp.dest(templateToCreate.outDir))\n                                .on(\"error\", reject)\n                                .on(\"end\", resolve);\n                        }));\n                    });\n\n                    Promise.all(promiseList.filter(promises))\n                        .then(function () {\n                            resolve();\n                        }, function (err) {\n                            reject(err);\n                        });\n                } else {\n                    resolve();\n                }\n            }\n        });\n    });\n};\n"
  },
  {
    "path": "gulp/lib/compile-rss.js",
    "content": "\"use strict\";\n\nvar fs = require(\"fs\"),\n    Promise = require(\"bluebird\"),\n    glob = require(\"glob\"),\n    moment = require(\"moment\"),\n    RSS = require(\"rss\"),\n    dates = require(\"../lib/dates\"),\n    resolvePaths = require(\"../lib/paths\"),\n    compileDrafts = require(\"../lib/drafts\");\n\nmodule.exports = function (rootPath) {\n    return new Promise(function(resolve, reject) {\n        var siteData = JSON.parse(fs.readFileSync(rootPath + \"/site.json\", \"utf8\"));\n        var gulpVersion = require(\"gulp/package\").version;\n\n        glob(rootPath + \"/build/content/posts/*.json\", {\n            cwd: \".\"\n        }, function (err, files) {\n            if (err) {\n                reject(err);\n            } else {\n                var posts = [];\n\n                files.forEach(function (file) {\n                    var fileData = JSON.parse(fs.readFileSync(file, \"utf8\"));\n\n                    if (fileData.status && fileData.status === \"draft\" && !compileDrafts()) {\n                        return;\n                    }\n\n                    var metaData = {\n                        title: fileData.title,\n                        description: resolvePaths.resolve(fileData.body, siteData.url),\n                        url: siteData.url + \"/\" + fileData.slug + \"/\",\n                        tags: (fileData.tags ? (fileData.tags.split ? fileData.tags.split(\" \") : fileData.tags) : undefined), // tags can be either string or array\n                        date: fileData.date\n                    };\n\n                    posts.push(metaData);\n                });\n\n                if (posts.length) {\n\n                    var feed = new RSS({\n                        title: siteData.title,\n                        description: siteData.description,\n                        generator: \"Gulp \" + gulpVersion,\n                        site_url: siteData.url,\n                        feed_url: siteData.url + \"/rss.xml\",\n                        ttl: 60\n                    });\n\n                    posts.sort(dates.sortFunc);\n\n                    posts.forEach(function (item) {\n                        feed.item({\n                            title: item.title,\n                            description: item.description,\n                            url: item.url,\n                            guid: item.url,\n                            categories: item.tags,\n                            date: moment(item.date, \"YYYY-MM-DD\").toDate()\n                        });\n                    });\n\n                    var xml = feed.xml();\n\n                    fs.writeFile(rootPath + \"/build/rss.xml\", xml, {\n                        encoding: \"utf8\"\n                    }, function (err) {\n                        if (err) {\n                            reject(err);\n                        }\n                        resolve();\n                    });\n                } else {\n                    resolve();\n                }\n            }\n        });\n    });\n};\n"
  },
  {
    "path": "gulp/lib/compile-tags.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    Promise = require(\"bluebird\"),\n    compileHandlebars = require(\"gulp-compile-handlebars\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\"),\n    glob = require(\"glob\"),\n    moment = require(\"moment\"),\n    _ = require(\"lodash\"),\n    compileOptions = require(\"../lib/compile-options\"),\n    tags = require(\"../lib/tags\"),\n    dates = require(\"../lib/dates\"),\n    resolvePaths = require(\"../lib/paths\"),\n    compileDrafts = require(\"../lib/drafts\"),\n    promiseList = require(\"../lib/promises\");\n\nmodule.exports = function (rootPath) {\n    return new Promise(function(resolve, reject) {\n        var siteData = JSON.parse(fs.readFileSync(rootPath + \"/site.json\", \"utf8\"));\n        var gulpVersion = require(\"gulp/package\").version;\n        var compileOptionsObj = compileOptions(rootPath);\n\n        glob(rootPath + \"/build/content/**/*.json\", {\n            cwd: \".\"\n        }, function (err, files) {\n            if (err) {\n                reject(err);\n            } else {\n                var tagPosts = {},\n                    posts = [],\n                    allPosts = [];\n\n                files.forEach(function (file) {\n                    var fileData = JSON.parse(fs.readFileSync(file, \"utf8\"));\n\n                    if (fileData.status && fileData.status === \"draft\" && !compileDrafts()) {\n                        return;\n                    }\n\n                    if (!fileData.tags || !fileData.date || !fileData.template) {\n                        return;\n                    }\n\n                    // check and fill-in missing file meta data\n                    fileData = compileOptionsObj.checkContent(fileData);\n\n                    var metaData = {\n                        title: fileData.title,\n                        description: resolvePaths.resolve(fileData.body, \"../..\"),\n                        url: \"../../\" + fileData.slug + \"/\",\n                        tagStr: fileData.tags,\n                        tags: (fileData.tags ? tags.getTagsAsLinks(\"../..\", fileData.tags) : undefined),\n                        date: fileData.date,\n                        post_class: \"post\" + (fileData.tags ? tags.getTagClasses(fileData.tags) : fileData.slug),\n                        meta: fileData\n                    };\n\n                    if (fileData.date && fileData.template === \"post.hbs\") {\n                        posts.push(metaData);\n                    }\n\n                    if (fileData.tags) {\n                        var tagList = fileData.tags.split(\" \");\n                        tagList.forEach(function (tag) {\n                            if (tagPosts[tag]) {\n                                tagPosts[tag].push(metaData);\n                            } else {\n                                tagPosts[tag] = [metaData];\n                            }\n                        });\n                    }\n                });\n\n                if (_.size(tagPosts)) {\n                    var promises = [];\n                    posts.sort(dates.sortFunc);\n                    allPosts = _.cloneDeep(posts);\n\n                    for (var tag in tagPosts) {\n                        // sort the tag posts\n                        tagPosts[tag].sort(dates.sortFunc);\n\n                        var templateData = {\n                            date: moment().format(\"YYYY-MM-DD\"),\n                            resourcePath: \"../..\",\n                            generator: \"Gulp \" + gulpVersion,\n                            meta_title: siteData.title,\n                            url: \"../..\",\n                            site: siteData,\n                            posts: tagPosts[tag],\n                            body_class: \"home-template\",\n                            rss: \"../..\" + siteData.rss,\n                            tag: tag,\n                            allDates: dates.getAllDatesAsLinks(\"../..\", allPosts),\n                            allTags: tags.getAllTagsAsLinks(\"../..\", allPosts)\n                        };\n\n                        if (siteData.maxItems && tagPosts[tag].length > siteData.maxItems) {\n                            // how many pages do we need to create?\n                            var totalPages = Math.ceil(tagPosts[tag].length / siteData.maxItems);\n\n                            // shorten posts\n                            var paginatedPosts = tagPosts[tag].splice(siteData.maxItems);\n\n                            for (var i = 1; i < totalPages; i++) {\n                                var pageNumber = i + 1;\n                                var nextPosts = paginatedPosts.splice(0, siteData.maxItems);\n\n                                // update the resource paths\n                                nextPosts.forEach(function (post) {\n                                    post.description = resolvePaths.resolve(post.meta.body, \"../../../..\");\n                                    post.url = \"../../../../\" + post.meta.slug;\n                                });\n\n                                // create custom template data for this paginated page\n                                var pageTemplateData = _.cloneDeep(templateData);\n                                _.extend(pageTemplateData, {\n                                    posts: nextPosts,\n                                    resourcePath: \"../../../..\",\n                                    url: \"../../../..\",\n                                    rss: \"../../../..\" + siteData.rss,\n                                    allDates: dates.getAllDatesAsLinks(\"../../../..\", allPosts),\n                                    allTags: tags.getAllTagsAsLinks(\"../../../..\", allPosts)\n                                });\n                                delete pageTemplateData.pages;\n\n                                // add pagination data\n                                if (pageNumber === 2) {\n                                    pageTemplateData.prevUrl = \"../../\";\n                                } else {\n                                    pageTemplateData.prevUrl = \"../\" + (pageNumber - 1);\n                                }\n\n                                if (pageNumber < totalPages) {\n                                    pageTemplateData.nextUrl = \"../\" + (pageNumber + 1);\n                                }\n\n                                pageTemplateData.totalPages = totalPages;\n\n                                promises.push(new Promise(function (resolve, reject) {\n                                    gulp.src(rootPath + \"/src/templates/index.hbs\")\n                                        .pipe(compileHandlebars(pageTemplateData, compileOptionsObj))\n                                        .pipe(rename(\"index.html\"))\n                                        .pipe(gulp.dest(rootPath + \"/build/tag/\" + tag + \"/page/\" + pageNumber))\n                                        .on(\"error\", reject)\n                                        .on(\"end\", resolve);\n                                }));\n                            }\n\n                            // update template\n                            templateData.nextUrl = \"../../tag/\" + tag + \"/page/2\";\n                            templateData.totalPages = totalPages;\n                        }\n\n                        promises.push(new Promise(function (resolve, reject) {\n                            gulp.src(rootPath + \"/src/templates/index.hbs\")\n                                .pipe(compileHandlebars(templateData, compileOptionsObj))\n                                .pipe(rename(\"index.html\"))\n                                .pipe(gulp.dest(rootPath + \"/build/tag/\" + tag))\n                                .on(\"error\", reject)\n                                .on(\"end\", resolve);\n                        }));\n                    }\n\n                    Promise.all(promiseList.filter(promises))\n                        .then(function () {\n                            resolve();\n                        }, function (err) {\n                            reject(err);\n                        });\n                } else {\n                    resolve();\n                }\n            }\n        });\n    });\n};\n"
  },
  {
    "path": "gulp/lib/dates.js",
    "content": "\"use strict\";\n\nvar moment = require(\"moment\");\n\nmodule.exports = {\n    getDateAsLink: function (path, dateMonth, dateStr) {\n        if (!dateMonth) {\n            return undefined;\n        }\n        return \"<a href=\\\"\" + path + \"/date/\" + dateMonth + \"\\\">\" + dateStr + \"</a>\";\n    },\n    getAllDatesAsLinks: function (path, posts) {\n        var allDates = {},\n            allDatesArray = [];\n        posts.forEach(function (post) {\n            var dateMonth = post.date.substr(0, 7); //2014-12\n            if (!allDates[dateMonth]) {\n                allDates[dateMonth] = path + \"/date/\" + dateMonth;\n            }\n        });\n        var keys = Object.keys(allDates);\n        if (keys.length) {\n            keys.sort();\n            keys.forEach(function (key) {\n                allDatesArray.push({\n                    dateMonth: key,\n                    dateStr: moment(key, \"YYYY-MM\").format(\"MMMM YYYY\"),\n                    dateLink: allDates[key]\n                });\n            });\n        }\n        return allDatesArray;\n    },\n    sortFunc: function (a, b) {\n        var timeA = new Date(a.date).getTime(),\n            timeB = new Date(b.date).getTime();\n        if (timeA > timeB) return -1;\n        if (timeA === timeB) return 0;\n        if (timeA < timeB) return 1;\n    }\n};\n"
  },
  {
    "path": "gulp/lib/downzero.js",
    "content": "\"use strict\";\n// Functions to imitate the behavior of Downsize@0.0.5 with \"words: \"0\"\" (heavily based on Downsize)\n// This is used to extract the first image from the post content which is used as a header\n\nvar stack, tagName, tagBuffer, truncatedText, parseState, pointer,\n    states = {\n        unitialized: 0,\n        tag_commenced: 1,\n        tag_string: -1,\n        tag_string_single: -2,\n        comment: -3\n    },\n    voidElements = [\"area\", \"base\", \"br\", \"col\", \"command\", \"embed\", \"hr\", \"img\", \"input\",\n        \"keygen\", \"link\", \"meta\", \"param\", \"source\", \"track\", \"wbr\"\n    ];\n\nfunction getTagName(tag) {\n    var tagName = (tag || \"\").match(/<\\/*([a-z0-9\\:\\-\\_]+)/i);\n    return tagName ? tagName[1] : null;\n}\n\nfunction closeTag(openingTag) {\n    var tagName = (getTagName(openingTag)) ? \"</\" + getTagName(openingTag) + \">\" : \"\";\n    return tagName;\n}\n\nfunction downzero(text) {\n    stack = [];\n    tagName = \"\";\n    tagBuffer = \"\";\n    truncatedText = \"\";\n    parseState = 0;\n    pointer = 0;\n\n    for (; pointer < text.length; pointer += 1) {\n        if (parseState !== states.unitialized) {\n            tagBuffer += text[pointer];\n        }\n\n        switch (text[pointer]) {\n            case \"<\":\n                if (parseState === states.unitialized && text[pointer + 1].match(/[a-z0-9\\-\\_\\/\\!]/)) {\n                    parseState = states.tag_commenced;\n                    tagBuffer += text[pointer];\n                }\n\n                break;\n            case \"!\":\n                if (parseState === states.tag_commenced && text[pointer - 1] === \"<\") {\n                    parseState = states.comment;\n                }\n\n                break;\n            case \"\\\"\":\n                if (parseState === states.tag_string) {\n                    parseState = states.tag_commenced;\n                } else if (parseState === states.tag_string_single) {\n                    // if double quote is found in a single quote string, ignore it and let the string finish\n                    break;\n                } else if (parseState !== states.unitialized) {\n                    parseState = states.tag_string;\n                }\n\n                break;\n            case \"'\":\n                if (parseState === states.tag_string_single) {\n                    parseState = states.tag_commenced;\n                } else if (parseState === states.tag_string) {\n                    break;\n                } else if (parseState !== states.unitialized) {\n                    parseState = states.tag_string_single;\n                }\n\n                break;\n            case \">\":\n                if (parseState === states.tag_commenced) {\n                    parseState = states.unitialized;\n                    truncatedText += tagBuffer;\n                    tagName = getTagName(tagBuffer);\n\n                    if (tagBuffer.match(/<\\s*\\//) && getTagName(stack[stack.length - 1]) === tagName) {\n                        stack.pop();\n                    } else if (voidElements.indexOf(tagName) < 0 && !tagBuffer.match(/\\/\\s*>$/)) {\n                        stack.push(tagBuffer);\n                    }\n                    tagBuffer = \"\";\n\n                    continue;\n                }\n\n                if (parseState === states.comment && text.substring(pointer - 2, pointer) === \"--\") {\n                    parseState = states.unitialized;\n                    truncatedText += tagBuffer;\n                    tagBuffer = \"\";\n\n                    continue;\n                }\n\n                break;\n            case \"-\":\n                break;\n        }\n\n        if (!parseState) {\n            break;\n        }\n    }\n\n    truncatedText += tagBuffer;\n\n    while (stack.length) {\n        truncatedText += closeTag(stack.pop());\n    }\n\n    return truncatedText;\n}\n\nmodule.exports = downzero;\n"
  },
  {
    "path": "gulp/lib/drafts.js",
    "content": "\"use strict\";\n\nvar minimist = require(\"minimist\");\n\nvar knownOptions = {\n    string: \"compile\",\n    default: {\n        compile: \"drafts\"\n    }\n};\n\nvar options = minimist(process.argv.slice(2), knownOptions);\n\nmodule.exports = function () {\n    if (options.compile === \"published\") {\n        return false;\n    }\n\n    if (process.env.GSD_PUBLISHED != null && process.env.GSD_PUBLISHED !== \"\") {\n        return false;\n    }\n\n    return true;\n};\n"
  },
  {
    "path": "gulp/lib/paths.js",
    "content": "\"use strict\";\n\nmodule.exports = {\n    /**\n     * Method to update all image and hyperlink URLs to paths relative to the site root\n     * @param {String} html The HTML containing images and hyperlinks\n     * @param {String} path The path to the site root\n     * @returns {String} The HTML with images and hyperlinks updated\n     */\n    resolve: function (html, path) {\n\n        // images\n        html = html.replace(/<img(.+)?src=\"([^\"]+)\"(.*)?>/gim, function (match, p1, p2, p3) {\n            var imagePath = p2;\n            if (/^\\//.test(imagePath)) {\n                imagePath = path + (path === \"\" ? p2.substring(1) : p2);\n            }\n            return \"<img\" + p1 + \"src=\\\"\" + imagePath + \"\\\"\" + p3 + \">\";\n        });\n\n        // links\n        html = html.replace(/<a(.+)?href=\"([^\"]+)\"(.*)?>/gim, function (match, p1, p2, p3) {\n            var linkPath = p2;\n            if (/^\\//.test(linkPath)) {\n                linkPath = path + (path === \"\" ? p2.substring(1) : p2);\n            }\n            return \"<a\" + p1 + \"href=\\\"\" + linkPath + \"\\\"\" + p3 + \">\";\n        });\n\n        return html;\n    }\n};\n"
  },
  {
    "path": "gulp/lib/promises.js",
    "content": "\"use strict\";\n\n/* simple filter for mocking a list of promises */\n\nmodule.exports = {\n    filter: function (promises) {\n        return promises;\n    }\n};\n"
  },
  {
    "path": "gulp/lib/remove-dir.js",
    "content": "\"use strict\";\n\nvar fs = require(\"fs\");\n\nvar rmDir = function (dirPath, removeSelf) {\n    if (removeSelf === undefined) {\n        removeSelf = true;\n    }\n    var files = [];\n    try {\n        files = fs.readdirSync(dirPath);\n    } catch (e) {\n        return e;\n    }\n\n    if (files.length > 0) {\n        for (var i = 0; i < files.length; i++) {\n            var filePath = dirPath + \"/\" + files[i];\n            if (fs.statSync(filePath).isFile()) {\n                fs.unlinkSync(filePath);\n            } else {\n                rmDir(filePath);\n            }\n        }\n    }\n    if (removeSelf) {\n        fs.rmdirSync(dirPath);\n    }\n};\n\nmodule.exports = rmDir;\n"
  },
  {
    "path": "gulp/lib/tags.js",
    "content": "\"use strict\";\n\t\nvar tagObjToArray = function (tagObj) {\n    var tags = [];\n    if (tagObj) {\n        if (typeof tagObj === \"string\" || tagObj instanceof String) {\n            tags = tagObj.split(\" \");\n        } else if (Array.isArray(tagObj)) {\n            tags = tagObj;\n        }\n    }\n    return tags;\n};\n\nmodule.exports = {\n    getTagClasses: function (tagObj) {\n        var tags = tagObjToArray(tagObj);\n        if (!tags.length) {\n            return undefined;\n        }\n        var classStr = \"\";\n        tags.forEach(function (tag) {\n            classStr += \" tag-\" + tag;\n        });\n        return classStr;\n    },\n    getTagsAsLinks: function (path, tagObj) {\n        var tags = tagObjToArray(tagObj);\n        if (!tags.length) {\n            return undefined;\n        }\n        var tagLinks = [];\n        tags.forEach(function (tag) {\n            tagLinks.push(\"<a href=\\\"\" + path + (path !== \"\" ? \"/\": \"\") + \"tag/\" + tag + \"\\\">\" + tag + \"</a>\");\n        });\n        return tagLinks.join(\"\");\n    },\n    getTagAsLink: function (path, tag) {\n        if (!tag) {\n            return undefined;\n        }\n        return \"<a href=\\\"\" + path + (path !== \"\" ? \"/\": \"\") + \"tag/\" + tag + \"\\\">\" + tag + \"</a>\";\n    },\n    getAllTagsAsLinks: function (path, posts) {\n        var allTags = {}, allTagsArray = [];\n        posts.forEach(function (post) {\n            if (post.tagStr) {\n                var tagList = tagObjToArray(post.tagStr);\n                tagList.forEach(function (tag) {\n                    if (!allTags[tag]) {\n                        allTags[tag] = path + (path !== \"\" ? \"/\": \"\") + \"tag/\" + tag;\n                    }\n                });\n            }\n        });\n        var keys = Object.keys(allTags);\n        if (keys.length) {\n            keys.sort();\n            keys.forEach(function (key) {\n                allTagsArray.push({\n                    tag: key,\n                    tagLink: allTags[key]\n                });\n            });\n        }\n        return allTagsArray;\n    }\n};\n"
  },
  {
    "path": "gulp/tasks/build.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"build\", [\"uncss\", \"concat-js\", \"image-min\", \"copy-assets\", \"minify-html\"]);\n"
  },
  {
    "path": "gulp/tasks/clobber.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    removeDir = require(\"../lib/remove-dir\");\n\ngulp.task(\"clobber\", function () {\n    return removeDir(\"./build\");\n});\n"
  },
  {
    "path": "gulp/tasks/compile.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    Promise = require(\"bluebird\"),\n    compileRss = require(\"../lib/compile-rss\"),\n    compileHome = require(\"../lib/compile-home\"),\n    compilePages = require(\"../lib/compile-pages\"),\n    compileTags = require(\"../lib/compile-tags\"),\n    compileDates = require(\"../lib/compile-dates\"),\n    removeDir = require(\"../lib/remove-dir\");\n\ngulp.task(\"compile\", [\"content\"], function (done) {\n    var rootPath = \".\";\n    var compilePromises = [];\n\n    // pages\n    compilePromises.push(compilePages(rootPath));\n\n    // tags\n    compilePromises.push(compileTags(rootPath));\n\n    // dates\n    compilePromises.push(compileDates(rootPath));\n\n    // rss feed compilation\n    compilePromises.push(compileRss(rootPath));\n\n    // index page generation\n    compilePromises.push(compileHome(rootPath));\n\n    Promise.all(compilePromises)\n        .then(function () {\n            removeDir(\"./build/content\");\n            done();\n        }, function () {\n            // call done even if there are errors\n            done();\n        });\n});\n\n"
  },
  {
    "path": "gulp/tasks/concat-js.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    concat = require(\"gulp-concat\"),\n    uglify = require(\"gulp-uglify\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\");\n\ngulp.task(\"concat-js\", function () {\n    var siteData = JSON.parse(fs.readFileSync(\"./site.json\", \"utf8\"));\n    var jsFiles = [\"./src/js/*.js\"];\n    if (siteData.concatJs) {\n        jsFiles = siteData.concatJs;\n    }\n    return gulp.src(jsFiles)\n        .pipe(concat(\"combined.js\"))\n        .pipe(uglify())\n        .pipe(rename({\n            suffix: \".min\"\n        }))\n        .pipe(gulp.dest(\"./build/js\"));\n});\n"
  },
  {
    "path": "gulp/tasks/content.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    markdownToJson = require(\"gulp-markdown-to-json\"),\n    marked = require(\"marked\");\n\ngulp.task(\"content\", function () {\n    return gulp.src(\"./src/content/**/*.md\")\n        .pipe(markdownToJson(marked))\n        .pipe(gulp.dest(\"./build/content\"));\n});\n"
  },
  {
    "path": "gulp/tasks/copy-assets.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"copy-assets\", [\"copy-fonts\"], function () {\n    return gulp.src([\"./src/favicon.ico\", \"./src/*.png\"])\n        .pipe(gulp.dest(\"./build\"));\n});\n"
  },
  {
    "path": "gulp/tasks/copy-css.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    fs = require(\"fs\"),\n    minifyCSS = require(\"gulp-minify-css\");\n\ngulp.task(\"copy-css\", [\"sass\"], function () {\n    var siteData = JSON.parse(fs.readFileSync(\"./site.json\", \"utf8\"));\n    var styleSheet = \"style.css\";\n    if (siteData.styleSheet) {\n        styleSheet = siteData.styleSheet;\n    }\n    return gulp.src([\"./src/css/**/*.css\", \"!./src/css/**/\" + styleSheet])\n        .pipe(minifyCSS())\n        .pipe(gulp.dest(\"./build/css\"));\n});\n"
  },
  {
    "path": "gulp/tasks/copy-fonts.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"copy-fonts\", function () {\n    return gulp.src([\"src/fonts/**/*\"])\n        .pipe(gulp.dest(\"./build/fonts\"));\n});\n"
  },
  {
    "path": "gulp/tasks/default.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    runSequence = require(\"run-sequence\");\n\ngulp.task(\"default\", function(done) {\n    process.env.GSD_PUBLISHED = \"true\";\n    runSequence(\"build\", done);\n});\n"
  },
  {
    "path": "gulp/tasks/develop.js",
    "content": "var gulp = require(\"gulp\"),\n    browserSync = require(\"browser-sync\");\n\ngulp.task(\"bs-reload\", function () {\n    browserSync.reload();\n});\n\ngulp.task(\"browser-sync\", function () {\n    browserSync.init([\"css/*.css\", \"js/*.js\"], {\n        server: {\n            baseDir: \"./\"\n        }\n    });\n});\n\ngulp.task(\"serve\", function () {\n    browserSync.init({\n        server: {\n            baseDir: \"./build\"\n        }\n    });\n});\n\ngulp.task(\"watch\", function () {\n    gulp.watch([\"./src/sass/**/*.scss\"], [\"sass\"]);\n    gulp.watch([\"./src/templates/**/*.hbs\"], [\"minify-html\"]);\n    gulp.watch([\"./src/js/**/*.js\"], [\"concat-js\"]);\n    gulp.watch([\"./src/images/**/*.{gif,jpg,png}\"], [\"image-min\"]);\n    gulp.watch([\"./src/content/**/*.md\"], [\"minify-html\"]);\n    gulp.watch([\"./build/**/*.*\"], [\"bs-reload\"]);\n});\n\ngulp.task(\"develop\", [\"watch\", \"serve\"]);\n"
  },
  {
    "path": "gulp/tasks/help.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"help\", function () {\n    console.log(\"Static site generator using Gulp\\n\\n\");\n    console.log(\"Tasks available:\\n\");\n    console.log(\"* default\\n\");\n    console.log(\"* develop\\n\");\n    console.log(\"* clobber\\n\");\n    console.log(\"* image-min\\n\");\n    console.log(\"* sass\\n\");\n    console.log(\"* server\\n\");\n    console.log(\"* help\\n\");\n});\n"
  },
  {
    "path": "gulp/tasks/image-min.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    imageminMozjpeg = require(\"imagemin-mozjpeg\"),\n    pngquant = require(\"imagemin-pngquant\"),\n    optipng = require(\"imagemin-optipng\"),\n    fs = require(\"fs\");\n\ngulp.task(\"image-min\", function () {\n    var siteData = JSON.parse(fs.readFileSync(\"./site.json\", \"utf8\"));\n    if (siteData.hasOwnProperty(\"imageCompression\") && !siteData.imageCompression) {\n        return gulp.src(\"./src/images/**/*.{png,jpg,jpeg,gif,svg}\")\n            .pipe(gulp.dest(\"./build/images\"));\n    } else {\n        return gulp.src(\"./src/images/**/*.{png,jpg,jpeg,gif,svg}\")\n            .pipe(optipng({ optimizationLevel: 3 })())\n            .pipe(pngquant({ quality: \"65-80\", speed: 4 })())\n            .pipe(imageminMozjpeg({ quality: 70 })())\n            .pipe(gulp.dest(\"./build/images\"));\n    }\n});\n"
  },
  {
    "path": "gulp/tasks/minify-html.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    minifyHTML = require(\"gulp-minify-html\");\n\ngulp.task(\"minify-html\", [\"compile\"], function () {\n    return gulp.src(\"./build/**/*.html\")\n        .pipe(minifyHTML({\n            comments: false,\n            spare: true\n        }))\n        .pipe(gulp.dest(\"./build\"));\n});\n"
  },
  {
    "path": "gulp/tasks/sass.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    sass = require(\"gulp-sass\"),\n    minifyCSS = require(\"gulp-minify-css\"),\n    rename = require(\"gulp-rename\");\n\ngulp.task(\"sass\", function () {\n    return gulp.src(\"./src/sass/**/*.scss\")\n        .pipe(sass())\n        .pipe(gulp.dest(\"./src/css\"))\n        .pipe(minifyCSS())\n        .pipe(rename({\n            suffix: \".min\"\n        }))\n        .pipe(gulp.dest(\"./build/css\"));\n});\n"
  },
  {
    "path": "gulp/tasks/server.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    open = require(\"gulp-open\"),\n    connect = require(\"gulp-connect\");\n\ngulp.task(\"server\", function () {\n    connect.server({\n        root: \"build\"\n    });\n    gulp.src(__filename).pipe(open({uri: \"http://localhost:8080\"}));\n});\n"
  },
  {
    "path": "gulp/tasks/test-ci.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"test-ci\", [\"test\"], function () {\n    var coveralls = require(\"gulp-coveralls\");\n    return gulp.src(\"./coverage/**/lcov.info\")\n        .pipe(coveralls());\n});\n"
  },
  {
    "path": "gulp/tasks/test.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\");\n\ngulp.task(\"test\", function (done) {\n    var mocha = require(\"gulp-mocha\"),\n        istanbul = require(\"gulp-istanbul\");\n\n    gulp.src([\"./gulp/lib/*.js\", \"./install/lib/*.js\"])\n        .pipe(istanbul())\n        .pipe(istanbul.hookRequire())\n        .on(\"finish\", function () {\n            gulp.src([\"./gulp/tests/*.spec.js\", \"./install/tests/*.spec.js\"])\n                .pipe(mocha())\n                .pipe(istanbul.writeReports())\n                .on(\"end\", done);\n        });\n});\n"
  },
  {
    "path": "gulp/tasks/uncss.js",
    "content": "\"use strict\";\n\nvar gulp = require(\"gulp\"),\n    glob = require(\"glob\"),\n    uncss = require(\"gulp-uncss\"),\n    minifyCSS = require(\"gulp-minify-css\"),\n    rename = require(\"gulp-rename\"),\n    fs = require(\"fs\");\n\ngulp.task(\"uncss\", [\"copy-css\"], function () {\n    var siteData = JSON.parse(fs.readFileSync(\"./site.json\", \"utf8\"));\n    var uncssIgnore;\n    if (siteData.uncssIgnore) {\n        uncssIgnore = siteData.uncssIgnore;\n    }\n    return gulp.src(\"./src/css/style.css\")\n        .pipe(uncss({\n            html: glob.sync(\"./build/**/*.html\"),\n            ignore: uncssIgnore\n        }))\n        .pipe(minifyCSS())\n        .pipe(rename({\n            suffix: \".min\"\n        }))\n        .pipe(gulp.dest(\"./build/css\"));\n});\n"
  },
  {
    "path": "gulp/tests/compile-dates.spec.js",
    "content": "\"use strict\";\n\nvar compileDates = require(\"../lib/compile-dates\"),\n    removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    Promise = require(\"bluebird\"),\n    sinon = require(\"sinon\"),\n    fs = require(\"fs\");\n\ndescribe(\"When compiling date pages\", function () {\n    var rootPath = \".tmp/compile-dates\";\n    var doneStub, errorStub;\n\n    before(function () {\n        doneStub = sinon.stub();\n        errorStub = sinon.stub();\n\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/compile-dates\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n\n        // set-up folders:\n        [\n            \"/src\",\n            \"/src/templates\",\n            \"/src/templates/partials\",\n            \"/build\",\n            \"/build/date\",\n            \"/build/date/page\",\n            \"/build/content\",\n            \"/build/content/pages\",\n            \"/build/content/posts\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(rootPath + dir)) {\n                fs.mkdirSync(rootPath + dir);\n            }\n        });\n\n        // set-up files:\n        fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\");\n        fs.writeFileSync(rootPath + \"/src/templates/partials/loop.hbs\", \"<ul>{{#each posts}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}</ul>\");\n        fs.writeFileSync(rootPath + \"/src/templates/partials/pagination.hbs\", \"<ul><li><a href=\\\"{{#if nextUrl}}{{nextUrl}}{{else}}#{{/if}}\\\">Older</a></li><li><a href=\\\"{{#if prevUrl}}{{prevUrl}}{{else}}#{{/if}}\\\">Newer</a></li></ul>\");\n        fs.writeFileSync(rootPath + \"/src/templates/index.hbs\", \"<div>Posts dated: {{dateStr}}{{> loop}}{{> pagination}}</div>\");\n    });\n\n    after(function () {\n        removeDir(rootPath);\n    });\n\n    describe(\"When compiling date pages\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha coke\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            compileDates(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should create the June 2014 date page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/date/2014-06/index.html\")).to.be.true;\n        });\n\n        it(\"Should create the December 2014 date page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/date/2014-12/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct date page content for June 2014\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: June 2014\" +\n                \"<ul><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-06/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should have the correct date page content for December 2014\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: December 2014\" +\n                \"<ul><li><a href=\\\"../../test-post2/\\\">Test post 2</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-12/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When an error occurs with the promises\", function () {\n        var promisesListStub, newCompileDates;\n\n        beforeEach(function (done) {\n            errorStub.reset();\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            promisesListStub = {\n                filter: function () {\n                    return [Promise.reject(\"An error occurred\")];\n                }\n            };\n\n            mockery.registerMock(\"../lib/promises\", promisesListStub);\n\n            newCompileDates = require(\"../lib/compile-dates\");\n\n            newCompileDates(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n\n        });\n\n        it(\"Should call the error function\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"../lib/promises\");\n            mockery.disable();\n        });\n    });\n\n    describe(\"When compiling date pages and excluding draft templates\", function () {\n        var minimistStub, newCompileDates;\n        \n        before(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n            \n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"status\\\":\\\"draft\\\",\\\"tags\\\":\\\"mocha coke\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            \n            newCompileDates = require(\"../lib/compile-dates\");\n            \n            newCompileDates(rootPath).then(done, errorStub);\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should have the correct date page content for June 2014\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: June 2014\" +\n                \"<ul><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-06/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When compiling date posts with pagination\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/site.json\", \"{ \\\"title\\\": \\\"Test site\\\", \\\"maxItems\\\": \\\"2\\\" }\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post3.json\", \"{\\\"slug\\\":\\\"test-post3\\\",\\\"title\\\":\\\"Test post 3\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post4.json\", \"{\\\"slug\\\":\\\"test-post4\\\",\\\"title\\\":\\\"Test post 4\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post5.json\", \"{\\\"slug\\\":\\\"test-post5\\\",\\\"title\\\":\\\"Test post 5\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post6.json\", \"{\\\"slug\\\":\\\"test-post6\\\",\\\"title\\\":\\\"Test post 6\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post7.json\", \"{\\\"slug\\\":\\\"test-post7\\\",\\\"title\\\":\\\"Test post 7\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\");\n            compileDates(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should have the correct date page content for December 2014\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: December 2014\" +\n                \"<ul><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li><li><a href=\\\"../../test-post2/\\\">Test post 2</a></li></ul>\" +\n                \"<ul><li><a href=\\\"../../date/2014-12/page/2\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-12/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should create the second paginated date page for December 2014\", function () {\n            expect(fs.existsSync(rootPath + \"/build/date/2014-12/page/2/index.html\")).to.be.true;\n        });\n\n        it(\"Should create the third paginated date page for December 2014\", function () {\n            expect(fs.existsSync(rootPath + \"/build/date/2014-12/page/3/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct content for the second paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: December 2014\" +\n                \"<ul><li><a href=\\\"../../../../test-post3\\\">Test post 3</a></li><li><a href=\\\"../../../../test-post4\\\">Test post 4</a></li></ul>\" +\n                \"<ul><li><a href=\\\"../3\\\">Older</a></li><li><a href=\\\"../../\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-12/page/2/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should have the correct content for the third paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"Posts dated: December 2014\" +\n                \"<ul><li><a href=\\\"../../../../test-post5\\\">Test post 5</a></li><li><a href=\\\"../../../../test-post6\\\">Test post 6</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"../2\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/date/2014-12/page/3/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When there are no posts for the date pages\", function () {\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\");\n            compileDates(rootPath).then(function () {\n                doneStub();\n                done();\n            }, function () {\n                errorStub();\n                done();\n            });\n        });\n\n        it(\"Should call done\", function () {\n            expect(doneStub.called).to.be.true;\n        });\n    });\n\n    describe(\"When a glob error occurs\", function () {\n        var globStub, newCompileDates;\n\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\");\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            globStub = function (paths, options, callback) {\n                callback({\n                    message: \"I threw an error\"\n                }, null);\n            };\n\n            mockery.registerMock(\"glob\", globStub);\n\n            newCompileDates = require(\"../lib/compile-dates\");\n\n            newCompileDates(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n        });\n\n        it(\"Should throw a glob error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({ message: \"I threw an error\" })).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"glob\");\n            mockery.disable();\n        });\n    });\n});\n"
  },
  {
    "path": "gulp/tests/compile-home.spec.js",
    "content": "\"use strict\";\n\nvar compileHome = require(\"../lib/compile-home\"),\n    removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    sinon = require(\"sinon\"),\n    Promise = require(\"bluebird\"),\n    fs = require(\"fs\");\n\ndescribe(\"Given the home page\", function () {\n    var rootPath = \".tmp/compile-home\";\n    var doneStub, errorStub;\n\n    before(function () {\n        doneStub = sinon.stub();\n        errorStub = sinon.stub();\n\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/compile-home\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n\n        // set-up folders:\n        [\n            \"/src\",\n            \"/src/templates\",\n            \"/src/templates/partials\",\n            \"/build\",\n            \"/build/page\",\n            \"/build/content\",\n            \"/build/content/pages\",\n            \"/build/content/posts\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(rootPath + dir)) {\n                fs.mkdirSync(rootPath + dir);\n            }\n        });\n\n        // set-up files:\n        fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/partials/loop.hbs\", \"<ul>{{#each pages}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}{{#each posts}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}</ul>\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/partials/pagination.hbs\", \"<ul><li><a href=\\\"{{#if nextUrl}}{{nextUrl}}{{else}}#{{/if}}\\\">Older</a></li><li><a href=\\\"{{#if prevUrl}}{{prevUrl}}{{else}}#{{/if}}\\\">Newer</a></li></ul>\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/index.hbs\", \"<div>{{> loop}}{{> pagination}}</div>\", { encoding: \"utf8\" });\n    });\n\n    after(function () {\n        removeDir(rootPath);\n    });\n\n    describe(\"When compiling the home page\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/build/content/pages/test-page.json\", \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileHome(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should create the static home page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct home page content\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul>\" +\n                \"<li>\" +\n                \"<a href=\\\"test-page/\\\">Test page</a>\" +\n                \"</li>\" +\n                \"<li>\" +\n                \"<a href=\\\"test-post1/\\\">Test post 1</a>\" +\n                \"</li>\" +\n                \"</ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When an error occurs with the promises\", function () {\n        var promisesListStub, newCompileHome;\n\n        beforeEach(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            promisesListStub = {\n                filter: function () {\n                    return [Promise.reject(\"An error occurred\")];\n                }\n            };\n\n            mockery.registerMock(\"../lib/promises\", promisesListStub);\n\n            newCompileHome = require(\"../lib/compile-home\");\n\n            newCompileHome(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n\n        });\n\n        it(\"Should call the error function\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"../lib/promises\");\n            mockery.disable();\n        });\n    });\n\n    describe(\"When compiling the home page excluding draft templates\", function () {\n        var minimistStub, newCompileHome;\n        \n        before(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n            \n            fs.writeFileSync(rootPath + \"/build/content/pages/test-page.json\", \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"status\\\":\\\"draft\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            \n            newCompileHome = require(\"../lib/compile-home\");\n\n            newCompileHome(rootPath).then(done, errorStub);\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should have the correct home page content\", function () {\n            var expectedHtml = \"<div><ul><li><a href=\\\"test-page/\\\">Test page</a></li></ul><ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul></div>\";\n            expect(fs.readFileSync(rootPath + \"/build/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When compiling the home page with pagination\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/site.json\", \"{ \\\"title\\\": \\\"Test site\\\", \\\"maxItems\\\": \\\"2\\\" }\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/pages/test-page.json\", \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post3.json\", \"{\\\"slug\\\":\\\"test-post3\\\",\\\"title\\\":\\\"Test post 3\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post4.json\", \"{\\\"slug\\\":\\\"test-post4\\\",\\\"title\\\":\\\"Test post 4\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post5.json\", \"{\\\"slug\\\":\\\"test-post5\\\",\\\"title\\\":\\\"Test post 5\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post6.json\", \"{\\\"slug\\\":\\\"test-post6\\\",\\\"title\\\":\\\"Test post 6\\\",\\\"date\\\":\\\"2015-02-20\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileHome(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should have the correct home page content\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"test-page/\\\">Test page</a></li><li><a href=\\\"test-post1/\\\">Test post 1</a></li><li><a href=\\\"test-post2/\\\">Test post 2</a></li></ul>\" +\n                \"<ul><li><a href=\\\"page/2\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should create the second paginated home page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/page/2/index.html\")).to.be.true;\n        });\n\n        it(\"Should create the third paginated home page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/page/3/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct home page content for the second paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"../../test-post3\\\">Test post 3</a></li><li><a href=\\\"../../test-post4\\\">Test post 4</a></li></ul>\" +\n                \"<ul><li><a href=\\\"../3\\\">Older</a></li><li><a href=\\\"../../\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/page/2/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should have the correct home page content for the third paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"../../test-post5\\\">Test post 5</a></li><li><a href=\\\"../../test-post6\\\">Test post 6</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"../2\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/page/3/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When compiling the home page content with no front matter\", function () {\n        before(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{ \\\"title\\\": \\\"Test site\\\" }\", { encoding: \"utf8\" });\n\n            [\n                \"/src\",\n                \"/src/templates\",\n                \"/src/templates/partials\",\n                \"/build\",\n                \"/build/content\"\n            ].forEach(function (dir) {\n                if (!fs.existsSync(rootPath + dir)) {\n                    fs.mkdirSync(rootPath + dir);\n                }\n            });\n\n            fs.writeFileSync(rootPath + \"/src/templates/partials/loop.hbs\", \"{{#each pages}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}{{#each posts}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/src/templates/index.hbs\", \"<div><ul>{{> loop}}</ul></div>\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/test-page.json\", \"{\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/test-post1.json\", \"{\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileHome(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should have the correct home page content\", function () {\n            expect(fs.readFileSync(rootPath + \"/build/index.html\", \"utf8\")).to.equal(\"<div><ul><li><a href=\\\"test-page-content/\\\">Test page content</a></li><li><a href=\\\"test-post-content/\\\">Test post content</a></li></ul></div>\");\n        });\n    });\n\n    describe(\"When there are no posts or pages for the home page\", function () {\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n            compileHome(rootPath).then(function () {\n                doneStub();\n                done();\n            }, function () {\n                errorStub();\n                done();\n            });\n        });\n\n        it(\"Should call done\", function () {\n            expect(doneStub.called).to.be.true;\n        });\n    });\n\n    describe(\"When a glob error occurs\", function () {\n        var globStub, newCompileHome;\n\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            globStub = function (paths, options, callback) {\n                callback({\n                    message: \"I threw an error\"\n                }, null);\n            };\n\n            mockery.registerMock(\"glob\", globStub);\n\n            newCompileHome = require(\"../lib/compile-home\");\n\n            newCompileHome(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n        });\n\n        it(\"Should throw a glob error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({ message: \"I threw an error\" })).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"glob\");\n            mockery.disable();\n        });\n    });\n});\n"
  },
  {
    "path": "gulp/tests/compile-options.spec.js",
    "content": "\"use strict\";\n\nvar compileOptions = require(\"../lib/compile-options\"),\n    Handlebars = require(\"handlebars\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"Given the compile options\", function () {\n    describe(\"When using the date helper\", function () {\n        beforeEach(function () {\n            Handlebars.registerHelper(\"date\", compileOptions(\".\").helpers.date);\n            this.html = \"<span>{{date format=\\\"MMM Do, YYYY\\\"}}</span>\";\n        });\n\n        it(\"Should format the date as MMM Do, YYYY\", function () {\n            var template = Handlebars.compile(this.html);\n            var result = template({\n                date: \"2015-10-15\"\n            });\n            expect(result).to.equal(\"<span>Oct 15th, 2015</span>\");\n        });\n    });\n\n    describe(\"When using the excerpt helper\", function () {\n        describe(\"When using the excerpt helper with characters\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"excerpt\", compileOptions(\".\").helpers.excerpt);\n                this.html = \"<p>{{{excerpt characters=100}}}...</p>\";\n            });\n\n            it(\"Should return an excerpt of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake po...</p>\");\n            });\n        });\n\n        describe(\"When using the excerpt helper with words\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"excerpt\", compileOptions(\".\").helpers.excerpt);\n                this.html = \"<p>{{{excerpt words=20}}}...</p>\";\n            });\n\n            it(\"Should return an excerpt of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw...</p>\");\n            });\n        });\n\n        describe(\"When using the excerpt helper without words or characters\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"excerpt\", compileOptions(\".\").helpers.excerpt);\n                this.html = \"<p>{{{excerpt}}}...</p>\";\n            });\n\n            it(\"Should return an excerpt of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut....</p>\");\n            });\n        });\n    });\n\n    describe(\"When using the content helper\", function () {\n        describe(\"When using the content helper with characters\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"content\", compileOptions(\".\").helpers.content);\n                this.html = \"{{{content characters=100}}}\";\n            });\n\n            it(\"Should return an content of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.</p>\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake po</p>\");\n            });\n        });\n\n        describe(\"When using the content helper with words\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"content\", compileOptions(\".\").helpers.content);\n                this.html = \"{{{content words=20}}}\";\n            });\n\n            it(\"Should return an content of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.</p>\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw</p>\");\n            });\n        });\n\n        describe(\"When using the content helper without words or characters\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"content\", compileOptions(\".\").helpers.content);\n                this.html = \"{{{content}}}\";\n            });\n\n            it(\"Should return an content of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.</p>\"\n                });\n                expect(result).to.equal(\"<p>Gingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee Candy canes brownie oat cake gummi bears cupcake powder donut.</p>\");\n            });\n        });\n\n        describe(\"When using the content helper with no words\", function () {\n            beforeEach(function () {\n                Handlebars.registerHelper(\"content\", compileOptions(\".\").helpers.content);\n                this.html = \"{{{content words=0}}}\";\n            });\n\n            it(\"Should return an content of the given text\", function () {\n                var template = Handlebars.compile(this.html);\n                var result = template({\n                    description: \"<p><img src=\\\"test.png\\\" alt=\\\"\\\"><span>Image</span></p>\"\n                });\n                expect(result).to.equal(\"<p><img src=\\\"test.png\\\" alt=\\\"\\\"><span></span></p>\");\n            });\n        });\n    });\n\n    describe(\"When using the resolve helper\", function () {\n        beforeEach(function () {\n            Handlebars.registerHelper(\"resolve\", compileOptions(\".\").helpers.resolve);\n            this.html = \"<link rel=\\\"shortcut icon\\\" href=\\\"{{resolve \\\"/favicon.ico\\\"}}\\\">\";\n        });\n\n        it(\"Should return a resolved path\", function () {\n            var template = Handlebars.compile(this.html);\n            var result = template({\n                resourcePath: \"..\"\n            });\n            expect(result).to.equal(\"<link rel=\\\"shortcut icon\\\" href=\\\"../favicon.ico\\\">\");\n        });\n\n        it(\"Should return a resolved path if no resourcePath is set\", function () {\n            var template = Handlebars.compile(this.html);\n            var result = template({});\n            expect(result).to.equal(\"<link rel=\\\"shortcut icon\\\" href=\\\"favicon.ico\\\">\");\n        });\n    });\n\n    describe(\"When using the checkContent function\", function () {\n        it(\"Should check the content and add missing page meta data\", function () {\n            var fileData = {\n                body: \"<p>Test page content.</p> <p>Blah blah blah</p>\"\n            };\n            fileData = compileOptions().checkContent(fileData);\n\n            expect(fileData).to.deep.equal({\n                slug: \"test-page-content-blah-blah-blah\",\n                template: \"page.hbs\",\n                title: \"Test page content. Blah blah blah\",\n                body: \"<p>Test page content.</p> <p>Blah blah blah</p>\"\n            });\n        });\n\n        it(\"Should check the content and add missing post meta data\", function () {\n            var fileData = {\n                date: \"2015-02-23\",\n                body: \"<p>Test post content.</p> <p>Blah blah blah</p>\"\n            };\n            fileData = compileOptions().checkContent(fileData);\n\n            expect(fileData).to.deep.equal({\n                slug: \"test-post-content-blah-blah-blah\",\n                template: \"post.hbs\",\n                title: \"Test post content. Blah blah blah\",\n                date: \"2015-02-23\",\n                body: \"<p>Test post content.</p> <p>Blah blah blah</p>\"\n            });\n        });\n    });\n\n    describe(\"When using the or helper\", function () {\n        beforeEach(function () {\n            Handlebars.registerHelper(\"or\", compileOptions(\".\").helpers.or);\n            this.html = \"<div>{{#if (or val1 val2)}}<span>Values matched</span>{{else}}<span>Values not matched</span>{{/if}}</div>\";\n        });\n\n        it(\"Should output the correct html when the values exist\", function () {\n            var template = Handlebars.compile(this.html);\n            var result = template({\n                val1: \"Test\"\n            });\n            expect(result).to.equal(\"<div><span>Values matched</span></div>\");\n        });\n\n        it(\"Should output the correct html when the values do not exist\", function () {\n            var template = Handlebars.compile(this.html);\n            var result = template({});\n            expect(result).to.equal(\"<div><span>Values not matched</span></div>\");\n        });\n    });\n});\n\n"
  },
  {
    "path": "gulp/tests/compile-pages.spec.js",
    "content": "\"use strict\";\n\nvar compilePages = require(\"../lib/compile-pages\"),\n    removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    Promise = require(\"bluebird\"),\n    sinon = require(\"sinon\"),\n    fs = require(\"fs\");\n\ndescribe(\"Given pages and posts\", function () {\n    var rootPath = \".tmp/compile-pages\";\n    var doneStub, errorStub;\n\n    before(function () {\n        doneStub = sinon.stub();\n        errorStub = sinon.stub();\n\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/compile-pages\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n\n        // set-up folders:\n        [\n            \"/src\",\n            \"/src/templates\",\n            \"/src/templates/partials\",\n            \"/build\",\n            \"/build/content\",\n            \"/build/content/pages\",\n            \"/build/content/posts\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(rootPath + dir)) {\n                fs.mkdirSync(rootPath + dir);\n            }\n        });\n\n        // set-up files:\n        fs.writeFileSync(rootPath + \"/site.json\",\n            \"{\\\"title\\\":\\\"Test site\\\",\\\"testSiteVar\\\":\\\"my test value\\\"}\", {\n                encoding: \"utf8\"\n            });\n        fs.writeFileSync(rootPath +\n            \"/src/templates/page.hbs\",\n            \"<div class=\\\"page\\\"><h1>{{post.title}}</h1>{{{post.body}}}<h3>{{site.testSiteVar}}</h3><h4>{{post.site.testSiteVar}}</h4></div>\", {\n                encoding: \"utf8\"\n            });\n        fs.writeFileSync(rootPath +\n            \"/src/templates/post.hbs\",\n            \"<div class=\\\"post\\\"><h1>{{post.title}}</h1>{{{post.body}}}<h3>{{site.testSiteVar}}</h3><h4>{{post.site.testSiteVar}}</h4></div>\", {\n                encoding: \"utf8\"\n            });\n    });\n\n    after(function () {\n        removeDir(rootPath);\n    });\n\n    describe(\"When compiling a page\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath +\n                \"/build/content/pages/test-page.json\",\n                \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n            compilePages(rootPath).then(done,\n                errorStub);\n        });\n\n        it(\"Should create the static page\", function () {\n            expect(fs.existsSync(rootPath +\n                \"/build/test-page/index.html\"\n            )).to.be.true;\n        });\n\n        it(\"Should have the correct page content\",\n            function () {\n                expect(fs.readFileSync(rootPath +\n                    \"/build/test-page/index.html\",\n                    \"utf8\")).to.equal(\n                    \"<div class=\\\"page\\\"><h1>Test page</h1><p>Test page content</p><h3>my test value</h3><h4>my test value</h4></div>\"\n                );\n            });\n    });\n\n    describe(\"When compiling a page with no slug\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath +\n                \"/build/content/pages/test-page-no-slug.json\",\n                \"{\\\"title\\\":\\\"Test page no slug\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n            compilePages(rootPath).then(done,\n                errorStub);\n        });\n\n        it(\"Should create the static page\", function () {\n            expect(fs.existsSync(rootPath +\n                \"/build/test-page-no-slug/index.html\"\n            )).to.be.true;\n        });\n\n        it(\"Should have the correct page content\",\n            function () {\n                expect(fs.readFileSync(rootPath +\n                    \"/build/test-page-no-slug/index.html\",\n                    \"utf8\")).to.equal(\n                    \"<div class=\\\"page\\\"><h1>Test page no slug</h1><p>Test page content</p><h3>my test value</h3><h4>my test value</h4></div>\"\n                );\n            });\n    });\n\n    describe(\"When compiling a post\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath +\n                \"/build/content/posts/test-post.json\",\n                \"{\\\"slug\\\":\\\"test-post\\\",\\\"title\\\":\\\"Test post\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n            compilePages(rootPath).then(done,\n                errorStub);\n        });\n\n        it(\"Should create the static post\", function () {\n            expect(fs.existsSync(rootPath +\n                \"/build/test-post/index.html\"\n            )).to.be.true;\n        });\n\n        it(\"Should have the correct post content\",\n            function () {\n                expect(fs.readFileSync(rootPath +\n                    \"/build/test-post/index.html\",\n                    \"utf8\")).to.equal(\n                    \"<div class=\\\"post\\\"><h1>Test post</h1><p>Test post content</p><h3>my test value</h3><h4>my test value</h4></div>\"\n                );\n            });\n    });\n\n    describe(\"When compiling a post with no slug\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath +\n                \"/build/content/posts/test-post-no-slug.json\",\n                \"{\\\"title\\\":\\\"Test post no slug\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n            compilePages(rootPath).then(done,\n                errorStub);\n        });\n\n        it(\"Should create the static post\", function () {\n            expect(fs.existsSync(rootPath +\n                \"/build/test-post-no-slug/index.html\"\n            )).to.be.true;\n        });\n\n        it(\"Should have the correct post content\",\n            function () {\n                expect(fs.readFileSync(rootPath +\n                    \"/build/test-post-no-slug/index.html\",\n                    \"utf8\")).to.equal(\n                    \"<div class=\\\"post\\\"><h1>Test post no slug</h1><p>Test post content</p><h3>my test value</h3><h4>my test value</h4></div>\"\n                );\n            });\n    });\n\n    describe(\"When an error occurs with the promises\", function () {\n        var promisesListStub, newCompilePages;\n\n        beforeEach(function (done) {\n            fs.writeFileSync(rootPath +\n                \"/build/content/pages/test-page.json\",\n                \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            promisesListStub = {\n                filter: function () {\n                    return [Promise.reject(\n                        \"An error occurred\"\n                    )];\n                }\n            };\n\n            mockery.registerMock(\n                \"../lib/promises\",\n                promisesListStub);\n\n            newCompilePages = require(\n                \"../lib/compile-pages\");\n\n            newCompilePages(rootPath).then(function () {\n                    done();\n                },\n                function (err) {\n                    errorStub(err);\n                    done();\n                });\n        });\n\n        it(\"Should call the error function\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\n                \"../lib/promises\");\n            mockery.disable();\n        });\n    });\n\n    describe(\"When compiling posts and excluding draft templates\", function () {\n        var minimistStub, newCompilePages;\n        \n        before(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n            \n            fs.writeFileSync(rootPath +\n                \"/build/content/posts/test-draft-post.json\",\n                \"{\\\"slug\\\":\\\"test-draft-post\\\",\\\"title\\\":\\\"Test draft post\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"status\\\":\\\"draft\\\",\\\"body\\\":\\\"<p>Test draft post content</p>\\\"}\", {\n                    encoding: \"utf8\"\n                });\n\n            newCompilePages = require(\"../lib/compile-pages\");\n\n            newCompilePages(rootPath).then(done,\n                errorStub);\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should not create the static post\",\n            function () {\n                expect(fs.existsSync(rootPath +\n                    \"/build/test-draft-post/index.html\"\n                )).to.be.false;\n            });\n    });\n\n    describe(\"When compiling posts and including tags\",\n        function () {\n            before(function (done) {\n                fs.writeFileSync(rootPath +\n                    \"/src/templates/post.hbs\",\n                    \"<div class=\\\"{{body_class}}\\\"><div class=\\\"post\\\"><h1>{{post.title}}</h1>{{{post.body}}}</div></div>\", {\n                        encoding: \"utf8\"\n                    });\n                fs.writeFileSync(rootPath +\n                    \"/build/content/posts/test-tagged-post.json\",\n                    \"{\\\"slug\\\":\\\"test-tagged-post\\\",\\\"title\\\":\\\"Test tagged post\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"tags\\\":\\\"tag1 tag2\\\",\\\"body\\\":\\\"<p>Test tagged post content</p>\\\"}\", {\n                        encoding: \"utf8\"\n                    });\n                compilePages(rootPath).then(done,\n                    errorStub);\n            });\n\n            it(\"Should have the correct post content\",\n                function () {\n                    expect(fs.readFileSync(rootPath +\n                        \"/build/test-tagged-post/index.html\",\n                        \"utf8\")).to.equal(\n                        \"<div class=\\\"post-template tag-tag1 tag-tag2\\\"><div class=\\\"post\\\"><h1>Test tagged post</h1><p>Test tagged post content</p></div></div>\"\n                    );\n                });\n        });\n\n    describe(\"When there are no posts or pages to compile\",\n        function () {\n            beforeEach(function (done) {\n                removeDir(rootPath);\n                fs.mkdirSync(rootPath);\n                fs.writeFileSync(rootPath +\n                    \"/site.json\",\n                    \"{\\\"title\\\":\\\"Test site\\\"}\", {\n                        encoding: \"utf8\"\n                    });\n                compilePages(rootPath).then(function () {\n                    doneStub();\n                    done();\n                }, function () {\n                    errorStub();\n                    done();\n                });\n            });\n\n            it(\"Should call done\", function () {\n                expect(doneStub.called).to.be.true;\n            });\n        });\n\n    describe(\"When a glob error occurs\", function () {\n        var globStub, newCompilePages;\n\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath +\n                \"/site.json\",\n                \"{\\\"title\\\":\\\"Test site\\\"}\", {\n                    encoding: \"utf8\"\n                });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            globStub = function (paths, options,\n                callback) {\n                callback({\n                    message: \"I threw an error\"\n                }, null);\n            };\n\n            mockery.registerMock(\"glob\",\n                globStub);\n\n            newCompilePages = require(\n                \"../lib/compile-pages\");\n\n            newCompilePages(rootPath).then(function () {\n                    done();\n                },\n                function (err) {\n                    errorStub(err);\n                    done();\n                });\n        });\n\n        it(\"Should throw a glob error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({\n                message: \"I threw an error\"\n            })).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"glob\");\n            mockery.disable();\n        });\n    });\n});"
  },
  {
    "path": "gulp/tests/compile-rss.spec.js",
    "content": "\"use strict\";\n\nvar compileRss = require(\"../lib/compile-rss\"),\n    removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    sinon = require(\"sinon\"),\n    fs = require(\"fs\");\n\ndescribe(\"Given the RSS feed\", function () {\n    var rootPath = \".tmp/compile-rss\";\n    var doneStub, errorStub;\n\n    before(function () {\n        doneStub = sinon.stub();\n        errorStub = sinon.stub();\n\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/compile-rss\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n\n        // set-up folders:\n        [\n            \"/build\",\n            \"/build/content\",\n            \"/build/content/pages\",\n            \"/build/content/posts\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(rootPath + dir)) {\n                fs.mkdirSync(rootPath + dir);\n            }\n        });\n\n        // set-up files:\n        fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n    });\n\n    describe(\"When compiling the rss feed\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/build/content/pages/test-page.json\", \"{\\\"slug\\\":\\\"test-page\\\",\\\"title\\\":\\\"Test page\\\",\\\"template\\\":\\\"page.hbs\\\",\\\"body\\\":\\\"<p>Test page content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-10\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-20\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileRss(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should create the static RSS xml file\", function () {\n            expect(fs.existsSync(rootPath + \"/build/rss.xml\")).to.be.true;\n        });\n\n        it(\"Should have the correct RSS content\", function () {\n            expect(fs.readFileSync(rootPath + \"/build/rss.xml\", \"utf8\")).to.match(/Test post 2/);\n        });\n    });\n\n    describe(\"When compiling the RSS feed excluding draft posts\", function () {\n        var minimistStub, newCompileRss;\n        \n        before(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n            \n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-10\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-20\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post3.json\", \"{\\\"slug\\\":\\\"test-post3\\\",\\\"title\\\":\\\"Test post 3\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-30\\\",\\\"status\\\":\\\"draft\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            \n            newCompileRss = require(\"../lib/compile-rss\");\n            \n            newCompileRss(rootPath).then(done, errorStub);\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should have the correct RSS content\", function () {\n            expect(fs.readFileSync(rootPath + \"/build/rss.xml\", \"utf8\")).to.not.match(/Test post 3/);\n        });\n    });\n\n    describe(\"When there are no posts for the RSS feed\", function () {\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n            compileRss(rootPath).then(function () {\n                doneStub();\n                done();\n            }, function () {\n                errorStub();\n                done();\n            });\n        });\n\n        it(\"Should call done\", function () {\n            expect(doneStub.called).to.be.true;\n        });\n    });\n\n    describe(\"When a fs writeFile error occurs\", function () {\n        var fsStub, globStub, newCompileRss;\n\n        before(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            globStub = function (paths, options, callback) {\n                callback(null, [\"./file1\", \"./file2\", \"/file3\"]);\n            };\n\n            fsStub = {\n                readdir: function (path, callback) {\n                    callback(null, [\"./file1\", \"./file2\", \"/file3\"]);\n                },\n                readFileSync: function () {\n                    return \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"date\\\":\\\"2015-01-10\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\";\n                },\n                writeFile: function (path, content, options, callback) {\n                    callback({\n                        message: \"I threw an error\"\n                    }, null);\n                }\n            };\n\n            mockery.registerMock(\"fs\", fsStub);\n            mockery.registerMock(\"glob\", globStub);\n\n            newCompileRss = require(\"../lib/compile-rss\");\n\n            newCompileRss(rootPath).then(function () {\n                //done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n        });\n\n        it(\"Should throw the writeFile error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({ message: \"I threw an error\" })).to.be.true;\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n    });\n\n    describe(\"When a glob error occurs\", function () {\n        var globStub, newCompileRss;\n\n        before(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            globStub = function (paths, options, callback) {\n                callback({\n                    message: \"I threw an error\"\n                }, null);\n            };\n\n            mockery.registerMock(\"glob\", globStub);\n\n            newCompileRss = require(\"../lib/compile-rss\");\n\n            newCompileRss(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n        });\n\n        it(\"Should throw a glob error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({ message: \"I threw an error\" })).to.be.true;\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n    });\n\n    after(function () {\n        removeDir(rootPath);\n    });\n});\n"
  },
  {
    "path": "gulp/tests/compile-tags.spec.js",
    "content": "\"use strict\";\n\nvar compileTags = require(\"../lib/compile-tags\"),\n    removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    Promise = require(\"bluebird\"),\n    sinon = require(\"sinon\"),\n    fs = require(\"fs\");\n\ndescribe(\"When compiling tag pages\", function () {\n    var rootPath = \".tmp/compile-tags\";\n    var doneStub, errorStub;\n\n    before(function () {\n        doneStub = sinon.stub();\n        errorStub = sinon.stub();\n\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/compile-tags\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n\n        // set-up folders:\n        [\n            \"/src\",\n            \"/src/templates\",\n            \"/src/templates/partials\",\n            \"/build\",\n            \"/build/tag\",\n            \"/build/tag/page\",\n            \"/build/content\",\n            \"/build/content/pages\",\n            \"/build/content/posts\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(rootPath + dir)) {\n                fs.mkdirSync(rootPath + dir);\n            }\n        });\n\n        // set-up files:\n        fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/partials/loop.hbs\", \"<ul>{{#each posts}}<li><a href=\\\"{{url}}\\\">{{title}}</a></li>{{/each}}</ul>\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/partials/pagination.hbs\", \"<ul><li><a href=\\\"{{#if nextUrl}}{{nextUrl}}{{else}}#{{/if}}\\\">Older</a></li><li><a href=\\\"{{#if prevUrl}}{{prevUrl}}{{else}}#{{/if}}\\\">Newer</a></li></ul>\", { encoding: \"utf8\" });\n        fs.writeFileSync(rootPath + \"/src/templates/index.hbs\", \"<div>{{> loop}}{{> pagination}}</div>\", { encoding: \"utf8\" });\n    });\n\n    after(function () {\n        removeDir(rootPath);\n    });\n\n    describe(\"When compiling tag pages\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha coke\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileTags(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should create the mocha tag page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/tag/mocha/index.html\")).to.be.true;\n        });\n\n        it(\"Should create the coke tag page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/tag/coke/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct mocha tag page content\", function () {\n            var expectedHtml = \"<div><ul><li><a href=\\\"../../test-post2/\\\">Test post 2</a></li><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li></ul><ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul></div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/mocha/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should have the correct coke tag page content\", function () {\n            var expectedHtml = \"<div><ul><li><a href=\\\"../../test-post2/\\\">Test post 2</a></li></ul><ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul></div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/coke/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When an error occurs with the promises\", function () {\n        var promisesListStub, newCompileTags;\n\n        beforeEach(function (done) {\n            errorStub.reset();\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            promisesListStub = {\n                filter: function () {\n                    return [Promise.reject(\"An error occurred\")];\n                }\n            };\n\n            mockery.registerMock(\"../lib/promises\", promisesListStub);\n\n            newCompileTags = require(\"../lib/compile-tags\");\n\n            newCompileTags(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n\n        });\n\n        it(\"Should call the error function\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"../lib/promises\");\n            mockery.disable();\n        });\n    });\n\n    describe(\"When compiling tag pages and excluding draft templates\", function () {\n        var minimistStub, newCompileTags;\n        \n        before(function (done) {\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-06-11\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"status\\\":\\\"draft\\\",\\\"tags\\\":\\\"mocha coke\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            \n            newCompileTags = require(\"../lib/compile-tags\");\n\n            newCompileTags(rootPath).then(done, errorStub);\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should have the correct mocha tag page content\", function () {\n            var expectedHtml = \"<div><ul><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li></ul><ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul></div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/mocha/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When compiling tag posts with pagination\", function () {\n        before(function (done) {\n            fs.writeFileSync(rootPath + \"/site.json\", \"{ \\\"title\\\": \\\"Test site\\\", \\\"maxItems\\\": \\\"2\\\" }\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post1.json\", \"{\\\"slug\\\":\\\"test-post1\\\",\\\"title\\\":\\\"Test post 1\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post2.json\", \"{\\\"slug\\\":\\\"test-post2\\\",\\\"title\\\":\\\"Test post 2\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post3.json\", \"{\\\"slug\\\":\\\"test-post3\\\",\\\"title\\\":\\\"Test post 3\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post4.json\", \"{\\\"slug\\\":\\\"test-post4\\\",\\\"title\\\":\\\"Test post 4\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post5.json\", \"{\\\"slug\\\":\\\"test-post5\\\",\\\"title\\\":\\\"Test post 5\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post6.json\", \"{\\\"slug\\\":\\\"test-post6\\\",\\\"title\\\":\\\"Test post 6\\\",\\\"date\\\":\\\"2014-12-05\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            fs.writeFileSync(rootPath + \"/build/content/posts/test-post7.json\", \"{\\\"slug\\\":\\\"test-post7\\\",\\\"title\\\":\\\"Test post 7\\\",\\\"tags\\\":\\\"mocha\\\",\\\"template\\\":\\\"post.hbs\\\",\\\"body\\\":\\\"<p>Test post content</p>\\\"}\", { encoding: \"utf8\" });\n            compileTags(rootPath).then(done, errorStub);\n        });\n\n        it(\"Should have the correct mocha tag page content\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"../../test-post1/\\\">Test post 1</a></li><li><a href=\\\"../../test-post2/\\\">Test post 2</a></li></ul>\" +\n                \"<ul><li><a href=\\\"../../tag/mocha/page/2\\\">Older</a></li><li><a href=\\\"#\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/mocha/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should create the second paginated mocha tag page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/tag/mocha/page/2/index.html\")).to.be.true;\n        });\n\n        it(\"Should create the third paginated mocha tag page\", function () {\n            expect(fs.existsSync(rootPath + \"/build/tag/mocha/page/3/index.html\")).to.be.true;\n        });\n\n        it(\"Should have the correct content for the second paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"../../../../test-post3\\\">Test post 3</a></li><li><a href=\\\"../../../../test-post4\\\">Test post 4</a></li></ul>\" +\n                \"<ul><li><a href=\\\"../3\\\">Older</a></li><li><a href=\\\"../../\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/mocha/page/2/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n\n        it(\"Should have the correct content for the third paginated page\", function () {\n            var expectedHtml = \"<div>\" +\n                \"<ul><li><a href=\\\"../../../../test-post5\\\">Test post 5</a></li><li><a href=\\\"../../../../test-post6\\\">Test post 6</a></li></ul>\" +\n                \"<ul><li><a href=\\\"#\\\">Older</a></li><li><a href=\\\"../2\\\">Newer</a></li></ul>\" +\n                \"</div>\";\n            expect(fs.readFileSync(rootPath + \"/build/tag/mocha/page/3/index.html\", \"utf8\")).to.equal(expectedHtml);\n        });\n    });\n\n    describe(\"When there are no posts for the tag pages\", function () {\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n            compileTags(rootPath).then(function () {\n                doneStub();\n                done();\n            }, function () {\n                errorStub();\n                done();\n            });\n        });\n\n        it(\"Should call done\", function () {\n            expect(doneStub.called).to.be.true;\n        });\n    });\n\n    describe(\"When a glob error occurs\", function () {\n        var globStub, newCompileTags;\n\n        beforeEach(function (done) {\n            removeDir(rootPath);\n            fs.mkdirSync(rootPath);\n            fs.writeFileSync(rootPath + \"/site.json\", \"{\\\"title\\\":\\\"Test site\\\"}\", { encoding: \"utf8\" });\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            mockery.deregisterAll();\n\n            globStub = function (paths, options, callback) {\n                callback({\n                    message: \"I threw an error\"\n                }, null);\n            };\n\n            mockery.registerMock(\"glob\", globStub);\n\n            newCompileTags = require(\"../lib/compile-tags\");\n\n            newCompileTags(rootPath).then(function () {\n                done();\n            }, function (err) {\n                errorStub(err);\n                done();\n            });\n        });\n\n        it(\"Should throw a glob error\", function () {\n            expect(errorStub.called).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(errorStub.calledWith({ message: \"I threw an error\" })).to.be.true;\n        });\n\n        afterEach(function () {\n            mockery.deregisterMock(\"glob\");\n            mockery.disable();\n        });\n    });\n});\n"
  },
  {
    "path": "gulp/tests/dates.spec.js",
    "content": "\"use strict\";\n\nvar dates = require(\"../lib/dates\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"When parsing dates\", function () {\n    beforeEach(function () {\n        this.dateMonth = \"2014-06\";\n        this.dateStr = \"June 2014\";\n        this.posts = [\n            { date: \"2014-06-11\" },\n            { date: \"2014-12-11\" },\n            { date: \"2014-03-11\" },\n            { date: \"2014-06-11\" }\n        ];\n    });\n\n    it(\"Should sort dates correctly\", function () {\n        this.posts.sort(dates.sortFunc);\n        expect(this.posts).to.deep.equal([\n            { date: \"2014-12-11\" },\n            { date: \"2014-06-11\" },\n            { date: \"2014-06-11\" },\n            { date: \"2014-03-11\" }\n        ]);\n    });\n\n    it(\"Should create date link\", function () {\n        expect(dates.getDateAsLink(\".\", this.dateMonth, this.dateStr)).to.equal(\"<a href=\\\"./date/2014-06\\\">June 2014</a>\");\n    });\n\n    it(\"Should return undefined if no date exists\", function () {\n        expect(dates.getDateAsLink(\".\", null)).to.be.undefined;\n    });\n\n    it(\"Should get all dates as links\", function () {\n        expect(dates.getAllDatesAsLinks(\".\", this.posts)).to.deep.equal([\n            { dateMonth: \"2014-03\", dateStr: \"March 2014\", dateLink: \"./date/2014-03\" },\n            { dateMonth: \"2014-06\", dateStr: \"June 2014\", dateLink: \"./date/2014-06\" },\n            { dateMonth: \"2014-12\", dateStr: \"December 2014\", dateLink: \"./date/2014-12\" }\n        ]);\n    });\n});\n"
  },
  {
    "path": "gulp/tests/downzero.spec.js",
    "content": "\"use strict\";\n\nvar downzero = require(\"../lib/downzero\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"When extracting html tags with double quotes\", function () {\n    beforeEach(function () {\n        this.html = \"<p><img src=\\\"/images/test.png\\\"></p> <p>This is the first paragraph.</p>\";\n    });\n\n    it(\"Should strip just the first tag from the html\", function () {\n        expect(downzero(this.html)).to.equal(\"<p><img src=\\\"/images/test.png\\\"></p>\");\n    });\n});\n\ndescribe(\"When extracting html tags with single quotes\", function () {\n    beforeEach(function () {\n        this.html = \"<p><img src=\\\"/images/test.png\\\"></p> <p>This is the \\\"first paragraph\\\".</p>\";\n    });\n\n    it(\"Should strip just the first tag from the html\", function () {\n        expect(downzero(this.html)).to.equal(\"<p><img src=\\\"/images/test.png\\\"></p>\");\n    });\n});\n\ndescribe(\"When extracting html tags with comments\", function () {\n    beforeEach(function () {\n        this.html = \"<p><!-- test comment --><img src=\\\"/images/test.png\\\"></p> <p>This is the first paragraph.</p>\";\n    });\n\n    it(\"Should strip just the first tag from the html\", function () {\n        expect(downzero(this.html)).to.equal(\"<p><!-- test comment --><img src=\\\"/images/test.png\\\"></p>\");\n    });\n});\n"
  },
  {
    "path": "gulp/tests/drafts.spec.js",
    "content": "\"use strict\";\n\nvar compileDrafts,\n    mockery = require(\"mockery\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"When working with compile options\", function () {\n    var minimistStub;\n\n    describe(\"When not working in draft mode\", function () {\n        before(function () {\n            mockery.enable({\n                warnOnReplace: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"published\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n\n            compileDrafts = require(\"../lib/drafts\");\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should return false if not compiling drafts\", function () {\n            expect(compileDrafts()).to.be.false;\n        });\n    });\n\n    describe(\"When working in draft mode\", function () {\n        before(function () {\n            mockery.enable({\n                warnOnReplace: false,\n                useCleanCache: true\n            });\n            minimistStub = function () {\n                return {\n                    compile: \"drafts\"\n                };\n            };\n            mockery.registerAllowable(\"../lib/drafts\");\n            mockery.registerMock(\"minimist\", minimistStub);\n\n            compileDrafts = require(\"../lib/drafts\");\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n\n        it(\"Should return true if compiling drafts\", function () {\n            expect(compileDrafts()).to.be.true;\n        });\n    });\n\n});\n"
  },
  {
    "path": "gulp/tests/paths.spec.js",
    "content": "\"use strict\";\n\nvar paths = require(\"../lib/paths\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"When replacing paths\", function () {\n    beforeEach(function () {\n        this.html = \"<p>This is a sentence <a href=\\\"/my-test-page\\\">with a link</a>.</p><p>This sentence contains an <img src=\\\"/images/test.png\\\" alt=\\\"\\\"> image.</p>\";\n    });\n\n    it(\"Should replace the link paths with relative links\", function () {\n        expect(paths.resolve(this.html, \"../..\")).to.match(/\\.\\.\\/\\.\\.\\/my-test-page/);\n    });\n\n    it(\"Should replace the image paths with relative links\", function () {\n        expect(paths.resolve(this.html, \"../..\")).to.match(/\\.\\.\\/\\.\\.\\/images\\/test\\.png/);\n    });\n});\n"
  },
  {
    "path": "gulp/tests/remove-dir.spec.js",
    "content": "\"use strict\";\n\nvar removeDir = require(\"../lib/remove-dir\"),\n    expect = require(\"chai\").expect,\n    mockery = require(\"mockery\"),\n    fs = require(\"fs\");\n\ndescribe(\"When removing directories\", function () {\n    beforeEach(function () {\n        // create the root path\n        [\n            \".tmp\",\n            \".tmp/remove-dir-test\"\n        ].forEach(function (dir) {\n            if (!fs.existsSync(dir)) {\n                fs.mkdirSync(dir);\n            }\n        });\n        \n        var files = {\n            \".tmp/remove-dir-test/file1\": \"This is test content\",\n            \".tmp/remove-dir-test/file2\": \"This is test content\",\n            \".tmp/remove-dir-test/file3\": \"This is test content\"\n        };\n\n        for (var file in files) {\n            if (files.hasOwnProperty(file)) {\n                fs.writeFileSync(file, files[file], { encoding: \"utf8\" });\n            }\n        }\n    });\n\n    after(function() {\n        removeDir(\".tmp/remove-dir-test\");\n    });\n\n    describe(\"When the temp directory structure is created\", function () {\n        it(\"Should have a temp directory structure\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test\")).to.be.true;\n        });\n\n        it(\"Should have a temp file in the directory\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test/file1\")).to.be.true;\n        });\n    });\n\n    describe(\"When removing the temp directory\", function () {\n        beforeEach(function () {\n            removeDir(\".tmp/remove-dir-test\");\n        });\n\n        it(\"Should remove the temp directory structure\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test\")).to.be.false;\n        });\n    });\n\n    describe(\"When removing the contents of the temp directory\", function () {\n        beforeEach(function () {\n            removeDir(\".tmp/remove-dir-test\", false);\n        });\n\n        it(\"Should not remove the temp directory structure\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test\")).to.be.true;\n        });\n\n        it(\"Should remove the temp file in the directory\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test/file1\")).to.be.false;\n        });\n    });\n\n    describe(\"When a nested directory of files exists\", function () {\n        beforeEach(function () {\n            if (!fs.existsSync(\".tmp/remove-dir-test/nested-dir\")) {\n                fs.mkdirSync(\".tmp/remove-dir-test/nested-dir\");\n            }\n            fs.writeFileSync(\".tmp/remove-dir-test/nested-dir/file1\", \"This is test content\", { encoding: \"utf8\" });\n        });\n\n        it(\"Should have a nested directory structure\", function () {\n            expect(fs.existsSync(\".tmp/remove-dir-test/nested-dir/file1\")).to.be.true;\n        });\n\n        describe(\"When the nested directory is removed\", function () {\n            beforeEach(function () {\n                removeDir(\".tmp/remove-dir-test\");\n            });\n\n            it(\"Should remove the temp directory structure\", function () {\n                expect(fs.existsSync(\".tmp/remove-dir-test\")).to.be.false;\n            });\n        });\n    });\n\n    describe(\"When the readdirSync function throws an error\", function () {\n        var fsStub, newRemoveDir, error;\n\n        before(function () {\n            removeDir(\".tmp/remove-dir-test\");\n\n            mockery.enable({\n                warnOnReplace: false,\n                warnOnUnregistered: false,\n                useCleanCache: true\n            });\n\n            fsStub = {\n                readdirSync: function () {\n                    throw new Error(\"readdirSync error!\");\n                }\n            };\n\n            mockery.registerMock(\"fs\", fsStub);\n\n            newRemoveDir = require(\"../lib/remove-dir\");\n\n            error = newRemoveDir(\".tmp/remove-dir-test\");\n        });\n\n        it(\"Should throw an error\", function () {\n            expect(error instanceof Error).to.be.true;\n        });\n\n        it(\"Should throw a specific error\", function () {\n            expect(error.message).to.equal(\"readdirSync error!\");\n        });\n\n        after(function () {\n            mockery.disable();\n        });\n    });\n});\n"
  },
  {
    "path": "gulp/tests/tags.spec.js",
    "content": "\"use strict\";\n\nvar tags = require(\"../lib/tags\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"When parsing tags\", function () {\n    beforeEach(function () {\n        this.tagStr = \"content gulp testing\";\n        this.tagArray = [\"content\", \"gulp\", \"testing\"];\n        this.posts = [\n            { tagStr: \"content\" },\n            { tagStr: \"gulp\" },\n            { tagStr: \"testing\" }\n        ];\n    });\n\n    it(\"Should create tag classes\", function () {\n        expect(tags.getTagClasses(this.tagStr)).to.equal(\" tag-content tag-gulp tag-testing\");\n    });\n\n    it(\"Should return undefined if no tags exist\", function () {\n        expect(tags.getTagClasses(null)).to.be.undefined;\n    });\n\n    it(\"Should support tags as Array\", function () {\n        expect(tags.getTagClasses(this.tagArray)).to.equal(\" tag-content tag-gulp tag-testing\");\n    });\n\n    it(\"Should create tag links from the root path\", function () {\n        var tagLinks = tags.getTagsAsLinks(\"\", this.tagStr);\n        expect(tagLinks).to.equal(\"<a href=\\\"tag/content\\\">content</a><a href=\\\"tag/gulp\\\">gulp</a><a href=\\\"tag/testing\\\">testing</a>\");\n    });\n\n    it(\"Should create tag links from a relative path\", function () {\n        var tagLinks = tags.getTagsAsLinks(\"../..\", this.tagStr);\n        expect(tagLinks).to.equal(\"<a href=\\\"../../tag/content\\\">content</a><a href=\\\"../../tag/gulp\\\">gulp</a><a href=\\\"../../tag/testing\\\">testing</a>\");\n    });\n\n    it(\"Should return undefined if no tags exist\", function () {\n        expect(tags.getTagsAsLinks(\"\", null)).to.be.undefined;\n    });\n\n    it(\"Should create tag link from the root path\", function () {\n        expect(tags.getTagAsLink(\"\", \"single\")).to.equal(\"<a href=\\\"tag/single\\\">single</a>\");\n    });\n\n    it(\"Should create tag link from a relative path\", function () {\n        expect(tags.getTagAsLink(\"../..\", \"single\")).to.equal(\"<a href=\\\"../../tag/single\\\">single</a>\");\n    });\n\n    it(\"Should return undefined if no tag exists\", function () {\n        expect(tags.getTagAsLink(\"\", null)).to.be.undefined;\n    });\n\n    it(\"Should get all tags as links from the root path\", function () {\n        expect(tags.getAllTagsAsLinks(\"\", this.posts)).to.deep.equal([\n            { tag: \"content\", tagLink: \"tag/content\" },\n            { tag: \"gulp\", tagLink: \"tag/gulp\" },\n            { tag: \"testing\", tagLink: \"tag/testing\" }\n        ]);\n    });\n\n    it(\"Should get all tags as links from a relative path\", function () {\n        expect(tags.getAllTagsAsLinks(\"../..\", this.posts)).to.deep.equal([\n            { tag: \"content\", tagLink: \"../../tag/content\" },\n            { tag: \"gulp\", tagLink: \"../../tag/gulp\" },\n            { tag: \"testing\", tagLink: \"../../tag/testing\" }\n        ]);\n    });\n});\n"
  },
  {
    "path": "gulpfile.js",
    "content": "\"use strict\";\n\nvar requireDir = require(\"require-dir\");\n\n// require all tasks in gulp/tasks, including sub-folders\nrequireDir(\"./gulp/tasks\", {\n    recurse: true\n});\n"
  },
  {
    "path": "install/content/pages/about.md",
    "content": "---\nslug: about\ntitle: About us\ntemplate: page.hbs\n---\n\nSweet sweet roll sweet roll dragée soufflé tootsie roll ice cream toffee. Jelly-o cake fruitcake tart. Bear claw oat cake cookie ice cream gummies.\n\nGummies gummies fruitcake chupa chups sweet roll cake oat cake muffin cake. Pastry bear claw jelly beans marzipan cake jujubes jelly-o pudding. Fruitcake marshmallow dragée carrot cake gummi bears pie.\n\nApple pie danish tiramisu muffin chocolate tiramisu topping pudding powder. Chocolate cake carrot cake dessert dessert apple pie gingerbread icing. Icing chupa chups muffin cake pastry. Apple pie cake gummi bears gummi bears marshmallow pudding liquorice.\n\n"
  },
  {
    "path": "install/content/posts/sample-blog-post.md",
    "content": "---\nslug: sample-blog-post\ntitle: Sample blog post\ntemplate: post.hbs\ndate: 2015-02-14\nauthor: Matt Levy\n---\n\n![](/images/sample-blog-post.jpg)\n\nGingerbread marshmallow fruitcake topping jelly-o halvah. Dragée icing cheesecake. Apple pie cake powder biscuit gingerbread tart gingerbread bonbon. Bear claw danish cake pie gummi bears macaroon tart jujubes toffee.\n\nSweet roll jelly beans danish tootsie roll icing sugar plum. Marshmallow danish marshmallow powder cake macaroon candy gummies. Cake gingerbread liquorice. Candy canes brownie oat cake gummi bears cupcake powder donut icing cake.\n\n"
  },
  {
    "path": "install/content/template.md",
    "content": "---\nslug: i-am-a-template\ntitle: I am a template\ntemplate: post.hbs\ndate: 2014-10-07\nauthor: Matt Levy\nstatus: draft\n---\n\n![](/images/i-am-a-template.jpg)\n\nThis is the template full of markdown text!\n"
  },
  {
    "path": "install/files.json",
    "content": "{\n    \"files\": [\n        {\n            \"file\": \"gulpfile.js\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"package.json\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"site.json\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \".editorconfig\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"content/template.md\",\n            \"encoding\": \"utf8\",\n            \"ignoreIfMissing\": true\n        },\n        {\n            \"file\": \"content/pages/about.md\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"content/posts/sample-blog-post.md\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"sass/style.scss\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"images/sample-blog-post.jpg\",\n            \"encoding\": \"binary\"\n        },\n        {\n            \"file\": \"templates/index.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/page.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/post.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/footer.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/header.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/loop.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/navigation.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/pagination.hbs\",\n            \"encoding\": \"utf8\"\n        },\n        {\n            \"file\": \"templates/partials/sidebar.hbs\",\n            \"encoding\": \"utf8\"\n        }\n    ]\n}"
  },
  {
    "path": "install/lib/json-file.js",
    "content": "var fs = require(\"fs\");\n\nmodule.exports.writeJsonFile = function(file, obj, options) {\n    options = options || {};\n\n    var spaces = typeof options === \"object\" && options !== null ? \"spaces\" in options ? options.spaces : this.spaces : this.spaces;\n\n    var str = JSON.stringify(obj, options.replacer, spaces) + \"\\n\";\n    \n    // not sure if fs.writeFileSync returns anything, but just in case\n    return fs.writeFileSync(file, str, options);\n};"
  },
  {
    "path": "install/lib/version-compare.js",
    "content": "\"use strict\";\n\nmodule.exports = function(v1, v2) {\n    var v1parts = (\"\" + v1).replace(/~|\\^|>=|>|<=|<|\\.x/i, \"\").split(\".\"),\n        v2parts = (\"\" + v2).replace(/~|\\^|>=|>|<=|<|\\.x/i, \"\").split(\".\"),\n        minLength = Math.min(v1parts.length, v2parts.length),\n        p1, p2, i;\n\n    // Compare tuple pair-by-pair.\n    for (i = 0; i < minLength; i++) {\n        // Convert to integer if possible, because \"8\" > \"10\".\n        p1 = parseInt(v1parts[i], 10);\n        p2 = parseInt(v2parts[i], 10);\n        \n        if (isNaN(p1)) {\n            return NaN;\n        }\n        if (isNaN(p2)) {\n            return NaN;\n        }\n        \n        if (p1 === p2) {\n            continue;\n        } else if (p1 > p2) {\n            return 1;\n        } else if (p1 < p2) {\n            return -1;\n        }        \n    }\n\n    // The longer tuple is always considered \"greater\"\n    if (v1parts.length === v2parts.length) {\n        return 0;\n    }\n\n    return (v1parts.length < v2parts.length) ? -1 : 1;\n};\n"
  },
  {
    "path": "install/sass/style.scss",
    "content": "@mixin clearfix() {\n  &:after {\n    content: \" \";\n    display: block;\n    clear: both;\n  }\n}\n\nbody {\n  font-family: sans-serif;\n}\n\n.container {\n  @include clearfix();\n}\n\n.top-nav {\n\n}\n\n.post {\n  .post-meta {\n\n  }\n}\n\n.sidebar {\n  ol {\n    list-style: none;\n    margin-left: 0;\n    padding-left: 0;\n  }\n}\n\n.row {\n  @include clearfix();\n}\n\n.pagination {\n    @include clearfix();\n\n    &.pagination-none {\n        display: none;\n    }\n}\n\n@media screen and (min-width: 768px) {\n\n  .main, article {\n    float: left;\n    width: 61%;\n  }\n\n  aside {\n    float: right;\n    width: 35%;\n  }\n\n}\n\n@media screen and (min-width: 992px) {\n\n  html {\n    background-color: #eee;\n  }\n\n  body {\n    max-width: 992px;\n    margin: 0 auto;\n    background-color: #fff;\n    padding: 15px;\n  }\n\n}\n"
  },
  {
    "path": "install/templates/index.hbs",
    "content": "{{> header}}\n\n{{> navigation}}\n\n<div class=\"container\">\n\n    <header>\n        <h1>{{site.title}}</h1>\n        {{#if tag}}\n            <p>Posts tagged: {{tag}}</p>\n        {{else}}\n            {{#if dateStr}}\n                <p>Posts dated: {{dateStr}}</p>\n            {{else}}\n                <p>{{site.description}}</p>\n            {{/if}}\n        {{/if}}\n    </header>\n\n    <div class=\"row\">\n        <div class=\"main\">\n            {{> loop}}\n\n            {{> pagination}}\n        </div>\n        <aside>\n            {{> sidebar}}\n        </aside>\n    </div>\n\n</div>\n\n{{> footer}}\n"
  },
  {
    "path": "install/templates/page.hbs",
    "content": "{{> header}}\n\n{{> navigation}}\n\n<div class=\"container\">\n\n    {{#post}}\n    <div class=\"row\">\n        <article>\n            <h1>{{title}}</h1>\n            {{{body}}}\n        </article>\n        <aside>\n            {{> sidebar}}\n        </aside>\n    </div>\n    {{/post}}\n\n</div>\n\n{{> footer}}\n"
  },
  {
    "path": "install/templates/partials/footer.hbs",
    "content": "<footer>\n    <p>Site built by the <a href=\"http://github.com/ducksoupdev/gulp-site-generator\">Gulp site generator</a>.</p>\n    <p>\n        <a href=\"#\">Back to top</a>\n    </p>\n</footer>\n\n<script type=\"text/javascript\" src=\"{{resolve \"/js/combined.min.js\"}}\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "install/templates/partials/header.hbs",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta name=\"description\" content=\"{{meta_description}}\">\n    <meta name=\"author\" content=\"\">\n    <link rel=\"icon\" href=\"{{resolve \"/favicon.ico\"}}\">\n    <title>{{meta_title}}</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"{{resolve \"/css/style.min.css\"}}\">\n    <meta name=\"generator\" content=\"{{generator}}\" />\n    <link rel=\"alternate\" type=\"application/rss+xml\" title=\"{{site.title}}\" href=\"{{rss}}\">\n</head>\n\n<body>\n"
  },
  {
    "path": "install/templates/partials/loop.hbs",
    "content": "{{#each pages}}\n    <div class=\"page\">\n        <h2><a href=\"{{url}}\">{{title}}</a></h2>\n        <p>{{{excerpt characters=230}}}...</p>\n    </div>\n{{/each}}\n\n{{#each posts}}\n    <div class=\"post\">\n        <h2><a href=\"{{url}}\">{{title}}</a></h2>\n        {{#if date}}\n            <p class=\"post-meta\">\n                {{date format=\"MMMM Do YYYY\"}}\n            </p>\n        {{/if}}\n        <p>{{{excerpt characters=230}}}...</p>\n    </div>\n{{/each}}"
  },
  {
    "path": "install/templates/partials/navigation.hbs",
    "content": "<div class=\"top-nav\">\n    <div class=\"container\">\n        <nav>\n            <a href=\"{{resolve \"/\"}}\">Home</a>\n            <a href=\"{{resolve \"/about\"}}\">About</a>\n        </nav>\n    </div>\n</div>"
  },
  {
    "path": "install/templates/partials/pagination.hbs",
    "content": "<nav class=\"pagination{{#if (or prevUrl nextUrl)}}{{else}} pagination-none{{/if}}\">\n  <ul>\n    <li class=\"previous{{#if nextUrl}}{{else}} disabled{{/if}}\"><a{{#if nextUrl}} href=\"{{nextUrl}}\" data-total-pages=\"{{totalPages}}\"{{else}} href=\"#\"{{/if}}><span aria-hidden=\"true\">&larr;</span> Older</a></li>\n    <li class=\"next{{#if prevUrl}}{{else}} disabled{{/if}}\"><a{{#if prevUrl}} href=\"{{prevUrl}}\" data-total-pages=\"{{totalPages}}\"{{else}} href=\"#\"{{/if}}>Newer <span aria-hidden=\"true\">&rarr;</span></a></li>\n  </ul>\n</nav>\n"
  },
  {
    "path": "install/templates/partials/sidebar.hbs",
    "content": "{{#if allDates}}\n    <div class=\"sidebar\">\n        <h4>Archives</h4>\n        <ul>\n            {{#each allDates}}\n                <li>\n                    <a href=\"{{dateLink}}\">{{dateStr}}</a>\n                </li>\n            {{/each}}\n        </ul>\n    </div>\n{{/if}}\n{{#if allTags}}\n    <div class=\"sidebar\">\n        <h4>Tags</h4>\n        <ul>\n            {{#each allTags}}\n                <li>\n                    <a href=\"{{tagLink}}\">{{tag}}</a>\n                </li>\n            {{/each}}\n        </ul>\n    </div>\n{{/if}}\n<div class=\"sidebar\">\n    <h4>Elsewhere</h4>\n    <ol>\n        <li><a href=\"#\">GitHub</a></li>\n        <li><a href=\"#\">Twitter</a></li>\n        <li><a href=\"#\">Facebook</a></li>\n    </ol>\n</div>"
  },
  {
    "path": "install/templates/post.hbs",
    "content": "{{> header}}\n\n{{> navigation}}\n\n<div class=\"container\">\n\n    {{#post}}\n        <div class=\"row\">\n            <article>\n                <h1>{{title}}</h1>\n                <p class=\"post-meta\">\n                    {{date format=\"MMMM Do YYYY\"}}\n                    by <span>{{author.name}}</span>\n                    {{#if tags}} on {{{tags}}}{{/if}}\n                </p>\n                {{{body}}}\n            </article>\n            <aside>\n                {{> sidebar}}\n            </aside>\n        </div>\n    {{/post}}\n\n</div>\n\n{{> footer}}\n"
  },
  {
    "path": "install/tests/version-compare.spec.js",
    "content": "\"use strict\";\n\nvar versionCompare = require(\"../lib/version-compare\"),\n    expect = require(\"chai\").expect;\n\ndescribe(\"version compare\", function() {\n    it(\"not compare invalid versions\", function() {\n        expect(versionCompare(\"a.v.s\", \"a.v.s\")).to.be.NaN;\n        expect(versionCompare(\"1.v.d\", \"a.v.s\")).to.be.NaN;\n    });\n    \n    it(\"compare dotted version strings\", function() {\n        expect(versionCompare(\"1.8\", \"1.8.1\")).to.equal(-1);\n        expect(versionCompare(\"1.8.3\", \"1.8.1\")).to.equal(1);\n        expect(versionCompare(\"1.8\", \"1.10\")).to.equal(-1);\n        expect(versionCompare(\"1.10.1\", \"1.10.1\")).to.equal(0);\n    });\n\n    it(\"compare longer is considered greater\", function() {\n        expect(versionCompare(\"1.10.1.0\", \"1.10.1\")).to.equal(1);\n        expect(versionCompare(\"1.10.1\", \"1.10.1.0\")).to.equal(-1);\n    });\n\n    it(\"compare string pairs\", function() {\n        expect(versionCompare(\"1.x\", \"1.x\")).to.equal(0);\n        expect(versionCompare(\"1.10.x\", \"1.10.x\")).to.equal(0);\n        expect(versionCompare(\"~1.10\", \"1.10\")).to.equal(0);\n        expect(versionCompare(\"^1.10\", \"1.10\")).to.equal(0);\n        expect(versionCompare(\">1.10\", \"1.10\")).to.equal(0);\n        expect(versionCompare(\">=1.10\", \"1.10\")).to.equal(0);\n        expect(versionCompare(\"<1.10\", \"1.10\")).to.equal(0);\n        expect(versionCompare(\"<=1.10\", \"1.10\")).to.equal(0);\n    });\n\n    it(\"compare mixed ints and string pairs\", function() {\n        expect(versionCompare(\"1.8\", \"1\")).to.equal(1);\n    });\n\n    it(\"compare plain numbers\", function() {\n        expect(versionCompare(\"4\", \"3\")).to.equal(1);\n    });\n});\n"
  },
  {
    "path": "install.js",
    "content": "\"use strict\";\n\n/*\n Simple install script for the gulp site generator\n\n * Copies the gulpfile.js, package.json and site.json files to the project root\n * Creates an src directory\n * Creates the following directories: src/content, src/templates, src/sass, src/content, src/content/pages src/content/posts\n * Creates the following files: src/content/*.md, src/templates/*.hbs, src/sass/*.scss, src/images/*.jpg\n \n */\n\nvar fs = require(\"fs\"),\n    path = require(\"path\"),\n    jsonFile = require(\"./install/lib/json-file\");\n    \nfunction extend(destination, source) {\n    for (var property in source) {\n        if (source[property] && source[property].constructor &&\n            source[property].constructor === Object) {\n            destination[property] = destination[property] || {};\n            destination[property] = extend(destination[property], source[property]);\n        } else {\n            destination[property] = source[property];\n        }\n    }\n    return destination;\n}\n\nvar rootPath = process.cwd(),\n    rootPathName = path.basename(__dirname),\n    filesInstalled = 0,\n    directoriesCreated = 0;\n\nvar fileIndex = fs.readFileSync(__dirname + \"/install/files.json\", { encoding: \"utf8\" });\nvar fileList = JSON.parse(fileIndex);\n\nif (!fs.existsSync(rootPath + \"/src\")) {\n    fs.mkdirSync(rootPath + \"/src\");\n    directoriesCreated++;\n}\n\nfileList.files.forEach(function (file) {\n    var contents = null, isRootFile = file.file.indexOf(\"/\") === -1;\n    \n    var filePath = (isRootFile ? rootPath + \"/\" + file.file : rootPath + \"/src/\" + file.file); \n    \n    if (!fs.existsSync(filePath)) {\n        if (!isRootFile) {\n            // create the directory if required\n            var dir = path.dirname(file.file), dirPath = path.join(rootPath + \"/src/\" + dir);\n            \n            if (!fs.existsSync(dirPath)) {\n                fs.mkdirSync(dirPath);\n                directoriesCreated++;\n            }\n            \n            contents = fs.readFileSync(__dirname + \"/install/\" + file.file, file.encoding);\n            fs.writeFileSync(filePath, contents, { encoding: file.encoding });\n            filesInstalled++;\n            \n        } else {\n            contents = fs.readFileSync(__dirname + \"/\" + file.file, file.encoding);\n\n            // replace the path to the gulp tasks\n            if (file.file === \"gulpfile.js\") {\n                contents = contents.replace(/\\.\\/gulp\\/tasks/, \"./\" + rootPathName + \"/gulp/tasks/\");\n            }\n\n            fs.writeFileSync(filePath, contents, { encoding: file.encoding });\n            filesInstalled++;\n        }\n    }\n});\n\n// package.json changes\nvar packages = null, \n    packagesContent = fs.readFileSync(rootPath + \"/package.json\", { encoding: \"utf8\" });\n\ntry {\n    packages = JSON.parse(packagesContent);\n    \n    // cleanup package.json\n    var dependencies = packages.dependencies;\n    packages.devDependencies = {};\n    extend(packages.devDependencies, dependencies);\n    \n    delete packages.dependencies;\n    delete packages.keywords;\n    delete packages.scripts;\n    packages.version = \"0.1.0\";\n    packages.name = \"\";\n    packages.description = \"\";\n    packages.author = \"\";\n    \n    // write out the new package.json\n    jsonFile.writeJsonFile(rootPath + \"/package.json\", packages, {\n        spaces: 4,\n        encoding: \"utf8\"\n    });\n} catch (err) {\n    console.error(err);\n}\n\nconsole.info(\"%d %s created and %d %s installed!\", \n        directoriesCreated, \n        (directoriesCreated === 1 ? \"directory\": \"directories\"), \n        filesInstalled,\n        (filesInstalled === 1 ? \"file\" : \"files\"));\n        \nif (directoriesCreated && filesInstalled) {\n    console.info(\"Run 'npm install' then 'gulp' to get started\");\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"gulp-site-generator\",\n  \"version\": \"0.3.2\",\n  \"description\": \"Static site generator using Gulp\",\n  \"main\": \"gulpfile.js\",\n  \"scripts\": {\n    \"test\": \"gulp test\",\n    \"debug\": \"mocha --debug-brk gulp/tests/*.spec.js\"\n  },\n  \"keywords\": [\n    \"gulp\",\n    \"static\",\n    \"generator\"\n  ],\n  \"author\": \"Matt Levy <ducksoupdev@gmail.com>\",\n  \"license\": \"ISC\",\n  \"dependencies\": {\n    \"bluebird\": \"3.5.0\",\n    \"downsize\": \"0.0.8\",\n    \"glob\": \"7.1.2\",\n    \"gulp\": \"3.9.1\",\n    \"gulp-compile-handlebars\": \"0.6.1\",\n    \"gulp-concat\": \"2.6.1\",\n    \"gulp-connect\": \"5.0.0\",\n    \"gulp-if\": \"2.0.2\",\n    \"gulp-markdown-to-json\": \"1.0.3\",\n    \"gulp-minify-css\": \"1.2.4\",\n    \"gulp-minify-html\": \"1.0.6\",\n    \"gulp-open\": \"2.0.0\",\n    \"gulp-rename\": \"1.2.2\",\n    \"gulp-replace\": \"0.6.1\",\n    \"gulp-sass\": \"3.1.0\",\n    \"gulp-uglify\": \"3.0.0\",\n    \"gulp-uncss\": \"1.0.6\",\n    \"gulp-util\": \"3.0.8\",\n    \"handlebars\": \"4.0.10\",\n    \"imagemin-mozjpeg\": \"5.1.0\",\n    \"imagemin-optipng\": \"4.3.0\",\n    \"imagemin-pngquant\": \"4.2.0\",\n    \"lodash\": \"4.17.4\",\n    \"markdown-it\": \"8.4.0\",\n    \"marked\": \"0.3.6\",\n    \"minimist\": \"1.2.0\",\n    \"moment\": \"2.18.1\",\n    \"mout\": \"1.0.0\",\n    \"relative\": \"3.0.2\",\n    \"require-dir\": \"0.3.2\",\n    \"rss\": \"1.2.2\",\n    \"run-sequence\": \"2.1.0\"\n  },\n  \"devDependencies\": {\n    \"browser-sync\": \"2.18.13\",\n    \"chai\": \"4.1.1\",\n    \"eslint\": \"4.5.0\",\n    \"github-changes\": \"1.1.0\",\n    \"gulp-coveralls\": \"0.1.4\",\n    \"gulp-istanbul\": \"1.1.2\",\n    \"gulp-mocha\": \"3.0.1\",\n    \"mocha\": \"3.5.0\",\n    \"mockery\": \"2.1.0\",\n    \"sinon\": \"3.2.1\"\n  }\n}\n"
  },
  {
    "path": "site.json",
    "content": "{\n  \"title\": \"\",\n  \"description\": \"\",\n  \"url\": \"\",\n  \"rss\": \"/rss.xml\",\n  \"maxItems\": 6,\n  \"concatJs\": [\n    \"./src/js/*.js\"\n  ],\n  \"styleSheet\": \"style.css\",\n  \"authors\": {\n    \"Matt Levy\": {\n      \"name\": \"Matt Levy\",\n      \"bio\": \"Practicing the art of front-end development\"\n    }\n  },\n  \"imageCompression\": true\n}\n"
  },
  {
    "path": "update.js",
    "content": "\"use strict\";\n\n/*\n Simple update script for the gulp site generator\n\n * Updates the package.json file in the project root\n * Copies any missing or new install files\n\n */\n\nvar fs = require(\"fs\"),\n    path = require(\"path\"),\n    jsonFile = require(\"./install/lib/json-file\"),\n    versionCompare = require(\"./install/lib/version-compare\");\n\nvar rootPath = process.cwd(),\n    rootPathName = path.basename(__dirname),\n    filesInstalled = 0,\n    directoriesCreated = 0;\n    \n// install missing files\nvar fileIndex = fs.readFileSync(__dirname + \"/install/files.json\", { encoding: \"utf8\" });\nvar fileList = JSON.parse(fileIndex);\n\nif (!fs.existsSync(rootPath + \"/src\")) {\n    fs.mkdirSync(rootPath + \"/src\");\n    directoriesCreated++;\n}\n\nfileList.files.forEach(function (file) {\n    var contents = null, isRootFile = file.file.indexOf(\"/\") === -1;\n    \n    var filePath = (isRootFile ? rootPath + \"/\" + file.file : rootPath + \"/src/\" + file.file);\n\n    if (file.hasOwnProperty(\"ignoreIfMissing\") && file[\"ignoreIfMissing\"] && !fs.existsSync(filePath)) {\n        return;\n    }\n    \n    if (!fs.existsSync(filePath)) {\n        if (!isRootFile) {\n            // create the directory if required\n            var dir = path.dirname(file.file), dirPath = path.join(rootPath + \"/src/\" + dir);\n            \n            if (!fs.existsSync(dirPath)) {\n                fs.mkdirSync(dirPath);\n                directoriesCreated++;\n            }\n            \n            contents = fs.readFileSync(__dirname + \"/install/\" + file.file, file.encoding);\n            fs.writeFileSync(filePath, contents, { encoding: file.encoding });\n            filesInstalled++;\n            \n        } else {\n            contents = fs.readFileSync(__dirname + \"/\" + file.file, file.encoding);\n\n            // replace the path to the gulp tasks\n            if (file.file === \"gulpfile.js\") {\n                contents = contents.replace(/\\.\\/gulp\\/tasks/, \"./\" + rootPathName + \"/gulp/tasks/\");\n            }\n\n            fs.writeFileSync(filePath, contents, { encoding: file.encoding });\n            filesInstalled++;\n        }\n    }\n});\n\nif (directoriesCreated || filesInstalled) {\n    console.info(\"%d %s created and %d %s installed!\", \n        directoriesCreated, \n        (directoriesCreated === 1 ? \"directory\": \"directories\"), \n        filesInstalled,\n        (filesInstalled === 1 ? \"file\" : \"files\"));\n}\n\n// update package.json file\nif (fs.existsSync(rootPath + \"/package.json\")) {\n    var updatedModules = [], packages, newPackages;\n    var packagesContent = fs.readFileSync(rootPath + \"/package.json\", { encoding: \"utf8\" });\n    var newPackageContents = fs.readFileSync(__dirname + \"/package.json\", { encoding: \"utf8\" });\n    \n    try {\n        packages = JSON.parse(packagesContent);\n        newPackages = JSON.parse(newPackageContents);\n    } catch (err) {\n        throw err;\n    }\n    \n    var packagesToUpdate = newPackages.dependencies;\n    \n    // compare each version and only update where the version to be installed is greater than the installed one\n    if (Object.keys(packagesToUpdate).length > 0) {\n        for (var moduleName in packagesToUpdate) {\n            if (packagesToUpdate.hasOwnProperty(moduleName)) {\n                var newModuleVersion = packagesToUpdate[moduleName];\n                if (!packages.devDependencies.hasOwnProperty(moduleName) ||\n                    versionCompare(packages.devDependencies[moduleName], newModuleVersion) < 0) {\n                    var oldModuleVersion = packages.devDependencies[moduleName];\n                    packages.devDependencies[moduleName] = newModuleVersion;\n                    updatedModules.push({\n                        name: moduleName,\n                        newVersion: newModuleVersion,\n                        oldVersion: oldModuleVersion\n                    });\n                }\n            }\n        }\n    }\n\n    // write out the new package.json\n    jsonFile.writeJsonFile(rootPath + \"/package.json\", packages, {\n        spaces: 4,\n        encoding: \"utf8\"\n    });\n    \n    var updatedModuleCount = Object.keys(updatedModules).length;\n\n    if (updatedModuleCount) {\n        console.info(\"%d %s updated in package.json!\", \n            updatedModuleCount, \n            (updatedModuleCount === 1 ? \"module\" : \"modules\"));\n        console.info(\"Run 'npm install'\");\n    }\n}\n"
  }
]