Index: /Dev/trunk/Gruntfile.js
===================================================================
--- /Dev/trunk/Gruntfile.js	(revision 463)
+++ /Dev/trunk/Gruntfile.js	(revision 463)
@@ -0,0 +1,109 @@
+/***************************************
+ * This Gruntfile is organized with two phases,
+ * compile and build. Compile will lint HTML,
+ * JavaScript and compile LESS. The build phase
+ * creates an optimized stand-alone build that
+ * can be distributed.
+ */
+
+module.exports = function(grunt) {
+
+    var buildDir = 'build/';
+    var srcDir   = 'src/';
+
+    grunt.initConfig({
+        clean: {
+            build: {
+                src: [buildDir]
+            }
+        },
+        coffee: {
+            options: {
+                bare: true
+            },
+            compile: {
+                files: [{
+                    expand: true,
+                    cwd: srcDir,
+                    src: ['client/qed-client/**/*.coffee', 'server/**/*.coffee'],
+                    dest: buildDir,
+                    ext: '.js'
+                }]
+            }
+        },
+        copy: {
+            compile: {
+                files: [{
+                    src: [srcDir+'**', '!**/*.coffee' ],
+                    dest: buildDir
+                }]
+            }
+        },
+        dojo: {
+            options: {
+                dojo: srcDir+'client/dojo/dojo.js'
+            },
+            build: {
+                options: {
+                    profile: srcDir+'client/client.profile.js',
+                    releaseDir: buildDir
+                }
+            }
+        },
+        htmlhint: {
+            options: {
+                htmlhintrc: srcDir+".htmlhintrc"
+            },
+            compile: {
+                files: [{
+                    expand: true,
+                    cwd: srcDir,
+                    src: ['client/*.html', 'client/qed-client/**/*.html']
+                }]
+            }
+        },
+        jshint: {
+            options: {
+                jshintrc: srcDir+".jshintrc"
+            },
+            compile: {
+                files: [{
+                    expand: true,
+                    cwd: srcDir,
+                    src: ['client/qed-client/**/*.js', 'server/**.js']
+                }]
+            }
+        },
+        less: {
+            options: {
+                strictImports: false,
+                dumpLineNumbers: "all"
+            },
+            compile: {
+                files: [{
+                    expand: true,
+                    cwd: srcDir,
+                    src: ['client/qed-client/css/qed.less'],
+                    dest: buildDir,
+                    ext: '.css'
+                }]
+            }
+        }
+    });
+
+    grunt.loadNpmTasks('grunt-contrib-clean');
+    grunt.loadNpmTasks('grunt-contrib-coffee');
+    grunt.loadNpmTasks('grunt-contrib-copy');
+    grunt.loadNpmTasks('grunt-contrib-jshint');
+    grunt.loadNpmTasks('grunt-contrib-less');
+    grunt.loadNpmTasks('grunt-curl');
+    grunt.loadNpmTasks('grunt-dojo');
+    grunt.loadNpmTasks('grunt-htmlhint');
+    grunt.loadNpmTasks('grunt-zip');
+
+    grunt.registerTask('compile', ['less:compile', 'jshint:compile', 'htmlhint:compile', 'coffee:compile', 'copy:compile']);
+    grunt.registerTask('build', ['clean:build', 'compile', 'dojo:build']);
+    grunt.registerTask('deploy', []);
+    grunt.registerTask('default', ['compile']);
+
+};
Index: /Dev/trunk/README.txt
===================================================================
--- /Dev/trunk/README.txt	(revision 462)
+++ /Dev/trunk/README.txt	(revision 463)
@@ -8,9 +8,5 @@
 - Install CouchDB
 - Install Node.js
