Index: Dev/trunk/src/package.json
===================================================================
--- Dev/trunk/src/package.json	(revision 526)
+++ Dev/trunk/src/package.json	(revision 527)
@@ -8,5 +8,4 @@
     "passport": "~0.1.18",
     "passport-local": "~0.1.6",
-    "request": "~2.21.0",
     "ya-csv": "~0.9.3",
     "tv4": "~1.0.16"
Index: Dev/trunk/src/server/api/categories.js
===================================================================
--- Dev/trunk/src/server/api/categories.js	(revision 526)
+++ Dev/trunk/src/server/api/categories.js	(revision 527)
@@ -15,4 +15,5 @@
         return couch.get(url,{query:{reduce:true,group:true,group_level:1}})
         .handle({
+            '-1': _.identity,
             200: function(result) {
                 return _.map(result.rows, function(item) {
@@ -29,4 +30,5 @@
             var sub = 'published' in req.query && 'published';
             getCategories(sub)
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -37,4 +39,5 @@
             var sub = 'published' in req.query && 'published';
             topics.getTopicsWithCategory(category,sub)
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
Index: Dev/trunk/src/server/api/open.js
===================================================================
--- Dev/trunk/src/server/api/open.js	(revision 526)
+++ Dev/trunk/src/server/api/open.js	(revision 527)
@@ -44,4 +44,5 @@
                 }
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -74,4 +75,5 @@
                 }
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -112,4 +114,5 @@
                 }
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -141,4 +144,5 @@
                 }
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
Index: Dev/trunk/src/server/api/questions.js
===================================================================
--- Dev/trunk/src/server/api/questions.js	(revision 526)
+++ Dev/trunk/src/server/api/questions.js	(revision 527)
@@ -17,4 +17,5 @@
         return couch.get(url,{query:query})
         .handle({
+            '-1': _.identity,
             200: util.handleRowDocs,
             default: util.handleUnknownResponse
@@ -26,4 +27,5 @@
         return couch.get(url,{query:query})
         .handle({
+            '-1': _.identity,
             200: util.handleRowDocs,
             default: util.handleUnknownResponse
@@ -35,4 +37,5 @@
         return couch.get(url,{query:query})
         .handle({
+            '-1': _.identity,
             200: util.handleRowDictOfValues,
             default: util.handleUnknownResponse
@@ -44,4 +47,5 @@
         return couch.get(url,{query:query})
         .handle({
+            '-1': _.identity,
             200: util.handleRowDocs,
             default: util.handleUnknownResponse
@@ -56,4 +60,5 @@
         return couch.get(url,{query:query})
         .handle({
+            '-1': _.identity,
             200: util.handleRowDocs,
             default: util.handleUnknownResponse
@@ -67,4 +72,5 @@
         return couch.get(url)
         .handle({
+            '-1': _.identity,
             200: util.handleRowDictOfValues,
             default: util.handleUnknownResponse
@@ -93,5 +99,6 @@
                 hr = getQuestions(sub);
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.post('/',
@@ -122,5 +129,6 @@
                 });
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.get('/:id',
@@ -160,5 +168,6 @@
                 });
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.delete('/:id',
Index: Dev/trunk/src/server/api/responses.js
===================================================================
--- Dev/trunk/src/server/api/responses.js	(revision 526)
+++ Dev/trunk/src/server/api/responses.js	(revision 527)
@@ -16,4 +16,5 @@
         return couch.get(url)
         .handle({
+            '-1': _.identity,
             200: util.handleRowValues,
             default: util.handleUnknownResponse
@@ -30,5 +31,6 @@
                 hr = util.getDocumentsOfType('Response');
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.get('/:id',
@@ -44,4 +46,5 @@
                 return util.postDocument('Response',doc);
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -64,5 +67,6 @@
                 hr = util.putDocument(id,rev,'Response',doc);
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.delete('/:id',
Index: Dev/trunk/src/server/api/surveyRuns.js
===================================================================
--- Dev/trunk/src/server/api/surveyRuns.js	(revision 526)
+++ Dev/trunk/src/server/api/surveyRuns.js	(revision 527)
@@ -30,5 +30,6 @@
                 });
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.get('/:id',
@@ -53,5 +54,6 @@
                 hr = util.putDocument(id,rev,'SurveyRun',doc);
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.delete('/:id',
@@ -70,5 +72,7 @@
                     }
                 }
-            }).handle(res.send.bind(res));
+            })
+            .handle({'-1': util.handleException})
+            .handle(res.send.bind(res));
         });
     app.get('/:id/responses',
@@ -77,4 +81,5 @@
             var id = req.params.id;
             responses.getResponsesBySurveyRunId(id)
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -85,4 +90,8 @@
             responses.getResponsesBySurveyRunId(id)
             .handle({
+                '-1': function(result) {
+                    util.handleException(result)
+                    .handle(res.send.bind(res));
+                },
                 200: function(responses) {
                     var answers = _.map(responses,function(response){
Index: Dev/trunk/src/server/api/surveys.js
===================================================================
--- Dev/trunk/src/server/api/surveys.js	(revision 526)
+++ Dev/trunk/src/server/api/surveys.js	(revision 527)
@@ -23,4 +23,5 @@
             couch.get(url)
             .handle({
+                '-1': _.identity,
                 200: function(result) {
                     return _.map(result.rows, function(item) {
@@ -30,4 +31,5 @@
                 default: util.handleUnknownResponse
             })
+            .handle({'-1': util.handleException})
             .handle(res.send.bind(res));
         });
@@ -45,5 +47,6 @@
                 hr = util.postDocument('Survey',doc);
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
     app.get('/:id',
@@ -66,4 +69,8 @@
                 util.putDocument(id,rev,'Survey',doc)
                 .handle({
+                    '-1': function(result) {
+                        util.handleException(result)
+                        .handle(res.send.bind(res));
+                    },
                     201: function(doc) {
                         res.set({
Index: Dev/trunk/src/server/api/topics.js
===================================================================
--- Dev/trunk/src/server/api/topics.js	(revision 526)
+++ Dev/trunk/src/server/api/topics.js	(revision 527)
@@ -14,4 +14,5 @@
         return couch.get(url,{query:{reduce:true,group:true}})
         .handle({
+            '-1': _.identity,
             200: function(result) {
                 return _.map(result.rows, function(item) { return {name:item.key, count:item.value}; });
@@ -24,4 +25,5 @@
         return couch.get(url,{query:{reduce:true,group:true,group_level:2,startkey:[category],endkey:[category,{}]}})
         .handle({
+            '-1': _.identity,
             200: function(result) {
                 return _.map(result.rows, function(item) { return { name:item.key[1], count:item.value }; });
@@ -41,5 +43,6 @@
                 hr = getTopics(sub);
             }
-            hr.handle(res.send.bind(res));
+            hr.handle({'-1': util.handleException})
+              .handle(res.send.bind(res));
         });
 
Index: Dev/trunk/src/server/api/util.js
===================================================================
--- Dev/trunk/src/server/api/util.js	(revision 526)
+++ Dev/trunk/src/server/api/util.js	(revision 527)
@@ -34,4 +34,11 @@
     };
 
+    var handleException = exports.handleException = function(error) {
+        return new HTTPResult(500,{
+            reason: error.message,
+            filename: error.filename,
+            lineNumber: error.lineNumber
+        });
+    };
     var handleUnknownResponse = exports.handleUnknownResponse = function(status,error) {
         return new HTTPResult(500,{error: error.reason});
@@ -77,4 +84,5 @@
         return couch.get(url)
         .handle({
+            '-1': _.identity,
             200: handleRowValues,
             404: function() { return {error: "Cannot find collection of type "+type}; },
@@ -89,4 +97,5 @@
         return couch.get(id,opts)
         .handle({
+            '-1': _.identity,
             200: function(doc){
                 if ( doc.type !== type ) {
@@ -114,4 +123,5 @@
             return couch.put(id,doc,opts)
             .handle({
+                '-1': _.identity,
                 201: function(res){
                     doc._id = res.id;
@@ -133,4 +143,5 @@
             return couch.delete(id,opts)
             .handle({
+                '-1': _.identity,
                 200: identity,
                 409: function(error) {
@@ -149,4 +160,5 @@
             return couch.post(doc)
             .handle({
+                '-1': _.identity,
                 201: function(response) {
                     doc._id = response.id;
@@ -164,4 +176,5 @@
         return function(req,res) {
             getDocumentsOfType(type)
+            .handle({'-1': handleException})
             .handle(res.send.bind(res));
         };
@@ -173,4 +186,8 @@
             getDocument(id,rev,type)
             .handle({
+                '-1': function(result) {
+                    handleException(result)
+                    .handle(res.send.bind(res));
+                },
                 200: function(doc){
                     res.set({
@@ -189,4 +206,8 @@
             putDocument(id,rev,type,doc)
             .handle({
+                '-1': function(result) {
+                    handleException(result)
+                    .handle(res.send.bind(res));
+                },
                 201: function(doc) {
                     res.set({
@@ -204,4 +225,5 @@
             var rev = etags.parse(req.header('If-Match'))[0] || (doc && doc._rev);
             deleteDocument(id,rev)
+            .handle({'-1': handleException})
             .handle(res.send.bind(res));
         };
@@ -212,4 +234,8 @@
             postDocument(type,doc)
             .handle({
+                '-1': function(result) {
+                    handleException(result)
+                    .handle(res.send.bind(res));
+                },
                 201: function(doc) {
                     res.set({
Index: Dev/trunk/src/server/util/couch.js
===================================================================
--- Dev/trunk/src/server/util/couch.js	(revision 526)
+++ Dev/trunk/src/server/util/couch.js	(revision 527)
@@ -1,4 +1,5 @@
 var request = require('./request')
   , _ = require('underscore')
+  , HTTPResult = require('./http-result')
   ;
 
@@ -42,12 +43,13 @@
 }
 
-function couchRequest (method, url, body, opts) {
+function couchRequest (method, url, body, opts, retries) {
+    body = body || {};
+    retries = _.isNumber(retries) ? retries : 3;
     var options = {
         method: method,
-        headers: {
-            'Content-Type': 'application/json; charset=utf-8',
-            'Accept': 'application/json'
-        },
-        body: JSON.stringify(stringifyFunctions(body || {}))
+        headers: {},
+        body: stringifyFunctions(body),
+        json: true,
+        timeout: 5000
     };
     if (opts) {
@@ -56,8 +58,15 @@
     }
     return request(url, options)
-        .handle({
-            '-1': _.identity,
-            default: function(status,result) { return JSON.parse(result); }
-        });
+    .handle(function(status,body){
+        if ( _.isUndefined(body) ) {
+            if ( retries > 0) {
+                return couchRequest(method,url,body,opts,retries-1);
+            } else {
+                return new HTTPResult(-1,new Error("No response after several retries."));
+            }
+        } else {
+            return body;
+        }
+    });
 }
 
Index: Dev/trunk/src/server/util/http-result.js
===================================================================
--- Dev/trunk/src/server/util/http-result.js	(revision 526)
+++ Dev/trunk/src/server/util/http-result.js	(revision 527)
@@ -39,9 +39,14 @@
 // _fire :: Handler -> ()
 HTTPResult.prototype._fire = function(handler) {
-    var ret = handler.f(this.status,this.result);
-    if ( ret instanceof HTTPResult ) {
-        ret.handle(handler.next.set.bind(handler.next));
-    } else {
-        handler.next.set(this.status,ret);
+    try {
+        var ret = handler.f(this.status,this.result);
+        if ( ret instanceof HTTPResult ) {
+            ret.handle(handler.next.set.bind(handler.next));
+        } else {
+            handler.next.set(this.status,ret);
+        }
+    } catch(ex) {
+        console.log('HTTPResult','exception',ex.toString(),ex.stack);
+        handler.next.set(-1,ex);
     }
 };
Index: Dev/trunk/src/server/util/request.js
===================================================================
--- Dev/trunk/src/server/util/request.js	(revision 526)
+++ Dev/trunk/src/server/util/request.js	(revision 527)
@@ -1,5 +1,6 @@
 var HTTPResult = require('./http-result')
-  , request = require('request')
-  , url = require('url')
+  , HTTP = require('http')
+  , HTTPS = require('https')
+  , URL = require('url')
   , _ = require('underscore')
   ;
@@ -9,14 +10,63 @@
     var result = new HTTPResult();
     
-    options = options ? _.clone(options) : {};
-    options.uri = url || options.uri;
-    
-    request(options,function(err,res,body){
-        if ( err ) {
-            result.set(-1,err);
-        } else {
-            result.set(res.statusCode,body);
-        }
+    var body = options.body;
+    delete options.body;
+
+    var json = options.json;
+    delete options.json;
+
+    var reqOpts = _.isString(url) ? URL.parse(url) : url;
+    _.extend(reqOpts,options);
+    if ( json === true ) {
+        options.headers = options.headers || {};
+        _.extend(options.headers,{
+            'Content-Type': 'application/json',
+            'Accepts': 'application/json'
+        });
+    }
+
+    var protocol = reqOpts.protocol;
+    var httpModule;
+    if ( protocol === 'http:' ) {
+        httpModule = HTTP;
+    } else if ( protocol === 'https:' ) {
+        httpModule = HTTPS;
+    } else {
+        throw new Error("Unknown protocol "+protocol);
+    }
+
+    var req = httpModule.request(reqOpts);
+    req.on('response', function(response) {
+        var data = "";
+        response.setEncoding('utf8');
+        response.on('data', function(chunk) {
+            data += chunk;
+        });
+        response.on('end', function() {
+            var body;
+            try {
+                if ( json ) {
+                    if ( data ) { body = JSON.parse(data); }
+                } else {
+                    body = data;
+                }
+                result.set(response.statusCode,body);
+            } catch (ex) {
+                console.log('error',data);
+                result.set(-1,ex);
+            }
+        });
+        response.on('error', function(error) {
+            result.set(-1,error);
+        });
     });
+    req.on('error', function(error){
+        result.set(-1,error);
+    });
+
+    if ( body ) {
+        req.write(json ? JSON.stringify(body) : body);
+    }
+    req.end();
 
     return result;
