Index: Dev/trunk/Gruntfile.js
===================================================================
--- Dev/trunk/Gruntfile.js	(revision 530)
+++ Dev/trunk/Gruntfile.js	(revision 531)
@@ -74,4 +74,10 @@
                        ,'heroku-config'
                        ,'http:db-push-local-to-cloud']);
+    grunt.registerTask('cloudant-url',
+                       "Print the Cloudant URL to the console.",
+                       ['path-check:heroku'
+                       ,'heroku-config'
+                       ,'print:herokuConfig.CLOUDANT_URL:CLOUDANT_URL'
+                       ]);
     grunt.registerTask('#',
                        "---\nTASKS BELOW ARE INTERNAL AND SHOULD NOT USUALLY BE CALLED FROM THE COMMAND-LINE\n---",
@@ -304,4 +310,9 @@
     grunt.loadTasks('./grunt-tasks');
 
+    grunt.registerTask('print',"Print a variable.",
+                       function(varname,name) {
+                            grunt.log.write(grunt.template.process((name||varname)+"=<%= "+varname+" %>"));
+                       });
+
     // UTIL FUNCTIONS
 
Index: Dev/trunk/src/client/qed-client/model/classes/_Class.js
===================================================================
--- Dev/trunk/src/client/qed-client/model/classes/_Class.js	(revision 530)
+++ Dev/trunk/src/client/qed-client/model/classes/_Class.js	(revision 531)
@@ -64,5 +64,5 @@
         },
         _formatDate: function(date) {
-            return stamp.toISOString(date,{zulu:true,milliseconds:false});
+            return stamp.toISOString(date,{zulu:true,milliseconds:true});
         },
         _sanitize: function(obj) {
Index: Dev/trunk/src/client/qed-client/model/classes/sessions.js
===================================================================
--- Dev/trunk/src/client/qed-client/model/classes/sessions.js	(revision 531)
+++ Dev/trunk/src/client/qed-client/model/classes/sessions.js	(revision 531)
@@ -0,0 +1,24 @@
+define([
+    "./_Class",
+    "./surveys",
+    "dojo/_base/declare"
+], function(_Class, surveys, declare) {
+
+    var Sessions = declare([_Class],{
+        _collection: 'sessions',
+        _type: 'Session',
+        create: function() {
+            var obj = {
+                type: this._type
+            };
+            return obj;
+        },
+        _deserialize: function(obj) {
+        },
+        _serialize: function(obj) {
+        }
+    });
+
+    return new Sessions();
+
+});
Index: Dev/trunk/src/client/qed-client/model/widgets/SurveyRunWidget.js
===================================================================
--- Dev/trunk/src/client/qed-client/model/widgets/SurveyRunWidget.js	(revision 530)
+++ Dev/trunk/src/client/qed-client/model/widgets/SurveyRunWidget.js	(revision 531)
@@ -11,5 +11,5 @@
             var endDateBox = this.endDateBox;
             this.own(this.startDateBox.on('change', function(value){
-                endDateBox.constraints.min  = value;
+                endDateBox.constraints.min = value;
             }));
         },
@@ -24,4 +24,6 @@
                 value.respondentCanDeleteOwnResponse ? ["on"] : [];
             this.inherited(arguments);
+            this.endDateBox.constraints.min =
+                this.startDateBox.get('value');
         }
     });