-- Install apache with rewrite,proxy and proxy_http modules enables
-- Run in console (cmd.exe):
-  C:\>cd <qed-root>/server/couchdb-admin/
-  C:\..\couchdb-admin\>run.bat config/config.js
-- Open http://localhost/.../qed/admin.html
+- 
 
 
Index: /Dev/trunk/docs/TODO.md
===================================================================
--- /Dev/trunk/docs/TODO.md	(revision 463)
+++ /Dev/trunk/docs/TODO.md	(revision 463)
@@ -0,0 +1,73 @@
+TODO
+====
+
+ * Have a generic page-wide note (rounded corner, close button thingy)
+   for notification (maybe completely replace the toaster?)
+ * Response:
+   - should we show response answers after submission?
+   - idem after the run ended?
+ * Questions
+   - Question is always shown as 'no topic' when no category is added to it.
+   - Fragile: widget creation relies on the names in Factory, but
+     these must match the types returned by the actual widgets. Fix
+     this.
+ * Codes
+   - Details need to be figured out. Now we have a code in one place,
+     we add indices to disambiguate. Should we allow code editing all
+     the way to the lowest detail? And should it be the complete code or
+     just additions?
+   - Check that question codes are unique in the database.
+   - It might be good to show the codes in GUI, so they know at least
+     which element will be called what
+ * Validation
+   - restore our json schema, there's probably several problems, it
+     was disabled because the questions didn't pass anymore.
+   - use it server side (and maybe client side as well?)
+ * Validate documents on the server before saving them.
+ * Implement authentication and later authorization.
+   - Can we hook in request API so stores work correctly?
+ * Export answers for a survey run
+   - Allow to include partial results, or just include submission date.
+   - Include an URL to the dataset/run so it can easily be traced back.
+   - Flatten object structure
+ * Check if it works on tablets. We could consider special tablet UI
+   later.
+ * Sessions
+   - modes: fixed, bulk, registration
+   - off-line session:
+     * provide a portal page where people can select available survey,
+       maybe later see progress.
+     * Allow for a registration round at the beginning (email, nick).
+     * Show name clearly in portal, to prevent mistakes with the
+       tablets.
+     * Allow sessions based on subnet or a session code (A23X5Y).
+     * Easy grouping of participants or selecting a subset for a
+       survey.
+     * On the server (localhost) show the ip(s) that people should
+       connect to.
+
+Checklist
+=========
+
+ * Form validation (use tooltips!)
+ * Input validation & escaping
+   - E.g. texts and labels of ScaleWidget are directly put in innerHTML, I don't think TextBox does any escaping.
+ * Output escaping
+ * Widget life-cycle
+   buildRendering -> widgets in code before set attributes
+   postCreate -> after all inits, but before in DOM
+   startup -> after insertion in DOM?
+ * Review current JSON formats, do they allow for extension or extra meta-data?
+ 
+Open issues
+===========
+
+ * Do different inputs in one question get different codes? E.g. in 
+   To ease exporting into other programs and easy communication, the codes
+   are important I think. It should be easy to pronounce, and easy to
+   find in the tool (people might get a dataset and not know where it
+   came from).
+ * What if a question is included in a survey multiple times. Use block
+   or allow a pre/post-fix on the code to differentiate it.
+   Should not be too much work, so if an scale with 5 items has 5 codes,
+   you should be able to set a prefix on all of them at once.
Index: v/trunk/docs/TODO.txt
===================================================================
--- /Dev/trunk/docs/TODO.txt	(revision 462)
+++ 	(revision )
@@ -1,48 +1,0 @@
-Todo
-====
-
- * Check that question codes are unique.
- * Validate documents on the server before saving them.
- * Implement authentication and later authorization.
- * Question is always shown as 'no topic' when no category is added to it.
- * Check that answers are saved correctly.
-   Answers to multi-item questions (like scales) are stored in an object
-   now with index as keys. This is not symmetrical with the fact that the
-   configuration is an array.
- * Export answers for a survey run
- * Revive json schema checks for our data.
-   Questions don't pass the schema at the moment.
- * Fragile: widget creation relies on the names in Factory, but these
-   must match the types returned by the actual widgets. Fix this.
- * Write a spec for the codes.
- * Don't allow Save in Question unless all question items are done editing.
- * Use node as a server, adopt the layout described in
-   http://dojotoolkit.org/documentation/tutorials/1.8/node/
-   This will require quite a lot of moving and creating a rest interface
-   -> can be just a proxy to CouchDB in he beginning.
-
-Checklist
-=========
-
- * Form validation (use tooltips!)
- * Input validation & escaping
-   - E.g. texts and labels of ScaleWidget are directly put in innerHTML, I don't think TextBox does any escaping.
- * Output escaping
- * Widget life-cycle
-   buildRendering -> widgets in code before set attributes
-   postCreate -> after all inits, but before in DOM
-   startup -> after insertion in DOM?
- * Review current JSON formats, do they allow for extension or extra meta-data?
- 
-Open issues
-===========
-
- * Do different inputs in one question get different codes? E.g. in 
-   To ease exporting into other programs and easy communication, the codes
-   are important I think. It should be easy to pronounce, and easy to
-   find in the tool (people might get a dataset and not know where it
-   came from).
- * What if a question is included in a survey multiple times. Use block
-   or allow a pre/post-fix on the code to differentiate it.
-   Should not be too much work, so if an scale with 5 items has 5 codes,
-   you should be able to set a prefix on all of them at once.
Index: /Dev/trunk/package.json
===================================================================
--- /Dev/trunk/package.json	(revision 463)
+++ /Dev/trunk/package.json	(revision 463)
@@ -0,0 +1,18 @@
+{
+  "name": "qed-full",
+  "version": "0.0.1",
+  "description": "QED Full",
+  "devDependencies": {
+    "grunt": "~0.4.0",
+    "grunt-contrib-copy": "~0.4.1",
+    "grunt-contrib-jshint": "~0.2.0",
+    "grunt-contrib-less": "~0.5.0",
+    "grunt-dojo": "~0.2.3",
+    "grunt-exec": "~0.4.1",
+    "grunt-htmlhint": "~0.4.0",
+    "grunt-contrib-clean": "~0.4.1",
+    "grunt-zip": "~0.9.0",
+    "grunt-curl": "~1.1.0",
+    "grunt-contrib-coffee": "~0.7.0"
+  }
+}
Index: v/trunk/src/Gruntfile.js
===================================================================
--- /Dev/trunk/src/Gruntfile.js	(revision 462)
+++ 	(revision )
@@ -1,115 +1,0 @@
-/***************************************
- * This Gruntfile is organized with two phases,
- * compile and build. Compile will lint HTML,
- * JavaScript and compile LESS. The build phase
- * creates an optimized stand-alone build that
- * can be distributed.
- */
-var fs = require('fs');
-var path = require('path');
-
-module.exports = function(grunt) {
-
-    var buildDir = '../build/';
-    var binDir = buildDir+'bin/';
-    var distDir = '../dist/';
-
-    grunt.initConfig({
-        clean: {
-            build: {
-                options: {
-                    force: true
-                },
-                src: [buildDir],
-            }
-        },
-        copy: {
-            build: {
-                files: [
-                    {src: ['client/*.html'], dest: buildDir},
-                    {src: ['server/**', '!**/node_modules/**'], dest: buildDir},
-                    {src: ['qed-server.key', 'qed-server.pem'], dest: buildDir},
-                ]
-            },
-            dist: {
-                files: [
-                    {src: ['client/bin/'], dest: binDir},
-                    {src: ['server/**', '!**/node_modules/**'], dest: buildDir},
-                    {src: ['qed-server.key', 'qed-server.pem'], dest: buildDir},
-                ]
-            }
-        },
-        'curl-dir': {
-            dist: {
-                src: [
-                    'http://apache.xl-mirror.nl/couchdb/binary/win/1.3.0/setup-couchdb-1.3.0_R15B03-1.exe',
-                    'http://nodejs.org/dist/v0.10.10/node-v0.10.10-x86.msi'
-                ],
-                dest: binDir
-            }
-        },
-        dojo: {
-            options: {
-                dojo: 'client/dojo/dojo.js',
-            },
-            build: {
-                options: {
-                    profile: 'client/client.profile.js'
-                }
-            }
-        },
-        htmlhint: {
-            options: {
-                htmlhintrc: ".htmlhintrc"
-            },
-            compile: {
-                files: {
-                    src: ['client/*.html', 'client/qed-client/**.html']
-                }
-            }
-        },
-        jshint: {
-            options: {
-                jshintrc: ".jshintrc"
-            },
-            compile: {
-                files: {
-                    src: ['client/qed-client/**/*.js', 'server/**.js', '!**/node_modules/**']
-                }
-            }
-        },
-        less: {
-            options: {
-                strictImports: false,
-                dumpLineNumbers: "all"
-            },
-            compile: {
-                files: {
-                    'client/qed-client/css/qed.css': 'client/qed-client/css/qed.less'
-                }
-            }
-        },
-        zip: {
-            dist: {
-                cwd: buildDir,
-                src: [buildDir+'**'],
-                dest: distDir+'qed-'+(new Date().toISOString())+'-x86.zip'
-            }
-        }
-    });
-
-    grunt.loadNpmTasks('grunt-contrib-clean');
-    grunt.loadNpmTasks('grunt-contrib-copy');
-    grunt.loadNpmTasks('grunt-contrib-jshint');
-    grunt.loadNpmTasks('grunt-contrib-less');
-    grunt.loadNpmTasks('grunt-curl');
-    grunt.loadNpmTasks('grunt-dojo');
-    grunt.loadNpmTasks('grunt-htmlhint');
-    grunt.loadNpmTasks('grunt-zip');
-
-    grunt.registerTask('compile', ['less:compile', 'jshint:compile', 'htmlhint:compile']);
-    grunt.registerTask('build', ['clean:build', 'compile', 'dojo:build', 'copy:build']);
-    grunt.registerTask('dist', ['build', 'copy:dist', 'curl-dir:dist', 'zip:dist']);
-    grunt.registerTask('default', ['compile']);
-
-};
Index: /Dev/trunk/src/Procfile
===================================================================
--- /Dev/trunk/src/Procfile	(revision 463)
+++ /Dev/trunk/src/Procfile	(revision 463)
@@ -0,0 +1,1 @@
+web: node server/heroku.js
Index: /Dev/trunk/src/client/client.profile.js
===================================================================
--- /Dev/trunk/src/client/client.profile.js	(revision 462)
+++ /Dev/trunk/src/client/client.profile.js	(revision 463)
@@ -2,5 +2,4 @@
     return {
         basePath: '.',
-        releaseDir: '../../build',
         releaseName: 'client',
         action: 'release',
Index: /Dev/trunk/src/client/qed-client/index.js
===================================================================
--- /Dev/trunk/src/client/qed-client/index.js	(revision 462)
+++ /Dev/trunk/src/client/qed-client/index.js	(revision 463)
@@ -1,16 +1,20 @@
 define([
-    'dojo/_base/array',
-    'dojo/parser',
-    './app/Content',
-    './app/Page',
-    './app/Router',
-    './ui/MainMenu',
-    './routes',
-    './store',
-    'dojo/domReady!',
-    './stddeps'
-],function(array,parser,Content,Page,Router,MainMenu,routes,store) {
+    "./app/Content",
+    "./app/Page",
+    "./app/Router",
+    "./routes",
+    "./store",
+    "./store/request",
+    "./ui/MainMenu",
+    "dojo/_base/array",
+    "dojo/parser",
+    "dojo/request/registry",
+    "./stddeps",
+    "dojo/domReady!"
+], function(Content, Page, Router, routes, store, request, MainMenu, array, parser, registry) {
+
+    registry.register(/.*/,request);
+    
     parser.parse();
-
     store.info()
     .then(function(){
Index: /Dev/trunk/src/client/qed-client/pages/surveyRun.js
===================================================================
--- /Dev/trunk/src/client/qed-client/pages/surveyRun.js	(revision 462)
+++ /Dev/trunk/src/client/qed-client/pages/surveyRun.js	(revision 463)
@@ -72,7 +72,9 @@
             var surveyRun = this.surveyRunWidget.get('value');
             if ( surveyRun.mode === "open" ) {
-                this.runURLNode.innerHTML = this._link(this._getGeneralURL(store.getIdentity(this.surveyRun)));
+                this.runURLNode.innerHTML =
+                    this._link(this._getGeneralURL(store.getIdentity(this.surveyRun)));
             } else {
-                this.runURLNode.innerHTML = "No general URL. Add individual respondents below.";
+                this.runURLNode.innerHTML =
+                    "No general URL. Add individual respondents below.";
             }
         },
@@ -102,9 +104,15 @@
                 });
             }
-            event.stop(evt);
+            if ( evt ) { event.stop(evt); }
             return false;
         },
         _onDiscard: function(evt) {
             Router.go('/surveys');
+            if ( evt ) { event.stop(evt); }
+            return false;
+        },
+        _onExport: function(evt) {
+            if ( evt ) { event.stop(evt); }
+            return false;
         }
     });
