Index: Dev/trunk/src/server/util/couch.js
===================================================================
--- Dev/trunk/src/server/util/couch.js	(revision 522)
+++ Dev/trunk/src/server/util/couch.js	(revision 525)
@@ -1,8 +1,5 @@
-var CouchDB, _ref,
-  __hasProp = {}.hasOwnProperty;
-
-var request = require('./q-request')
+var request = require('./request')
   , _ = require('underscore')
-  , Q = require('q');
+  ;
 
 function CouchDB(url, db) {
@@ -58,26 +55,9 @@
         if (opts.headers) { _.extend(options.headers, opts.headers); }
     }
-    var req = request(url, options);
-    var res = req.response
-    .then(function(res) {
-        return req.then(function(res) {
-            return JSON.parse(res);
-        }, function(err) {
-            return Q.reject(JSON.parse(err));
+    return request(url, options)
+        .handle({
+            '-1': _.identity,
+            default: function(status,result) { return JSON.parse(result); }
         });
-    }, function(err) {
-        return Q.reject(err);
-    });
-    res.response = req.response
-    .then(function(res) {
-        return {
-            statusCode: res.statusCode,
-            headers: res.headers,
-            body: JSON.parse(res.body)
-        };
-    }, function(err) {
-        return Q.reject({error:err.message});
-    });
-    return res;
 }
 
@@ -108,3 +88,3 @@
 }
 
-exports.CouchDB = CouchDB;
+module.exports = CouchDB;
Index: Dev/trunk/src/server/util/crypto-token.js
===================================================================
--- Dev/trunk/src/server/util/crypto-token.js	(revision 522)
+++ Dev/trunk/src/server/util/crypto-token.js	(revision 525)
@@ -1,14 +1,12 @@
-var Q = require('q')
+var HTTPResult = require('./http-result')
   , crypto = require('crypto');
 
 module.exports = function(bytes) {
-    var q = Q.defer();
-    crypto.randomBytes(bytes || 8, function(ex, buf) {
-        if ( ex ) {
-            q.reject(ex);
-        } else {
-            q.resolve(buf.toString('hex'));
-        }
-    });
-    return q.promise;
+    bytes  =bytes || 8;
+    var result = new HTTPResult();
+    crypto.randomBytes(bytes, result.asCallback(201));
+    return result
+        .then(function(buf){
+            return buf.toString('hex');
+        });
 };
Index: Dev/trunk/src/server/util/http-result.js
===================================================================
--- Dev/trunk/src/server/util/http-result.js	(revision 522)
+++ Dev/trunk/src/server/util/http-result.js	(revision 525)
@@ -1,4 +1,14 @@
-// <init> :: status? -> result? -> HTTPResult
+var _ = require('underscore')
+  ;
+
+var when;
+
+// type Callback = status:Number -> result:Any -> Either HTTPResult Any
+// type Handler = { f:Callback, next:HTTPResult }
+
+// <init> :: status:Number? -> result:Any? -> HTTPResult
+var counter = 0;
 function HTTPResult(status,result) {
+    this.id = counter++;
     this.status = 0;
     this.result = null;
@@ -9,19 +19,4 @@
 }
 
-HTTPResult.fromResponsePromise = function(promise,errorHandler) {
-    var result = new HTTPResult();
-    promise.then(function(response){
-        result.set(response.statusCode,response.body);
-    }, errorHandler && function(error){
-        var ret = errorHandler(error);
-        if ( ret.constructor === HTTPResult ) {
-            ret.handle(result.set.bind(result));
-        } else {
-            result.set(500,ret);
-        }
-    });
-    return result;
-};
-
 // isSet :: Bool
 HTTPResult.prototype.isSet = function() {
@@ -29,32 +24,34 @@
 };
 
-// set :: status -> result? -> ()
+// set :: status:Number -> result:Any? -> ()
 HTTPResult.prototype.set = function(status,result) {
-    if ( this.isSet() ) { throw new Error("Result was already set."); }
-    if ( typeof status !== 'number' ) { throw new Error("Status must be a number."); }
+    if ( this.isSet() ) {
+        throw new Error("Result was already set.");
+    }
+    if ( !_.isNumber(status) ) {
+        throw new Error("Status must be a number.");
+    }
     this.status = status;
     this.result = result;
-    for ( var i = 0; i < this._handlers.length; i++ ) {
-        this._fire(this._handlers[i]);
+    _.each(this._handlers,this._fire.bind(this));
+};
+
+// _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);
     }
 };
 