Index: Dev/trunk/src/client/qed-client/pages/surveyRuns.js
===================================================================
--- Dev/trunk/src/client/qed-client/pages/surveyRuns.js	(revision 531)
+++ Dev/trunk/src/client/qed-client/pages/surveyRuns.js	(revision 531)
@@ -0,0 +1,79 @@
+define([
+    "../app/Page",
+    "../app/Router",
+    "../model/classes/surveyRuns",
+    "../widgets/LineWithActionsWidget",
+    "dojo/_base/array",
+    "dojo/_base/declare",
+    "dojo/_base/lang",
+    "dojo/when",
+    "dojo/text!./templates/surveyRuns.html"
+], function(Page, Router, surveyRuns, LineWithActionsWidget, array, declare, lang, when, template) {
+    return declare([Page],{
+        templateString: template,
+        startup: function() {
+            if ( this._started ) { return; }
+            this.inherited(arguments);
+            this.currentTab.set('title','Current (<span class="qedLoading"></span>)');
+            this.pastTab.set('title','Past (<span class="qedLoading"></span>)');
+            this.futureTab.set('title','Future (<span class="qedLoading"></span>)');
+            this.refresh();
+        },
+        _onRunDetails: function(surveyRun) {
+            Router.go(surveyRuns.getObjectPath(surveyRun));
+        },
+        _onRunDelete: function(surveyRun) {
+            if ( !confirm("Are you sure you want to delete this survey run?") ) {
+                return;
+            }
+            surveyRuns.remove(surveyRun)
+            .then(lang.hitch(this,function(){
+                this.notify("SurveyRun successfully deleted.");
+                this.refreshRuns();
+            }),lang.hitch(this,function(err){
+                this.notify(err.error,'error');
+            }));
+        },
+        refresh: function() {
+            this.refreshGroup('current','Current');
+            this.refreshGroup('past','Past');
+            this.refreshGroup('future','Future');
+        },
+        refreshGroup: function(sub,subname) {
+            var tab = this[sub+'Tab'];
+            var container = this[sub+'Container'];
+            container.set('content','Loading <span class="qedLoading"></span> survey runs.');
+            var qs = {};
+            qs[sub] = true;
+            when(surveyRuns.query(qs),
+                 lang.hitch(this,function(surveyRuns){
+                container.set('content','');
+                tab.set('title',subname+' ('+surveyRuns.length+')');
+                array.forEach(surveyRuns,function(surveyRun){
+                    var w = new LineWithActionsWidget({
+                        title: surveyRun.title || "",
+                        actions:[{
+                            callback: lang.hitch(this,'_onRunDetails',
+                                                 surveyRun),
+                            properties: {
+                                label: 'Details',
+                                tooltip: 'Show details for this run',
+                                icon: 'Edit'
+                            }
+                        },{
+                            callback: lang.hitch(this,'_onRunDelete',
+                                                 surveyRun),
+                            properties: {
+                                label: 'Delete',
+                                tooltip: 'Delete this run',
+                                icon: 'Delete'
+                            }
+                        }]
+                    });
+                    container.addChild(w);
+                },this);
+            }));
+        }
+    });
+});
+
Index: Dev/trunk/src/client/qed-client/pages/surveys.js
===================================================================
--- Dev/trunk/src/client/qed-client/pages/surveys.js	(revision 530)
+++ Dev/trunk/src/client/qed-client/pages/surveys.js	(revision 531)
@@ -18,5 +18,4 @@
             this.draftsTab.set('title','Drafts (<span class="qedLoading"></span>)');
             this.publishedTab.set('title','Published (<span class="qedLoading"></span>)');
-            this.runsTab.set('title','Runs (<span class="qedLoading"></span>)');
             this.refresh();
         },
