// Generated by CoffeeScript 1.3.3
var Backbone, BasePlugin, CSON, Collection, DocPad, DocumentModel, ElementsCollection, EventEmitterEnhanced, Events, FileModel, FilesCollection, MetaCollection, Model, PluginLoader, QueryCollection, ScriptsCollection, StylesCollection, View, airbrake, balUtil, caterpillar, growl, pathUtil, queryEngine, util, _, _ref,
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
  __slice = [].slice;

pathUtil = require('path');

_ = require('underscore');

caterpillar = require('caterpillar');

CSON = require('cson');

balUtil = require('bal-util');

util = require('util');

EventEmitterEnhanced = balUtil.EventEmitterEnhanced;

airbrake = null;

growl = null;

_ref = require(__dirname + '/base'), queryEngine = _ref.queryEngine, Backbone = _ref.Backbone, Events = _ref.Events, Model = _ref.Model, Collection = _ref.Collection, View = _ref.View, QueryCollection = _ref.QueryCollection;

FileModel = require(__dirname + '/models/file');

DocumentModel = require(__dirname + '/models/document');

FilesCollection = require(__dirname + '/collections/files');

ElementsCollection = require(__dirname + '/collections/elements');

MetaCollection = require(__dirname + '/collections/meta');

ScriptsCollection = require(__dirname + '/collections/scripts');

StylesCollection = require(__dirname + '/collections/styles');

PluginLoader = require(__dirname + '/plugin-loader');

BasePlugin = require(__dirname + '/plugin');

require(__dirname + '/prototypes');

/*
The DocPad Class
It extends the EventSystem from bal-util to provide system events
It allows us to support multiple instances of docpad at the same time
*/


