// Simple implementation of dynamic scoping, for use in browsers

var nextSlot = 0;
var currentValues = [];

Meteor.EnvironmentVariable = function () {
  this.slot = nextSlot++;
};

var EVp = Meteor.EnvironmentVariable.prototype;

EVp.get = function () {
  return currentValues[this.slot];
};

EVp.getOrNullIfOutsideFiber = function () {
  return this.get();
};

EVp.withValue = function (value, func) {
  var saved = currentValues[this.slot];
  try {
    currentValues[this.slot] = value;
    var ret = func();
  } finally {
    currentValues[this.slot] = saved;
  }
  return ret;
};

Meteor.bindEnvironment = function (func, onException, _this) {
  // needed in order to be able to create closures inside func and
  // have the closed variables not change back to their original
  // values
  var boundValues = currentValues.slice();

  if (!onException || typeof(onException) === 'string') {
    var description = onException || "callback of async function";
    onException = function (error) {
      Meteor._debug(
        "Exception in " + description + ":",
        error && error.stack || error
      );
    };
  }

  return function (/* arguments */) {
    var savedValues = currentValues;
    try {
      currentValues = boundValues;
      var ret = func.apply(_this, arguments);
    } catch (e) {
      // note: callback-hook currently relies on the fact that if onException
      // throws in the browser, the wrapped call throws.
      onException(e);
    } finally {
      currentValues = savedValues;
    }
    return ret;
  };
};

Meteor._nodeCodeMustBeInFiber = function () {
  // no-op on browser
};


var getCordovaPluginsList = function(sand) {

var env = files.currentEnvWithPathsAdded(files.getCurrentNodeBinDir());

var lines = selftest.execFileSync('cordova', ['plugins'],

cwd: files.pathJoin(sand.cwd, '.meteor', 'local', 'cordova-build'),

keep keep keep keep replace keep keep keep keep

var lines = execFileSync('cordova', ['plugins'],


import { FinishedUpgraders } from '../project-context.js';

import { allUpgraders } from '../upgraders.js';

import { execFileSync } from '../utils/processes.js';

var selftest = require('../tool-testing/selftest.js');
var Sandbox = selftest.Sandbox;
var files = require('../fs/files.js');
var _ = require('underscore');

// Copy the contents of one file to another.  In these series of tests, we often
// want to switch contents of package.js files. It is more legible to copy in
// the backup file rather than trying to write into it manually.
//
// XXX: Surely there is a function for this in fs?
// XXX: In which case, perhaps move this to sandbox.
var copyFile = function(from, to, sand) {
  var contents = sand.read(from);
  if (!contents) {
    throw new Error("File " + from + " does not exist.");
  };
  sand.write(to, contents);
};

// Given a sandbox, that has the app as its currend cwd, read the versions file
// and read the plugins list.
//
// sand: a sandbox, that has the main app directory as its cwd.
var getCordovaPluginsList = function(sand) {
  var env = files.currentEnvWithPathsAdded(files.getCurrentNodeBinDir());
  env.METEOR_WAREHOUSE_DIR = sand.warehouse;

  var lines = selftest.execFileSync('cordova', ['plugins'],
    {
      cwd: files.pathJoin(sand.cwd, '.meteor', 'local', 'cordova-build'),
      env: env
    }).split("\n");
  if (lines[0].match(/No plugins/)) {
    lines = [];
  }
  lines.sort();
  return lines;
}

// Given a sandbox, that has the app as its currend cwd, read the versions file
// and check that it contains the plugins that we are looking for. We don't
// check the order, we just want to make sure that the right dependencies are
// in.
//
// sand: a sandbox, that has the main app directory as its cwd.
// plugins: an array of plugins in order.
var checkCordovaPlugins = selftest.markStack(function(sand, plugins) {
  var cordovaPlugins = getCordovaPluginsList(sand);

  plugins = _.clone(plugins).sort();

  var i = 0;
  _.each(cordovaPlugins, function(line) {
    if (!line || line === '') {
      return;
    }
    // XXX should check for the version as well?
    selftest.expectEqual(line.split(' ')[0], plugins[i]);
    i++;
  });
  selftest.expectEqual(plugins.length, i);
});

// Like the function above but only looks if a certain plugin is on the list
var checkCordovaPluginExists = selftest.markStack(function(sand, plugin) {
  var cordovaPlugins = getCordovaPluginsList(sand);
  var found = false;
  cordovaPlugins = cordovaPlugins.map(function (line) {
    if (line && line !== '') {
      return line.split(' ')[0];
    }
  });
  selftest.expectTrue(_.contains(cordovaPlugins, plugin));
});

// Given a sandbox, that has the app as its cwd, read the cordova plugins
// file and check that it contains exactly the plugins specified, in order.
//
// sand: a sandbox, that has the main app directory as its cwd.
// plugins: an array of plugins in order. Plugins can be of the form:
//
//    standard-app-plugins (ie: name), in which case this will match any
//    version of that plugin as long as it is included.
//
//    awesome-plugin@1.0.0 (ie: name@version) to match that name at that
//    version explicitly. This is for plugins that we included at a specific
//    version.
var checkUserPlugins = function(sand, plugins) {
  var lines = sand.read(".meteor/cordova-plugins").split("\n");
  var depend = {};
  _.each(lines, function(line) {
    if (!line) {
      return;
    }
    // plugins are stored of the form foo@1.0.0, so this should give us an
    // array [foo, 1.0.0].
    var split = line.split('@');
    var plugins = split[0];
    depend[plugins] = split[1];
  });
  var i = 0;

  _.each(plugins, function (plugins) {
    var split = plugins.split('@');
    if (split.length > 1) {
      selftest.expectEqual(depend[split[0]], split[1]);
    } else {
      var exists = _.has(depend, split[0]);
      selftest.expectEqual(exists, true);
    }
    i++;
  });
  selftest.expectEqual(plugins.length, i);
};

var startAppOnAndroidEmulator = function (s) {
  var run = s.run("run", "android");
  // Building and running the app on the Android Emulator can take a long time.
  run.waitSecs(60);
  run.match("Started app on Android Emulator");
  return run;
}

var addPlatform = function (s, platform) {
  var run = s.run("add-platform", "android");
  // Cordova may need to download cordova-android if it's not already
  // cached (in ~/.cordova).
  run.waitSecs(30);
  run.match("added platform");
}

// Add plugins to an app. Change the contents of the plugins and their
// dependencies, make sure that the app still refreshes.
selftest.define("change cordova plugins", ["cordova"], function () {
  var s = new Sandbox();
  var run;

  s.set("METEOR_WATCH_PRIORITIZE_CHANGED", "false");

  // Starting a run
  s.createApp("myapp", "package-tests");
  s.cd("myapp");
  run = s.run();
  run.match("myapp");
  run.match("proxy");
  run.waitSecs(30);
  run.match("MongoDB");
  run.match("your app");
  run.match("running at");
  run.match("localhost");

  // Add a local package contains-cordova-plugin.
  s.write(".meteor/packages", "meteor-base \n contains-cordova-plugin");
  run.match("restarted");

  // Change something in the plugin.
  s.cp('packages/contains-cordova-plugin/package2.js', 'packages/contains-cordova-plugin/package.js');
  run.match("restarted");

  // Introduce an error.
  s.cp('packages/contains-cordova-plugin/package3.js', 'packages/contains-cordova-plugin/package.js');
  run.match("valid version");

  // Fix the error.
  s.cp('packages/contains-cordova-plugin/package2.js', 'packages/contains-cordova-plugin/package.js');
  run.match("restarted");
});

// Add plugins through the command line, and make sure that the correct set of
// changes is reflected in .meteor/packages, .meteor/versions and list
selftest.define("add cordova plugins", ["slow", "cordova"], function () {
  var s = new Sandbox();
  var run;

  // Starting a run
  s.createApp("myapp", "package-tests");
  s.cd("myapp");
  s.set("METEOR_OFFLINE_CATALOG", "t");

  run = s.run("remove", "meteor-base");
  run.match("removed");

  run = s.run("run", "android");
  run.matchErr("Please add the Android platform to your project first");
  run.match("meteor add-platform ");

  run = addPlatform(s, 'android');

  run = s.run("add", "cordova:cordova-plugin-camera@1.2.0");
  run.match("Added Cordova plugin cordova-plugin-camera");
  run.expectExit(0);

  run = s.run("add", "cordova:cordova-plugin-file");
  run.matchErr("exact version");
  run.expectExit(1);

  // The current behavior doesn't fail if a plugin is not in the registry until
  // build time.
  run = s.run("add", "cordova:foo@1.0.0");
  run.match("Added Cordova plugin foo");
  run.expectExit(0);

  run = s.run("remove", "cordova:foo");
  run.match("Removed Cordova plugin foo");
  run.expectExit(0);

  checkUserPlugins(s, ["cordova-plugin-camera"]);

  run = s.run("add", "contains-cordova-plugin");
  run.match("added,");
  run.match("contains a cordova plugin");
  run.expectExit(0);

  checkUserPlugins(s, ["cordova-plugin-camera"]);

  run = s.run("list");
  run.match("cordova-plugin-camera");

  run = s.run("list-platforms");
  run.match("android");

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);

  checkCordovaPlugins(s, ["cordova-plugin-camera",
    "com.phonegap.plugins.facebookconnect"]);

  // Remove a plugin
  run = s.run("remove", "contains-cordova-plugin");
  run.match("removed");

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);

  run = s.run("remove", "cordova:cordova-plugin-camera");
  run.match("Removed");
  run.expectExit(0);

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);

  checkCordovaPlugins(s, []);

  run = s.run("add", "cordova:cordova-plugin-device@1.0.1");
  run.match("Added");
  run.expectExit(0);

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);
  checkCordovaPlugins(s, ["cordova-plugin-device"]);

  run = s.run("remove", "cordova:cordova-plugin-device");
  run.match("Removed");
  run.expectExit(0);

  run = s.run("add", "cordova:com.example.plugin@file://");
  run.matchErr("exact version");
  run.expectExit(1);

  run = s.run("add", "cordova:com.example.plugin@file://../../plugin_directory");
  run.match("Added Cordova plugin com.example.plugin");
  run.expectExit(0);

  checkUserPlugins(s, ["com.example.plugin"]);

  // This should fail beacuse the plugin does not exists at the specified path
  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(30);
  run.expectExit(1);

  checkCordovaPlugins(s, []);

  // Add a package with Cordova.depends with local plugin (added from path)
  run = s.run("add", "empty-cordova-plugin");
  run.match("added,");
  run.match("contains an empty cordova plugin");
  run.expectExit(0);
});