@@ -56,24 +55,11 @@
         _onRunSurvey:function(survey){
             var surveyRun = surveyRuns.create();
-            surveyRun.title = 'Run of "' + survey.title + '" of '+(new Date().toString());
+            surveyRun.title = 'Run of "'+survey.title+'" of '+
+                              (new Date().toString());
             surveyRun.survey = survey;
             surveyRuns.save(surveyRun)
             .then(lang.hitch(this,function(surveyRun){
-                this._onRunDetails(surveyRun);
-            }),lang.hitch(this,function(err){
-                this.notify(err.error,'error');
-            }));
-        },
-        _onRunDetails: function(surveyRun) {
-            Router.go(surveyRuns.getObjectPath(surveyRun));
-        },
-        _onRunDelete: function(surveyRun) {
-            if ( !confirm("Are you sure you want to delete this survey run?") ) {
-                return;
-            }
-            surveyRuns.remove(surveyRun)
-            .then(lang.hitch(this,function(){
-                this.notify("SurveyRun successfully deleted.");
-                this.refreshRuns();
+                Router.go(surveyRuns.getObjectPath(
+                    surveyRuns.getId(surveyRun)));
             }),lang.hitch(this,function(err){
                 this.notify(err.error,'error');
@@ -83,10 +69,10 @@
             this.refreshDrafts();
             this.refreshPublished();
-            this.refreshRuns();
         },
         refreshDrafts: function() {
-            this.draftsContainer.set('content','');
+            this.draftsContainer.set('content','Loading draft surveys <span class="qedLoading"></span>');
             when(surveys.query({drafts:true}), lang.hitch(this,function(surveys) {
                 this.draftsTab.set('title','Drafts ('+surveys.length+')');
+                this.draftsContainer.set('content','');
                 array.forEach(surveys,function(survey){
                     var w = new LineWithActionsWidget({
@@ -127,6 +113,7 @@
         },
         refreshPublished: function() {
-            this.publishedContainer.set('content','');
+            this.publishedContainer.set('content','Loading published surveys <span class="qedLoading"></span>');
             when(surveys.query({published:true}), lang.hitch(this, function(surveys) {
+                this.publishedContainer.set('content','');
                 this.publishedTab.set('title','Published ('+surveys.length+')');
                 array.forEach(surveys,function(survey){
@@ -152,31 +139,4 @@
                 },this);
             }));
-        },
-        refreshRuns: function() {
-            this.runsContainer.set('content','');
-            when(surveyRuns.query(), lang.hitch(this,function(surveyRuns){
-                this.runsTab.set('title','Runs ('+surveyRuns.length+')');
-                array.forEach(surveyRuns,function(surveyRun){
-                    var w = new LineWithActionsWidget({
-                        title: surveyRun.title || "",
-                        actions:[{
-                            callback: lang.hitch(this,'_onRunDetails',surveyRun),
-                            properties: {
-                                label: 'Details',
-                                tooltip: 'Show details for this run',
-                                icon: 'Edit'
-                            }
-                        },{
-                            callback: lang.hitch(this,'_onRunDelete',surveyRun),
-                            properties: {
-                                label: 'Delete',
-                                tooltip: 'Delete this run',
-                                icon: 'Delete'
-                            }
-                        }]
-                    });
-                    this.runsContainer.addChild(w);
-                },this);
-            }));
         }
     });
Index: Dev/trunk/src/client/qed-client/pages/templates/surveyRuns.html
===================================================================
--- Dev/trunk/src/client/qed-client/pages/templates/surveyRuns.html	(revision 531)
+++ Dev/trunk/src/client/qed-client/pages/templates/surveyRuns.html	(revision 531)
@@ -0,0 +1,55 @@
+<div>
+
+    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">
+        <h2>
+            <span class="rftIcon rftIconSurvey"></span>
+            <span class="headerText">Survey Results</span>
+        </h2>
+    </div>
+
+    <div data-dojo-attach-point="tabContainer"
+         data-dojo-type="dijit/layout/TabContainer"
+         class="blue" data-dojo-props="tabPosition:'left-h',region:'center'">
+
+        <div data-dojo-type="dijit/layout/BorderContainer"
+             title="Current"
+             data-dojo-attach-point="currentTab">
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'center'"
+                 data-dojo-attach-point="currentContainer">
+            </div>
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'bottom'"
+                 style="height: 40px;">
+            </div>
+        </div>
+
+        <div data-dojo-type="dijit/layout/BorderContainer"
+             title="Future"
+             data-dojo-attach-point="futureTab">
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'center'"
+                 data-dojo-attach-point="futureContainer">
+            </div>
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'bottom'"
+                 style="height: 40px;">
+            </div>
+        </div>
+
+        <div data-dojo-type="dijit/layout/BorderContainer"
+             title="Past"
+             data-dojo-attach-point="pastTab">
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'center'"
+                 data-dojo-attach-point="pastContainer">
+            </div>
+            <div data-dojo-type="dijit/layout/ContentPane"
+                 data-dojo-props="region: 'bottom'"
+                 style="height: 40px;">
+            </div>
+        </div>
+
+    </div>
+
+</div>
Index: Dev/trunk/src/client/qed-client/pages/templates/surveys.html
===================================================================
--- Dev/trunk/src/client/qed-client/pages/templates/surveys.html	(revision 530)
+++ Dev/trunk/src/client/qed-client/pages/templates/surveys.html	(revision 531)
@@ -34,16 +34,4 @@
         </div>
 
-        <div data-dojo-type="dijit/layout/BorderContainer"
-             title="Runs"
-             data-dojo-attach-point="runsTab">
-            <div data-dojo-type="dijit/layout/ContentPane"
-                 data-dojo-props="region: 'center'"
-                 data-dojo-attach-point="runsContainer">
-            </div>
-            <div data-dojo-type="dijit/layout/ContentPane"
-                 data-dojo-props="region: 'bottom'"
-                 style="height: 40px;">
-            </div>
-        </div>
     </div>
 
Index: Dev/trunk/src/client/qed-client/routes.js
===================================================================
--- Dev/trunk/src/client/qed-client/routes.js	(revision 530)
+++ Dev/trunk/src/client/qed-client/routes.js	(revision 531)
@@ -1,4 +1,5 @@
 define([
     "./model/classes/questions",
+    "./model/classes/sessions",
     "./model/classes/surveyRuns",
     "./model/classes/surveys",
@@ -9,6 +10,7 @@
     "./pages/survey",
     "./pages/surveyRun",
+    "./pages/surveyRuns",
     "./pages/surveys"
-], function(questionsClass, surveyRunsClass, surveysClass, index, previewSurvey, question, questions, survey, surveyRun, surveys) {
+], function(questionsClass, sessionsClass, surveyRunsClass, surveysClass, index, previewSurvey, question, questions, survey, surveyRun, surveyRuns, surveys) {
 
     return [
@@ -19,7 +21,8 @@
         { path: surveysClass.getCollectionPath(), constructor: surveys },
         { path: surveysClass.getObjectPath(':objectId'), constructor: survey },
+        { path: surveyRunsClass.getCollectionPath(), constructor: surveyRuns },
         { path: surveyRunsClass.getObjectPath(':objectId'), constructor: surveyRun },
-        //{ path: "/sessions", constructor: sessions },
-        //{ path: "/session/:sessionId", constructor: session },
+        //{ path: sessionsClass.getObjectPath(''), constructor: sessions },
+        //{ path: sessionsClass.getObjectPath(':objectId'), constructor: session },
         { path: surveysClass.getPreviewPath(':surveyId'), constructor: previewSurvey }
     ];
Index: Dev/trunk/src/client/qed-client/ui/templates/MainMenu.html
===================================================================
--- Dev/trunk/src/client/qed-client/ui/templates/MainMenu.html	(revision 530)
+++ Dev/trunk/src/client/qed-client/ui/templates/MainMenu.html	(revision 531)
@@ -1,16 +1,25 @@
 <div class="mainMenu">
     <div  data-dojo-type="dijit/MenuBar">
-        <div class="rftMainMenuButton" data-dojo-type="./MenuBarLink" data-dojo-props="path:'/sessions'">Sessions</div>
-        <div class="rftMainMenuButton" data-dojo-type="dijit/PopupMenuBarItem">
+        <div class="rftMainMenuButton"
+             data-dojo-type="./MenuBarLink" data-dojo-props="path:'/sessions'">Sessions</div>
+        <div class="rftMainMenuButton"
+             data-dojo-type="dijit/PopupMenuBarItem">
             <span>Content</span>
             <div data-dojo-type="dijit/DropDownMenu">
-                <div data-dojo-type="./MenuLink" class="blue bgColorHover" data-dojo-props="path:'/surveys', iconClass:'rftIcon rftIconSurvey'">Surveys</div>
-                <div data-dojo-type="./MenuLink" class="orange bgColorHover" data-dojo-props="path:'/questions', iconClass:'rftIcon rftIconQuestion'">Questions</div>
-                <div data-dojo-type="./MenuLink" class="purple bgColorHover" data-dojo-props="path:'/applications', iconClass: 'rftIcon rftIconApplication'">Applications</div>
-                <div data-dojo-type="./MenuLink" class="red bgColorHover" data-dojo-props="path:'/dashboards', iconClass: 'rftIcon rftIconDashboard'">Dashboards</div>
+                <div data-dojo-type="./MenuLink"
+                     class="blue bgColorHover"
+                     data-dojo-props="path:'/surveys', iconClass:'rftIcon rftIconSurvey'">
+                  Surveys</div>
+                <div data-dojo-type="./MenuLink"
+                     class="orange bgColorHover"
+                     data-dojo-props="path:'/questions', iconClass:'rftIcon rftIconQuestion'">
+                  Questions</div>
             </div>
         </div>
-        <div class="rftMainMenuButton" data-dojo-type="./MenuBarLink" data-dojo-props="path:'/results'">Results</div>
-        <div class="rftMainMenuButton" data-dojo-type="./SessionMenu"></div>
+        <div class="rftMainMenuButton"
+             data-dojo-type="./MenuBarLink" data-dojo-props="path:'/surveyRuns'">
+          Results</div>
+        <div class="rftMainMenuButton"
+             data-dojo-type="./SessionMenu"></div>
     </div>
 </div>
Index: Dev/trunk/src/server/api/responses.js
===================================================================
--- Dev/trunk/src/server/api/responses.js	(revision 530)
+++ Dev/trunk/src/server/api/responses.js	(revision 531)
@@ -13,9 +13,9 @@
 
     var getResponsesBySurveyRunId = exports.getResponsesBySurveyRunId = function(surveyRunId) {
-        var url = '_design/responses/_view/by_surveyrun?key='+JSON.stringify(surveyRunId);
-        return couch.get(url)
+        return couch.get('_design/responses/_view/by_surveyrun',
+                         {query:{key:surveyRunId,reduce:false,include_docs:true}})
         .handle({
             '-1': _.identity,
-            200: util.handleRowValues,
+            200: util.handleRowDocs,
             default: util.handleUnknownResponse
         });
Index: Dev/trunk/src/server/api/surveyRuns.js
===================================================================
--- Dev/trunk/src/server/api/surveyRuns.js	(revision 530)
+++ Dev/trunk/src/server/api/surveyRuns.js	(revision 531)
@@ -15,5 +15,49 @@
     app.get('/',
         util.ensureMIME(util.JSON_MIME),
-        util.makeDocsGet('SurveyRun'));
+        function(req,res) {
+            var qs = {reduce:false,include_docs:true};
+            var now = new Date().toISOString();
+            var hr;
+            if ( 'current' in req.query ) {
+                // we make the assumption that there will be fewer
+                // runs with no or a future enddate than with a
+                // startdate in the past, i.e. we assume fewer future
+                // surveys are planned than past surveys are run.
+                hr = couch.get('_design/surveyRuns/_view/by_end_date',{
+                    query: {startkey:now,reduce:false,include_docs:true}
+                }).handle({
+                    '-1': _.identity,
+                    200: function(result) {
+                        return _.filter(
+                            util.handleRowDocs(result),
+                            function(doc){
+                                return !doc.startDate ||
+                                       doc.startDate <= now;
+                            });
+                    },
+                    default: util.handleUnknownResponse
+                });
+            } else if ( 'future' in req.query ) {
+                hr = couch.get('_design/surveyRuns/_view/by_start_date',{
+                    query: {startkey:now,reduce:false,include_docs:true}
+                }).handle({
+                    '-1': _.identity,
+                    200: util.handleRowDocs,
+                    default: util.handleUnknownResponse
+                });
+            } else if ( 'past' in req.query ) {
+                hr = couch.get('_design/surveyRuns/_view/by_end_date',{
+                    query: {endkey:now,reduce:false,include_docs:true}
+                }).handle({
+                    '-1': _.identity,
+                    200: util.handleRowDocs,
+                    default: util.handleUnknownResponse
+                });
+            } else {
+                hr = util.getDocumentsOfType('SurveyRun');
+            }
+            hr.handle({'-1': util.handleException})
+            .handle(res.send.bind(res));
+        });
     app.post('/',
         util.ensureMIME(util.JSON_MIME),
Index: Dev/trunk/src/server/api/util.js
===================================================================
--- Dev/trunk/src/server/api/util.js	(revision 530)
+++ Dev/trunk/src/server/api/util.js	(revision 531)
@@ -81,9 +81,9 @@
 
     var getDocumentsOfType = exports.getDocumentsOfType = function(type) {
-        var url = '_design/default/_view/by_type?key='+JSON.stringify(type);
-        return couch.get(url)
+        return couch.get('_design/default/_view/by_type',
+                         {query:{reduce:false,include_docs:true,key:type}})
         .handle({
             '-1': _.identity,
-            200: handleRowValues,
+            200: handleRowDocs,
             404: function() { return {error: "Cannot find collection of type "+type}; },
             default: handleUnknownResponse
Index: Dev/trunk/src/server/bin/upgrade-db-dates-2014-03-26.js
===================================================================
--- Dev/trunk/src/server/bin/upgrade-db-dates-2014-03-26.js	(revision 531)
+++ Dev/trunk/src/server/bin/upgrade-db-dates-2014-03-26.js	(revision 531)
@@ -0,0 +1,53 @@
+var env = require('../env')
+  , upgradeCouch = require('../config/upgrade-couchdb')
+  , cryptoken = require('../util/crypto-token')
+  , HTTPResult = require('../util/http-result')
+  , _ = require('underscore')
+  ;
+
+var rewrites = {
+    SurveyRun: function(doc) {
+        rewriteDate(doc,'publicationDate');
+        rewriteDate(doc,'startDate');
+        rewriteDate(doc,'endDate');
+        rewriteDoc(doc.survey);
+        return doc;
+    },
+    Survey: function(doc) {
+        rewriteDate(doc,'publicationDate');
+        _.each(doc.questions,rewriteDoc);
+        return doc;
+    },
+    Question: function(doc) {
+        rewriteDate(doc,'publicationDate');
+        return doc;
+    },
+    Response: function(doc) {
+        rewriteDate(doc,'publicationDate');
+        return doc;
+    }
+};
+
+function rewriteDate(doc,field) {
+    if ( field in doc ) {
+        doc[field] = new Date(doc[field]).toISOString();
+        return true;
+    } else {
+        return false;
+    }
+}
+
+function rewriteDoc(doc) {
+    if ( doc.type in rewrites ) {
+        return rewrites[doc.type](doc);
+    } else {
+        return HTTPResult.fail();
+    }
+}
+
+upgradeCouch(env.couchServerURL,env.dbName,rewriteDoc)
+.then(function(res){
+    console.log("done",res);
+}, function(err){
+    console.error("fail",err);
+});
Index: Dev/trunk/src/server/config/couchdb-design-docs.js
===================================================================
--- Dev/trunk/src/server/config/couchdb-design-docs.js	(revision 530)
+++ Dev/trunk/src/server/config/couchdb-design-docs.js	(revision 531)
@@ -30,5 +30,5 @@
         _id: "schemaInfo",
         version: "4",
-        viewsVersion: "1"
+        viewsVersion: "2"
     },
 
@@ -49,6 +49,7 @@
             by_type: {
                 map: function(doc){
-                    emit(doc.type, doc);
-                }
+                    emit(doc.type, 1);
+                },
+                reduce: function(keys,values){ return sum(values); }
             },
             typeless: {
@@ -104,5 +105,5 @@
                     emit(doc.topic||"(default)",1);
                 },
-                reduce: function(key, values, rereduce) { return sum(values); }
+                reduce: function(key, values ) { return sum(values); }
             },
             all_variables: {
@@ -137,12 +138,15 @@
                 map: function(doc){
                     if ( doc.type !== 'Question' ) { return; }
-                    emit(doc.code,doc);
-                }
+                    emit(doc.code,1);
+                },
+                reduce: function(key, values) { return sum(values); }
             },
             published_by_code: {
                 map: function(doc){
-                    if ( doc.type !== 'Question' || !doc.publicationDate ) { return; }
-                    emit(doc.code,doc);
-                }
+                    if ( doc.type !== 'Question' ||
+                         !doc.publicationDate ) { return; }
+                    emit(doc.code,1);
+                },
+                reduce: function(key, values) { return sum(values); }
             },
             lib: {
@@ -159,5 +163,6 @@
             drafts: {
                 map: function(doc){
-                    if ( doc.type !== 'Survey' || doc.publicationDate ) { return; }
+                    if ( doc.type !== 'Survey' ||
+                         doc.publicationDate ) { return; }
                     emit(doc._id,doc);
                 }
@@ -165,5 +170,6 @@
             published: {
                 map: function(doc){
-                    if ( doc.type !== 'Survey' || !doc.publicationDate ) { return; }
+                    if ( doc.type !== 'Survey' ||
+                         !doc.publicationDate ) { return; }
                     emit(doc._id,doc);
                 }
@@ -176,11 +182,17 @@
         language: "javascript",
         views: {
-            by_dates: {
+            by_start_date: {
                 map: function(doc){
                     if ( doc.type !== 'SurveyRun' ) { return; }
-                    var startDate = doc.startDate || "";
-                    var endDate = doc.endDate || {};
-                    emit([startDate,endDate,doc.liveName||null],doc);
-                }
+                    emit(doc.startDate||null,1);
+                },
+                reduce: function(keys,values){ return sum(values); }
+            },
+            by_end_date: {
+                map: function(doc){
+                    if ( doc.type !== 'SurveyRun' ) { return; }
+                    emit(doc.endDate||{},1);
+                },
+                reduce: function(keys,values){ return sum(values); }
             }
         }
@@ -194,6 +206,7 @@
                 map: function(doc){
                     if ( doc.type !== 'Response' ) { return; }
-                    emit(doc.surveyRunId, doc);
-                }
+                    emit(doc.surveyRunId, 1);
+                },
+                reduce: function(keys,values){ return sum(values); }
             }
         }
Index: Dev/trunk/src/server/config/couchdb-schema.json
===================================================================
--- Dev/trunk/src/server/config/couchdb-schema.json	(revision 530)
+++ Dev/trunk/src/server/config/couchdb-schema.json	(revision 531)
@@ -10,6 +10,8 @@
   "definitions": {
     "nonEmptyString": { "type": "string", "minLength": 1 },
-    "codeString": { "type": "string", "pattern": "^[A-Za-z0-9]+$" },
-    "subcodeString": { "type": "string", "pattern": "^[A-Za-z0-9]*$" },
+    "code": { "type": "string", "pattern": "^[A-Za-z0-9]+$" },
+    "subcode": { "type": "string", "pattern": "^[A-Za-z0-9]*$" },
+    "datetime": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}Z$"},
+    "html5Email": {"type": "string", "pattern": "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"},
     "schemaInfo": {
       "type": "object",
@@ -40,8 +42,8 @@
           "_rev": { "$ref": "#/definitions/nonEmptyString" },
           "categories": { "type": "array", "items": { "$ref": "#/definitions/nonEmptyString" } },
-          "code": { "$ref": "#/definitions/codeString" },
+          "code": { "$ref": "#/definitions/code" },
           "content": { "type": "array", "items": { "$ref": "#/definitions/content/any" } },
           "description": { "$ref": "#/definitions/nonEmptyString" },
-          "publicationDate": { "type": "string", "format": "datetime" },
+          "publicationDate": { "$ref": "#/definitions/datetime" },
           "title": { "$ref": "#/definitions/nonEmptyString" },
           "topic": { "$ref": "#/definitions/nonEmptyString" }
@@ -57,5 +59,5 @@
           "_rev": { "$ref": "#/definitions/nonEmptyString" },
           "description": { "$ref": "#/definitions/nonEmptyString" },
-          "publicationDate": { "type": "string", "format": "datetime" },
+          "publicationDate": { "$ref": "#/definitions/datetime" },
           "questions": { "type": "array", "items": { "$ref": "#/definitions/docs/Question" } },
           "title": { "$ref": "#/definitions/nonEmptyString" }
@@ -71,10 +73,9 @@
           "_rev": { "$ref": "#/definitions/nonEmptyString" },
           "description": { "$ref": "#/definitions/nonEmptyString" },
-          "endDate": { "type": "string", "format": "datetime" },
-          "liveName": { "$ref": "#/definitions/nonEmptyString" },
+          "endDate": { "$ref": "#/definitions/datetime" },
           "mode": { "type": "string", "enum": [ "open", "closed" ] },
           "respondentCanDeleteOwnResponse": { "type": "boolean" },
           "secret": { "$ref": "#/definitions/nonEmptyString" },
-          "startDate": { "type": "string", "format": "datetime" },
+          "startDate": { "$ref": "#/definitions/datetime" },
           "survey": { "$ref": "#/definitions/docs/Survey" },
           "title": { "$ref": "#/definitions/nonEmptyString" }
@@ -96,6 +97,5 @@
               "additionalProperties": false
           },
-          "email": { "type": "string", "format": "email" },
-          "publicationDate": { "type": "string", "format": "datetime" },
+          "publicationDate": { "$ref": "#/definitions/datetime" },
           "secret": { "$ref": "#/definitions/nonEmptyString" },
           "surveyRunId": { "$ref": "#/definitions/nonEmptyString" }
@@ -149,5 +149,5 @@
         "properties": {
           "type": { "type": "string", "pattern": "^StringInput$" },
-          "subcode": { "$ref": "#/definitions/subcodeString" },
+          "subcode": { "$ref": "#/definitions/subcode" },
           "text": { "$ref": "#/definitions/nonEmptyString" }
         },
@@ -160,5 +160,5 @@
           "type": { "type": "string", "pattern": "^TextInput$" },
           "maxLength": { "type": "integer" },
-          "subcode": { "$ref": "#/definitions/subcodeString" },
+          "subcode": { "$ref": "#/definitions/subcode" },
           "text": { "$ref": "#/definitions/nonEmptyString" }
         },
@@ -173,5 +173,5 @@
           "max": { "type": "integer" },
           "places": { "type": "integer" },
-          "subcode": { "$ref": "#/definitions/subcodeString" },
+          "subcode": { "$ref": "#/definitions/subcode" },
           "text": { "$ref": "#/definitions/nonEmptyString" }
         },
@@ -193,5 +193,5 @@
               "minLabel": { "$ref": "#/definitions/nonEmptyString" },
               "maxLabel": { "$ref": "#/definitions/nonEmptyString" },
-              "subcode": { "$ref": "#/definitions/subcodeString" },
+              "subcode": { "$ref": "#/definitions/subcode" },
               "text": { "$ref": "#/definitions/nonEmptyString" }
             },
@@ -219,10 +219,10 @@
               "type": "object",
               "properties": {
-                  "subcode": { "$ref": "#/definitions/subcodeString" }
+                  "subcode": { "$ref": "#/definitions/subcode" }
               },
               "required": ["subcode"],
               "additionalProperties": false
           },
-          "subcode": { "$ref": "#/definitions/subcodeString" }
+          "subcode": { "$ref": "#/definitions/subcode" }
         },
         "required":["type","items","subcode"],
@@ -236,5 +236,5 @@
               "type": "object",
               "properties": {
-                "subcode": { "$ref": "#/definitions/subcodeString" },
+                "subcode": { "$ref": "#/definitions/subcode" },
                 "text": { "$ref": "#/definitions/nonEmptyString" }
               },
@@ -245,5 +245,5 @@
               "type": "object",
               "properties": {
-                "subcode": { "$ref": "#/definitions/subcodeString" }
+                "subcode": { "$ref": "#/definitions/subcode" }
               },
               "required": ["subcode"],
Index: Dev/trunk/src/server/util/http-result.js
===================================================================
--- Dev/trunk/src/server/util/http-result.js	(revision 530)
+++ Dev/trunk/src/server/util/http-result.js	(revision 531)
@@ -63,4 +63,10 @@
                 if ( status in fOrObj ) {
                     return fOrObj[status](result);
+                } else if ( status >= 200 && status < 300 &&
+                            'success' in fOrObj ) {
+                    return fOrObj.success(status,result);
+                } else if ( !(status >= 200 && status < 300) &&
+                            'failure' in fOrObj ) {
+                    return fOrObj.failure(status,result);
                 } else if ( 'default' in fOrObj ) {
                     return fOrObj['default'](status,result);
Index: Dev/trunk/src/server/util/validator.js
===================================================================
--- Dev/trunk/src/server/util/validator.js	(revision 530)
+++ Dev/trunk/src/server/util/validator.js	(revision 531)
@@ -1,24 +1,3 @@
 var tv4 = require('tv4');
-
-// from: http://www.w3.org/TR/html5/forms.html#valid-e-mail-address
-var html5EmailRe = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
-var datetimeRe = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z/;
-
-tv4.addFormat({
-    email: function(data){
-        if ( typeof data === "string" && html5EmailRe.test(data) ) {
-            return null;
-        } else {
-            return "Probably an invalid email address.";
-        }
-    },
-    datetime: function(data){
-        if ( typeof data === "string" && datetimeRe.test(data) ) {
-            return null;
-        } else {
-            return "Invalid timestamp.";
-        }
-    }
-});
 
 module.exports = function() {