Index: /Dev/trunk/src/client/qed-client/pages/templates/response.html
===================================================================
--- /Dev/trunk/src/client/qed-client/pages/templates/response.html	(revision 462)
+++ /Dev/trunk/src/client/qed-client/pages/templates/response.html	(revision 463)
@@ -1,5 +1,6 @@
 <div class="blue">
 
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region:'top'">
         <h2>
             <span class="rftIcon rftIconSurvey"></span>
@@ -9,10 +10,14 @@
     </div>
     
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'" data-dojo-attach-point="content">
-        <div name="answers" data-dojo-type="../model/widgets/SurveyRenderWidget" data-dojo-attach-point="surveyWidget"></div>
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region:'center'" data-dojo-attach-point="content">
+        <div name="answers"
+             data-dojo-type="../model/widgets/SurveyRenderWidget"
+             data-dojo-attach-point="surveyWidget"></div>
     </div>
     
 
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'bottom'">
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region:'bottom'">
         <button data-dojo-type="dijit/form/Button"
                 type="submit"
Index: /Dev/trunk/src/client/qed-client/pages/templates/surveyRun.html
===================================================================
--- /Dev/trunk/src/client/qed-client/pages/templates/surveyRun.html	(revision 462)
+++ /Dev/trunk/src/client/qed-client/pages/templates/surveyRun.html	(revision 463)
@@ -1,28 +1,58 @@
 <div class="blue">
 
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'">
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region:'top'">
         <h2>
             <span class="rftIcon rftIconSurvey"></span>