selftest.define("remove cordova plugins", ['cordova'], function () {
  var s = new Sandbox();
  var run;

  s.createApp("myapp", "package-tests");
  s.cd("myapp");
  run = s.run("add", "cordova:cordova-plugin-camera@0.3.0");
  run.expectExit(0);

  checkUserPlugins(s, ["cordova-plugin-camera"]);

  // Removing a plugin that hasn't been added should say that it isn't
  // in this project.
  run = s.run("remove", "cordova:blahblah");
  run.matchErr("not in this project");
  run.forbidAll("Removed");
  run.expectExit(1);

  run = s.run("remove", "cordova:blahblah",
              "cordova:cordova-plugin-camera");
  run.matchErr("not in this project");
  run.match("Removed");
  run.expectExit(1);
  checkUserPlugins(s, []);

  run = s.run("add", "cordova:com.example.plugin@file://../../plugin_directory");
  run.match("Added Cordova plugin com.example.plugin");
  run.expectExit(0);
  checkUserPlugins(s, ["com.example.plugin"]);

  run = s.run("remove", "cordova:com.example.plugin");
  run.match("Removed");
  run.expectExit(0);
  checkUserPlugins(s, []);

});

selftest.define("meteor exits when cordova platforms it is currently running \
are removed", ["slow", "cordova"], function () {
  var s = new Sandbox();
  var run;

  s.createApp("myapp", "package-tests");
  s.cd("myapp");

  addPlatform(s, "android");

  run = startAppOnAndroidEmulator(s);

  // Remove a platform via command line
  platformRun = s.run("remove-platform", "android");
  platformRun.match("removed platform");

  run.waitSecs(60);
  run.matchErr("Your app's platforms have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  addPlatform(s, "android");

  // Remove a platform in .meteor/platforms
  run = startAppOnAndroidEmulator(s);

  platforms = s.read(files.pathJoin(".meteor", "platforms"));
  platforms = platforms.replace(/android/g, "");
  s.write(files.pathJoin(".meteor", "platforms"), platforms);

  run.waitSecs(60);
  run.matchErr("Your app's platforms have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);
});

selftest.define("meteor reinstalls only local cordova plugins on consecutive builds/runs", ["slow", "cordova"], function () {
  var s = new Sandbox();
  var run;

  s.createApp("myapp", "package-tests");
  s.cd("myapp");

  run = addPlatform(s, 'android');

  var
    pluginPath          = '../cordova-local-plugin',
    pluginSource        = "packages/empty-cordova-plugin/plugin",
    androidPluginSource = ".meteor/local/cordova-build/platforms/android/src";

  // Copy fake cordova plugin to ../cordova-local-plugin
  s.mkdir(pluginPath);
  s.cp(pluginSource + '/plugin.xml', pluginPath + '/plugin.xml');
  s.mkdir(pluginPath + '/www');
  s.mkdir(pluginPath + '/src');
  s.mkdir(pluginPath + '/src/android');
  s.cp(pluginSource + '/www/Empty.js', pluginPath +'/www/Empty.js');
  s.cp(
    pluginSource + '/src/android/Empty.java',
    pluginPath + '/src/android/Empty.java'
  );

  // Add the local cordova plugin
  run = s.run("add", "cordova:com.cordova.empty@file://../cordova-local-plugin");
  run.match("Added Cordova plugin com.cordova.empty");
  run.expectExit(0);

  checkUserPlugins(s, ["com.cordova.empty"]);

  // Run meteor and check if the cordova android build have the plugin file.
  run = startAppOnAndroidEmulator(s);
  run.stop();

  selftest.expectTrue(
    s.read(
      androidPluginSource + "/com/cordova/empty/Empty.java"
    ).indexOf('change') === -1
  );
  selftest.expectTrue(
    s.read(
      androidPluginSource + "/com/cordova/empty/Empty.java"
    ).indexOf('CordovaPlugin') > -1
  );

  // Copy changed file to the plugin
  s.cp(
    pluginSource + '/src/android/Empty_changed.java',
    pluginPath + '/src/android/Empty.java'
  );

  // Check if the local plugin will be refreshed
  run = startAppOnAndroidEmulator(s);
  run.stop();

  selftest.expectTrue(
    s.read(
      androidPluginSource + "/com/cordova/empty/Empty.java"
    ).indexOf('change') > -1
  );

  // Now test the same scenario but with builds
  s.cp(
    pluginSource + '/src/android/Empty.java',
    pluginPath + '/src/android/Empty.java'
  );

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);

  selftest.expectTrue(
    s.read(
      '../a/android/project/src/com/cordova/empty/Empty.java'
    ).indexOf('change') === -1
  );

  checkCordovaPluginExists(s, "com.cordova.empty");

  s.cp(
    pluginSource + '/src/android/Empty_changed.java',
    pluginPath + '/src/android/Empty.java'
  );

  run = s.run("build", '../a', "--server", "localhost:3000");
  run.waitSecs(60);
  run.expectExit(0);

  selftest.expectTrue(
    s.read(
      '../a/android/project/src/com/cordova/empty/Empty.java'
    ).indexOf('change') > -1
  );
});

selftest.define("meteor exits when cordova plugins change", ["slow", "cordova"], function () {
  var s = new Sandbox();
  var run;

  s.createApp("myapp", "package-tests");
  s.cd("myapp");

  addPlatform(s, "android");

  run = startAppOnAndroidEmulator(s);

  // First add a plugin directly.
  var pluginRun = s.run("add", "cordova:cordova-plugin-camera@1.0.0");
  pluginRun.expectExit(0);

  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  run = startAppOnAndroidEmulator(s);

  // This shouldn't cause an exit because it contains the same plugin
  // that we're already using.
  pluginRun = s.run("add", "contains-old-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.match("restarted");

  pluginRun = s.run("remove", "contains-old-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.match("restarted");

  // This exits because it contains a new plugin, facebookconnect.
  pluginRun = s.run("add", "contains-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  run = startAppOnAndroidEmulator(s);

  pluginRun = s.run("remove", "contains-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  run = startAppOnAndroidEmulator(s);

  pluginRun = s.run("remove", "cordova:cordova-plugin-camera");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  // Adding and removing just a Meteor package that contains plugins
  // should also cause the tool to exit.
  run = startAppOnAndroidEmulator(s);

  pluginRun = s.run("add", "contains-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  run = startAppOnAndroidEmulator(s);

  pluginRun = s.run("remove", "contains-cordova-plugin");
  pluginRun.expectExit(0);
  run.waitSecs(60);
  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);

  // Adding a package with a newer version of a plugin that we're
  // already using should also cause us to restart.
  pluginRun = s.run("add", "contains-old-cordova-plugin");
  pluginRun.expectExit(0);

  run = startAppOnAndroidEmulator(s);

  pluginRun = s.run("add", "contains-camera-cordova-plugin");
  pluginRun.expectExit(0);

  run.matchErr("Your app's Cordova plugins have changed");
  run.matchErr("Restart meteor");
  run.expectExit(254);
});

var buildAndCheckPluginInStar = selftest.markStack(function (s, name, version) {
  var run = s.run(
    "build", '../a', "--server", "localhost:3000", "--directory");
  run.waitSecs(60);
  run.expectExit(0);

  var starJson = JSON.parse(s.read('../a/bundle/star.json'));
  var program = _.findWhere(starJson.programs, { name: "web.cordova" });
  if (! program) {
    selftest.fail("No cordova program in star.json?");
    return;
  }
  var plugins = program.cordovaDependencies;
  selftest.expectEqual(plugins[name], version);
});

selftest.define("cordova plugins in star.json, direct and transitive", ["slow", "cordova"], function () {
  var s = new Sandbox();
  var run;

  // Starting a run
  s.createApp("myapp", "package-tests");
  s.cd("myapp");
  s.set("METEOR_OFFLINE_CATALOG", "t");

  run = addPlatform(s, 'android');

  // Add a direct dependency: it should appear in star.json after we
  // build.
  run = s.run("add", "cordova:cordova-plugin-camera@1.0.0");
  run.expectExit(0);

  buildAndCheckPluginInStar(s, "cordova-plugin-camera", "1.0.0");

  // Add a Cordova dependency from a package, at a newer version: the
  // plugin should appear in star.json at the version added in the
  // direct dependency, even though it's older than the version that the
  // package uses.
  run = s.run("add", "contains-camera-cordova-plugin");
  run.expectExit(0);

  buildAndCheckPluginInStar(s, "cordova-plugin-camera", "1.0.0");

  // After removing the direct dependency, star.json should contain
  // camera@1.2.0, the version used by the package.
  run = s.run("remove", "cordova:cordova-plugin-camera");
  run.expectExit(0);

  buildAndCheckPluginInStar(s, "cordova-plugin-camera", "1.2.0");

  // If we add another package that uses an older version of the plugin,
  // the version in star.json shouldn't change.
  run = s.run("add", "contains-old-cordova-plugin");
  run.expectExit(0);

  buildAndCheckPluginInStar(s, "cordova-plugin-camera", "1.2.0");

  // If we remove the package that uses a newer version, the version in
  // star.json should change.
  run = s.run("remove", "contains-camera-cordova-plugin");
  run.expectExit(0);

  buildAndCheckPluginInStar(s, "cordova-plugin-camera", "1.0.0");
});


# ddp-common
[Source code of released version](https://github.com/meteor/meteor/tree/master/packages/ddp-common) | [Source code of development version](https://github.com/meteor/meteor/tree/devel/packages/ddp-common)
***


var autoupdateVersionCordova = __meteor_runtime_config__.autoupdateVersionCordova || "unknown";

// The collection of acceptable client versions.
ClientVersions = new Mongo.Collection("meteor_autoupdate_clientVersions");

Autoupdate = {};

Autoupdate.newClientAvailable = function() {
  return !! ClientVersions.findOne({
    _id: 'version-cordova',
    version: {$ne: autoupdateVersionCordova}
  });
};

var retry = new Retry({
  // Unlike the stream reconnect use of Retry, which we want to be instant
  // in normal operation, this is a wacky failure. We don't want to retry
  // right away, we can start slowly.
  //
  // A better way than timeconstants here might be to use the knowledge
  // of when we reconnect to help trigger these retries. Typically, the
  // server fixing code will result in a restart and reconnect, but
  // potentially the subscription could have a transient error.
  minCount: 0, // don't do any immediate retries
  baseTimeout: 30*1000 // start with 30s
});
var failures = 0;

Autoupdate._retrySubscription = function() {
  var appId = __meteor_runtime_config__.appId;
  Meteor.subscribe("meteor_autoupdate_clientVersions", appId, {
    onError: function(error) {
      console.log("autoupdate subscription failed:", error);
      failures++;
      retry.retryLater(failures, function() {
        // Just retry making the subscription, don't reload the whole
        // page. While reloading would catch more cases (for example,
        // the server went back a version and is now doing old-style hot
        // code push), it would also be more prone to reload loops,
        // which look really bad to the user. Just retrying the
        // subscription over DDP means it is at least possible to fix by
        // updating the server.
        Autoupdate._retrySubscription();
      });
    },
    onReady: function() {
      if (Package.reload) {
        var checkNewVersionDocument = function(doc) {
          var self = this;
          if (doc.version !== autoupdateVersionCordova) {
            newVersionAvailable();
          }
        };

        var handle = ClientVersions.find({_id: 'version-cordova'}).observe({
          added: checkNewVersionDocument,
          changed: checkNewVersionDocument
        });
      }
    }
  });
};

Meteor.startup(function() {
  WebAppLocalServer.onNewVersionReady(function() {
    if (Package.reload) {
      Package.reload.Reload._reload();
    }
  });

  Autoupdate._retrySubscription();
});

var newVersionAvailable = function() {
  WebAppLocalServer.checkForUpdates();
}


filename = filename.replace('./core/client/tpl/', '');

keep keep keep keep keep replace keep keep keep keep keep

filename = filename.replace('core/client/tpl/', '');

{{!< default}}

Settings

General

Content

General

                <button class="button-save">Save</button>

            {{#with settings}}
            <form id="settings-general">
                <fieldset>

                        Blog Title
                        <input id="blog-title" type="text" value="{{title}}" />

How your blog name appears on the site

                        Blog Logo

Display a logo on your site in place of blog title

                        Blog Icon

The icon for your blog, used in your browser tab and elsewhere

                        Email Address
                        <input id="email-address" type="text" value="{{email}}" />

Address to use for admin notifications

                            <input type="checkbox" value="1" /> Show my email address on my public profile

                        URL Structure
                        <select id="url-structure" name="general[urlstructure]">
                            <option value="post-name">Simple Post Name</option>
                            <option value="date-based">Date Based</option>
                            <option value="number based">Number Based</option>
                            <option value="custom">Custom...</option>
                        </select>

                </fieldset>

                <fieldset>

                        Time Zone
                        <select id="url-structure" name="general[timezone]">
                            <option value="1">Vienna (UTC+1)</option>
                        </select>

                </fieldset>

            {{/with}}
            </form>

Content

                <button class="button-save">Save</button>

            <form id="settings-general">
                <fieldset>

                        Typography
                        <select id="url-structure" name="general[urlstructure]">
                            <option value="post-name">Lato (Light)</option>
                        </select>

Sexy sans-serif font that will make your toes tickle.

                            <input type="checkbox" value="1" /> Load fonts directly from Google

                        Post Options

                            <input type="checkbox" value="1" /> Display Post Meta

Post Author / Date / Views

                            <input type="checkbox" value="1" /> Show Author Box After Post

                            <input type="checkbox" value="1" /> Enable Comments

                </fieldset>

                <fieldset>

                        SEO Title Pattern
                        <input id="seo-title" type="text" value="[Post Name] - [Site Title]" />

The pattern used to display your title tags

                        SEO Description Pattern
                        <input id="seo-description" type="text" value="Auto" />

The pattern used to display your meta descriptions

                        Google+

                            <input type="checkbox" value="1" /> Connect to author profile on Google

                        Home Page Description
                        <textarea id="blog-description"></textarea>

Display a logo on your site in place of blog title

                </fieldset>

            </form>

Users

                <button class="button-add">New User</button>

Invited Users

Some Name

                            Invitation Sent: 7 hours ago

Active Users

                    <form class="user-search">

                            <input class="user-search-input" type="text"/>

                    </form>

Some Name

                            Last Seen: 7 hours ago

                        Admin

Some Name

                            Last Seen: 2 days ago

                        Editor

Appearance

Raw json be here

Active theme: {{json settings.activeTheme}}

Available themes: {{json availableThemes}}

Available plugins: {{json availablePlugins}}


var User = require('./user').User,
    Permission = require('./permission').Permission,
    GhostBookshelf = require('./base'),
    Role,
    Roles;

Role = GhostBookshelf.Model.extend({
    tableName: 'roles',

    users: function () {
        return this.belongsToMany(User);
    },

    permissions: function () {
        return this.belongsToMany(Permission);
    }
});

Roles = GhostBookshelf.Collection.extend({
    model: Role
});

module.exports = {
    Role: Role,
    Roles: Roles
};


/*globals Handlebars, moment
*/
(function () {
    "use strict";
    Handlebars.registerHelper('dateFormat', function (context, block) {
        var f = block.hash.format || "MMM Do, YYYY",
            timeago = block.hash.timeago,
            date;
        if (timeago) {
            date = moment(context).fromNow();
        } else {
            date = moment(context).format(f);
        }
        return date;
    });
}());


<!doctype html>

  <meta charset="utf-8">

  <title>Ghost</title>

  <meta name="description" content="">
  <meta name="author" content="">

  <meta name="HandheldFriendly" content="True">
  <meta name="MobileOptimized" content="320">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <link rel="stylesheet" href="../core/admin/assets/css/screen.css">

  <link rel="shortcut icon" href="/favicon.ico">
  <link rel="logo" type="image/svg" href="assets/images/logo.svg"/>
  <meta http-equiv="cleartype" content="on">

    Ghost

Dashboard

Blog

Pages

Settings

                    John O'Nolan

Your Profile

Help / Support

Keyboard Shortcuts

Sign Out

        Blog Posts Search

Ut Enim ad Minim Veniam Quis Nostrud

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

              <time datetime="2013-01-04" class="date">Today</time>
              News, Category
              1,934

        Published + Featured

Edit

View

Delete

Ut Enim ad Minim Veniam Quis Nostrud Exercitation Ullamco

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu.

This is a Heading 2

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim.

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

This is a Heading 3

Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet

Lorem ipsum dolor sit amet


<img src="/core/client/assets/img/logo.png" alt="logo" height="38" width="381"/>

Display a logo on your site in place of blog title

keep keep keep replace keep keep keep keep keep

<img src="/public/img/logo.png" alt="logo" height="38" width="381"/>


/*! normalize.css v2.1.0 | MIT License | git.io/normalize */

/* ==========================================================================
   HTML5 display definitions
   ========================================================================== */

/**
 * Correct `block` display not defined in IE 8/9.
 */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
nav,
section,
summary {
    display: block;
}

/**
 * Correct `inline-block` display not defined in IE 8/9.
 */

audio,
canvas,
video {
    display: inline-block;
}

/**
 * Prevent modern browsers from displaying `audio` without controls.
 * Remove excess height in iOS 5 devices.
 */

audio:not([controls]) {
    display: none;
    height: 0;
}

/**
 * Address styling not present in IE 8/9.
 */

[hidden] {
    display: none;
}

/* ==========================================================================
   Base
   ========================================================================== */

/**
 * 1. Set default font family to sans-serif.
 * 2. Prevent iOS text size adjust after orientation change, without disabling
 *    user zoom.
 */

html {
    font-family: sans-serif; /* 1 */
    -webkit-text-size-adjust: 100%; /* 2 */
    -ms-text-size-adjust: 100%; /* 2 */
}

/**
 * Remove default margin.
 */

body {
    margin: 0;
}

/* ==========================================================================
   Links
   ========================================================================== */

/**
 * Address `outline` inconsistency between Chrome and other browsers.
 */

a:focus {
    outline: thin dotted;
}

/**
 * Improve readability when focused and also mouse hovered in all browsers.
 */

a:active,
a:hover {
    outline: 0;
}

/* ==========================================================================
   Typography
   ========================================================================== */

/**
 * Address variable `h1` font-size and margin within `section` and `article`
 * contexts in Firefox 4+, Safari 5, and Chrome.
 */

h1 {
    font-size: 2em;
    margin: 0.67em 0;
}

/**
 * Address styling not present in IE 8/9, Safari 5, and Chrome.
 */

abbr[title] {
    border-bottom: 1px dotted;
}

/**
 * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
 */

b,
strong {
    font-weight: bold;
}

/**
 * Address styling not present in Safari 5 and Chrome.
 */

dfn {
    font-style: italic;
}

/**
 * Address differences between Firefox and other browsers.
 */

hr {
    -moz-box-sizing: content-box;
    box-sizing: content-box;
    height: 0;
}

/**
 * Address styling not present in IE 8/9.
 */

mark {
    background: #ff0;
    color: #000;
}

/**
 * Correct font family set oddly in Safari 5 and Chrome.
 */

code,
kbd,
pre,
samp {
    font-family: monospace, serif;
    font-size: 1em;
}

/**
 * Improve readability of pre-formatted text in all browsers.
 */

pre {
    white-space: pre-wrap;
}

/**
 * Set consistent quote types.
 */

q {
    quotes: "\201C" "\201D" "\2018" "\2019";
}

/**
 * Address inconsistent and variable font size in all browsers.
 */

small {
    font-size: 80%;
}

/**
 * Prevent `sub` and `sup` affecting `line-height` in all browsers.
 */

sub,
sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

/* ==========================================================================
   Embedded content
   ========================================================================== */

/**
 * Remove border when inside `a` element in IE 8/9.
 */

img {
    border: 0;
}

/**
 * Correct overflow displayed oddly in IE 9.
 */

svg:not(:root) {
    overflow: hidden;
}

/* ==========================================================================
   Figures
   ========================================================================== */

/**
 * Address margin not present in IE 8/9 and Safari 5.
 */

figure {
    margin: 0;
}

/* ==========================================================================
   Forms
   ========================================================================== */

/**
 * Define consistent border, margin, and padding.
 */

fieldset {
    border: 1px solid #c0c0c0;
    margin: 0 2px;
    padding: 0.35em 0.625em 0.75em;
}

/**
 * 1. Correct `color` not being inherited in IE 8/9.
 * 2. Remove padding so people aren't caught out if they zero out fieldsets.
 */

legend {
    border: 0; /* 1 */
    padding: 0; /* 2 */
}

/**
 * 1. Correct font family not being inherited in all browsers.
 * 2. Correct font size not being inherited in all browsers.
 * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome.
 */

button,
input,
select,
textarea {
    font-family: inherit; /* 1 */
    font-size: 100%; /* 2 */
    margin: 0; /* 3 */
}

/**
 * Address Firefox 4+ setting `line-height` on `input` using `!important` in
 * the UA stylesheet.
 */

button,
input {
    line-height: normal;
}

/**
 * Address inconsistent `text-transform` inheritance for `button` and `select`.
 * All other form control elements do not inherit `text-transform` values.
 * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
 * Correct `select` style inheritance in Firefox 4+ and Opera.
 */

button,
select {
    text-transform: none;
}

/**
 * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
 *    and `video` controls.
 * 2. Correct inability to style clickable `input` types in iOS.
 * 3. Improve usability and consistency of cursor style between image-type
 *    `input` and others.
 */

button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
    -webkit-appearance: button; /* 2 */
    cursor: pointer; /* 3 */
}

/**
 * Re-set default cursor for disabled elements.
 */

button[disabled],
html input[disabled] {
    cursor: default;
}

/**
 * 1. Address box sizing set to `content-box` in IE 8/9.
 * 2. Remove excess padding in IE 8/9.
 */

input[type="checkbox"],
input[type="radio"] {
    box-sizing: border-box; /* 1 */
    padding: 0; /* 2 */
}

/**
 * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome.
 * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome
 *    (include `-moz` to future-proof).
 */

input[type="search"] {
    -webkit-appearance: textfield; /* 1 */
    -moz-box-sizing: content-box;
    -webkit-box-sizing: content-box; /* 2 */
    box-sizing: content-box;
}

/**
 * Remove inner padding and search cancel button in Safari 5 and Chrome
 * on OS X.
 */

input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
    -webkit-appearance: none;
}

/**
 * Remove inner padding and border in Firefox 4+.
 */

button::-moz-focus-inner,
input::-moz-focus-inner {
    border: 0;
    padding: 0;
}

/**
 * 1. Remove default vertical scrollbar in IE 8/9.
 * 2. Improve readability and alignment in all browsers.
 */

textarea {
    overflow: auto; /* 1 */
    vertical-align: top; /* 2 */
}

/* ==========================================================================
   Tables
   ========================================================================== */

/**
 * Remove most spacing between table cells.
 */

table {
    border-collapse: collapse;
    border-spacing: 0;
}


/*
 * These are the styles used to control the look and feel of the widgetised
 * dashboard of the Ghost admin system. The first screen you see on login.
 *
 * Table of Contents:
 * Widget Base
 * Widget Sizes
 * Widget Variations
 * Individual Widgets
 *  Clock / Date
 *  Ghost Image
 *  Unique Visitors
 *  Facebook Likes
 *  Google Plus
 *  Twitter
 *  Campaign Monitor
 *  Upcoming Posts
 *  Most Popular Posts
 *  Posts This Week
 *  Instagram
 *  RSS
 *  Klout
 *  Bounce Rate
 *  Average time On Site
 *  Last.Fm
 *  Post Ideas
 *  Tweets
 *  Backups
 */

/* ==========================================================================
   Widget Base
   ========================================================================== */

%widget, .widget  {
  width: 340px;
  height: 300px;
  float:left;
  position:relative;
  background-color:#fff;
  box-shadow: $shadow;

  .widget-content {
    @include box-sizing(border-box);
    margin-bottom: 40px;
    padding: 20px;
  }

  .widget-footer, .widget-header {
    @include box-sizing(border-box);
    width: 100%;
    height: 40px;
    font-size: 1.2em;
    color: $midbrown;
    border-top: 1px solid $lightbrown;

    .widget-title {
      display: inline-block;
      padding-top: 7px;
      padding-left: 15px;
      vertical-align: middle;
      text-transform: uppercase;
    }
  }

  .widget-settings-toggle {
    @include box-sizing(border-box);
    display: block;
    height: 39px;
    width: 46px;
    float: right;
    padding: 7px 14px;
    border-left: 1px solid $lightbrown;
    cursor: pointer;
    @include icon($i-settings, 1em);
  }

  .widget-footer {
    position: absolute;
    bottom: 0;
  }
}

.ui-draggable-dragging {
  z-index: 9999; // Keep dragged Widget ontop
}

/* ==========================================================================
   Widget Sizes
   ========================================================================== */

.widget-1x2  {
  height: 610px;
}

.widget-2x2  {
  width: 690px;
  height: 610px;
}

.widget-2x1  {
  width: 690px;
}

/* ==========================================================================
   Widget Variations
   ========================================================================== */

/* ==========================================================================
   Number Widgets base styles
   ========================================================================== */

%widget-number, .widget-number {
  @extend %widget;

  .widget-content {
    .info {
      margin-top: 30px;

      .count {
        display: block;
        font-size: 5em;
        line-height: 1em;
        font-weight: 400;
        color: $darkgrey;
      }

      .sub {
        font-size: 2em;
        color: #9b9b9b;

        mark {
          background-color: transparent;
          font-weight: bold;

          &.up {
            color: $green;
          }
          &.down {
            color: $red;
          }
        }
      }
    }
  } // .widget-content

  &.widget-2x2  {
    .widget-content {
      .info {
        margin-top: 100px;

        .count {
          font-size: 9em;
        }

        .sub {
          font-size: 2.5em;
        }
      }
    }
  }
} // %widget-number, .widget-number

/* ==========================================================================
   Settings panel base styles
   ========================================================================== */

.widget-settings {
  @extend %widget;
  background-color: #2d3032;

  .widget-header {
    height: 40px;
    border-top: none;
    border-bottom: 1px solid #4a4a4a;
    color: $midgrey;
  }

  .widget-content {
    padding: 0;
  }

  label {
    width:100%;
    height: 40px;
    display: block;
    border-bottom: 1px solid #4a4a4a;
    font-size: 1.2em;
  }

  .title {
    @include box-sizing(border-box);
    display: inline-block;
    width: 100px;
    height: 100%;
    padding: 8px;
    color: #E3EDF2;
    text-transform: uppercase;
    text-align: right;
  }

  input[type="text"] {
    @include box-sizing(border-box);
    height: 100%;
    padding: 8px;
    color: $midgrey;
    text-transform: none;
    background: none;
    border: none;
    border-left: 1px solid #4a4a4a;
  }

  .widget-footer, .widget-header {
    border-color: #4a4a4a;
  }

  .widget-size-options {
    display: inline-block;
    height: 100%;
    padding-top: 10px;
    padding-left: 10px;

    .size-options-container {
      @include box-sizing(border-box);
      display: inline-block;
      width: 20px;
      height: 20px;
      padding: 3px;
      cursor: pointer;

    }

    .mini-widget {
      background: $midgrey;
      margin: 1px;
      float: left;

      &.active {
        background: #ffffff;
      }
    }

    .size-1x1 {
      width: 5px;
      height: 5px;
    }
    .size-2x1 {
      width: 12px;
      height: 5px;
    }
    .size-1x2 {
      width: 5px;
      height: 12px;
    }
    .size-2x2 {
      width: 12px;
      height: 12px;
    }

    .active {
      background: #171819;
    }
  } // .widget-size-options

  .widget-settings-toggle {
    border-color: #4a4a4a;

    &.close {
      @include icon($i-x, 1em);
    }
    &.done {
      background-color: $green;
      color: rgba(255,255,255,0.7);
      @include icon($i-check, 1em);
    }
  }

} // .widget-settings

/* ==========================================================================
   Individual Widgets
   ========================================================================== */

/* ==========================================================================
   Clock / Date
   ========================================================================== */

.widget-time  {
  @extend %widget;

  .summary {
    margin-bottom: 30px;
    font-size: 1.4em;
    color: #9b9b9b;

    .day {
      float: left;
    }
    .weather {
      float: right;
      @include icon-after($i-weather-sun);
    }

  }

  time {
    margin-top: 30px;

    .clock {
      display: block;
      font-size: 5em;
      line-height: 1em;
      font-weight: 400;
      color: $darkgrey;
    }

    .date {
      font-size: 2em;
      color: #9b9b9b;
    }
  }
} // .widget-time

/* ==========================================================================
   Ghost Image
   ========================================================================== */

.widget-image  {
  @extend %widget;

  .widget-content {
    height: 100%;
    background-image: url(../img/dash/Image@2x.png);
    background-size: 100% 100%;
  }

  .widget-footer {
    margin-top: -40px;
    opacity: 0;
    background: #ffffff;
    @include transition(opacity 200ms linear);
  }

  &:hover {
    .widget-footer {
      opacity: 1;
    }
  }

  &.widget-settings {
      .widget-content {
          background-image: none;
      }
      .widget-footer {
          background: inherit;
          opacity: 1;
      }
  }

} // .widget-image

/* ==========================================================================
   Unique Visitors
   ========================================================================== */

.widget-stats  {
  @extend %widget-number;
}

/* ==========================================================================
   Facebook Likes
   ========================================================================== */

.widget-facebook  {
  @extend %widget-number;

  .info {
    .faces {
      display: block;
      width: 100%;
      height: 30px;
      margin-top: 25px;
      background-image: url("../img/dash/Facebook_Images@2x.png");
      background-size: 100% 100%;
    }
  }
}

/* ==========================================================================
   Google Plus
   ========================================================================== */

.widget-gplus  {
  @extend %widget-number;
}

/* ==========================================================================
   Twitter
   ========================================================================== */

.widget-twitter  {
  @extend %widget;
}

/* ==========================================================================
   Campaign Monitor
   ========================================================================== */

.widget-campaignmonitor  {
  @extend %widget-number;
}

/* ==========================================================================
   Upcoming Posts
   ========================================================================== */

.widget-posts  {
  @extend %widget;
  position: relative;

  .chart  {
    @include box-sizing(border-box);
    width: 250px;
    height: 250px;
    position: relative;
    z-index: 1;
    margin: 0 auto;
    background: #242628;
    border: #efefef 54px solid;
    border-radius: 250px;

    .sheen { // Bourbon gradient mixin not appropriate for this use-case.
      width: 71px;
      height: 142px;
      position: absolute;
      top: 0;
      background-image: -webkit-gradient(linear, left bottom, right top, from(rgba(251, 255, 242, 0.00)), to(rgba(254, 253, 255, 1.00)));
      background-image: -webkit-linear-gradient(left bottom, rgba(251, 255, 242, 0.00), rgba(254, 253, 255, 1.00));
      background-image: -moz-linear-gradient(left bottom, rgba(251, 255, 242, 0.00), rgba(254, 253, 255, 1.00));
      background-image: -o-linear-gradient(left bottom, rgba(251, 255, 242, 0.00), rgba(254, 253, 255, 1.00));
      background-image: -ms-linear-gradient(left bottom, rgba(251, 255, 242, 0.00), rgba(254, 253, 255, 1.00));
      background-image: linear-gradient(left bottom, rgba(251, 255, 242, 0.00), rgba(254, 253, 255, 1.00));
      filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1,StartColorStr='#fbfff2', EndColorStr='#fefdff');
      border-radius: 71px 0 0 71px;
      @include transform(rotate(45deg));
      @include transform-origin(100% 50%);
      opacity: 0.05;
    }

    #poststats  {
      position: relative;
      top:-54px;
      left: -54px;
    }

    .data  {
      position: absolute;
      top: 5px;
      color: $midgrey;
      font-size: 13px;
      list-style: none;

      .ready  {
        font-size: 18px;
        vertical-align: -5%;
        margin-right: 5px;
        color: $green;
      }

      .pending  {
        font-size: 18px;
        vertical-align: -5%;
        margin-right: 5px;
        color: #f9e15d;
      }

      .draft  {
        font-size: 18px;
        vertical-align: -5%;
        margin-right: 5px;
        color: $red;
      }

    }

  }
} // .widget-posts

/* ==========================================================================
   Popular Posts
   ========================================================================== */

.widget-popular {
  @extend %widget;
  background: none;

  .widget-content {
    padding: 0;
  }

  .nav {
    list-style: none;
    width: 100%;
    margin: 0;
    padding: 0;
  }

  .tab {
    @include box-sizing(border-box);
    display: inline-block;
    height: 35px;
    margin: 0;
    margin-top: 5px;
    padding: 5px 15px 0;
    float: left;
    vertical-align: bottom;
    background: #CDCCC5;
    border-left: 1px solid $midbrown;

    &:first-child {
      border: none;
    }

    &.active {
      height: 40px;
      margin: 0;
      padding-top: 10px;
      background: #ffffff;
    }

    a {
      vertical-align: middle;
      display: inline-block;
      color: #8D8C85;
    }
  }

  .post-list {
    max-height: 538px; // For overflow, dont way to make dynamic
    background: #ffffff;
    overflow: auto;
  }

  .post-item {
    @include box-sizing(border-box);
    display: block;
    min-height: 80px;
    width: 100%;
    padding: 20px;
    border-bottom: 1px solid $lightbrown;
  }

  .post-title {
    font-size: 1.25em;
    font-weight: normal;
  }

  .post-date {
    @include icon($i-calendar);
    margin-right: 20px;
    color: $brown;
  }

  .post-count {
    @include icon($i-stats);
    color: $brown;
  }

  .widget-footer {
    background: #ffffff;
  }
} // .widget-popular

/* ==========================================================================
   Posts This Week
   ========================================================================== */

.widget-postsWeek {
  @extend %widget;
}

/* ==========================================================================
   Instagram
   ========================================================================== */

.widget-instagram {
  @extend %widget;
  overflow: hidden;

  .widget-content {
    padding: 0;
  }

  .photo {
    height: 100%;
    width: 100%;
  }

  .widget-footer {
    background: rgba(0,0,0,0.4);
    border: none;

    .widget-title {
      color: #fff;
    }
  }

  .widget-settings-toggle {
    border: none;
  }
} // .widget-instagram

/* ==========================================================================
   RSS
   ========================================================================== */

.widget-rss {
  @extend %widget;
}

/* ==========================================================================
   Klout
   ========================================================================== */

.widget-klout  {
  @extend %widget-number;
}

/* ==========================================================================
   Bounce Rate
   ========================================================================== */

.widget-bounce  {
  @extend %widget-number;
}

/* ==========================================================================
   Average Time On Site
   ========================================================================== */

.widget-avgTime  {
  @extend %widget-number;
}

/* ==========================================================================
   Last.Fm
   ========================================================================== */

.widget-lastfm  {
  @extend %widget;
  overflow: hidden;

  .widget-content {
    padding: 0;
  }

  .cover {
    height: 100%;
    width: 100%;
  }

  .banner {
    @include box-sizing(border-box);
    display: block;
    width: 100%;
    padding: 20px;
    position: absolute;
    top: 80px;
    background: rgba(0,0,0,0.7);

    .song-artist, .song-title {
      display: block;
      color: #ffffff;
    }

    .song-artist {
      font-size: 2em;
      font-weight: bold;
      line-height: 1em;
    }

    .song-title {
      font-size: 1.2em;
    }
  }

  .widget-footer {
    background: #ffffff;
  }

} // .widget-lastfm

/* ==========================================================================
   Post Ideas
   ========================================================================== */

.widget-ideas {
  @extend %widget;

  .widget-content {
    padding: 0;
  }
  .idea-title {
    @include box-sizing(border-box);
    display: block;
    width: 100%;
    height: 80px;
    margin-bottom: 10px;
    padding: 20px;
    font-size: 2em;
    border: none;
    border-bottom: 1px solid $lightbrown;
  }
  .idea-content {
    @include box-sizing(border-box);
    width: 100%;
    padding: 20px;
    font-size: 1.2em;
    border: none;
    resize: none;
  }

  .idea-title:focus, .idea-content:focus {
    outline: none;
  }
} // .widget-ideas

/* ==========================================================================
   Tweets
   ========================================================================== */

.widget-tweets {
  @extend %widget;

  .twitter-display-image {
    width: 30px;
    height: 30px;
    margin-right: 10px;
    display: inline-block;
    float: left;
    border-radius: 15px;

    img {
      width: 100%;
      height: 100%;
      border-radius: 15px;
    }
  }

  .twitter-name {
    font-weight: bold;
    font-size: 1.5em;
    margin-right: 5px;
  }

  .twitter-handle {
    color: $midbrown;
    font-size: 1.2em;
  }

  .latest-tweet {
    margin-top: 15px;
    margin-bottom: 15px;
    font-size: 1.5em;

    a {
      color: $orange;
      font-weight: bold;
    }
  }

  .tweet-time {
    color: $midbrown;
  }
  .twitter-functions {
    float: right;
    font-size: 1.2em;

    a:hover {
      text-decoration: none;
    }

    .reply {
      @include icon($i-reply, '', $midbrown);
      margin-right: 5px;
    }
    .retweet {
      @include icon($i-repost, '', $midbrown);
      margin-right: 5px;
    }
    .favourite {
      @include icon($i-unfeatured, '', $midbrown);
    }
  }
} // .widget-tweets

/* ==========================================================================
   Backups
   ========================================================================== */

.widget-backups {
  @extend %widget;
}

/*

.dashboard-controls  {
	@extend %box;
	padding:0 15px;

	.text  {
		padding:12px 0;
	}
}

.controls-nav  {
	float:left;
	margin-left:20px;
	ul  {
		border-left: $lightgrey 1px solid;

		li  {
			margin: 0;
			border-right: 1px solid $lightgrey;

			a  {
				padding: 12px 15px;
				color: $grey;

				span  {
					color: $darkgrey;
				}

				&:hover  {
					color: $darkgrey;
					text-decoration: none;
				}
			}
		}
	}
}

.widget-stats  {
	span  {
		display: block;
		font-size: 1.6em;
		line-height: 1.2em;
		color: $grey;
		margin-bottom: 15px;
		strong  {
			font-size: 1.2em;
		}
	}
	span:first-child  {
		font-size: 5.4em;
		line-height: 1.4em;
		color: #000;
		margin-bottom: 0;
	}
}

@media only screen and (min-width: 1200px)  {
	.span4 .vert2  {
		.widget-stats  {
			span  {
				font-size: 2.6em;
				strong  {
					font-size: 1.2em;
				}
			}
			span:first-child  {
				font-size: 12.4em;
			}
		}
	}
}

// Time & Date Box
.time-date  {
	.time  {
		font-size: 7.4em;
		line-height: 0.7em;
		border-bottom: 1px solid $lightgrey;
		span  {
			font-size: 0.2em;
			color: $grey;
			text-transform: uppercase;
			font-style: normal;
		}
		@media only screen and (min-width: 1400px)  {
			span  {
				font-size: 0.3em;
			}
		}
	}
	.date  {
		font-size: 2.2em;
		line-height: 1em;
		font-weight: bold;
		color: #000;
		padding: 15px 0;
		span  {
			font-size: 0.7em;
			font-weight: normal;
			display: block;
			line-height: 1em;
			color: $grey;
		}
	}
}

// Post Statuses Box
.post-statuses  {
	.status-levels  {
		width: 30%;
		div  {
			text-indent: -9999px;
		}
	}
	.status-text  {
		width: 70%;
		text-transform: uppercase;
		font-size: 1.2em;
		color: $grey;
		div  {
			background: none;
			padding: 15px 0;
		}
		strong  {
			font-size: 1.6em;
			width: 60px;
			padding-right: 5px;
			text-align: right;
			display: inline-block;
		}
	}
	.scheduled  {
		background: $green;
		strong  {
			color: $green;
		}
	}
	.pending  {
		background: #fcd039;
		strong  {
			color: #fcd039;
		}
	}
	.draft  {
		background: $red;
		strong  {
			color: $red;
		}
	}
}

.todays-traffic  {
	ul  {
		li  {
			position: relative;
			padding: 10px;
			margin-bottom: 1px;
			div  {
				position: relative;
				z-index: 99;
			}
		}
		li:before  {
			content: '';
			position: absolute;
			height: 34px;
			top: 0;
			left: 0;
			z-index: 20;
		}
		li:nth-child(1):before  {
			background: $blue;
			width: 80%;
		}
		li:nth-child(2):before  {
			background: lighten($blue, 3%);
			width: 60%;
		}
		li:nth-child(3):before  {
			background: lighten($blue, 6%);
			width: 40%;
		}
		li:nth-child(4):before  {
			background: lighten($blue, 10%);
			width: 20%;
		}
	}
}

.table  {
	width: 100%;
	display: block;
	margin-bottom: 10px;
	thead, tbody, tr  {
		display: block;
	}
	@media only screen and (min-width: 400px)  {
		thead  {
			display: none;
		}
	}
	tbody  {
		tr  {
			background: $lightbrown;
			margin-top: 5px;
			display: block;
			position: relative;
			&:first-child  {
				margin-top: 0;
			}
		}
		@media only screen and (min-width: 1200px)  {
			tr  {
				padding: 0 10px 0 40px;
				margin-top: 15px;
			}
		}
		td  {
			padding: 10px;
			text-align: right;
			color: $grey;
			strong  {
				color: #000;
			}
			span  {
				display: none;
			}
			@media only screen and (min-width: 500px)  {
				span  {
					display: inline;
				}
			}
			.callout  {
				color: $green;
			}
			&:first-child  {
				text-align: left;
			}
		}
	}
	.user-img  {
		position: absolute;
		top: 0;
		left: 0;
		display: none;
	}
	@media only screen and (min-width: 1200px)  {
		.user-img  {
			display: block;
		}
	}

}
*/


/*global window, document, Ghost, Backbone, $, _ */
(function () {
    "use strict";

    Ghost.Router = Backbone.Router.extend({

        routes: {
            ''                 : 'dashboard',
            'content/'         : 'blog',
            'settings/'        : 'settings',
            'settings(/:pane)' : 'settings',
            'editor/'          : 'editor',
            'editor(/:id)'     : 'editor',
            'debug/'           : 'debug'
        },

        blog: function () {
            var posts = new Ghost.Collections.Posts();
            posts.fetch({ data: { status: 'all', orderBy: ['updated_at', 'DESC'] } }).then(function () {
                Ghost.currentView = new Ghost.Views.Blog({ el: '#main', collection: posts });
            });
        },

        settings: function (pane) {
            var settings = new Ghost.Models.Settings();
            settings.fetch().then(function () {
                Ghost.currentView = new Ghost.Views.Settings({ el: '#main', model: settings, pane: pane });
            });
        },

        editor: function (id) {
            var post = new Ghost.Models.Post();
            post.urlRoot = Ghost.settings.apiRoot + '/posts';
            if (id) {
                post.id = id;
                post.fetch().then(function () {
                    Ghost.currentView = new Ghost.Views.Editor({ el: '#main', model: post });
                });
            } else {
                Ghost.currentView = new Ghost.Views.Editor({ el: '#main', model: post });
            }
        },

        debug: function () {
            Ghost.currentView = new Ghost.Views.Debug({ el: "#main" });
        },

        dashboard: function () {
            var widgets = new Ghost.Collections.Widgets();

            widgets.add({
                title: "LINZ, AUSTRIA",
                name: "time",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.time",
                content: {
                    template: 'custom/time',
                    data: {
                        day: "Today",
                        weather: "12",
                        time: "12:42PM",
                        date: "Monday / March 5 / 2013"
                    }
                },
                settings: {
                    settingsPane: true,
                    options: [{
                        title: "Timezone",
                        value: "GMT"
                    }]
                }
            });

            widgets.add({
                title: "Ghost",
                name: "image",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.image",
                size: "2x1",
                content: {
                    template: 'default/blank'
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Upcoming Posts",
                name: "posts",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.posts",
                content: {
                    template: 'custom/upcoming-posts',
                    data: {
                        ready: 9,
                        pending: 4,
                        draft: 1
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Unique Visitors (7 days)",
                name: "stats",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.stats",
                size: "2x2",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "293,051",
                            sub: {
                                value: "+14%",
                                dir: "up",
                                item: "",
                                period: "in the last 7 days"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Facebook Likes",
                name: "facebook",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.facebook",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "12,329",
                            sub: {
                                value: "-3",
                                dir: "down",
                                item: "likes",
                                period: "today"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Google Plus",
                name: "gplus",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.gplus",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "4,103",
                            sub: {
                                item: "have you in circles"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Twitter",
                name: "twitter",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.twitter",
                content: {
                    template: 'default/blank'
                },
                settings: {
                    settingsPane: true,
                    enabled: true,
                    options: [
                        {
                            title: "Account",
                            value: "@JohnONolan"
                        },
                        {
                            title: "Display",
                            value: "Last Tweets"
                        },
                        {
                            title: "Quantity",
                            value: 6
                        }
                    ]
                }
            });

            widgets.add({
                title: "Campaign Monitor",
                name: "campaignmonitor",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.campaignmonitor",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "5,693",
                            sub: {
                                value: "+63",
                                dir: "up",
                                item: "subscribers",
                                period: "this week"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Most Popular Posts",
                name: "popular",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.popular",
                size: "1x2",
                content: {
                    template: 'custom/popular-posts',
                    data: {
                        posts: [
                            {
                                title: "The Night of The Headless Horseman Part II",
                                time: "Yesterday",
                                count: "3,128"
                            },
                            {
                                title: "Latin Script & Why it's Particularly Boring to Read",
                                time: "Wednesday",
                                count: "1,345"
                            },
                            {
                                title: "59 Signs Your Cat and/or Dog Might be Planning To Kill You",
                                time: "Tuesday",
                                count: "824"
                            },
                            {
                                title: "A Love Letter to Emma Stone",
                                time: "Today",
                                count: "293"
                            },
                            {
                                title: "Lorem Ipsum Dolor Sit Amet & Other Funny Moments",
                                time: "Yesterday",
                                count: "124"
                            },
                            {
                                title: "Matt Does Git",
                                time: "Thursday",
                                count: "100"
                            }
                        ]
                    }
                }
            });

            widgets.add({
                title: "Posts This Week (Out Of 20)",
                name: "postsWeek",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.postsWeek",
                content: {
                    template: 'default/blank'
                }
            });

            widgets.add({
                title: "Your RSS News Feed",
                name: "rss",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.rss",
                size: "2x2",
                content: {
                    template: 'default/blank'
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Instagram",
                name: "instagram",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.instagram",
                content: {
                    template: 'custom/instagram',
                    data: {
                        image: "http://f.cl.ly/items/303f3y1n3I2L1F10343E/instagram.jpg"
                    }
                },
                settings: {
                    settingsPane: true,
                    options: [{
                        title: "Account",
                        value: "@JohnONolan"
                    }]
                }
            });

            widgets.add({
                title: "Klout",
                name: "klout",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.klout",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "64.23",
                            sub: {
                                value: "-0.42",
                                dir: "down",
                                item: "",
                                period: "in the last 30 days"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Bounce Rate",
                name: "bounce",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.bounce",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "40.21%",
                            sub: {
                                value: "-2.53%",
                                dir: "up",
                                item: "",
                                period: "in the last month"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Average Time On Site",
                name: "avgTime",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.avgTime",
                content: {
                    template: 'default/number',
                    data: {
                        number: {
                            count: "2m 16s",
                            sub: {
                                value: "+31.4%",
                                dir: "up",
                                item: "",
                                period: "in the last month"
                            }
                        }
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Last.fm",
                name: "lastfm",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.lastfm",
                content: {
                    template: 'custom/lastfm',
                    data: {
                        cover: "http://f.cl.ly/items/0p0r3T3v3M0R0H1k1p0S/imagine_dragons.png",
                        artist: "Imagine Dragons",
                        title: "On Top of The World"
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Post Ideas",
                name: "ideas",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.ideas",
                size: "2x1",
                content: {
                    template: 'custom/post-ideas'
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Twitter",
                name: "tweets",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.tweets",
                content: {
                    template: 'custom/tweets',
                    data: {
                        avatar: "http://f.cl.ly/items/1A1S0D3T3p1g1B2Z3J0u/ghost_twitter.jpeg",
                        name: "Ghost",
                        handle: "@TryGhost",
                        tweet: "If you're exploring the @twitterapi, be sure and bring the new field guide along. dev.twitter.com/blog/...",
                        time: "3 May 12"
                    }
                },
                settings: {
                    settingsPane: true
                }
            });

            widgets.add({
                title: "Backups",
                name: "backups",
                author: "Matthew Harrison-Jones",
                applicationID: "com.ghost.backups",
                content: {
                    template: 'default/blank'
                },
                settings: {
                    settingsPane: true
                }
            });

            //widgets.fetch().then(function () {
            Ghost.currentView = new Ghost.Views.Dashboard({ el: '#main', collection: widgets });
            //});
        }
    });
}());


<img src="/core/client/assets/img/test-icon.png" alt="logo" height="38" width="38"/>

The icon for your blog, used in your browser tab and elsewhere

<img src="/public/img/test-icon.png" alt="logo" height="38" width="38"/>


{{title}}

        <time datetime="2013-01-04" class="date">
            {{#if published}}
                Published {{dateFormat published_at timeago="True"}}
            {{else}}
                Draft
            {{/if}}
        </time>
        {{!1,934}}


[submodule "content/themes/casper"]
	path = content/themes/casper
	url = git@github.com:TryGhost/Casper.git


{{#if messages}}
    {{#each messages.error}}

          {{.}}
          Close

    {{/each}}
    {{#each messages.success}}

            {{.}}
            Close

    {{/each}}
    {{#each messages.warn}}

            {{.}}
            Close

    {{/each}}
    {{#each messages.info}}

            {{.}}
            Close

    {{/each}}
{{/if}}


keep keep keep keep replace keep keep keep keep keep

var path = require('path'),
    buildDirectory = path.resolve(process.cwd(), '.build'),
    distDirectory =  path.resolve(process.cwd(), '.dist'),
    configureGrunt = function (grunt) {

        var cfg = {
            // Common paths to be used by tasks
            paths: {
                adminAssets: './core/client/assets',
                build: buildDirectory,
                nightlyBuild: path.join(buildDirectory, 'nightly'),
                weeklyBuild: path.join(buildDirectory, 'weekly'),
                buildBuild: path.join(buildDirectory, 'build'),
                dist: distDirectory,
                nightlyDist: path.join(distDirectory, 'nightly'),
                weeklyDist: path.join(distDirectory, 'weekly'),
                buildDist: path.join(distDirectory, 'build')
            },
            buildType: 'Build',
            pkg: grunt.file.readJSON('package.json'),

            // JSLint all the things!
            jslintm: {
                server: {
                    directives: {
                        // node environment
                        node: true,
                        // browser environment
                        browser: false,
                        // allow dangling underscores in var names
                        nomen: true,
                        // allow to do statements
                        todo: true,
                        // allow unused parameters
                        unparam: true,
                        // don't require use strict pragma
                        sloppy: true
                    },
                    files: {
                        src: [
                            "*.js",
                            "core/*.js",
                            "core/server/**/*.js"
                        ]
                    }
                },
                client: {
                    directives: {
                        // node environment
                        node: false,
                        // browser environment
                        browser: true,
                        // allow dangling underscores in var names
                        nomen: true,
                        // allow to do statements
                        todo: true,
                         // allow unused parameters
                        unparam: true
                    },
                    files: {
                        src: "core/client/**/*.js"
                    },
                    exclude: [
                        "core/client/assets/**/*.js",
                        "core/client/tpl/**/*.js"
                    ]
                },
                shared: {
                    directives: {
                        // node environment
                        node: true,
                        // browser environment
                        browser: false,
                        // allow dangling underscores in var names
                        nomen: true,
                        // allow to do statements
                        todo: true,
                        // allow unused parameters
                        unparam: true,
                        // don't require use strict pragma
                        sloppy: true
                    },
                    files: {
                        src: [
                            "core/shared/**/*.js"
                        ]
                    }
                }
            },

            mochacli: {
                options: {
                    ui: "bdd",
                    reporter: "spec"
                },

                all: {
                    src: ['core/test/**/*_spec.js']
                },

                api: {
                    src: ['core/test/**/api*_spec.js']
                },

                perm: {
                    src: ['core/test/**/permissions_spec.js']
                }
            },

            // Compile all the SASS!
            sass: {
                admin: {
                    files: {
                        '<%= paths.adminAssets %>/css/screen.css': '<%= paths.adminAssets %>/sass/screen.scss'
                    }
                }
            },

            shell: {
                bourbon: {
                    command: 'bourbon install --path <%= paths.adminAssets %>/sass/modules/'
                }
            },

            handlebars: {
                core: {
                    options: {
                        namespace: "JST",
                        processName: function (filename) {
                            filename = filename.replace('./core/client/tpl/', '');
                            return filename.replace('.hbs', '');
                        }
                    },
                    files: {
                        "core/client/tpl/hbs-tpl.js": "core/client/tpl/**/*.hbs"
                    }
                }
            },

            groc: {
                docs: {
                    options: {
                        "out": "./docs/",
                        "glob": [
                            "README.md",
                            "config.js",
                            "index.js",
                            "core/ghost.js",
                            "core/server/**/*.js",
                            "core/shared/**/*.js",
                            "core/client/**/*.js"
                        ],
                        "except": [
                            "!core/client/assets/**/*.js",
                            "!core/client/tpl/**/*.js"
                        ]
                    }
                }
            },

            watch: {
                handlebars: {
                    files: 'core/client/tpl/**/*.hbs',
                    tasks: ['handlebars']
                },
                sass: {
                    files: '<%= paths.adminAssets %>/sass/**/*',
                    tasks: ['sass:admin']
                }
            },

            copy: {
                nightly: {
                    files: [{
                        expand: true,
                        src: [
                            '**',
                            '!node_modules/**',
                            '!core/server/data/*.db',
                            '!.sass*',
                            '!.af*',
                            '!.git*',
                            '!.groc*',
                            '!.travis.yml'
                        ],
                        dest: "<%= paths.nightlyBuild %>/<%= pkg.version %>/"
                    }]
                },
                weekly: {
                    files: [{
                        expand: true,
                        src: [
                            '**',
                            '!node_modules/**',
                            '!core/server/data/*.db',
                            '!.sass*',
                            '!.af*',
                            '!.git*',
                            '!.groc*',
                            '!.travis.yml'
                        ],
                        dest: "<%= paths.weeklyBuild %>/<%= pkg.version %>/"
                    }]
                },
                build: {
                    files: [{
                        expand: true,
                        src: [
                            '**',
                            '!node_modules/**',
                            '!core/server/data/*.db',
                            '!.sass*',
                            '!.af*',
                            '!.git*',
                            '!.groc*',
                            '!.iml*',
                            '!.travis.yml'
                        ],
                        dest: "<%= paths.buildBuild %>/"
                    }]
                }
            },

            compress: {
                nightly: {
                    options: {
                        archive: "<%= paths.nightlyDist %>/Ghost-Nightly-<%= pkg.version %>.zip"
                    },
                    expand: true,
                    cwd: "<%= paths.nightlyBuild %>/<%= pkg.version %>/",
                    src: ["**"]
                },
                weekly: {
                    options: {
                        archive: "<%= paths.weeklyDist %>/Ghost-Weekly-<%= pkg.version %>.zip"
                    },
                    expand: true,
                    cwd: "<%= paths.weeklyBuild %>/<%= pkg.version %>/",
                    src: ["**"]
                },
                build: {
                    options: {
                        archive: "<%= paths.buildDist %>/Ghost-Build.zip"
                    },
                    expand: true,
                    cwd: "<%= paths.buildBuild %>/",
                    src: ["**"]
                }
            },

            bump: {
                options: {
                    tagName: '%VERSION%',
                    commitMessage: '<%= buildType %> Release %VERSION%',
                    tagMessage: '<%= buildType %> Release %VERSION%',
                    pushTo: "origin build"
                }
            }
        };

        grunt.initConfig(cfg);

        grunt.loadNpmTasks("grunt-jslint");
        grunt.loadNpmTasks("grunt-mocha-cli");
        grunt.loadNpmTasks("grunt-shell");
        grunt.loadNpmTasks("grunt-bump");

        grunt.loadNpmTasks("grunt-contrib-compress");
        grunt.loadNpmTasks("grunt-contrib-copy");
        grunt.loadNpmTasks("grunt-contrib-watch");
        grunt.loadNpmTasks("grunt-contrib-sass");
        grunt.loadNpmTasks("grunt-contrib-handlebars");
        grunt.loadNpmTasks('grunt-groc');

        // Update the package information after changes
        grunt.registerTask('updateCurrentPackageInfo', function () {
            cfg.pkg = grunt.file.readJSON('package.json');
        });

        grunt.registerTask('setCurrentBuildType', function (type) {
            cfg.buildType = type;
        });

        // jslintm aliased to jslint
        grunt.registerTask("jslint", ["jslintm"]);

        // Prepare the project for development
        // TODO: Git submodule init/update (https://github.com/jaubourg/grunt-update-submodules)?
        grunt.registerTask("init", ["shell:bourbon", "sass:admin", 'handlebars']);

        // Run API tests only
        grunt.registerTask("test-api", ["mochacli:api"]);

        // Run permisisons tests only
        grunt.registerTask("test-p", ["mochacli:perm"]);

        // Run tests and lint code
        grunt.registerTask("validate", ["jslint", "mochacli:all"]);

        // Generate Docs
        grunt.registerTask("docs", ["groc"]);

        /* Nightly builds
         * - Do our standard build steps (sass, handlebars, etc)
         * - Bump patch version in package.json, commit, tag and push
         * - Copy files to build-folder/#/#{version} directory
         * - Clean out unnecessary files (travis, .git*, .af*, .groc*)
         * - Zip files in build folder to dist-folder/#{version} directory
         */
        grunt.registerTask("nightly", [
            "setCurrentBuildType:Nightly",
            "shell:bourbon",
            "sass:admin",
            "handlebars",
            "bump:build",
            "updateCurrentPackageInfo",
            "copy:nightly",
            "compress:nightly"
        ]);

        grunt.registerTask("weekly", [
            "setCurrentBuildType:Weekly",
            "shell:bourbon",
            "sass:admin",
            "handlebars",
            "bump:build",
            "updateCurrentPackageInfo",
            "copy:weekly",
            "compress:weekly"
        ]);

        grunt.registerTask("build", [
            "shell:bourbon",
            "sass:admin",
            "handlebars",
            "copy:build",
            "compress:build"
        ]);

        // When you just say "grunt"
        grunt.registerTask("default", ['sass:admin', 'handlebars']);
    };

module.exports = configureGrunt;