DocPad = (function(_super) {
  var _ref1, _ref2, _ref3;

  __extends(DocPad, _super);

  DocPad.prototype.Events = Events;

  DocPad.prototype.Model = Model;

  DocPad.prototype.Collection = Collection;

  DocPad.prototype.View = View;

  DocPad.prototype.QueryCollection = QueryCollection;

  DocPad.prototype.FileModel = FileModel;

  DocPad.prototype.DocumentModel = DocumentModel;

  DocPad.prototype.FilesCollection = FilesCollection;

  DocPad.prototype.ElementsCollection = ElementsCollection;

  DocPad.prototype.MetaCollection = MetaCollection;

  DocPad.prototype.ScriptsCollection = ScriptsCollection;

  DocPad.prototype.StylesCollection = StylesCollection;

  DocPad.prototype.PluginLoader = PluginLoader;

  DocPad.prototype.BasePlugin = BasePlugin;

  DocPad.prototype.version = null;

  DocPad.prototype.getVersion = function() {
    return this.version;
  };

  DocPad.prototype.serverExpress = null;

  DocPad.prototype.serverHttp = null;

  DocPad.prototype.getServer = function(both) {
    var serverExpress, serverHttp;
    serverExpress = this.serverExpress, serverHttp = this.serverHttp;
    if (both) {
      return {
        serverExpress: serverExpress,
        serverHttp: serverHttp
      };
    } else {
      return serverExpress;
    }
  };

  DocPad.prototype.setServer = function(servers) {
    this.serverExpress = servers.serverExpress;
    return this.serverHttp = servers.serverHttp;
  };

  DocPad.prototype.loggerInstance = null;

  DocPad.prototype.getLogger = function() {
    return this.loggerInstance;
  };

  DocPad.prototype.setLogger = function(value) {
    this.loggerInstance = value;
    return this;
  };

  DocPad.prototype.runnerInstance = null;

  DocPad.prototype.getRunner = function() {
    return this.runnerInstance;
  };

  DocPad.prototype.events = ['docpadReady', 'extendTemplateData', 'extendCollections', 'docpadLoaded', 'consoleSetup', 'generateBefore', 'populateCollections', 'generateAfter', 'parseBefore', 'parseAfter', 'contextualizeBefore', 'contextualizeAfter', 'renderBefore', 'render', 'renderDocument', 'renderAfter', 'writeBefore', 'writeAfter', 'serverBefore', 'serverExtend', 'serverAfter'];

  DocPad.prototype.getEvents = function() {
    return this.events;
  };

  DocPad.prototype.database = null;

  DocPad.prototype.getDatabase = function() {
    return this.database;
  };

  DocPad.prototype.blocks = null;

  /* {
  		# A collection of meta elements
  		meta: null  # Elements Collection
  
  		# A collection of script elements
  		scripts: null  # Scripts Collection
  
  		# Collection of style elements
  		styles: null  # Styles Collection
  	}
  */


  DocPad.prototype.getBlock = function(name, clone) {
    var block, classname;
    block = this.blocks[name];
    if (clone) {
      classname = name[0].toUpperCase() + name.slice(1) + 'Collection';
      block = new this[classname](block.models);
    }
    return block;
  };

  DocPad.prototype.setBlock = function(name, value) {
    this.blocks[name] = value;
    return this;
  };

  DocPad.prototype.collections = null;

  /* {
  		# Documents collection
  		documents: null  # QueryEngine Collection
  
  		# Files collection
  		files: null  # QueryEngine Collection
  
  		# Layouts collection
  		layouts: null  # QueryEngine Collection
  	}
  */


  DocPad.prototype.getCollection = function(name) {
    return this.collections[name];
  };

  DocPad.prototype.setCollection = function(name, value) {
    this.collections[name] = value;
    return this;
  };

  DocPad.prototype.getFiles = function(query, sorting, paging) {
    var key, result;
    key = JSON.stringify({
      query: query,
      sorting: sorting,
      paging: paging
    });
    result = this.getCollection(key);
    if (!result) {
      result = this.getDatabase().findAllLive(query, sorting, paging);
      this.setCollection(key, result);
    }
    return result;
  };

  DocPad.prototype.getFile = function(query, sorting, paging) {
    var result;
    result = this.getDatabase().findOne(query, sorting, paging);
    return result;
  };

  DocPad.prototype.getFilesAtPath = function(path, sorting, paging) {
    var query, result;
    query = {
      $or: [
        {
          relativePath: {
            $startsWith: path
          }
        }, {
          fullPath: {
            $startsWith: path
          }
        }
      ]
    };
    result = this.getFiles(query, sorting, paging);
    return result;
  };

  DocPad.prototype.getFileAtPath = function(path, sorting, paging) {
    var query, result;
    query = {
      $or: [
        {
          relativePath: path
        }, {
          fullPath: path
        }
      ]
    };
    result = this.getDatabase().findOne(query, sorting, paging);
    return result;
  };

  DocPad.prototype.skeletonsCollection = null;

  DocPad.prototype.getSkeletons = function(next) {
    var docpad, locale;
    docpad = this;
    locale = this.getLocale();
    if (this.skeletonsCollection != null) {
      return next(null, this.skeletonsCollection);
    }
    this.skeletonsCollection = new Collection();
    this.skeletonsCollection.comparator = queryEngine.generateComparator({
      position: 1,
      name: 1
    });
    this.getExchange(function(err, exchange) {
      var index, skeleton, skeletonKey, _ref1, _ref2, _ref3, _ref4;
      if (err) {
        return next(err);
      }
      index = 0;
      _ref1 = exchange.skeletons;
      for (skeletonKey in _ref1) {
        if (!__hasProp.call(_ref1, skeletonKey)) continue;
        skeleton = _ref1[skeletonKey];
        if ((_ref2 = skeleton.id) == null) {
          skeleton.id = skeletonKey;
        }
        if ((_ref3 = skeleton.name) == null) {
          skeleton.name = skeletonKey;
        }
        if ((_ref4 = skeleton.position) == null) {
          skeleton.position = index;
        }
        docpad.skeletonsCollection.add(new Model(skeleton));
        ++index;
      }
      docpad.skeletonsCollection.add(new Model({
        id: 'none',
        name: locale.skeletonNoneName,
        description: locale.skeletonNoneDescription,
        position: Infinity
      }));
      return next(null, docpad.skeletonsCollection);
    });
    return this;
  };

  DocPad.prototype.slowPlugins = null;

  DocPad.prototype.loadedPlugins = null;

  DocPad.prototype.exchange = null;

  DocPad.prototype.corePath = pathUtil.join(__dirname, '..', '..');

  DocPad.prototype.libPath = __dirname;

  DocPad.prototype.mainPath = pathUtil.join(__dirname, 'docpad');

  DocPad.prototype.packagePath = pathUtil.join(__dirname, '..', '..', 'package.json');

  DocPad.prototype.userConfigPath = '.docpad.cson';

  DocPad.prototype.initialTemplateData = null;

  DocPad.prototype.pluginsTemplateData = null;

  DocPad.prototype.getTemplateData = function(userTemplateData) {
    var docpad, templateData, _base, _base1, _ref1;
    userTemplateData || (userTemplateData = {});
    docpad = this;
    if ((_ref1 = this.initialTemplateData) == null) {
      this.initialTemplateData = {
        site: {},
        referencesOthers: function(flag) {
          var document;
          document = this.getDocument();
          document.referencesOthers();
          return null;
        },
        getDocument: function() {
          return this.documentModel;
        },
        getPath: function(path, parentPath) {
          var document;
          document = this.getDocument();
          path = document.getPath(path, parentPath);
          return path;
        },
        getFiles: function(query, sorting, paging) {
          var result;
          this.referencesOthers();
          result = docpad.getFiles(query, sorting, paging);
          return result;
        },
        getFile: function(query, sorting, paging) {
          var result;
          this.referencesOthers();
          result = docpad.getFile(query, sorting, paging);
          return result;
        },
        getFilesAtPath: function(path, sorting, paging) {
          var result;
          this.referencesOthers();
          path = this.getPath(path);
          result = docpad.getFilesAtPath(path, sorting, paging);
          return result;
        },
        getFileAtPath: function(relativePath) {
          var path, result;
          this.referencesOthers();
          path = this.getPath(relativePath);
          result = docpad.getFileAtPath(path);
          return result;
        },
        getDatabase: function() {
          this.referencesOthers();
          return docpad.getDatabase();
        },
        getCollection: function(name) {
          this.referencesOthers();
          return docpad.getCollection(name);
        },
        getBlock: function(name) {
          return docpad.getBlock(name, true);
        },
        include: function(subRelativePath) {
          var err, locale, result;
          result = this.getFileAtPath(subRelativePath);
          if (result) {
            return result.get('contentRendered') || result.get('content');
          } else {
            locale = this.getLocale();
            err = new Error(util.format(locale.includeFailed, subRelativePath));
            throw err;
          }
        }
      };
    }
    templateData = balUtil.extend({}, this.initialTemplateData, this.pluginsTemplateData, this.config.templateData, userTemplateData);
    (_base = templateData.site).date || (_base.date = new Date());
    (_base1 = templateData.site).keywords || (_base1.keywords = []);
    if (_.isString(templateData.site.keywords)) {
      templateData.site.keywords = templateData.site.keywords.split(/,\s*/g);
    }
    return templateData;
  };

  DocPad.prototype.locales = {
    en: CSON.parseFileSync(pathUtil.join(__dirname, '..', '..', 'locale', 'en.cson'))
  };

  DocPad.prototype.config = null;

  DocPad.prototype.instanceConfig = null;

  DocPad.prototype.websiteConfig = null;

  DocPad.prototype.websitePackageConfig = null;

  DocPad.prototype.userConfig = {
    name: null,
    email: null,
    username: null,
    subscribed: null,
    subscribeTryAgain: null
  };

  DocPad.prototype.initialConfig = {
    force: false,
    enableUnlistedPlugins: true,
    enabledPlugins: {},
    skipUnsupportedPlugins: true,
    plugins: {},
    exchangeUrl: 'https://docpad.org/exchange.json',
    rootPath: process.cwd(),
    packagePath: 'package.json',
    latestPackageUrl: 'https://docpad.org/latest.json',
    configPaths: ['docpad.js', 'docpad.coffee', 'docpad.json', 'docpad.cson'],
    outPath: 'out',
    srcPath: 'src',
    documentsPaths: ['documents'],
    filesPaths: ['files', 'public'],
    layoutsPaths: ['layouts'],
    pluginPaths: [],
    pluginsPaths: ['node_modules', 'plugins'],
    serverExpress: null,
    serverHttp: null,
    extendServer: true,
    port: (_ref1 = (_ref2 = (_ref3 = process.env.VCAP_APP_PORT) != null ? _ref3 : process.env.VMC_APP_PORT) != null ? _ref2 : process.env.PORT) != null ? _ref1 : 9778,
    maxAge: 86400000,
    middlewareStandard: true,
    middlewareBodyParser: true,
    middlewareMethodOverride: true,
    middlewareExpressRouter: true,
    middleware404: true,
    middleware500: true,
    logLevel: ((__indexOf.call(process.argv, '-d') >= 0) ? 7 : 6),
    logger: null,
    growl: true,
    catchExceptions: true,
    reportErrors: true,
    airbrakeToken: 'e7374dd1c5a346efe3895b9b0c1c0325',
    checkVersion: false,
    welcome: false,
    prompts: false,
    helperUrl: 'https://docpad.org/helper/',
    safeMode: false,
    templateData: {},
    collections: {},
    events: {},
    regenerateEvery: false,
    env: process.env.NODE_ENV || 'development',
    environments: {
      development: {
        maxAge: false,
        checkVersion: process.argv.length >= 2 && /docpad$/.test(process.argv[1]),
        welcome: process.argv.length >= 2 && /docpad$/.test(process.argv[1]),
        prompts: process.argv.length >= 2 && /docpad$/.test(process.argv[1])
      }
    }
  };

  DocPad.prototype.regenerateTimer = null;

  DocPad.prototype.getLocale = function() {
    return this.locales.en;
  };

  DocPad.prototype.getEnvironment = function() {
    return this.getConfig().env;
  };

  DocPad.prototype.getEnvironments = function() {
    return this.getEnvironment().split(/[, ]+/);
  };

  DocPad.prototype.getConfig = function() {
    return this.config || {};
  };

  function DocPad(instanceConfig, next) {
    this.server = __bind(this.server, this);

    this.serverMiddleware500 = __bind(this.serverMiddleware500, this);

    this.serverMiddleware404 = __bind(this.serverMiddleware404, this);

    this.serverMiddlewareRouter = __bind(this.serverMiddlewareRouter, this);

    this.serveDocument = __bind(this.serveDocument, this);

    this.skeleton = __bind(this.skeleton, this);

    this.run = __bind(this.run, this);

    this.watch = __bind(this.watch, this);

    this.render = __bind(this.render, this);

    this.generate = __bind(this.generate, this);

    this.generatePostpare = __bind(this.generatePostpare, this);

    this.generateRender = __bind(this.generateRender, this);

    this.generateParse = __bind(this.generateParse, this);

    this.generateClean = __bind(this.generateClean, this);

    this.generateCheck = __bind(this.generateCheck, this);

    this.generatePrepare = __bind(this.generatePrepare, this);

    this.action = __bind(this.action, this);

    this.ensureFileOrDocument = __bind(this.ensureFileOrDocument, this);

    this.ensureDocument = __bind(this.ensureDocument, this);

    this.ensureFile = __bind(this.ensureFile, this);

    this.createDocument = __bind(this.createDocument, this);

    this.createFile = __bind(this.createFile, this);

    this.notify = __bind(this.notify, this);

    this.warn = __bind(this.warn, this);

    this.error = __bind(this.error, this);

    this.log = __bind(this.log, this);

    this.fatal = __bind(this.fatal, this);

    this.clean = __bind(this.clean, this);

    this.install = __bind(this.install, this);

    this.load = __bind(this.load, this);

    this.ready = __bind(this.ready, this);

    var configEventContext, docpad, logger, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(instanceConfig, next), instanceConfig = _ref4[0], next = _ref4[1];
    docpad = this;
    this.setMaxListeners(0);
    configEventContext = {
      docpad: docpad
    };
    _.each(this.getEvents(), function(eventName) {
      return docpad.on(eventName, function(opts, next) {
        var args, eventHandler, _ref5;
        eventHandler = (_ref5 = docpad.getConfig().events) != null ? _ref5[eventName] : void 0;
        if (balUtil.isFunction(eventHandler)) {
          args = [opts, next];
          return balUtil.fireWithOptionalCallback(eventHandler, args, configEventContext);
        } else {
          return next();
        }
      });
    });
    this.runnerInstance = new balUtil.Group('sync', function(err) {
      if (err) {
        return docpad.error(err);
      }
    });
    this.runnerInstance.total = Infinity;
    logger = new caterpillar.Logger({
      transports: {
        formatter: {
          module: module
        }
      }
    });
    this.setLogger(logger);
    this.setLogLevel(6);
    this.on('log', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.log.apply(this, args);
    });
    this.slowPlugins = {};
    this.loadedPlugins = {};
    this.exchange = {};
    this.pluginsTemplateData = {};
    this.instanceConfig = {};
    this.locales = balUtil.dereference(this.locales);
    this.userConfig = balUtil.dereference(this.userConfig);
    this.initialConfig = balUtil.dereference(this.initialConfig);
    if (instanceConfig.load === false) {
      if (typeof next === "function") {
        next(null, docpad);
      }
    } else {
      this.action('load ready', instanceConfig, function(err) {
        if (err) {
          return docpad.fatal(err);
        }
        return typeof next === "function" ? next(null, docpad) : void 0;
      });
    }
    this;

  }

  DocPad.prototype.ready = function(opts, next) {
    var docpad, instanceConfig, locale, pluginName, pluginsList, tasks, _ref4,
      _this = this;
    _ref4 = balUtil.extractOptsAndCallback(instanceConfig, next), instanceConfig = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    this.compareVersion();
    if (this.getDebugging()) {
      pluginsList = ((function() {
        var _i, _len, _ref5, _results;
        _ref5 = _.keys(this.loadedPlugins).sort();
        _results = [];
        for (_i = 0, _len = _ref5.length; _i < _len; _i++) {
          pluginName = _ref5[_i];
          _results.push("" + pluginName + " v" + this.loadedPlugins[pluginName].version);
        }
        return _results;
      }).call(this)).join(', ');
    } else {
      pluginsList = _.keys(this.loadedPlugins).sort().join(', ');
    }
    this.log('info', util.format(locale.welcome, "v" + (this.getVersion())));
    this.log('info', util.format(locale.welcomePlugins, pluginsList));
    this.log('info', util.format(locale.welcomeEnvironment, this.getEnvironment()));
    tasks = new balUtil.Group(function(err) {
      if (err) {
        return docpad.error(err);
      }
      return typeof next === "function" ? next(null, docpad) : void 0;
    });
    tasks.push(function(complete) {
      if (!docpad.config.welcome) {
        return complete();
      }
      return _this.emitSync('welcome', {
        docpad: docpad
      }, complete);
    });
    tasks.push(function(complete) {
      return _this.emitSync('docpadReady', {
        docpad: docpad
      }, complete);
    });
    tasks.sync();
    return this;
  };

  DocPad.prototype.load = function(instanceConfig, next) {
    var docpad, locale, preTasks, _ref4,
      _this = this;
    _ref4 = balUtil.extractOptsAndCallback(instanceConfig, next), instanceConfig = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    instanceConfig || (instanceConfig = {});
    this.websitePackageConfig = {};
    this.websiteConfig = {};
    this.config = {};
    balUtil.extend(this.instanceConfig, instanceConfig);
    preTasks = new balUtil.Group(function(err) {
      var configPackage, configPackages, configsToMerge, env, envConfig, envs, key, postTasks, type, typePath, typePaths, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _len5, _m, _n, _ref5, _ref6, _ref7;
      if (err) {
        return next(err);
      }
      _this.config.env = _this.instanceConfig.env || _this.websiteConfig.env || _this.websitePackageConfig.env || _this.initialConfig.env;
      envs = _this.getEnvironments();
      configPackages = [_this.initialConfig, _this.userConfig, _this.websitePackageConfig, _this.websiteConfig, _this.instanceConfig];
      configsToMerge = [_this.config];
      for (_i = 0, _len = configPackages.length; _i < _len; _i++) {
        configPackage = configPackages[_i];
        configsToMerge.push(configPackage);
        for (_j = 0, _len1 = envs.length; _j < _len1; _j++) {
          env = envs[_j];
          envConfig = (_ref5 = configPackage.environments) != null ? _ref5[env] : void 0;
          if (envConfig) {
            configsToMerge.push(envConfig);
          }
        }
      }
      balUtil.deepExtendPlainObjects.apply(balUtil, configsToMerge);
      if (_this.config.server) {
        _this.setServer(_this.config.server);
      }
      if (_this.config.logger) {
        _this.setLogger(_this.config.logger);
      }
      _this.setLogLevel(_this.config.logLevel);
      _this.config.rootPath = pathUtil.resolve(_this.config.rootPath);
      _this.config.outPath = pathUtil.resolve(_this.config.rootPath, _this.config.outPath);
      _this.config.srcPath = pathUtil.resolve(_this.config.rootPath, _this.config.srcPath);
      _ref6 = ['documents', 'files', 'layouts'];
      for (_k = 0, _len2 = _ref6.length; _k < _len2; _k++) {
        type = _ref6[_k];
        typePaths = _this.config[type + 'Paths'];
        for (key = _l = 0, _len3 = typePaths.length; _l < _len3; key = ++_l) {
          typePath = typePaths[key];
          typePaths[key] = pathUtil.resolve(_this.config.srcPath, typePath);
        }
      }
      _ref7 = ['plugins'];
      for (_m = 0, _len4 = _ref7.length; _m < _len4; _m++) {
        type = _ref7[_m];
        typePaths = _this.config[type + 'Paths'];
        for (key = _n = 0, _len5 = typePaths.length; _n < _len5; key = ++_n) {
          typePath = typePaths[key];
          typePaths[key] = pathUtil.resolve(_this.config.rootPath, typePath);
        }
      }
      if (_this.config.catchExceptions) {
        process.setMaxListeners(0);
        process.on('uncaughtException', _this.error);
      } else {
        process.removeListener('uncaughtException', _this.error);
      }
      if (_this.config.reportErrors && /win/.test(process.platform) === false) {
        try {
          airbrake = require('airbrake').createClient(_this.config.airbrakeToken);
        } catch (err) {
          airbrake = false;
        }
      }
      if (_this.regenerateTimer) {
        clearInterval(_this.regenerateTimer);
        _this.regenerateTimer = null;
      }
      if (_this.config.regenerateEvery) {
        _this.regenerateTimer = setInterval(function() {
          docpad.log('info', locale.renderInterval);
          return docpad.action('generate');
        }, _this.config.regenerateEvery);
      }
      postTasks = new balUtil.Group(function(err) {
        return next(err, _this.config);
      });
      postTasks.push(function(complete) {
        return _this.loadPlugins(complete);
      });
      postTasks.push(function(complete) {
        return _this.createCollections(complete);
      });
      postTasks.push(function(complete) {
        return _this.emitSync('extendTemplateData', {
          templateData: _this.pluginsTemplateData
        }, complete);
      });
      postTasks.push(function(complete) {
        return _this.emitSync('docpadLoaded', {}, complete);
      });
      return postTasks.sync();
    });
    preTasks.push(function(complete) {
      return balUtil.getHomePath(function(err, homePath) {
        var dropboxPath;
        if (err) {
          return complete(err);
        }
        dropboxPath = pathUtil.join(homePath, 'Dropbox');
        return balUtil.exists(dropboxPath, function(dropboxPathExists) {
          var userConfigDirPath;
          userConfigDirPath = dropboxPathExists ? dropboxPath : homePath;
          _this.userConfigPath = pathUtil.join(userConfigDirPath, _this.userConfigPath);
          return complete();
        });
      });
    });
    preTasks.push(function(complete) {
      return _this.loadConfigPath(_this.userConfigPath, function(err, data) {
        if (err) {
          return complete(err);
        }
        balUtil.extend(_this.userConfig, data || {});
        return complete();
      });
    });
    preTasks.push(function(complete) {
      return _this.loadConfigPath(_this.packagePath, function(err, data) {
        if (err) {
          return complete(err);
        }
        data || (data = {});
        _this.version = data.version;
        if (airbrake) {
          airbrake.appVersion = data.version;
        }
        return complete();
      });
    });
    preTasks.push(function(complete) {
      var rootPath, websitePackagePath;
      rootPath = pathUtil.resolve(_this.instanceConfig.rootPath || _this.initialConfig.rootPath);
      websitePackagePath = pathUtil.resolve(rootPath, _this.instanceConfig.packagePath || _this.initialConfig.packagePath);
      return _this.loadConfigPath(websitePackagePath, function(err, data) {
        if (err) {
          return complete(err);
        }
        data || (data = {});
        data.docpad || (data.docpad = {});
        balUtil.extend(_this.websitePackageConfig, data.docpad);
        return complete();
      });
    });
    preTasks.push(function(complete) {
      var configPath, configPaths, index, rootPath, _i, _len;
      rootPath = pathUtil.resolve(_this.instanceConfig.rootPath || _this.websitePackageConfig.rootPath || _this.initialConfig.rootPath);
      configPaths = _this.instanceConfig.configPaths || _this.websitePackageConfig.configPaths || _this.initialConfig.configPaths;
      for (index = _i = 0, _len = configPaths.length; _i < _len; index = ++_i) {
        configPath = configPaths[index];
        configPaths[index] = pathUtil.resolve(rootPath, configPath);
      }
      return _this.loadConfigPaths(configPaths, function(err, data) {
        if (err) {
          return complete(err);
        }
        data || (data = {});
        balUtil.extend(_this.websiteConfig, data);
        return complete();
      });
    });
    preTasks.sync();
    return this;
  };

  DocPad.prototype.install = function(opts, next) {
    var docpad, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    this.initNodeModules({
      path: this.config.rootPath,
      output: true,
      next: function(err) {
        if (err) {
          return next(err);
        }
        return docpad.load(function(err) {
          return next(err);
        });
      }
    });
    return this;
  };

  DocPad.prototype.clean = function(opts, next) {
    var docpad, locale, outPath, rootPath, _ref4, _ref5;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    _ref5 = this.config, rootPath = _ref5.rootPath, outPath = _ref5.outPath;
    docpad.log('debug', 'Cleaning files');
    docpad.resetCollections(function(err) {
      if (err) {
        return next(err);
      }
      if (rootPath.indexOf(outPath) !== -1) {
        return next();
      } else {
        return balUtil.rmdirDeep(outPath, function(err, list, tree) {
          if (!err) {
            docpad.log('debug', locale.renderClean);
          }
          return next();
        });
      }
    });
    return this;
  };

  DocPad.prototype.updateUserConfig = function(data, next) {
    var docpad, userConfigPath, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(data, next), data = _ref4[0], next = _ref4[1];
    docpad = this;
    userConfigPath = this.userConfigPath;
    if (data) {
      balUtil.extend(this.userConfig, data);
    }
    CSON.stringify(this.userConfig, function(err, userConfigString) {
      if (err) {
        return next(err);
      }
      return balUtil.writeFile(userConfigPath, userConfigString, 'utf8', function(err) {
        return next(err);
      });
    });
    return this;
  };

  DocPad.prototype.loadConfigUrl = function(configUrl, next) {
    var locale, request;
    locale = this.getLocale();
    request = require('request');
    this.log('debug', util.format(locale.loadingConfigUrl, configUrl));
    request(configUrl, function(err, res, body) {
      if (err) {
        return next(err);
      }
      return CSON.parse(body, next);
    });
    return this;
  };

  DocPad.prototype.loadConfigPath = function(configPath, next) {
    var locale;
    locale = this.getLocale();
    this.log('debug', util.format(locale.loadingConfigPath, configPath));
    balUtil.exists(configPath, function(exists) {
      if (!exists) {
        return next(null, null);
      }
      return CSON.parseFile(configPath, next);
    });
    return this;
  };

  DocPad.prototype.loadConfigPaths = function(configPaths, next) {
    var docpad, result, tasks;
    docpad = this;
    result = {};
    if (!_.isArray(configPaths)) {
      configPaths = [configPaths];
    }
    tasks = new balUtil.Group(function(err) {
      return next(err, result);
    });
    _.each(configPaths, function(configPath) {
      return tasks.push(function(complete) {
        return docpad.loadConfigPath(configPath, function(err, config) {
          if (err) {
            return complete(err);
          }
          if (config) {
            result = config;
            return tasks.exit();
          } else {
            return complete();
          }
        });
      });
    });
    tasks.sync();
    return this;
  };

  DocPad.prototype.createCollections = function(next) {
    var config, database, docpad, documentsCollection, filesCollection, htmlCollection, layoutsCollection, locale, metaBlock, scriptsBlock, stylesBlock, stylesheetCollection, tasks;
    docpad = this;
    config = this.config;
    locale = this.getLocale();
    this.database = database = new FilesCollection();
    this.collections = {};
    this.blocks = {};
    config.collections || (config.collections = {});
    documentsCollection = database.createLiveChildCollection().setQuery('isDocument', {
      $or: {
        isDocument: true,
        fullPath: {
          $startsWith: config.documentsPaths
        }
      }
    }).on('add', function(model) {
      docpad.log('debug', util.format(locale.addingDocument, model.attributes.fullPath));
      return _.defaults(model.attributes, {
        isDocument: true,
        render: true,
        write: true
      });
    });
    filesCollection = database.createLiveChildCollection().setQuery('isFile', {
      $or: {
        isFile: true,
        fullPath: {
          $startsWith: config.filesPaths
        }
      }
    }).on('add', function(model) {
      docpad.log('debug', util.format(locale.addingFile, model.attributes.fullPath));
      return _.defaults(model.attributes, {
        isFile: true,
        render: false,
        write: true
      });
    });
    layoutsCollection = database.createLiveChildCollection().setQuery('isLayout', {
      $or: {
        isLayout: true,
        fullPath: {
          $startsWith: config.layoutsPaths
        }
      }
    }).on('add', function(model) {
      docpad.log('debug', util.format(locale.addingLayout, model.attributes.fullPath));
      return _.defaults(model.attributes, {
        isLayout: true,
        render: false,
        write: false
      });
    });
    htmlCollection = database.createLiveChildCollection().setQuery('isHTML', {
      $or: {
        isDocument: true,
        isFile: true
      },
      outExtension: 'html'
    }).on('add', function(model) {
      return docpad.log('debug', util.format(locale.addingHtml, model.attributes.fullPath));
    });
    stylesheetCollection = database.createLiveChildCollection().setQuery('isStylesheet', {
      $or: {
        isDocument: true,
        isFile: true
      },
      outExtension: {
        $in: ['css', 'scss', 'sass', 'styl', 'stylus', 'less']
      }
    }).on('add', function(model) {
      docpad.log('debug', util.format(locale.addingStylesheet, model.attributes.fullPath));
      return model.attributes.referencesOthers = true;
    });
    this.setCollection('documents', documentsCollection);
    this.setCollection('files', filesCollection);
    this.setCollection('layouts', layoutsCollection);
    this.setCollection('html', htmlCollection);
    this.setCollection('stylesheets', stylesheetCollection);
    metaBlock = new MetaCollection();
    scriptsBlock = new ScriptsCollection();
    stylesBlock = new StylesCollection();
    this.setBlock('meta', metaBlock);
    this.setBlock('scripts', scriptsBlock);
    this.setBlock('styles', stylesBlock);
    tasks = new balUtil.Group(function(err) {
      if (err) {
        docpad.error(err);
      }
      return docpad.emitSync('extendCollections', {}, next);
    });
    _.each(this.config.collections, function(fn, name) {
      return tasks.push(function(complete) {
        var collection;
        if (fn.length === 2) {
          return fn.call(docpad, database, function(err, collection) {
            if (err) {
              docpad.error(err);
            }
            if (collection) {
              collection.live(true);
              docpad.setCollection(name, collection);
            }
            return complete();
          });
        } else {
          collection = fn.call(docpad, database);
          if (collection) {
            collection.live(true);
            docpad.setCollection(name, collection);
          }
          return complete();
        }
      });
    });
    tasks.async();
    return this;
  };

  DocPad.prototype.resetCollections = function(next) {
    this.getDatabase().reset([]);
    this.getBlock('meta').reset([]).add(['<meta http-equiv="X-Powered-By" content="DocPad"/>']);
    this.getBlock('scripts').reset([]);
    this.getBlock('styles').reset([]);
    this.emitSync('populateCollections', {}, next);
    return this;
  };

  DocPad.prototype.initGitRepo = function(opts) {
    balUtil.initGitRepo(opts);
    return this;
  };

  DocPad.prototype.initNodeModules = function(opts) {
    var _ref4, _ref5;
    if (opts == null) {
      opts = {};
    }
    if ((_ref4 = opts.force) == null) {
      opts.force = this.config.force;
    }
    if ((_ref5 = opts.output) == null) {
      opts.output = this.getDebugging();
    }
    balUtil.initNodeModules(opts);
    return this;
  };

  DocPad.prototype.setLogLevel = function(level) {
    this.getLogger().setLevel(level);
    return this;
  };

  DocPad.prototype.getLogLevel = function() {
    return this.config.logLevel;
  };

  DocPad.prototype.getDebugging = function() {
    return this.getLogLevel() === 7;
  };

  DocPad.prototype.fatal = function(err) {
    var docpad;
    docpad = this;
    if (!err) {
      return this;
    }
    this.error(err, 'err', function() {
      if (docpad.config.catchExceptions) {
        return process.exit(-1);
      } else {
        throw err;
      }
    });
    return this;
  };

  DocPad.prototype.log = function() {
    var args, logger;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    logger = this.getLogger();
    logger.log.apply(logger, args);
    return this;
  };

  DocPad.prototype.error = function(err, type, next) {
    var docpad, locale;
    if (type == null) {
      type = 'err';
    }
    docpad = this;
    locale = this.getLocale();
    if (!err || err.logged) {
      if (typeof next === "function") {
        next();
      }
      return this;
    }
    err.logged = true;
    if (!(err instanceof Error)) {
      err = new Error(err);
    }
    err.logged = true;
    docpad.log(type, locale.errorOccured, err.message, err.stack);
    if (docpad.config.reportErrors && airbrake) {
      err.params = {
        docpadVersion: this.version,
        docpadConfig: this.config
      };
      airbrake.notify(err, function(airbrakeErr, airbrakeUrl) {
        if (airbrakeErr) {
          console.log(airbrakeErr);
        }
        console.log(util.format(locale.errorLoggedTo, airbrakeUrl));
        return typeof next === "function" ? next() : void 0;
      });
    } else {
      if (typeof next === "function") {
        next();
      }
    }
    return this;
  };

  DocPad.prototype.warn = function(message, err, next) {
    var docpad;
    docpad = this;
    docpad.log('warn', message);
    docpad.error(err, 'warn', next);
    return this;
  };

  DocPad.prototype.notify = function() {
    var args;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    if (!this.config.growl) {
      return this;
    }
    try {
      if (growl == null) {
        growl = require('growl');
      }
      if (growl) {
        growl.apply(growl, args);
      }
    } catch (err) {

    }
    return this;
  };

  DocPad.prototype.createFile = function(data, options) {
    var docpad, file;
    if (data == null) {
      data = {};
    }
    if (options == null) {
      options = {};
    }
    docpad = this;
    options = balUtil.extend({
      outDirPath: this.config.outPath
    }, options);
    file = new FileModel(data, options);
    file.on('log', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.log.apply(docpad, args);
    });
    file.on('render', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.emitSync.apply(docpad, ['render'].concat(__slice.call(args)));
    });
    return file;
  };

  DocPad.prototype.createDocument = function(data, options) {
    var docpad, document;
    if (data == null) {
      data = {};
    }
    if (options == null) {
      options = {};
    }
    docpad = this;
    options = balUtil.extend({
      outDirPath: this.config.outPath
    }, options);
    document = new DocumentModel(data, options);
    document.on('log', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.log.apply(docpad, args);
    });
    document.on('getLayout', function(opts, next) {
      var layout, layoutId, layouts;
      layoutId = opts.layoutId;
      layouts = docpad.getCollection('layouts');
      layout = layouts.findOne({
        id: layoutId
      });
      if (!layout) {
        layout = layouts.findOne({
          relativePath: layoutId
        });
      }
      if (!layout) {
        layout = layouts.findOne({
          relativeBase: layoutId
        });
      }
      return next(null, {
        layout: layout
      });
    });
    document.on('render', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.emitSync.apply(docpad, ['render'].concat(__slice.call(args)));
    });
    document.on('renderDocument', function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      return docpad.emitSync.apply(docpad, ['renderDocument'].concat(__slice.call(args)));
    });
    return document;
  };

  DocPad.prototype.ensureFile = function(data, options) {
    var database, result;
    if (data == null) {
      data = {};
    }
    if (options == null) {
      options = {};
    }
    database = this.getDatabase();
    result = database.findOne({
      fullPath: data.fullPath
    });
    if (!result) {
      result = this.createFile(data, options);
      database.add(result);
    }
    return result;
  };

  DocPad.prototype.ensureDocument = function(data, options) {
    var database, result;
    if (data == null) {
      data = {};
    }
    if (options == null) {
      options = {};
    }
    database = this.getDatabase();
    result = database.findOne({
      fullPath: data.fullPath
    });
    if (!result) {
      result = this.createDocument(data, options);
      database.add(result);
    }
    return result;
  };

  DocPad.prototype.ensureFileOrDocument = function(data, options) {
    var database, dirPath, docpad, fileFullPath, result, _i, _j, _len, _len1, _ref4, _ref5;
    if (data == null) {
      data = {};
    }
    if (options == null) {
      options = {};
    }
    docpad = this;
    database = this.getDatabase();
    fileFullPath = data.fullPath || null;
    result = database.findOne({
      fullPath: fileFullPath
    });
    if (!result) {
      if (fileFullPath) {
        _ref4 = docpad.config.documentsPaths.concat(docpad.config.layoutsPaths);
        for (_i = 0, _len = _ref4.length; _i < _len; _i++) {
          dirPath = _ref4[_i];
          if (fileFullPath.indexOf(dirPath) === 0) {
            data.relativePath || (data.relativePath = fileFullPath.replace(dirPath, '').replace(/^[\/\\]/, ''));
            result = this.createDocument(data, options);
            break;
          }
        }
        if (!result) {
          _ref5 = docpad.config.filesPaths;
          for (_j = 0, _len1 = _ref5.length; _j < _len1; _j++) {
            dirPath = _ref5[_j];
            if (fileFullPath.indexOf(dirPath) === 0) {
              data.relativePath || (data.relativePath = fileFullPath.replace(dirPath, '').replace(/^[\/\\]/, ''));
              result = this.createFile(data, options);
              break;
            }
          }
        }
      }
      if (!result) {
        result = this.createFile(data, options);
      }
      database.add(result);
    }
    return result;
  };

  DocPad.prototype.parseDirectory = function(opts, next) {
    var createFunction, filesToLoad, locale, me, path;
    if (opts == null) {
      opts = {};
    }
    me = this;
    locale = this.getLocale();
    path = opts.path, createFunction = opts.createFunction;
    filesToLoad = new FilesCollection();
    if (!balUtil.existsSync(path)) {
      me.log('debug', util.format(locale.renderDirectoryNonexistant, path));
      return next();
    }
    me.log('debug', util.format(locale.renderDirectoryParsing, path));
    balUtil.scandir({
      path: path,
      ignorePatterns: true,
      fileAction: function(fileFullPath, fileRelativePath, nextFile, fileStat) {
        var data, file, options;
        data = {
          fullPath: fileFullPath,
          relativePath: fileRelativePath
        };
        options = {
          stat: fileStat
        };
        file = createFunction(data, options);
        filesToLoad.add(file);
        return nextFile();
      },
      next: function(err) {
        if (err) {
          return next(err);
        }
        me.log('debug', util.format(locale.renderDirectoryParsed, path));
        return me.loadFiles({
          collection: filesToLoad
        }, function(err) {
          return next(err);
        });
      }
    });
    return this;
  };

  DocPad.prototype.getPlugin = function(pluginName) {
    return this.loadedPlugins[pluginName];
  };

  DocPad.prototype.hasPlugins = function() {
    return _.isEmpty(this.loadedPlugins) === false;
  };

  DocPad.prototype.loadPlugins = function(next) {
    var docpad, locale, snore, tasks,
      _this = this;
    docpad = this;
    locale = this.getLocale();
    this.slowPlugins = {};
    snore = this.createSnore(function() {
      return docpad.log('notice', util.format(locale.pluginsSlow, _.keys(docpad.slowPlugins).join(', ')));
    });
    tasks = new balUtil.Group(function(err) {
      docpad.slowPlugins = {};
      snore.clear();
      return next(err);
    });
    _.each(this.config.pluginsPaths || [], function(pluginsPath) {
      var exists;
      exists = balUtil.existsSync(pluginsPath);
      if (exists) {
        return tasks.push(function(complete) {
          return _this.loadPluginsIn(pluginsPath, complete);
        });
      }
    });
    _.each(this.config.pluginPaths || [], function(pluginPath) {
      var exists;
      exists = balUtil.existsSync(pluginPath);
      if (exists) {
        return tasks.push(function(complete) {
          return _this.loadPlugin(pluginPath, complete);
        });
      }
    });
    tasks.async();
    return this;
  };

  DocPad.prototype.loadedPlugin = function(pluginName, next) {
    var docpad, loaded;
    docpad = this;
    loaded = docpad.loadedPlugins[pluginName] != null;
    next(null, loaded);
    return this;
  };

  DocPad.prototype.loadPlugin = function(fileFullPath, _next) {
    var config, docpad, enabled, loader, locale, next, pluginName;
    docpad = this;
    config = this.config;
    locale = this.getLocale();
    next = function(err) {
      delete docpad.slowPlugins[pluginName];
      return _next(err);
    };
    loader = new PluginLoader({
      dirPath: fileFullPath,
      docpad: this,
      BasePlugin: BasePlugin
    });
    pluginName = loader.pluginName;
    enabled = (config.enableUnlistedPlugins && (config.enabledPlugins[pluginName] != null) === false) || config.enabledPlugins[pluginName] === true;
    if (docpad.loadedPlugins[pluginName] != null) {
      return _next();
    }
    docpad.slowPlugins[pluginName] = true;
    if (!enabled) {
      docpad.log('debug', util.format(locale.pluginSkipped, pluginName));
      return next();
    } else {
      docpad.log('debug', util.format(locale.pluginLoading, pluginName));
      loader.exists(function(err, exists) {
        if (err || !exists) {
          return next(err);
        }
        return loader.unsupported(function(err, unsupported) {
          if (err) {
            return next(err);
          }
          if (unsupported) {
            if (unsupported === 'version' && docpad.config.skipUnsupportedPlugins === false) {
              docpad.log('warn', util.format(locale.pluginContinued, pluginName));
            } else {
              if (unsupported === 'type') {
                docpad.log('debug', util.format(locale.pluginSkippedDueTo, pluginName, unsupported));
              } else {
                docpad.log('warn', util.format(locale.pluginSkippedDueTo, pluginName, unsupported));
              }
              return next();
            }
          }
          return loader.load(function(err) {
            if (err) {
              return next(err);
            }
            return loader.create({}, function(err, pluginInstance) {
              if (err) {
                return next(err);
              }
              docpad.loadedPlugins[loader.pluginName] = pluginInstance;
              docpad.log('debug', util.format(locale.pluginLoaded, pluginName));
              return next();
            });
          });
        });
      });
    }
    return this;
  };

  DocPad.prototype.loadPluginsIn = function(pluginsPath, next) {
    var docpad, locale;
    docpad = this;
    locale = this.getLocale();
    docpad.log('debug', util.format(locale.pluginsLoadingFor, pluginsPath));
    balUtil.scandir({
      path: pluginsPath,
      ignorePatterns: true,
      fileAction: false,
      dirAction: function(fileFullPath, fileRelativePath, _nextFile) {
        var nextFile, pluginName;
        pluginName = pathUtil.basename(fileFullPath);
        if (fileFullPath === pluginsPath) {
          return _nextFile(null, false);
        }
        nextFile = function(err, skip) {
          if (err) {
            docpad.warn(util.format(locale.pluginFailedToLoad, pluginName, fileFullPath) + '\n' + locale.errorFollows, err);
          }
          return _nextFile(null, skip);
        };
        return docpad.loadPlugin(fileFullPath, function(err) {
          return nextFile(err, true);
        });
      },
      next: function(err) {
        docpad.log('debug', util.format(locale.pluginsLoadedFor, pluginsPath));
        return next(err);
      }
    });
    return this;
  };

  DocPad.prototype.createSnore = function(message) {
    var docpad, snore;
    docpad = this;
    snore = {
      snoring: false,
      timer: setTimeout(function() {
        snore.clear();
        snore.snoring = true;
        if (_.isFunction(message)) {
          return message();
        } else {
          return docpad.log('notice', message);
        }
      }, 5000),
      clear: function() {
        if (snore.timer) {
          clearTimeout(snore.timer);
          return snore.timer = false;
        }
      }
    };
    return snore;
  };

  DocPad.prototype.compareVersion = function() {
    var docpad, notify;
    if (!this.config.checkVersion) {
      return this;
    }
    docpad = this;
    notify = this.notify;
    balUtil.packageCompare({
      local: this.packagePath,
      remote: this.config.latestPackageUrl,
      newVersionCallback: function(details) {
        docpad.notify(util.format(locale.upgradeNotification, details.local.name));
        return docpad.log('notice', util.format(locale.upgradeDetails, details.local.version, details.remote.version, details.remote.homepage));
      }
    });
    return this;
  };

  DocPad.prototype.getExchange = function(next) {
    if (!_.isEmpty(this.exchange)) {
      return next(null, this.exchange);
    }
    this.loadConfigUrl(this.config.exchangeUrl, function(err, parsedData) {
      if (err) {
        return next(err);
      }
      this.exchange = parsedData;
      return next(null, parsedData);
    });
    return this;
  };

  DocPad.prototype.installSkeleton = function(skeletonModel, destinationPath, next) {
    var docpad, packagePath, repoConfig;
    docpad = this;
    packagePath = pathUtil.join(destinationPath, 'package.json');
    repoConfig = {
      path: destinationPath,
      url: skeletonModel.get('repo'),
      branch: skeletonModel.get('branch'),
      remote: 'skeleton',
      output: true,
      next: function(err) {
        if (err) {
          return docpad.error(err);
        }
        return docpad.initNodeModules({
          path: destinationPath,
          output: true,
          next: function(err) {
            if (err) {
              return docpad.error(err);
            }
            return next();
          }
        });
      }
    };
    balUtil.ensurePath(destinationPath, function(err) {
      if (err) {
        return docpad.error(err);
      }
      return docpad.initGitRepo(repoConfig);
    });
    return this;
  };

  DocPad.prototype.loadFiles = function(opts, next) {
    var collection, database, docpad, locale, tasks;
    if (opts == null) {
      opts = {};
    }
    docpad = this;
    locale = this.getLocale();
    database = this.getDatabase();
    collection = opts.collection;
    docpad.log('debug', util.format(locale.loadingFiles, collection.length));
    tasks = new balUtil.Group(function(err) {
      if (err) {
        return next(err);
      }
      return docpad.emitSync('loadAfter', {
        collection: collection
      }, function(err) {
        docpad.log('debug', util.format(locale.loadedFiles, collection.length));
        return next();
      });
    });
    collection.forEach(function(file) {
      return tasks.push(function(complete) {
        var fileRelativePath;
        fileRelativePath = file.get('relativePath');
        docpad.log('debug', util.format(locale.loadingFile, fileRelativePath));
        return file.load(function(err) {
          var fileIgnored, fileParse;
          if (err) {
            docpad.warn(util.format(locale.loadingFileFailed, fileRelativePath) + "\n" + locale.errorFollows, err);
            return complete();
          }
          fileIgnored = file.get('ignored');
          fileParse = file.get('parse');
          if (fileIgnored || ((fileParse != null) && !fileParse)) {
            docpad.log('info', util.format(locale.loadingFileIgnored, fileRelativePath));
            collection.remove(file);
            return complete();
          } else {
            docpad.log('debug', util.format(locale.loadedFile, fileRelativePath));
          }
          database.add(file);
          return complete();
        });
      });
    });
    if (tasks.total) {
      docpad.emitSync('loadBefore', {
        collection: collection
      }, function(err) {
        if (err) {
          return next(err);
        }
        return tasks.async();
      });
    } else {
      tasks.exit();
    }
    return this;
  };

  DocPad.prototype.contextualizeFiles = function(opts, next) {
    var collection, docpad, locale, tasks, templateData;
    if (opts == null) {
      opts = {};
    }
    docpad = this;
    locale = this.getLocale();
    collection = opts.collection, templateData = opts.templateData;
    docpad.log('debug', util.format(locale.contextualizingFiles, collection.length));
    tasks = new balUtil.Group(function(err) {
      if (err) {
        return next(err);
      }
      return docpad.emitSync('contextualizeAfter', {
        collection: collection
      }, function(err) {
        if (err) {
          return next(err);
        }
        docpad.log('debug', util.format(locale.contextualizedFiles, collection.length));
        return next();
      });
    });
    if (typeof opts.setProgressIndicator === "function") {
      opts.setProgressIndicator(function() {
        return ['contextualizeFiles', tasks.completed, tasks.total];
      });
    }
    collection.forEach(function(file, index) {
      return tasks.push(function(complete) {
        return file.contextualize(complete);
      });
    });
    if (tasks.total) {
      docpad.emitSync('contextualizeBefore', {
        collection: collection,
        templateData: templateData
      }, function(err) {
        if (err) {
          return next(err);
        }
        return tasks.async();
      });
    } else {
      tasks.exit();
    }
    return this;
  };

  DocPad.prototype.renderFiles = function(opts, next) {
    var collection, docpad, locale, tasks, templateData,
      _this = this;
    if (opts == null) {
      opts = {};
    }
    docpad = this;
    locale = this.getLocale();
    collection = opts.collection, templateData = opts.templateData;
    docpad.log('debug', util.format(locale.renderingFiles, collection.length));
    tasks = new balUtil.Group(function(err) {
      if (err) {
        return next(err);
      }
      return docpad.emitSync('renderAfter', {
        collection: collection
      }, function(err) {
        if (err) {
          return next(err);
        }
        docpad.log('debug', util.format(locale.renderedFiles, collection.length));
        return next();
      });
    });
    if (typeof opts.setProgressIndicator === "function") {
      opts.setProgressIndicator(function() {
        return ['renderFiles', tasks.completed, tasks.total];
      });
    }
    collection.forEach(function(file) {
      return tasks.push(function(complete) {
        var dynamic, relativePath, render;
        dynamic = file.get('dynamic');
        render = file.get('render');
        relativePath = file.get('relativePath');
        if (dynamic || ((render != null) && !render) || !relativePath) {
          return complete();
        } else if (file.render != null) {
          return file.render({
            templateData: templateData
          }, complete);
        } else {
          return complete();
        }
      });
    });
    if (tasks.total) {
      docpad.emitSync('renderBefore', {
        collection: collection,
        templateData: templateData
      }, function(err) {
        if (err) {
          return next(err);
        }
        return tasks.async();
      });
    } else {
      tasks.exit();
    }
    return this;
  };

  DocPad.prototype.writeFiles = function(opts, next) {
    var collection, docpad, locale, tasks, templateData,
      _this = this;
    if (opts == null) {
      opts = {};
    }
    docpad = this;
    locale = this.getLocale();
    collection = opts.collection, templateData = opts.templateData;
    docpad.log('debug', util.format(locale.writingFiles, collection.length));
    tasks = new balUtil.Group(function(err) {
      if (err) {
        return next(err);
      }
      return docpad.emitSync('writeAfter', {
        collection: collection
      }, function(err) {
        if (err) {
          return next(err);
        }
        docpad.log('debug', util.format(locale.wroteFiles, collection.length));
        return next();
      });
    });
    if (typeof opts.setProgressIndicator === "function") {
      opts.setProgressIndicator(function() {
        return ['writeFiles', tasks.completed, tasks.total];
      });
    }
    collection.forEach(function(file, index) {
      return tasks.push(function(complete) {
        var dynamic, relativePath, write;
        dynamic = file.get('dynamic');
        write = file.get('write');
        relativePath = file.get('relativePath');
        if (dynamic || ((write != null) && !write) || !relativePath) {
          return complete();
        } else if (file.writeRendered != null) {
          return file.writeRendered(complete);
        } else if (file.write != null) {
          return file.write(complete);
        } else {
          return complete(new Error(locale.unknownModelInCollection));
        }
      });
    });
    if (tasks.total) {
      docpad.emitSync('writeBefore', {
        collection: collection,
        templateData: templateData
      }, function(err) {
        if (err) {
          return next(err);
        }
        return tasks.async();
      });
    } else {
      tasks.exit();
    }
    return this;
  };

  DocPad.prototype.action = function(action, opts, next) {
    var actions, docpad, forward, locale, runner, tasks, _ref4,
      _this = this;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    runner = this.getRunner();
    locale = this.getLocale();
    actions = action.split(/[,\s]+/g);
    if (actions.length > 1) {
      tasks = new balUtil.Group(function(err) {
        return next(err);
      });
      _.each(actions, function(action) {
        return tasks.push(function(complete) {
          return docpad.action(action, opts, complete);
        });
      });
      tasks.sync();
      return docpad;
    }
    this.log('debug', util.format(locale.actionStart, action));
    if (next == null) {
      next = function(err) {
        if (err) {
          return docpad.fatal(err);
        }
      };
    }
    forward = function() {
      var args;
      args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
      _this.log('debug', util.format(locale.actionFinished, action));
      return balUtil.wait(0, function() {
        return next.apply(null, args);
      });
    };
    runner.pushAndRun(function(complete) {
      var fn;
      fn = docpad[action] || docpad.run;
      return fn(opts, function() {
        var args;
        args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
        forward.apply(null, args);
        return complete();
      });
    });
    return this;
  };

  DocPad.prototype.generatePrepare = function(opts, next) {
    var docpad, locale, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    docpad.log('info', locale.renderGenerating);
    docpad.notify((new Date()).toLocaleTimeString(), {
      title: locale.renderGeneratingNotification
    });
    docpad.emitSync('generateBefore', {
      server: docpad.getServer()
    }, function(err) {
      return next(err);
    });
    return this;
  };

  DocPad.prototype.generateCheck = function(opts, next) {
    var docpad, locale, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    if (!docpad.hasPlugins()) {
      docpad.log('warn', locale.renderNoPlugins);
    }
    balUtil.exists(docpad.config.srcPath, function(exists) {
      var err;
      if (exists === false) {
        err = new Error(locale.renderNonexistant);
        return next(err);
      } else {
        return next();
      }
    });
    return this;
  };

  DocPad.prototype.generateClean = function(opts, next) {
    var docpad, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    docpad.resetCollections(next);
    return this;
  };

  DocPad.prototype.generateParse = function(opts, next) {
    var config, database, docpad, locale, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    database = this.getDatabase();
    config = docpad.config;
    locale = this.getLocale();
    this.emitSync('parseBefore', {}, function(err) {
      var tasks;
      if (err) {
        return next(err);
      }
      docpad.log('debug', locale.renderParsing);
      tasks = new balUtil.Group(function(err) {
        if (err) {
          return next(err);
        }
        return docpad.emitSync('parseAfter', {}, function(err) {
          if (err) {
            return next(err);
          }
          docpad.log('debug', locale.renderParsed);
          return next(err);
        });
      });
      _.each(config.documentsPaths, function(documentsPath) {
        return tasks.push(function(complete) {
          return docpad.parseDirectory({
            path: documentsPath,
            collection: database,
            createFunction: docpad.createDocument
          }, complete);
        });
      });
      _.each(config.filesPaths, function(filesPath) {
        return tasks.push(function(complete) {
          return docpad.parseDirectory({
            path: filesPath,
            collection: database,
            createFunction: docpad.createFile
          }, complete);
        });
      });
      _.each(config.layoutsPaths, function(layoutsPath) {
        return tasks.push(function(complete) {
          return docpad.parseDirectory({
            path: layoutsPath,
            collection: database,
            createFunction: docpad.createDocument
          }, complete);
        });
      });
      return tasks.async();
    });
    return this;
  };

  DocPad.prototype.generateRender = function(opts, next) {
    var collection, docpad, setProgressIndicator, templateData, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    templateData = opts.templateData || this.getTemplateData();
    collection = opts.collection || this.getDatabase();
    setProgressIndicator = opts.setProgressIndicator || null;
    balUtil.flow({
      object: docpad,
      action: 'contextualizeFiles renderFiles renderFiles writeFiles',
      args: [
        {
          collection: collection,
          templateData: templateData,
          setProgressIndicator: setProgressIndicator
        }
      ],
      next: function(err) {
        return next(err);
      }
    });
    return this;
  };

  DocPad.prototype.generatePostpare = function(opts, next) {
    var docpad, locale, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    docpad.emitSync('generateAfter', {
      server: docpad.getServer()
    }, function(err) {
      var _ref5;
      if (err) {
        return next(err);
      }
      docpad.log('info', util.format(locale.renderGenerated, (_ref5 = opts.count) != null ? _ref5 : 'all'));
      docpad.notify((new Date()).toLocaleTimeString(), {
        title: locale.renderGeneratedNotification
      });
      return next();
    });
    return this;
  };

  DocPad.prototype.lastGenerate = null;

  DocPad.prototype.generate = function(opts, next) {
    var docpad, finish, locale, progressIndicator, progressInterval, showProgress, _ref4, _ref5;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    if ((_ref5 = docpad.lastGenerate) == null) {
      docpad.lastGenerate = new Date('1970');
    }
    locale = this.getLocale();
    progressIndicator = null;
    opts.setProgressIndicator = function(_progressIndicator) {
      return progressIndicator = _progressIndicator;
    };
    showProgress = function() {
      var completed, percent, progress, stage, total;
      progress = typeof progressIndicator === "function" ? progressIndicator() : void 0;
      if (progress) {
        stage = progress[0], completed = progress[1], total = progress[2];
        percent = Math.floor((completed / total) * 100) + '%';
        return docpad.log('info', util.format(locale.renderProgress, stage, percent));
      }
    };
    progressInterval = setInterval(showProgress, 10000);
    finish = function(err) {
      clearInterval(progressInterval);
      progressInterval = null;
      return next(err);
    };
    if ((opts.reset != null) && opts.reset === false) {
      docpad.generatePrepare(function(err) {
        var database, filesToReload;
        if (err) {
          return finish(err);
        }
        database = docpad.getDatabase();
        filesToReload = opts.filesToReload || new FilesCollection();
        filesToReload.add(database.findAll({
          mtime: {
            $gte: docpad.lastGenerate
          }
        }).models);
        docpad.lastGenerate = new Date();
        return docpad.loadFiles({
          collection: filesToReload
        }, function(err) {
          var allStandalone, filesToRender;
          if (err) {
            return finish(err);
          }
          filesToRender = opts.filesToRender || new FilesCollection();
          filesToRender.on('add', function(fileToRender) {
            if (fileToRender.get('isLayout')) {
              return filesToRender.add(database.findAll({
                layout: fileToRender.id
              }).models);
            }
          });
          allStandalone = true;
          filesToReload.forEach(function(fileToReload) {
            if (fileToReload.get('standalone') !== true) {
              allStandalone = false;
              return false;
            }
          });
          if (allStandalone === false) {
            filesToRender.add(database.findAll({
              referencesOthers: true
            }).models);
          }
          filesToRender.add(filesToReload.models);
          return docpad.generateRender({
            collection: filesToRender
          }, function(err) {
            if (err) {
              return finish(err);
            }
            return docpad.generatePostpare({
              count: filesToRender.length
            }, function(err) {
              return finish(err);
            });
          });
        });
      });
    } else {
      docpad.lastGenerate = new Date();
      balUtil.flow({
        object: docpad,
        action: 'generatePrepare generateCheck generateClean generateParse generateRender generatePostpare',
        args: [opts],
        next: function(err) {
          return finish(err);
        }
      });
    }
    return this;
  };

  DocPad.prototype.loadAndRenderDocument = function(document, opts, next) {
    balUtil.flow({
      object: document,
      action: 'load contextualize render',
      args: [opts],
      next: function(err) {
        var result;
        result = document.get('contentRendered');
        return next(err, result, document);
      }
    });
    return this;
  };

  DocPad.prototype.renderDocument = function(document, opts, next) {
    document.render(opts, next);
    return this;
  };

  DocPad.prototype.renderPath = function(path, opts, next) {
    var attributes, document;
    attributes = balUtil.extend({
      fullPath: path
    }, opts.attributes);
    document = this.ensureDocument(attributes);
    this.loadAndRenderDocument(document, opts, next);
    return this;
  };

  DocPad.prototype.renderData = function(content, opts, next) {
    var attributes, document;
    attributes = balUtil.extend({
      filename: opts.filename,
      data: content
    }, opts.attributes);
    document = this.createDocument(attributes);
    this.loadAndRenderDocument(document, opts, next);
    return this;
  };

  DocPad.prototype.renderText = function(text, opts, next) {
    var attributes, document, _ref4;
    attributes = balUtil.extend({
      filename: opts.filename,
      data: text,
      body: text,
      content: text
    }, opts.attributes);
    document = this.createDocument(attributes);
    if ((_ref4 = opts.actions) == null) {
      opts.actions = ['renderExtensions', 'renderDocument'];
    }
    balUtil.flow({
      object: document,
      action: 'normalize contextualize render',
      args: [opts],
      next: function(err) {
        var result;
        result = document.get('contentRendered');
        return next(err, result, document);
      }
    });
    return this;
  };

  DocPad.prototype.render = function(opts, next) {
    var err, locale, path, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    locale = this.getLocale();
    if (opts.document) {
      this.renderDocument(opts.document, opts, next);
    } else if (opts.data) {
      this.renderData(opts.data, opts, next);
    } else if (opts.text) {
      this.renderText(opts.text, opts, next);
    } else {
      path = opts.path || opts.fullPath || opts.filename || null;
      if (path) {
        this.renderPath(path, opts, next);
      } else {
        err = new Error(locale.renderInvalidOptions);
        return next(err);
      }
    }
    return this;
  };

  DocPad.prototype.watch = function(opts, next) {
    var changeHandler, closeWatchers, database, docpad, locale, performGenerate, queueRegeneration, regenerateDelay, regenerateTimer, resetWatchers, watchr, watchrs, _ref4;
    watchr = require('watchr');
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    locale = this.getLocale();
    database = this.getDatabase();
    watchrs = [];
    closeWatchers = function() {
      var _i, _len;
      for (_i = 0, _len = watchrs.length; _i < _len; _i++) {
        watchr = watchrs[_i];
        watchr.close();
        watchr = null;
      }
      return watchrs = [];
    };
    resetWatchers = function(next) {
      var tasks;
      closeWatchers();
      tasks = new balUtil.Group(next);
      tasks.total = 2;
      watchrs = watchr.watch({
        paths: docpad.config.configPaths,
        listener: function() {
          docpad.log('info', util.format(locale.watchConfigChange, new Date().toLocaleTimeString()));
          return docpad.action('load', function(err) {
            if (err) {
              return docpad.fatal(err);
            }
            return performGenerate({
              reset: true
            });
          });
        },
        next: tasks.completer()
      });
      return watchrs.push(watchr.watch({
        path: docpad.config.srcPath,
        listener: changeHandler,
        next: tasks.completer(),
        ignorePatterns: true
      }));
    };
    regenerateTimer = null;
    regenerateDelay = 100;
    queueRegeneration = function() {
      if (regenerateTimer) {
        clearTimeout(regenerateTimer);
        regenerateTimer = null;
      }
      return regenerateTimer = setTimeout(performGenerate, regenerateDelay);
    };
    performGenerate = function(opts) {
      var _ref5;
      opts || (opts = {});
      if ((_ref5 = opts.reset) == null) {
        opts.reset = false;
      }
      docpad.log(util.format(locale.watchRegenerating, new Date().toLocaleTimeString()));
      return docpad.action('generate', opts, function(err) {
        if (err) {
          docpad.error(err);
        }
        return docpad.log(util.format(locale.watchRegenerated, new Date().toLocaleTimeString()));
      });
    };
    changeHandler = function(eventName, filePath, fileCurrentStat, filePreviousStat) {
      var file;
      docpad.log('debug', util.format(locale.watchChange, new Date().toLocaleTimeString()), eventName, filePath);
      if (balUtil.commonIgnorePatterns.test(pathUtil.basename(filePath))) {
        docpad.log('debug', util.format(locale.watchIgnoredChange, new Date().toLocaleTimeString()), filePath);
        return;
      }
      if ((fileCurrentStat || filePreviousStat).isDirectory()) {
        docpad.log('debug', util.format(locale.watchDirectoryChange, new Date().toLocaleTimeString()), filePath);
        return;
      }
      file = docpad.ensureFileOrDocument({
        fullPath: filePath
      });
      if (eventName === 'unlink') {
        database.remove(file);
        queueRegeneration();
        return file["delete"](function(err) {
          if (err) {
            return docpad.error(err);
          }
        });
      } else if (eventName === 'new' || eventName === 'change') {
        file.setStat(fileCurrentStat);
        return queueRegeneration();
      }
    };
    docpad.log(locale.watchStart);
    resetWatchers(function(err) {
      docpad.log(locale.watchStarted);
      return next(err);
    });
    return this;
  };

  DocPad.prototype.run = function(opts, next) {
    var destinationPath, docpad, locale, runDocpad, srcPath, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    srcPath = this.config.srcPath;
    destinationPath = this.config.rootPath;
    locale = this.getLocale();
    runDocpad = function() {
      return balUtil.flow({
        object: docpad,
        action: 'generate server watch',
        args: [opts],
        next: function(err) {
          return next(err);
        }
      });
    };
    if (balUtil.existsSync(srcPath)) {
      runDocpad();
    } else {
      balUtil.readdir(destinationPath, function(err, files) {
        if (err) {
          return next(err);
        }
        if (files.length) {
          docpad.log('warn', "\n" + locale.skeletonNonexistant);
          return next();
        } else {
          return docpad.skeleton(opts, function(err) {
            if (err) {
              return next(err);
            }
            return runDocpad();
          });
        }
      });
    }
    return this;
  };

  DocPad.prototype.skeleton = function(opts, next) {
    var destinationPath, docpad, locale, selectSkeletonCallback, skeletonId, srcPath, useNoSkeleton, useSkeleton, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    skeletonId = this.config.skeleton;
    srcPath = this.config.srcPath;
    destinationPath = this.config.rootPath;
    selectSkeletonCallback = opts.selectSkeletonCallback || null;
    locale = this.getLocale();
    useSkeleton = function(skeletonModel) {
      docpad.log('info', util.format(locale.skeletonInstall, skeletonModel.get('name'), destinationPath));
      return docpad.installSkeleton(skeletonModel, destinationPath, function(err) {
        if (err) {
          return next(err);
        }
        return docpad.load(function(err) {
          if (err) {
            return next(err);
          }
          docpad.log('info', locale.skeletonInstalled);
          return next(err);
        });
      });
    };
    useNoSkeleton = function() {
      return balUtil.ensurePath(srcPath, function(err) {
        var tasks;
        if (err) {
          return next(err);
        }
        tasks = new balUtil.Group(next);
        tasks.total = 3;
        balUtil.ensurePath(docpad.config.documentsPaths[0], tasks.completer());
        balUtil.ensurePath(docpad.config.layoutsPaths[0], tasks.completer());
        return balUtil.ensurePath(docpad.config.filesPaths[0], tasks.completer());
      });
    };
    balUtil.exists(srcPath, function(exists) {
      if (exists) {
        docpad.log('warn', locale.skeletonExists);
        return next();
      }
      if (skeletonId) {
        return useSkeleton();
      } else {
        return docpad.getSkeletons(function(err, skeletonsCollection) {
          if (err) {
            return next(err);
          }
          return selectSkeletonCallback(skeletonsCollection, function(err, skeletonModel) {
            if (err) {
              return next(err);
            }
            if ((skeletonModel != null) === false || skeletonModel.id === 'none') {
              return useNoSkeleton();
            } else {
              return useSkeleton(skeletonModel);
            }
          });
        });
      }
    });
    return this;
  };

  DocPad.prototype.serveDocument = function(opts, next) {
    var content, contentType, docpad, document, dynamic, err, req, res, templateData, _ref4;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    document = opts.document, err = opts.err, req = opts.req, res = opts.res;
    docpad = this;
    if (!document) {
      if (opts.statusCode != null) {
        return res.send(opts.statusCode);
      } else {
        return next();
      }
    }
    contentType = document.get('outContentType') || document.get('contentType');
    res.setHeader('Content-Type', contentType);
    dynamic = document.get('dynamic');
    if (dynamic) {
      templateData = balUtil.extend({}, req.templateData || {}, {
        req: req,
        err: err
      });
      templateData = docpad.getTemplateData(templateData);
      document.render({
        templateData: templateData
      }, function(err) {
        var content;
        content = document.get('contentRendered') || document.get('content') || document.getData();
        if (err) {
          docpad.error(err);
          return next(err);
        } else {
          if (opts.statusCode != null) {
            return res.send(opts.statusCode, content);
          } else {
            return res.send(content);
          }
        }
      });
    } else {
      content = document.get('contentRendered') || document.get('content') || document.getData();
      if (content) {
        if (opts.statusCode != null) {
          return res.send(opts.statusCode, content);
        } else {
          return res.send(content);
        }
      } else {
        if (opts.statusCode != null) {
          return res.send(opts.statusCode);
        } else {
          return next();
        }
      }
    }
    return this;
  };

  DocPad.prototype.serverMiddlewareHeader = function(req, res, next) {
    var tools;
    tools = res.get('X-Powered-By').split(/[,\s]+/g);
    tools.push('DocPad');
    tools = tools.join(',');
    res.set('X-Powered-By', tools);
    return next();
  };

  DocPad.prototype.serverMiddlewareRouter = function(req, res, next) {
    var database, docpad, document, pageUrl, url;
    docpad = this;
    database = docpad.getDatabase();
    if (!database) {
      return next();
    }
    pageUrl = req.url.replace(/\?.*/, '');
    document = database.findOne({
      urls: {
        $has: pageUrl
      }
    });
    if (!document) {
      return next();
    }
    url = document.get('url');
    if (url !== pageUrl) {
      return res.redirect(301, url);
    }
    return docpad.serveDocument({
      document: document,
      req: req,
      res: res,
      next: next
    });
  };

  DocPad.prototype.serverMiddleware404 = function(req, res, next) {
    var database, docpad, document;
    docpad = this;
    database = docpad.getDatabase();
    if (!database) {
      return res.send(500);
    }
    document = database.findOne({
      relativeOutPath: '404.html'
    });
    return docpad.serveDocument({
      document: document,
      req: req,
      res: res,
      next: next,
      statusCode: 404
    });
  };

  DocPad.prototype.serverMiddleware500 = function(err, req, res, next) {
    var database, docpad, document;
    docpad = this;
    database = docpad.getDatabase();
    if (!database) {
      return res.send(500);
    }
    document = database.findOne({
      relativeOutPath: '500.html'
    });
    return docpad.serveDocument({
      document: document,
      err: err,
      req: req,
      res: res,
      next: next,
      statusCode: 500
    });
  };

  DocPad.prototype.server = function(opts, next) {
    var complete, config, docpad, express, http, locale, serverExpress, serverHttp, startServer, _ref10, _ref11, _ref12, _ref4, _ref5, _ref6, _ref7, _ref8, _ref9;
    http = null;
    express = null;
    _ref4 = balUtil.extractOptsAndCallback(opts, next), opts = _ref4[0], next = _ref4[1];
    docpad = this;
    config = this.config;
    locale = this.getLocale();
    serverExpress = null;
    serverHttp = null;
    if ((_ref5 = opts.middlewareBodyParser) == null) {
      opts.middlewareBodyParser = (_ref6 = config.middlewareBodyParser) != null ? _ref6 : config.middlewareStandard;
    }
    if ((_ref7 = opts.middlewareMethodOverride) == null) {
      opts.middlewareMethodOverride = (_ref8 = config.middlewareMethodOverride) != null ? _ref8 : config.middlewareStandard;
    }
    if ((_ref9 = opts.middlewareExpressRouter) == null) {
      opts.middlewareExpressRouter = (_ref10 = config.middlewareExpressRouter) != null ? _ref10 : config.middlewareStandard;
    }
    if ((_ref11 = opts.middleware404) == null) {
      opts.middleware404 = config.middleware404;
    }
    if ((_ref12 = opts.middleware500) == null) {
      opts.middleware500 = config.middleware500;
    }
    complete = function(err) {
      if (err) {
        return next(err);
      }
      return docpad.emitSync('serverAfter', {
        server: serverExpress,
        serverExpress: serverExpress,
        serverHttp: serverHttp,
        express: express
      }, function(err) {
        if (err) {
          return next(err);
        }
        docpad.log('debug', 'Server setup');
        return next();
      });
    };
    startServer = function() {
      var address, serverDir, serverHostname, serverLocation, serverPort;
      try {
        serverHttp.listen(config.port);
        address = serverHttp.address();
        if (address == null) {
          throw new Error(util.format(locale.serverInUse, config.port));
        }
        serverHostname = address.address === '0.0.0.0' ? 'localhost' : address.address;
        serverPort = address.port;
        serverLocation = "http://" + serverHostname + ":" + serverPort + "/";
        serverDir = config.outPath;
        return docpad.log('info', util.format(locale.serverStarted, serverLocation, serverDir));
      } catch (err) {
        return complete(err);
      } finally {
        return complete();
      }
    };
    docpad.emitSync('serverBefore', {}, function(err) {
      var _ref13;
      if (err) {
        return complete(err);
      }
      _ref13 = docpad.getServer(true), serverExpress = _ref13.serverExpress, serverHttp = _ref13.serverHttp;
      if (!serverExpress && !serverHttp) {
        if (http == null) {
          http = require('http');
        }
        if (express == null) {
          express = require('express');
        }
        serverExpress = opts.serverExpress || express();
        serverHttp = opts.serverHttp || http.createServer(serverExpress);
        docpad.setServer({
          serverExpress: serverExpress,
          serverHttp: serverHttp
        });
      }
      if (!config.extendServer) {
        return startServer();
      } else {
        if (express == null) {
          express = require('express');
        }
        if (opts.middlewareBodyParser !== false) {
          serverExpress.use(express.bodyParser());
        }
        if (opts.middlewareMethodOverride !== false) {
          serverExpress.use(express.methodOverride());
        }
        docpad.emitSync('serverExtend', {
          server: serverExpress,
          serverExpress: serverExpress,
          serverHttp: serverHttp,
          express: express
        }, function(err) {
          if (err) {
            return next(err);
          }
          serverExpress.use(docpad.serverMiddlewareHeader);
          if (opts.middlewareExpressRouter !== false) {
            serverExpress.use(serverExpress.router);
          }
          serverExpress.use(docpad.serverMiddlewareRouter);
          if (config.maxAge) {
            serverExpress.use(express["static"](config.outPath, {
              maxAge: config.maxAge
            }));
          } else {
            serverExpress.use(express["static"](config.outPath));
          }
          if (opts.middleware404 !== false) {
            serverExpress.use(docpad.serverMiddleware404);
          }
          if (opts.middleware500 !== false) {
            return serverExpress.error(docpad.serverMiddleware500);
          }
        });
        return startServer();
      }
    });
    return this;
  };

  return DocPad;

})(EventEmitterEnhanced);

module.exports = {
  DocPad: DocPad,
  queryEngine: queryEngine,
  Backbone: Backbone,
  createInstance: function() {
    var args;
    args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
    return (function(func, args, ctor) {
      ctor.prototype = func.prototype;
      var child = new ctor, result = func.apply(child, args), t = typeof result;
      return t == "object" || t == "function" ? result || child : child;
    })(DocPad, args, function(){});
  }
};