-            <span class="headerText" data-dojo-attach-point="titleNode">SurveyRun Editor</span>
+            <span class="headerText"
+                  data-dojo-attach-point="titleNode">SurveyRun Editor</span>
         </h2>
     </div>
     
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'">
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region:'center'">
         <fieldset class="qedFieldset">
             <legend>Survey</legend>
-            <div data-dojo-type="../model/widgets/SurveySummary" data-dojo-attach-point="surveySummaryWidget"></div>
+            <div data-dojo-type="../model/widgets/SurveySummary"
+                 data-dojo-attach-point="surveySummaryWidget"></div>
         </fieldset>
         <fieldset class="qedFieldset">
             <legend>Run Details</legend>
-            <div data-dojo-type="../model/widgets/SurveyRunWidget" data-dojo-attach-point="surveyRunWidget"></div>
+            <div data-dojo-type="../model/widgets/SurveyRunWidget"
+                 data-dojo-attach-point="surveyRunWidget"></div>
         </fieldset>
         <fieldset class="qedFieldset">
             <legend>Response Details</legend>
-            <div><div class="qedLabel">General URL</div><div class="qedField" data-dojo-attach-point="runURLNode" style="overflow: ellipsis"></div></div>
-            <div><div class="qedLabel">Responses <span data-dojo-attach-point="responsesCountNode"></span></div><div class="qedField qedFill" data-dojo-attach-point="responsesNode"></div></div>
+            <div>
+                <div class="qedLabel">General URL</div>
+                <div class="qedField"
+                     data-dojo-attach-point="runURLNode"
+                     style="overflow: ellipsis"></div>
+            </div>
+            <div>
+                <div class="qedLabel">Response count</div>
+                <div data-dojo-attach-point="responsesCountNode"></div>
+            </div>
+            <div>
+                <div class="qedLabel">In progress count</div>
+                <div data-dojo-attach-point="inprogressCountNode"></div>
+            </div>
+            <div>
+                <div class="qedLabel">Responses (including partial)</div>
+                <div class="qedField qedFill"
+                     data-dojo-attach-point="responsesNode"></div>
+            </div>
+            <div>
+                <div class="qedLabel">Export results</div>
+                <button data-dojo-type="dijit/form/Button"
+                        class="qedField blue"
+                        data-dojo-props="baseClass: 'rftBlockButton', iconClass: 'rftIcon rftIconSave'"
+                        data-dojo-attach-event="onClick:_onExport">To CSV</button>
+            </div>
         </fieldset>
     </div>
     