-// _fire :: (status -> result -> Either HTTPResult Any) -> ()
-HTTPResult.prototype._fire = function(f) {
-    var ret = f(this.status,this.result);
-    if ( ret.constructor === HTTPResult ) {
-        ret.handle(f._next.set.bind(f._next));
-    } else {
-        f._next.set(this.status,ret);
-    }
-};
-
-/* handle :: Either (status -> result -> Either HTTPResult Any)
- *                  {number: (result -> Either HTTPResult Any),
- *                   'default': (status -> result -> Either HTTPResult Any)}
+/* handle :: Either Callback
+ *                  {status:Number*: (result -> Either HTTPResult Any),
+ *                   'default'?: Callback}
  *           -> HTTPResult
  */
 HTTPResult.prototype.handle = function(fOrObj) {
-    var f = typeof fOrObj === 'function' ?
+    var f = _.isFunction(fOrObj) ?
             fOrObj :
             function(status,result) {
@@ -67,11 +64,64 @@
                 }
             };
-    f._next = new HTTPResult();
+    var next = new HTTPResult();
+    var handler = {
+        f: f,
+        next: next
+    };
     if ( this.isSet() ) {
-        this._fire(f);
+        this._fire(handler);
     } else {
-        this._handlers.push(f);
+        this._handlers.push(handler);
     }
-    return f._next;
+    return next;
+};
+
+// then :: onSuccess:(result:Any -> status:Number)? ->
+//         onError:(result:Any -> status:Number)? -> HTTPResult
+HTTPResult.prototype.then = function(onSuccess,onError) {
+    var f = function(status,result) {
+        if ( status >= 200 && status < 300 && onSuccess ) {
+            if ( onSuccess ) {
+                result = onSuccess(result,status);
+            }
+        } else {
+            if ( onError ) {
+                result = onError(result,status);
+            }
+        }
+        return result;
+    };
+    return this.handle(f);
+};
+
+HTTPResult.prototype.asCallback = function(status) {
+    status = status || 200;
+    return function(ex,result) {
+        if ( ex ) {
+            this.set(-1,ex);
+        } else {
+            this.set(status,result);
+        }
+    }.bind(this);
+};
+
+// when :: Either HTTPResult Any -> HTTPResult
+when = HTTPResult.when = function(status,valueOrResult) {
+    status = status || 200;
+    if ( valueOrResult instanceof HTTPResult ) {
+        return valueOrResult;
+    } else {
+        return new HTTPResult(status,valueOrResult);
+    }
+};
+
+// ok :: result:Any? -> HTTPResult
+HTTPResult.ok = function(result) {
+    return new HTTPResult(200,result);
+};
+
+// fail :: error:Any? -> HTTPResult
+HTTPResult.fail = function(error) {
+    return new HTTPResult(-1,error);
 };
 
Index: Dev/trunk/src/server/util/object.js
===================================================================
--- Dev/trunk/src/server/util/object.js	(revision 525)
+++ Dev/trunk/src/server/util/object.js	(revision 525)
@@ -0,0 +1,30 @@
+var _ = require('underscore')
+  ;
+
+var exportFields = exports.collectFields = function collectFields(field,obj) {
+    if ( _.isObject(obj) ) {
+        return _.reduce(obj,function(vals,val,key){
+            if ( key === field ) {
+                vals.push(val);
+            }
+            return vals.concat(collectFields(field,val));
+        },[]);
+    } else {
+        return [];
+    }
+};
+
+var findDuplicates = exports.findDuplicates = function(array,iterator) {
+    iterator = iterator || _.identity;
+    array = _.sortBy(array,iterator);
+    return _.chain(_.initial(array))
+            .zip(_.rest(array))
+            .reduce(function(dups,nAndSn){
+                if ( iterator(nAndSn[0]) === iterator(nAndSn[1]) &&
+                     nAndSn[0] !== _.last(dups) ) {
+                    return dups.concat([nAndSn[0]]);
+                }
+                return dups;
+            },[])
+            .value();
+};
Index: Dev/trunk/src/server/util/q-request.js
===================================================================
--- Dev/trunk/src/server/util/q-request.js	(revision 522)
+++ 	(revision )
@@ -1,30 +1,0 @@
-var q = require('q'),
-    request = require('request'),
-    url = require('url'),
-    _ = require('underscore');
-
-module.exports = function(url, options) {
-
-    var dfd_body = q.defer();
-    var dfd_response = q.defer();
-    dfd_body.promise.response = dfd_response.promise;
-    
-    options = options ? _.clone(options) : {};
-    options.uri = url || options.uri;
-    
-    request(options,function(err,res,body){
-        if ( err ) {
-            dfd_response.reject(err);
-        } else {
-            dfd_response.resolve(res);
-            if ( res.statusCode >= 200 && res.statusCode < 300 ) {
-                dfd_body.resolve(body);
-            } else {
-                dfd_body.reject(body);
-            }
-        }
-    });
-
-    return dfd_body.promise;
-    
-};
Index: Dev/trunk/src/server/util/request.js
===================================================================
--- Dev/trunk/src/server/util/request.js	(revision 525)
+++ Dev/trunk/src/server/util/request.js	(revision 525)
@@ -0,0 +1,24 @@
+var HTTPResult = require('./http-result')
+  , request = require('request')
+  , url = require('url')
+  , _ = require('underscore')
+  ;
+
+module.exports = function(url, options) {
+
+    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);
+        }
+    });
+
+    return result;
+    
+};