-    <div data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region: 'bottom'" style="height: 40px;">
+    <div data-dojo-type="dijit/layout/ContentPane"
+         data-dojo-props="region: 'bottom'" style="height: 40px;">
         <button data-dojo-type="dijit/form/Button"
                 class="blue"
Index: /Dev/trunk/src/client/qed-client/store/CouchStore.js
===================================================================
--- /Dev/trunk/src/client/qed-client/store/CouchStore.js	(revision 462)
+++ /Dev/trunk/src/client/qed-client/store/CouchStore.js	(revision 463)
@@ -5,5 +5,5 @@
     "dojo/_base/json",
     "dojo/_base/lang",
-    "dojo/request",
+    "dojo/request/registry",
     "dojo/store/util/QueryResults"
 ], function(Deferred, array, declare, json, lang, request, QueryResults) {
Index: /Dev/trunk/src/client/qed-client/store/request.js
===================================================================
--- /Dev/trunk/src/client/qed-client/store/request.js	(revision 463)
+++ /Dev/trunk/src/client/qed-client/store/request.js	(revision 463)
@@ -0,0 +1,36 @@
+define([
+    "dojo/Deferred",
+    "dojo/request"
+], function(Deferred, request) {
+
+    var authenticated = true;
+    var queue = [];
+    
+    var _request = function(url, options) {
+        var dfd = new Deferred();
+        if ( authenticated ) {
+            request(url,options).response.then(function(response){
+                console.log(response);
+            }, function(error){
+                if ( error.response.status === 401 ) {
+                    queue.push({
+                        url: url,
+                        options: options,
+                        dfd: dfd
+                    });
+                    console.log("Retry goes here :)");
+                } else {
+                    dfd.reject(error);
+                }
+            });
+        } else {
+            queue.push({
+                url: url,
+                options: options,
+                dfd: dfd
+            });
+        }
+        return dfd.promise;
+    };
+    return _request;
+});
Index: /Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee
===================================================================
--- /Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee	(revision 463)
+++ /Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.coffee	(revision 463)
@@ -0,0 +1,45 @@
+define [
+    "dijit/_Container",
+    "dijit/form/_FormMixin",
+    "dojo/_base/array",
+    "dojo/_base/declare",
+    "dojo/_base/event"
+], (_Container, _FormMixin, array, declare, event) ->
+    declare [_Container,_FormMixin],
+        name: ""
+        value: null
+        disabled: false
+        readOnly: false
+
+        postCreate: () ->
+            @inherited arguments
+            if @domNode.tagName.toLowerCase() isnt "form"
+                console.warn "Not scoping a _ComplexValueMixin in a form element can cause name clashes. E.g. radio buttons might stop working correctly. It is recommended to use <form> as the root element in your template for", @declaredClass
+
+        _setDisabledAttr: (value) ->
+            @_set "disabled", value
+            array.forEach @_getDescendantFormWidgets() (child) => 
+                child.set "disabled", value
+
+        _setReadOnlyAttr: (value) ->
+            @_set "readOnly", value
+            array.forEach @_getDescendantFormWidgets() (child) =>
+                child.set "readOnly", value
+
+        focus: () ->
+            children = @_getDescendantFormWidgets()
+            children[0].focus() if children.length > 0
+
+        onSubmit: (e) =>
+            # since this widget is used to create more complex
+            # widgets within other forms, the onSubmit must either be
+            # ignored or propagated, but not handled here.
+            event.stop e if e
+            false
+
+        _onSubmit: (e) =>
+            # since this widget is used to create more complex
+            # widgets within other forms, the onSubmit must either be
+            # ignored or propagated, but not handled here.
+            event.stop if e
+            false
Index: v/trunk/src/client/qed-client/widgets/_ComplexValueMixin.js
===================================================================
--- /Dev/trunk/src/client/qed-client/widgets/_ComplexValueMixin.js	(revision 462)
+++ 	(revision )
@@ -1,52 +1,0 @@
-define([
-    "dijit/_Container",
-    "dijit/form/_FormMixin",
-    "dojo/_base/array",
-    "dojo/_base/declare",
-    "dojo/_base/event"
-], function(_Container, _FormMixin, array, declare, event) {
-    return declare([_Container,_FormMixin],{
-        name: "",
-        value: null,
-        disabled: false,
-        readOnly: false,
-        postCreate: function() {
-            this.inherited(arguments);
-            if ( this.domNode.tagName.toLowerCase() !== "form" ) {
-                console.warn("Not scoping a _ComplexValueMixin in a form element can cause name clashes. E.g. radio buttons might stop working correctly. It is recommended to use <form> as the root element in your template for "+this.declaredClass+".");
-            }
-        },
-        _setDisabledAttr: function(value) {
-            this._set("disabled", value);
-            array.forEach(this._getDescendantFormWidgets(), function(child){
-                child.set("disabled", value);
-            });
-        },
-        _setReadOnlyAttr: function(value) {
-            this._set("readOnly", value);
-            array.forEach(this._getDescendantFormWidgets(), function(child){
-                child.set("readOnly", value);
-            });
-        },
-        focus: function() {
-            var children = this._getDescendantFormWidgets();
-            if ( children.length > 0 ) {
-                children[0].focus();
-            }
-        },
-        onSubmit: function(e) {
-            // since this widget is used to create more complex
-            // widgets within other forms, the onSubmit must either be
-            // ignored or propagated, but not handled here.
-            if ( e ) { event.stop(e); }
-            return false;
-        },
-        _onSubmit: function(e) {
-            // since this widget is used to create more complex
-            // widgets within other forms, the onSubmit must either be
-            // ignored or propagated, but not handled here.
-            if ( e ) { event.stop(e); }
-            return false;
-        }
-    });
-});
Index: /Dev/trunk/src/package.json
===================================================================
--- /Dev/trunk/src/package.json	(revision 462)
+++ /Dev/trunk/src/package.json	(revision 463)
@@ -1,22 +1,16 @@
 {
-  "name": "qed-full",
+  "name": "qed-server",
   "version": "0.0.1",
-  "description": "QED Full",
-  "devDependencies": {
-    "grunt": "~0.4.0",
-    "grunt-contrib-copy": "~0.4.1",
-    "grunt-contrib-jshint": "~0.2.0",
-    "grunt-contrib-less": "~0.5.0",
-    "grunt-dojo": "~0.2.3",
-    "grunt-exec": "~0.4.1",
-    "grunt-htmlhint": "~0.4.0",
-    "grunt-contrib-clean": "~0.4.1",
-    "grunt-zip": "~0.9.0",
-    "grunt-curl": "~1.1.0"
+  "description": "QED Server",
+  "dependencies": {
+    "simple-http-proxy": "~0.5.2",
+    "express": "~3.2.3",
+    "underscore": "~1.4.4",
+    "passport": "~0.1.17",
+    "passport-local": "~0.1.6"
   },
-  "dependencies": {
-    "underscore": "~1.4.4",
-    "q": "~0.9.4",
-    "q-io": "~1.7.0"
+  "engines": {
+    "node": "0.10.x",
+    "npm": "1.2.x"
   }
 }
Index: /Dev/trunk/src/server/app.js
===================================================================
--- /Dev/trunk/src/server/app.js	(revision 463)
+++ /Dev/trunk/src/server/app.js	(revision 463)
@@ -0,0 +1,67 @@
+var express = require("express");
+var passport = require("passport"),
+    passportLocal = require("passport-local");
+var fs = require("fs");
+var path = require("path");
+var proxy = require("simple-http-proxy");
+var _ = require("underscore");
+
+function assertSetting(name, settings, validate) {
+    if ( typeof settings[name] === 'undefined' ) {
+        throw new Error("Required setting '"+name+"' undefined.");
+    }
+    if ( _.isFunction(validate) && !validate(settings[name]) ) {
+        throw new Error("Setting '"+name+"' with value '"+settings[name]+"' is invalid.");
+    }
+}
+
+exports.App = function(settings) {
+
+    assertSetting("couchDbURL", settings, _.isString);
+    
+    function clientPath(relativePath) {
+        return path.resolve(__dirname+'/../client/'+relativePath);
+    }
+
+    passport.use(new passportLocal.Strategy(function(username, password, done){
+        if ( username === "igor" && password === "mayer" ) {
+            done(null,{ username: "igor" });
+        } else {
+            done(null,false,{ message: 'Invalid credentials.' });
+        }
+    }));
+
+    var app = express();
+    app.use(express.logger());
+    app.use(express.compress());
+    app.use(express.favicon());
+
+    app.use(express.cookieParser());
+    app.use(express.bodyParser());
+    app.use(express.session({ secret: "quasi experimental design" }));
+
+    // initialize passport
+    app.use(passport.initialize());
+    app.use(passport.session());
+
+    // static resources
+    app.get('/', function(request, response){
+        response.sendfile(clientPath('index.html'));
+    });
+    app.get('/*.html', function(request, response) {
+        response.sendfile(clientPath(request.path));
+    });
+    _.each(['/dojo', '/dijit', '/dojox', '/qed', '/qed-client'], function(dir){
+        app.use(dir, express.static(clientPath(dir)));
+    });
+
+    // url to login (might work on others as well?)
+    // you should then have a session to work with
+    app.post('/api/login', passport.authenticate('local'));
+
+    // forward to couch
+    app.use('/data/couch', passport.authenticate('local'), proxy(settings.couchDbURL));
+
+    return app;
+
+};
Index: /Dev/trunk/src/server/heroku.js
===================================================================
--- /Dev/trunk/src/server/heroku.js	(revision 463)
+++ /Dev/trunk/src/server/heroku.js	(revision 463)
@@ -0,0 +1,8 @@
+var app = require('./app').App({
+    couchDbURL: 'http://localhost:5984/qed'
+});
+
+var port = process.env.PORT || 5000;
+app.listen(port, function() {
+    console.log('Listening on port',port);
+});
Index: v/trunk/src/server/package.json
===================================================================
--- /Dev/trunk/src/server/package.json	(revision 462)
+++ 	(revision )
@@ -1,10 +1,0 @@
-{
-  "name": "qed-server",
-  "version": "0.0.1",
-  "description": "QED Server",
-  "dependencies": {
-    "simple-http-proxy": "~0.5.2",
-    "express": "~3.2.3",
-    "underscore": "~1.4.4"
-  }
-}
Index: v/trunk/src/server/server.js
===================================================================
--- /Dev/trunk/src/server/server.js	(revision 462)
+++ 	(revision )
@@ -1,43 +1,0 @@
-var express = require("express");
-var fs = require("fs");
-var https = require("https");
-var os = require("os");
-var path = require("path");
-var proxy = require("simple-http-proxy");
-var _ = require("underscore");
-
-function clientPath(relativePath) {
-    return path.resolve('../client/'+relativePath);
-}
-
-var httpsOptions = {
-    key: fs.readFileSync(path.resolve('../qed-server.key')),
-    cert: fs.readFileSync(path.resolve('../qed-server.pem'))
-};
-
-var app = express();
-app.use(express.logger());
-app.use(express.compress());
-app.use(express.favicon());
-app.get('/', function(request, response){
-    response.sendfile(clientPath('index.html'));
-});
-app.get('/*.html', function(request, response) {
-    response.sendfile(clientPath(request.path));
-});
-_.each(['/dojo', '/dijit', '/dojox', '/qed', '/qed-client'], function(dir){
-    app.use(dir, express.static(clientPath(dir)));
-});
-app.use('/data/couch', proxy('http://localhost:5984/qed'));
-
-var server = https.createServer(httpsOptions, app);
-server.listen(8443);
-
-console.log(
-    "Listening on " + 
-    _.chain(os.networkInterfaces())
-     .map(function(value,key){ return value; })
-     .flatten()
-     .filter(function(intf){ return intf.family === "IPv4" && !intf.internal; })
-     .reduce(function(urls, intf){ return urls+', http://'+intf.address+':8443/'; }, "http://127.0.0.1:8443/")
-     .value() + ".");
Index: /Dev/trunk/src/server/standalone.js
===================================================================
--- /Dev/trunk/src/server/standalone.js	(revision 463)
+++ /Dev/trunk/src/server/standalone.js	(revision 463)
@@ -0,0 +1,26 @@
+var fs = require("fs");
+var https = require("https");
+var os = require("os");
+var path = require("path");
+var _ = require("underscore");
+
+var app = require('./app').App({
+    couchDbURL: 'http://localhost:5984/qed'
+});
+
+var httpsOptions = {
+    key: fs.readFileSync(path.resolve('../qed-server.key')),
+    cert: fs.readFileSync(path.resolve('../qed-server.pem'))
+};
+
+var server = https.createServer(httpsOptions, app);
+server.listen(8443);
+
+console.log(
+    "Listening on " + 
+    _.chain(os.networkInterfaces())
+     .map(function(value,key){ return value; })
+     .flatten()
+     .filter(function(intf){ return intf.family === "IPv4" && !intf.internal; })
+     .reduce(function(urls, intf){ return urls+', http://'+intf.address+':8443/'; }, "http://127.0.0.1:8443/")
+     .value() + ".");
