http://git-wip-us.apache.org/repos/asf/usergrid-javascript/blob/94020d26/usergrid.js
----------------------------------------------------------------------
diff --git a/usergrid.js b/usergrid.js
new file mode 100644
index 0000000..5989d8a
--- /dev/null
+++ b/usergrid.js
@@ -0,0 +1,3286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+var UsergridEventable = function() {
+    throw Error("'UsergridEventable' is not intended to be invoked directly");
+};
+
+UsergridEventable.prototype = {
+    bind: function(event, fn) {
+        this._events = this._events || {};
+        this._events[event] = this._events[event] || [];
+        this._events[event].push(fn);
+    },
+    unbind: function(event, fn) {
+        this._events = this._events || {};
+        if (event in this._events === false) return;
+        this._events[event].splice(this._events[event].indexOf(fn), 1);
+    },
+    trigger: function(event) {
+        this._events = this._events || {};
+        if (event in this._events === false) return;
+        for (var i = 0; i < this._events[event].length; i++) {
+            this._events[event][i].apply(this, 
Array.prototype.slice.call(arguments, 1));
+        }
+    }
+};
+
+UsergridEventable.mixin = function(destObject) {
+    var props = [ "bind", "unbind", "trigger" ];
+    for (var i = 0; i < props.length; i++) {
+        if (props[i] in destObject.prototype) {
+            console.warn("overwriting '" + props[i] + "' on '" + 
destObject.name + "'.");
+            console.warn("the previous version can be found at '_" + props[i] 
+ "' on '" + destObject.name + "'.");
+            destObject.prototype["_" + props[i]] = 
destObject.prototype[props[i]];
+        }
+        destObject.prototype[props[i]] = UsergridEventable.prototype[props[i]];
+    }
+};
+
+(function() {
+    var name = "Logger", global = this, overwrittenName = global[name], 
exports;
+    /* logging */
+    function Logger(name) {
+        this.logEnabled = true;
+        this.init(name, true);
+    }
+    Logger.METHODS = [ "log", "error", "warn", "info", "debug", "assert", 
"clear", "count", "dir", "dirxml", "exception", "group", "groupCollapsed", 
"groupEnd", "profile", "profileEnd", "table", "time", "timeEnd", "trace" ];
+    Logger.prototype.init = function(name, logEnabled) {
+        this.name = name || "UNKNOWN";
+        this.logEnabled = logEnabled || true;
+        var addMethod = function(method) {
+            this[method] = this.createLogMethod(method);
+        }.bind(this);
+        Logger.METHODS.forEach(addMethod);
+    };
+    Logger.prototype.createLogMethod = function(method) {
+        return Logger.prototype.log.bind(this, method);
+    };
+    Logger.prototype.prefix = function(method, args) {
+        var prepend = "[" + method.toUpperCase() + "][" + name + "]:   ";
+        if ([ "log", "error", "warn", "info" ].indexOf(method) !== -1) {
+            if ("string" === typeof args[0]) {
+                args[0] = prepend + args[0];
+            } else {
+                args.unshift(prepend);
+            }
+        }
+        return args;
+    };
+    Logger.prototype.log = function() {
+        var args = [].slice.call(arguments);
+        method = args.shift();
+        if (Logger.METHODS.indexOf(method) === -1) {
+            method = "log";
+        }
+        if (!(this.logEnabled && console && console[method])) return;
+        args = this.prefix(method, args);
+        console[method].apply(console, args);
+    };
+    Logger.prototype.setLogEnabled = function(logEnabled) {
+        this.logEnabled = logEnabled || true;
+    };
+    Logger.mixin = function(destObject) {
+        destObject.__logger = new Logger(destObject.name || "UNKNOWN");
+        var addMethod = function(method) {
+            if (method in destObject.prototype) {
+                console.warn("overwriting '" + method + "' on '" + 
destObject.name + "'.");
+                console.warn("the previous version can be found at '_" + 
method + "' on '" + destObject.name + "'.");
+                destObject.prototype["_" + method] = 
destObject.prototype[method];
+            }
+            destObject.prototype[method] = 
destObject.__logger.createLogMethod(method);
+        };
+        Logger.METHODS.forEach(addMethod);
+    };
+    global[name] = Logger;
+    global[name].noConflict = function() {
+        if (overwrittenName) {
+            global[name] = overwrittenName;
+        }
+        return Logger;
+    };
+    return global[name];
+})();
+
+(function(global) {
+    var name = "Promise", overwrittenName = global[name], exports;
+    function Promise() {
+        this.complete = false;
+        this.error = null;
+        this.result = null;
+        this.callbacks = [];
+    }
+    Promise.prototype.then = function(callback, context) {
+        var f = function() {
+            return callback.apply(context, arguments);
+        };
+        if (this.complete) {
+            f(this.error, this.result);
+        } else {
+            this.callbacks.push(f);
+        }
+    };
+    Promise.prototype.done = function(error, result) {
+        this.complete = true;
+        this.error = error;
+        this.result = result;
+        if (this.callbacks) {
+            for (var i = 0; i < this.callbacks.length; i++) 
this.callbacks[i](error, result);
+            this.callbacks.length = 0;
+        }
+    };
+    Promise.join = function(promises) {
+        var p = new Promise(), total = promises.length, completed = 0, errors 
= [], results = [];
+        function notifier(i) {
+            return function(error, result) {
+                completed += 1;
+                errors[i] = error;
+                results[i] = result;
+                if (completed === total) {
+                    p.done(errors, results);
+                }
+            };
+        }
+        for (var i = 0; i < total; i++) {
+            promises[i]().then(notifier(i));
+        }
+        return p;
+    };
+    Promise.chain = function(promises, error, result) {
+        var p = new Promise();
+        if (promises === null || promises.length === 0) {
+            p.done(error, result);
+        } else {
+            promises[0](error, result).then(function(res, err) {
+                promises.splice(0, 1);
+                if (promises) {
+                    Promise.chain(promises, res, err).then(function(r, e) {
+                        p.done(r, e);
+                    });
+                } else {
+                    p.done(res, err);
+                }
+            });
+        }
+        return p;
+    };
+    global[name] = Promise;
+    global[name].noConflict = function() {
+        if (overwrittenName) {
+            global[name] = overwrittenName;
+        }
+        return Promise;
+    };
+    return global[name];
+})(this);
+
+(function() {
+    var name = "Ajax", global = this, overwrittenName = global[name], exports;
+    function partial() {
+        var args = Array.prototype.slice.call(arguments);
+        var fn = args.shift();
+        return fn.bind(this, args);
+    }
+    function Ajax() {
+        this.logger = new global.Logger(name);
+        var self = this;
+        function encode(data) {
+            var result = "";
+            if (typeof data === "string") {
+                result = data;
+            } else {
+                var e = encodeURIComponent;
+                for (var i in data) {
+                    if (data.hasOwnProperty(i)) {
+                        result += "&" + e(i) + "=" + e(data[i]);
+                    }
+                }
+            }
+            return result;
+        }
+        function request(m, u, d) {
+            var p = new Promise(), timeout;
+            self.logger.time(m + " " + u);
+            (function(xhr) {
+                xhr.onreadystatechange = function() {
+                    if (this.readyState === 4) {
+                        self.logger.timeEnd(m + " " + u);
+                        clearTimeout(timeout);
+                        p.done(null, this);
+                    }
+                };
+                xhr.onerror = function(response) {
+                    clearTimeout(timeout);
+                    p.done(response, null);
+                };
+                xhr.oncomplete = function(response) {
+                    clearTimeout(timeout);
+                    self.logger.timeEnd(m + " " + u);
+                    self.info("%s request to %s returned %s", m, u, 
this.status);
+                };
+                xhr.open(m, u);
+                if (d) {
+                    if ("object" === typeof d) {
+                        d = JSON.stringify(d);
+                    }
+                    xhr.setRequestHeader("Content-Type", "application/json");
+                    xhr.setRequestHeader("Accept", "application/json");
+                }
+                timeout = setTimeout(function() {
+                    xhr.abort();
+                    p.done("API Call timed out.", null);
+                }, 3e4);
+                xhr.send(encode(d));
+            })(new XMLHttpRequest());
+            return p;
+        }
+        this.request = request;
+        this.get = partial(request, "GET");
+        this.post = partial(request, "POST");
+        this.put = partial(request, "PUT");
+        this.delete = partial(request, "DELETE");
+    }
+    global[name] = new Ajax();
+    global[name].noConflict = function() {
+        if (overwrittenName) {
+            global[name] = overwrittenName;
+        }
+        return exports;
+    };
+    return global[name];
+})();
+
+/*
+ *  This module is a collection of classes designed to make working with
+ *  the Appigee App Services API as easy as possible.
+ *  Learn more at http://Usergrid.com/docs/usergrid
+ *
+ *   Copyright 2012 Usergrid Corporation
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  @author rod simpson ([email protected])
+ *  @author matt dobson ([email protected])
+ *  @author ryan bridges ([email protected])
+ */
+window.console = window.console || {};
+
+window.console.log = window.console.log || function() {};
+
+function extend(subClass, superClass) {
+    var F = function() {};
+    F.prototype = superClass.prototype;
+    subClass.prototype = new F();
+    subClass.prototype.constructor = subClass;
+    subClass.superclass = superClass.prototype;
+    if (superClass.prototype.constructor == Object.prototype.constructor) {
+        superClass.prototype.constructor = superClass;
+    }
+    return subClass;
+}
+
+function propCopy(from, to) {
+    for (var prop in from) {
+        if (from.hasOwnProperty(prop)) {
+            if ("object" === typeof from[prop] && "object" === typeof 
to[prop]) {
+                to[prop] = propCopy(from[prop], to[prop]);
+            } else {
+                to[prop] = from[prop];
+            }
+        }
+    }
+    return to;
+}
+
+function NOOP() {}
+
+function isValidUrl(url) {
+    if (!url) return false;
+    var doc, base, anchor, isValid = false;
+    try {
+        doc = document.implementation.createHTMLDocument("");
+        base = doc.createElement("base");
+        base.href = base || window.lo;
+        doc.head.appendChild(base);
+        anchor = doc.createElement("a");
+        anchor.href = url;
+        doc.body.appendChild(anchor);
+        isValid = !(anchor.href === "");
+    } catch (e) {
+        console.error(e);
+    } finally {
+        doc.head.removeChild(base);
+        doc.body.removeChild(anchor);
+        base = null;
+        anchor = null;
+        doc = null;
+        return isValid;
+    }
+}
+
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+var uuidValueRegex = 
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
+
+function isUUID(uuid) {
+    return !uuid ? false : uuidValueRegex.test(uuid);
+}
+
+/*
+ *  method to encode the query string parameters
+ *
+ *  @method encodeParams
+ *  @public
+ *  @params {object} params - an object of name value pairs that will be 
urlencoded
+ *  @return {string} Returns the encoded string
+ */
+function encodeParams(params) {
+    var queryString;
+    if (params && Object.keys(params)) {
+        queryString = [].slice.call(arguments).reduce(function(a, b) {
+            return a.concat(b instanceof Array ? b : [ b ]);
+        }, []).filter(function(c) {
+            return "object" === typeof c;
+        }).reduce(function(p, c) {
+            !(c instanceof Array) ? p = 
p.concat(Object.keys(c).map(function(key) {
+                return [ key, c[key] ];
+            })) : p.push(c);
+            return p;
+        }, []).reduce(function(p, c) {
+            c.length === 2 ? p.push(c) : p = p.concat(c);
+            return p;
+        }, []).reduce(function(p, c) {
+            c[1] instanceof Array ? c[1].forEach(function(v) {
+                p.push([ c[0], v ]);
+            }) : p.push(c);
+            return p;
+        }, []).map(function(c) {
+            c[1] = encodeURIComponent(c[1]);
+            return c.join("=");
+        }).join("&");
+    }
+    return queryString;
+}
+
+/*
+ *  method to determine whether or not the passed variable is a function
+ *
+ *  @method isFunction
+ *  @public
+ *  @params {any} f - any variable
+ *  @return {boolean} Returns true or false
+ */
+function isFunction(f) {
+    return f && f !== null && typeof f === "function";
+}
+
+/*
+ *  a safe wrapper for executing a callback
+ *
+ *  @method doCallback
+ *  @public
+ *  @params {Function} callback - the passed-in callback method
+ *  @params {Array} params - an array of arguments to pass to the callback
+ *  @params {Object} context - an optional calling context for the callback
+ *  @return Returns whatever would be returned by the callback. or false.
+ */
+function doCallback(callback, params, context) {
+    var returnValue;
+    if (isFunction(callback)) {
+        if (!params) params = [];
+        if (!context) context = this;
+        params.push(context);
+        returnValue = callback.apply(context, params);
+    }
+    return returnValue;
+}
+
+(function(global) {
+    var name = "Usergrid", overwrittenName = global[name];
+    var VALID_REQUEST_METHODS = [ "GET", "POST", "PUT", "DELETE" ];
+    function Usergrid() {
+        this.logger = new Logger(name);
+    }
+    Usergrid.isValidEndpoint = function(endpoint) {
+        return true;
+    };
+    Usergrid.Request = function(method, endpoint, query_params, data, 
callback) {
+        var p = new Promise();
+        /*
+         Create a logger
+         */
+        this.logger = new global.Logger("Usergrid.Request");
+        this.logger.time("process request " + method + " " + endpoint);
+        /*
+         Validate our input
+         */
+        this.endpoint = endpoint + "?" + encodeParams(query_params);
+        this.method = method.toUpperCase();
+        this.data = "object" === typeof data ? JSON.stringify(data) : data;
+        if (VALID_REQUEST_METHODS.indexOf(this.method) === -1) {
+            throw new UsergridInvalidHTTPMethodError("invalid request method 
'" + this.method + "'");
+        }
+        /*
+         Prepare our request
+         */
+        if (!isValidUrl(this.endpoint)) {
+            this.logger.error(endpoint, this.endpoint, 
/^https:\/\//.test(endpoint));
+            throw new UsergridInvalidURIError("The provided endpoint is not 
valid: " + this.endpoint);
+        }
+        /* a callback to make the request */
+        var request = function() {
+            return Ajax.request(this.method, this.endpoint, this.data);
+        }.bind(this);
+        /* a callback to process the response */
+        var response = function(err, request) {
+            return new Usergrid.Response(err, request);
+        }.bind(this);
+        /* a callback to clean up and return data to the client */
+        var oncomplete = function(err, response) {
+            p.done(err, response);
+            this.logger.info("REQUEST", err, response);
+            doCallback(callback, [ err, response ]);
+            this.logger.timeEnd("process request " + method + " " + endpoint);
+        }.bind(this);
+        /* and a promise to chain them all together */
+        Promise.chain([ request, response ]).then(oncomplete);
+        return p;
+    };
+    Usergrid.Response = function(err, response) {
+        var p = new Promise();
+        var data = null;
+        try {
+            data = JSON.parse(response.responseText);
+        } catch (e) {
+            data = {};
+        }
+        Object.keys(data).forEach(function(key) {
+            Object.defineProperty(this, key, {
+                value: data[key],
+                enumerable: true
+            });
+        }.bind(this));
+        Object.defineProperty(this, "logger", {
+            enumerable: false,
+            configurable: false,
+            writable: false,
+            value: new global.Logger(name)
+        });
+        Object.defineProperty(this, "success", {
+            enumerable: false,
+            configurable: false,
+            writable: true,
+            value: true
+        });
+        Object.defineProperty(this, "err", {
+            enumerable: false,
+            configurable: false,
+            writable: true,
+            value: err
+        });
+        Object.defineProperty(this, "status", {
+            enumerable: false,
+            configurable: false,
+            writable: true,
+            value: parseInt(response.status)
+        });
+        Object.defineProperty(this, "statusGroup", {
+            enumerable: false,
+            configurable: false,
+            writable: true,
+            value: this.status - this.status % 100
+        });
+        switch (this.statusGroup) {
+          case 200:
+            this.success = true;
+            break;
+
+          case 400:
+          case 500:
+          case 300:
+          case 100:
+          default:
+            this.success = false;
+            break;
+        }
+        if (this.success) {
+            p.done(null, this);
+        } else {
+            p.done(UsergridError.fromResponse(data), this);
+        }
+        return p;
+    };
+    Usergrid.Response.prototype.getEntities = function() {
+        var entities;
+        if (this.success) {
+            entities = this.data ? this.data.entities : this.entities;
+        }
+        return entities || [];
+    };
+    Usergrid.Response.prototype.getEntity = function() {
+        var entities = this.getEntities();
+        return entities[0];
+    };
+    Usergrid.VERSION = Usergrid.USERGRID_SDK_VERSION = "0.11.0";
+    global[name] = Usergrid;
+    global[name].noConflict = function() {
+        if (overwrittenName) {
+            global[name] = overwrittenName;
+        }
+        return Usergrid;
+    };
+    return global[name];
+})(this);
+
+(function() {
+    var name = "Client", global = this, overwrittenName = global[name], 
exports;
+    var AUTH_ERRORS = [ "auth_expired_session_token", 
"auth_missing_credentials", "auth_unverified_oath", "expired_token", 
"unauthorized", "auth_invalid" ];
+    Usergrid.Client = function(options) {
+        this.URI = options.URI || "https://api.usergrid.com";;
+        if (options.orgName) {
+            this.set("orgName", options.orgName);
+        }
+        if (options.appName) {
+            this.set("appName", options.appName);
+        }
+        if (options.qs) {
+            this.setObject("default_qs", options.qs);
+        }
+        this.buildCurl = options.buildCurl || false;
+        this.logging = options.logging || false;
+    };
+    /*
+   *  Main function for making requests to the API.  Can be called directly.
+   *
+   *  options object:
+   *  `method` - http method (GET, POST, PUT, or DELETE), defaults to GET
+   *  `qs` - object containing querystring values to be appended to the uri
+   *  `body` - object containing entity body for POST and PUT requests
+   *  `endpoint` - API endpoint, for example 'users/fred'
+   *  `mQuery` - boolean, set to true if running management query, defaults to 
false
+   *
+   *  @method request
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.request = function(options, callback) {
+        var method = options.method || "GET";
+        var endpoint = options.endpoint;
+        var body = options.body || {};
+        var qs = options.qs || {};
+        var mQuery = options.mQuery || false;
+        var orgName = this.get("orgName");
+        var appName = this.get("appName");
+        var default_qs = this.getObject("default_qs");
+        var uri;
+        /*var logoutCallback=function(){
+        if (typeof(this.logoutCallback) === 'function') {
+            return this.logoutCallback(true, 'no_org_or_app_name_specified');
+        }
+    }.bind(this);*/
+        if (!mQuery && !orgName && !appName) {
+            return logoutCallback();
+        }
+        if (mQuery) {
+            uri = this.URI + "/" + endpoint;
+        } else {
+            uri = this.URI + "/" + orgName + "/" + appName + "/" + endpoint;
+        }
+        if (this.getToken()) {
+            qs.access_token = this.getToken();
+        }
+        if (default_qs) {
+            qs = propCopy(qs, default_qs);
+        }
+        var self = this;
+        var req = new Usergrid.Request(method, uri, qs, body, function(err, 
response) {
+            /*if (AUTH_ERRORS.indexOf(response.error) !== -1) {
+            return logoutCallback();
+        }*/
+            if (err) {
+                doCallback(callback, [ err, response, self ], self);
+            } else {
+                doCallback(callback, [ null, response, self ], self);
+            }
+        });
+    };
+    /*
+   *  function for building asset urls
+   *
+   *  @method buildAssetURL
+   *  @public
+   *  @params {string} uuid
+   *  @return {string} assetURL
+   */
+    Usergrid.Client.prototype.buildAssetURL = function(uuid) {
+        var self = this;
+        var qs = {};
+        var assetURL = this.URI + "/" + this.orgName + "/" + this.appName + 
"/assets/" + uuid + "/data";
+        if (self.getToken()) {
+            qs.access_token = self.getToken();
+        }
+        var encoded_params = encodeParams(qs);
+        if (encoded_params) {
+            assetURL += "?" + encoded_params;
+        }
+        return assetURL;
+    };
+    /*
+   *  Main function for creating new groups. Call this directly.
+   *
+   *  @method createGroup
+   *  @public
+   *  @params {string} path
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.createGroup = function(options, callback) {
+        var group = new Usergrid.Group({
+            path: options.path,
+            client: this,
+            data: options
+        });
+        group.save(function(err, response) {
+            doCallback(callback, [ err, response, group ], group);
+        });
+    };
+    /*
+   *  Main function for creating new entities - should be called directly.
+   *
+   *  options object: options {data:{'type':'collection_type', 'key':'value'}, 
uuid:uuid}}
+   *
+   *  @method createEntity
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.createEntity = function(options, callback) {
+        var entity = new Usergrid.Entity({
+            client: this,
+            data: options
+        });
+        entity.save(function(err, response) {
+            doCallback(callback, [ err, response, entity ], entity);
+        });
+    };
+    /*
+   *  Main function for getting existing entities - should be called directly.
+   *
+   *  You must supply a uuid or (username or name). Username only applies to 
users.
+   *  Name applies to all custom entities
+   *
+   *  options object: options {data:{'type':'collection_type', 'name':'value', 
'username':'value'}, uuid:uuid}}
+   *
+   *  @method createEntity
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.getEntity = function(options, callback) {
+        var entity = new Usergrid.Entity({
+            client: this,
+            data: options
+        });
+        entity.fetch(function(err, response) {
+            doCallback(callback, [ err, response, entity ], entity);
+        });
+    };
+    /*
+   *  Main function for restoring an entity from serialized data.
+   *
+   *  serializedObject should have come from entityObject.serialize();
+   *
+   *  @method restoreEntity
+   *  @public
+   *  @param {string} serializedObject
+   *  @return {object} Entity Object
+   */
+    Usergrid.Client.prototype.restoreEntity = function(serializedObject) {
+        var data = JSON.parse(serializedObject);
+        var options = {
+            client: this,
+            data: data
+        };
+        var entity = new Usergrid.Entity(options);
+        return entity;
+    };
+    /*
+   *  Main function for creating new counters - should be called directly.
+   *
+   *  options object: options {timestamp:0, category:'value', counters:{name : 
value}}
+   *
+   *  @method createCounter
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, response, counter)
+   */
+    Usergrid.Client.prototype.createCounter = function(options, callback) {
+        var counter = new Usergrid.Counter({
+            client: this,
+            data: options
+        });
+        counter.save(callback);
+    };
+    /*
+   *  Main function for creating new assets - should be called directly.
+   *
+   *  options object: options {name:"photo.jpg", path:"/user/uploads", 
"content-type":"image/jpeg", owner:"F01DE600-0000-0000-0000-000000000000", 
file: FileOrBlobObject }
+   *
+   *  @method createCounter
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, response, counter)
+   */
+    Usergrid.Client.prototype.createAsset = function(options, callback) {
+        var file = options.file;
+        if (file) {
+            options.name = options.name || file.name;
+            options["content-type"] = options["content-type"] || file.type;
+            options.path = options.path || "/";
+            delete options.file;
+        }
+        var asset = new Usergrid.Asset({
+            client: this,
+            data: options
+        });
+        asset.save(function(err, response, asset) {
+            if (file && !err) {
+                asset.upload(file, callback);
+            } else {
+                doCallback(callback, [ err, response, asset ], asset);
+            }
+        });
+    };
+    /*
+   *  Main function for creating new collections - should be called directly.
+   *
+   *  options object: options {client:client, type: type, qs:qs}
+   *
+   *  @method createCollection
+   *  @public
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.createCollection = function(options, callback) {
+        options.client = this;
+        return new Usergrid.Collection(options, function(err, data, 
collection) {
+            console.log("createCollection", arguments);
+            doCallback(callback, [ err, collection, data ]);
+        });
+    };
+    /*
+   *  Main function for restoring a collection from serialized data.
+   *
+   *  serializedObject should have come from collectionObject.serialize();
+   *
+   *  @method restoreCollection
+   *  @public
+   *  @param {string} serializedObject
+   *  @return {object} Collection Object
+   */
+    Usergrid.Client.prototype.restoreCollection = function(serializedObject) {
+        var data = JSON.parse(serializedObject);
+        data.client = this;
+        var collection = new Usergrid.Collection(data);
+        return collection;
+    };
+    /*
+   *  Main function for retrieving a user's activity feed.
+   *
+   *  @method getFeedForUser
+   *  @public
+   *  @params {string} username
+   *  @param {function} callback
+   *  @return {callback} callback(err, data, activities)
+   */
+    Usergrid.Client.prototype.getFeedForUser = function(username, callback) {
+        var options = {
+            method: "GET",
+            endpoint: "users/" + username + "/feed"
+        };
+        this.request(options, function(err, data) {
+            if (err) {
+                doCallback(callback, [ err ]);
+            } else {
+                doCallback(callback, [ err, data, data.getEntities() ]);
+            }
+        });
+    };
+    /*
+   *  Function for creating new activities for the current user - should be 
called directly.
+   *
+   *  //user can be any of the following: "me", a uuid, a username
+   *  Note: the "me" alias will reference the currently logged in user (e.g. 
'users/me/activties')
+   *
+   *  //build a json object that looks like this:
+   *  var options =
+   *  {
+   *    "actor" : {
+   *      "displayName" :"myusername",
+   *      "uuid" : "myuserid",
+   *      "username" : "myusername",
+   *      "email" : "myemail",
+   *      "picture": "http://path/to/picture";,
+   *      "image" : {
+   *          "duration" : 0,
+   *          "height" : 80,
+   *          "url" : "http://www.gravatar.com/avatar/";,
+   *          "width" : 80
+   *      },
+   *    },
+   *    "verb" : "post",
+   *    "content" : "My cool message",
+   *    "lat" : 48.856614,
+   *    "lon" : 2.352222
+   *  }
+   *
+   *  @method createEntity
+   *  @public
+   *  @params {string} user // "me", a uuid, or a username
+   *  @params {object} options
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.createUserActivity = function(user, options, 
callback) {
+        options.type = "users/" + user + "/activities";
+        options = {
+            client: this,
+            data: options
+        };
+        var entity = new Usergrid.Entity(options);
+        entity.save(function(err, data) {
+            doCallback(callback, [ err, data, entity ]);
+        });
+    };
+    /*
+   *  Function for creating user activities with an associated user entity.
+   *
+   *  user object:
+   *  The user object passed into this function is an instance of 
Usergrid.Entity.
+   *
+   *  @method createUserActivityWithEntity
+   *  @public
+   *  @params {object} user
+   *  @params {string} content
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.createUserActivityWithEntity = function(user, 
content, callback) {
+        var username = user.get("username");
+        var options = {
+            actor: {
+                displayName: username,
+                uuid: user.get("uuid"),
+                username: username,
+                email: user.get("email"),
+                picture: user.get("picture"),
+                image: {
+                    duration: 0,
+                    height: 80,
+                    url: user.get("picture"),
+                    width: 80
+                }
+            },
+            verb: "post",
+            content: content
+        };
+        this.createUserActivity(username, options, callback);
+    };
+    /*
+   *  A private method to get call timing of last call
+   */
+    Usergrid.Client.prototype.calcTimeDiff = function() {
+        var seconds = 0;
+        var time = this._end - this._start;
+        try {
+            seconds = (time / 10 / 60).toFixed(2);
+        } catch (e) {
+            return 0;
+        }
+        return seconds;
+    };
+    /*
+   *  A public method to store the OAuth token for later use - uses 
localstorage if available
+   *
+   *  @method setToken
+   *  @public
+   *  @params {string} token
+   *  @return none
+   */
+    Usergrid.Client.prototype.setToken = function(token) {
+        this.set("token", token);
+    };
+    /*
+   *  A public method to get the OAuth token
+   *
+   *  @method getToken
+   *  @public
+   *  @return {string} token
+   */
+    Usergrid.Client.prototype.getToken = function() {
+        return this.get("token");
+    };
+    Usergrid.Client.prototype.setObject = function(key, value) {
+        if (value) {
+            value = JSON.stringify(value);
+        }
+        this.set(key, value);
+    };
+    Usergrid.Client.prototype.set = function(key, value) {
+        var keyStore = "apigee_" + key;
+        this[key] = value;
+        if (typeof Storage !== "undefined") {
+            if (value) {
+                localStorage.setItem(keyStore, value);
+            } else {
+                localStorage.removeItem(keyStore);
+            }
+        }
+    };
+    Usergrid.Client.prototype.getObject = function(key) {
+        return JSON.parse(this.get(key));
+    };
+    Usergrid.Client.prototype.get = function(key) {
+        var keyStore = "apigee_" + key;
+        var value = null;
+        if (this[key]) {
+            value = this[key];
+        } else if (typeof Storage !== "undefined") {
+            value = localStorage.getItem(keyStore);
+        }
+        return value;
+    };
+    /*
+   * A public facing helper method for signing up users
+   *
+   * @method signup
+   * @public
+   * @params {string} username
+   * @params {string} password
+   * @params {string} email
+   * @params {string} name
+   * @param {function} callback
+   * @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.signup = function(username, password, email, 
name, callback) {
+        var self = this;
+        var options = {
+            type: "users",
+            username: username,
+            password: password,
+            email: email,
+            name: name
+        };
+        this.createEntity(options, callback);
+    };
+    /*
+   *
+   *  A public method to log in an app user - stores the token for later use
+   *
+   *  @method login
+   *  @public
+   *  @params {string} username
+   *  @params {string} password
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.login = function(username, password, callback) {
+        var self = this;
+        var options = {
+            method: "POST",
+            endpoint: "token",
+            body: {
+                username: username,
+                password: password,
+                grant_type: "password"
+            }
+        };
+        self.request(options, function(err, response) {
+            var user = {};
+            if (err) {
+                if (self.logging) console.log("error trying to log user in");
+            } else {
+                var options = {
+                    client: self,
+                    data: response.user
+                };
+                user = new Usergrid.Entity(options);
+                self.setToken(response.access_token);
+            }
+            doCallback(callback, [ err, response, user ]);
+        });
+    };
+    Usergrid.Client.prototype.reAuthenticateLite = function(callback) {
+        var self = this;
+        var options = {
+            method: "GET",
+            endpoint: "management/me",
+            mQuery: true
+        };
+        this.request(options, function(err, response) {
+            if (err && self.logging) {
+                console.log("error trying to re-authenticate user");
+            } else {
+                self.setToken(response.data.access_token);
+            }
+            doCallback(callback, [ err ]);
+        });
+    };
+    Usergrid.Client.prototype.reAuthenticate = function(email, callback) {
+        var self = this;
+        var options = {
+            method: "GET",
+            endpoint: "management/users/" + email,
+            mQuery: true
+        };
+        this.request(options, function(err, response) {
+            var organizations = {};
+            var applications = {};
+            var user = {};
+            var data;
+            if (err && self.logging) {
+                console.log("error trying to full authenticate user");
+            } else {
+                data = response.data;
+                self.setToken(data.token);
+                self.set("email", data.email);
+                localStorage.setItem("accessToken", data.token);
+                localStorage.setItem("userUUID", data.uuid);
+                localStorage.setItem("userEmail", data.email);
+                var userData = {
+                    username: data.username,
+                    email: data.email,
+                    name: data.name,
+                    uuid: data.uuid
+                };
+                var options = {
+                    client: self,
+                    data: userData
+                };
+                user = new Usergrid.Entity(options);
+                organizations = data.organizations;
+                var org = "";
+                try {
+                    var existingOrg = self.get("orgName");
+                    org = organizations[existingOrg] ? 
organizations[existingOrg] : organizations[Object.keys(organizations)[0]];
+                    self.set("orgName", org.name);
+                } catch (e) {
+                    err = true;
+                    if (self.logging) {
+                        console.log("error selecting org");
+                    }
+                }
+                applications = self.parseApplicationsArray(org);
+                self.selectFirstApp(applications);
+                self.setObject("organizations", organizations);
+                self.setObject("applications", applications);
+            }
+            doCallback(callback, [ err, data, user, organizations, 
applications ], self);
+        });
+    };
+    /*
+   *  A public method to log in an app user with facebook - stores the token 
for later use
+   *
+   *  @method loginFacebook
+   *  @public
+   *  @params {string} username
+   *  @params {string} password
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.loginFacebook = function(facebookToken, 
callback) {
+        var self = this;
+        var options = {
+            method: "GET",
+            endpoint: "auth/facebook",
+            qs: {
+                fb_access_token: facebookToken
+            }
+        };
+        this.request(options, function(err, data) {
+            var user = {};
+            if (err && self.logging) {
+                console.log("error trying to log user in");
+            } else {
+                var options = {
+                    client: self,
+                    data: data.user
+                };
+                user = new Usergrid.Entity(options);
+                self.setToken(data.access_token);
+            }
+            doCallback(callback, [ err, data, user ], self);
+        });
+    };
+    /*
+   *  A public method to get the currently logged in user entity
+   *
+   *  @method getLoggedInUser
+   *  @public
+   *  @param {function} callback
+   *  @return {callback} callback(err, data)
+   */
+    Usergrid.Client.prototype.getLoggedInUser = function(callback) {
+        var self = this;
+        if (!this.getToken()) {
+            doCallback(callback, [ new UsergridError("Access Token not set"), 
null, self ], self);
+        } else {
+            var options = {
+                method: "GET",
+                endpoint: "users/me"
+            };
+            this.request(options, function(err, response) {
+                if (err) {
+                    if (self.logging) {
+                        console.log("error trying to log user in");
+                    }
+                    console.error(err, response);
+                    doCallback(callback, [ err, response, self ], self);
+                } else {
+                    var options = {
+                        client: self,
+                        data: response.getEntity()
+                    };
+                    var user = new Usergrid.Entity(options);
+                    doCallback(callback, [ null, response, user ], self);
+                }
+            });
+        }
+    };
+    /*
+   *  A public method to test if a user is logged in - does not guarantee that 
the token is still valid,
+   *  but rather that one exists
+   *
+   *  @method isLoggedIn
+   *  @public
+   *  @return {boolean} Returns true the user is logged in (has token and 
uuid), false if not
+   */
+    Usergrid.Client.prototype.isLoggedIn = function() {
+        var token = this.getToken();
+        return "undefined" !== typeof token && token !== null;
+    };
+    /*
+   *  A public method to log out an app user - clears all user fields from 
client
+   *
+   *  @method logout
+   *  @public
+   *  @return none
+   */
+    Usergrid.Client.prototype.logout = function() {
+        this.setToken();
+    };
+    /*
+   *  A public method to destroy access tokens on the server
+   *
+   *  @method logout
+   *  @public
+   *  @param {string} username the user associated with the token to revoke
+   *  @param {string} token set to 'null' to revoke the token of the currently 
logged in user
+   *    or set to token value to revoke a specific token
+   *  @param {string} revokeAll set to 'true' to revoke all tokens for the user
+   *  @return none
+   */
+    Usergrid.Client.prototype.destroyToken = function(username, token, 
revokeAll, callback) {
+        var options = {
+            client: self,
+            method: "PUT"
+        };
+        if (revokeAll === true) {
+            options.endpoint = "users/" + username + "/revoketokens";
+        } else if (token === null) {
+            options.endpoint = "users/" + username + "/revoketoken?token=" + 
this.getToken();
+        } else {
+            options.endpoint = "users/" + username + "/revoketoken?token=" + 
token;
+        }
+        this.request(options, function(err, data) {
+            if (err) {
+                if (self.logging) {
+                    console.log("error destroying access token");
+                }
+                doCallback(callback, [ err, data, null ], self);
+            } else {
+                if (revokeAll === true) {
+                    console.log("all user tokens invalidated");
+                } else {
+                    console.log("token invalidated");
+                }
+                doCallback(callback, [ err, data, null ], self);
+            }
+        });
+    };
+    /*
+   *  A public method to log out an app user - clears all user fields from 
client
+   *  and destroys the access token on the server.
+   *
+   *  @method logout
+   *  @public
+   *  @param {string} username the user associated with the token to revoke
+   *  @param {string} token set to 'null' to revoke the token of the currently 
logged in user
+   *   or set to token value to revoke a specific token
+   *  @param {string} revokeAll set to 'true' to revoke all tokens for the user
+   *  @return none
+   */
+    Usergrid.Client.prototype.logoutAndDestroyToken = function(username, 
token, revokeAll, callback) {
+        if (username === null) {
+            console.log("username required to revoke tokens");
+        } else {
+            this.destroyToken(username, token, revokeAll, callback);
+            if (revokeAll === true || token === this.getToken() || token === 
null) {
+                this.setToken(null);
+            }
+        }
+    };
+    /*
+   *  A private method to build the curl call to display on the command line
+   *
+   *  @method buildCurlCall
+   *  @private
+   *  @param {object} options
+   *  @return {string} curl
+   */
+    Usergrid.Client.prototype.buildCurlCall = function(options) {
+        var curl = [ "curl" ];
+        var method = (options.method || "GET").toUpperCase();
+        var body = options.body;
+        var uri = options.uri;
+        curl.push("-X");
+        curl.push([ "POST", "PUT", "DELETE" ].indexOf(method) >= 0 ? method : 
"GET");
+        curl.push(uri);
+        if ("object" === typeof body && Object.keys(body).length > 0 && [ 
"POST", "PUT" ].indexOf(method) !== -1) {
+            curl.push("-d");
+            curl.push("'" + JSON.stringify(body) + "'");
+        }
+        curl = curl.join(" ");
+        console.log(curl);
+        return curl;
+    };
+    Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) 
{
+        size = size || 50;
+        var image = "https://apigee.com/usergrid/images/user_profile.png";;
+        try {
+            if (picture) {
+                image = picture;
+            } else if (email.length) {
+                image = "https://secure.gravatar.com/avatar/"; + MD5(email) + 
"?s=" + size + 
encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png";);
+            }
+        } catch (e) {} finally {
+            return image;
+        }
+    };
+    global[name] = Usergrid.Client;
+    global[name].noConflict = function() {
+        if (overwrittenName) {
+            global[name] = overwrittenName;
+        }
+        return exports;
+    };
+    return global[name];
+})();
+
+var ENTITY_SYSTEM_PROPERTIES = [ "metadata", "created", "modified", 
"oldpassword", "newpassword", "type", "activated", "uuid" ];
+
+/*
+ *  A class to Model a Usergrid Entity.
+ *  Set the type and uuid of entity in the 'data' json object
+ *
+ *  @constructor
+ *  @param {object} options {client:client, data:{'type':'collection_type', 
uuid:'uuid', 'key':'value'}}
+ */
+Usergrid.Entity = function(options) {
+    this._data = {};
+    this._client = undefined;
+    if (options) {
+        this.set(options.data || {});
+        this._client = options.client || {};
+    }
+};
+
+/*
+ *  method to determine whether or not the passed variable is a Usergrid Entity
+ *
+ *  @method isEntity
+ *  @public
+ *  @params {any} obj - any variable
+ *  @return {boolean} Returns true or false
+ */
+Usergrid.Entity.isEntity = function(obj) {
+    return obj && obj instanceof Usergrid.Entity;
+};
+
+/*
+ *  method to determine whether or not the passed variable is a Usergrid Entity
+ *  That has been saved.
+ *
+ *  @method isPersistedEntity
+ *  @public
+ *  @params {any} obj - any variable
+ *  @return {boolean} Returns true or false
+ */
+Usergrid.Entity.isPersistedEntity = function(obj) {
+    return isEntity(obj) && isUUID(obj.get("uuid"));
+};
+
+/*
+ *  returns a serialized version of the entity object
+ *
+ *  Note: use the client.restoreEntity() function to restore
+ *
+ *  @method serialize
+ *  @return {string} data
+ */
+Usergrid.Entity.prototype.serialize = function() {
+    return JSON.stringify(this._data);
+};
+
+/*
+ *  gets a specific field or the entire data object. If null or no argument
+ *  passed, will return all data, else, will return a specific field
+ *
+ *  @method get
+ *  @param {string} field
+ *  @return {string} || {object} data
+ */
+Usergrid.Entity.prototype.get = function(key) {
+    var value;
+    if (arguments.length === 0) {
+        value = this._data;
+    } else if (arguments.length > 1) {
+        key = [].slice.call(arguments).reduce(function(p, c, i, a) {
+            if (c instanceof Array) {
+                p = p.concat(c);
+            } else {
+                p.push(c);
+            }
+            return p;
+        }, []);
+    }
+    if (key instanceof Array) {
+        var self = this;
+        value = key.map(function(k) {
+            return self.get(k);
+        });
+    } else if ("undefined" !== typeof key) {
+        value = this._data[key];
+    }
+    return value;
+};
+
+/*
+ *  adds a specific key value pair or object to the Entity's data
+ *  is additive - will not overwrite existing values unless they
+ *  are explicitly specified
+ *
+ *  @method set
+ *  @param {string} key || {object}
+ *  @param {string} value
+ *  @return none
+ */
+Usergrid.Entity.prototype.set = function(key, value) {
+    if (typeof key === "object") {
+        for (var field in key) {
+            this._data[field] = key[field];
+        }
+    } else if (typeof key === "string") {
+        if (value === null) {
+            delete this._data[key];
+        } else {
+            this._data[key] = value;
+        }
+    } else {
+        this._data = {};
+    }
+};
+
+Usergrid.Entity.prototype.getEndpoint = function() {
+    var type = this.get("type"), nameProperties = [ "uuid", "name" ], name;
+    if (type === undefined) {
+        throw new UsergridError("cannot fetch entity, no entity type 
specified", "no_type_specified");
+    } else if (/^users?$/.test(type)) {
+        nameProperties.unshift("username");
+    }
+    name = this.get(nameProperties).filter(function(x) {
+        return x !== null && "undefined" !== typeof x;
+    }).shift();
+    return name ? [ type, name ].join("/") : type;
+};
+
+/*
+ *  Saves the entity back to the database
+ *
+ *  @method save
+ *  @public
+ *  @param {function} callback
+ *  @return {callback} callback(err, response, self)
+ */
+Usergrid.Entity.prototype.save = function(callback) {
+    var self = this, type = this.get("type"), method = "POST", entityId = 
this.get("uuid"), changePassword, entityData = this.get(), options = {
+        method: method,
+        endpoint: type
+    };
+    if (entityId) {
+        options.method = "PUT";
+        options.endpoint += "/" + entityId;
+    }
+    options.body = Object.keys(entityData).filter(function(key) {
+        return ENTITY_SYSTEM_PROPERTIES.indexOf(key) === -1;
+    }).reduce(function(data, key) {
+        data[key] = entityData[key];
+        return data;
+    }, {});
+    self._client.request(options, function(err, response) {
+        var entity = response.getEntity();
+        if (entity) {
+            self.set(entity);
+            self.set("type", /^\//.test(response.path) ? 
response.path.substring(1) : response.path);
+        }
+        if (err && self._client.logging) {
+            console.log("could not save entity");
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ *
+ * Updates the user's password
+ */
+Usergrid.Entity.prototype.changePassword = function(oldpassword, newpassword, 
callback) {
+    var self = this;
+    if ("function" === typeof oldpassword && callback === undefined) {
+        callback = oldpassword;
+        oldpassword = self.get("oldpassword");
+        newpassword = self.get("newpassword");
+    }
+    self.set({
+        password: null,
+        oldpassword: null,
+        newpassword: null
+    });
+    if (/^users?$/.test(self.get("type")) && oldpassword && newpassword) {
+        var options = {
+            method: "PUT",
+            endpoint: "users/" + self.get("uuid") + "/password",
+            body: {
+                uuid: self.get("uuid"),
+                username: self.get("username"),
+                oldpassword: oldpassword,
+                newpassword: newpassword
+            }
+        };
+        self._client.request(options, function(err, response) {
+            if (err && self._client.logging) {
+                console.log("could not update user");
+            }
+            doCallback(callback, [ err, response, self ], self);
+        });
+    } else {
+        throw new UsergridInvalidArgumentError("Invalid arguments passed to 
'changePassword'");
+    }
+};
+
+/*
+ *  refreshes the entity by making a GET call back to the database
+ *
+ *  @method fetch
+ *  @public
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Entity.prototype.fetch = function(callback) {
+    var endpoint, self = this;
+    endpoint = this.getEndpoint();
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, response) {
+        var entity = response.getEntity();
+        if (entity) {
+            self.set(entity);
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ *  deletes the entity from the database - will only delete
+ *  if the object has a valid uuid
+ *
+ *  @method destroy
+ *  @public
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ *
+ */
+Usergrid.Entity.prototype.destroy = function(callback) {
+    var self = this;
+    var endpoint = this.getEndpoint();
+    var options = {
+        method: "DELETE",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, response) {
+        if (!err) {
+            self.set(null);
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ *  connects one entity to another
+ *
+ *  @method connect
+ *  @public
+ *  @param {string} connection
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ *
+ */
+Usergrid.Entity.prototype.connect = function(connection, entity, callback) {
+    this.addOrRemoveConnection("POST", connection, entity, callback);
+};
+
+/*
+ *  disconnects one entity from another
+ *
+ *  @method disconnect
+ *  @public
+ *  @param {string} connection
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ *
+ */
+Usergrid.Entity.prototype.disconnect = function(connection, entity, callback) {
+    this.addOrRemoveConnection("DELETE", connection, entity, callback);
+};
+
+/*
+ *  adds or removes a connection between two entities
+ *
+ *  @method addOrRemoveConnection
+ *  @public
+ *  @param {string} method
+ *  @param {string} connection
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ *
+ */
+Usergrid.Entity.prototype.addOrRemoveConnection = function(method, connection, 
entity, callback) {
+    var self = this;
+    if ([ "POST", "DELETE" ].indexOf(method.toUpperCase()) == -1) {
+        throw new UsergridInvalidArgumentError("invalid method for connection 
call. must be 'POST' or 'DELETE'");
+    }
+    var connecteeType = entity.get("type");
+    var connectee = this.getEntityId(entity);
+    if (!connectee) {
+        throw new UsergridInvalidArgumentError("connectee could not be 
identified");
+    }
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        throw new UsergridInvalidArgumentError("connector could not be 
identified");
+    }
+    var endpoint = [ connectorType, connector, connection, connecteeType, 
connectee ].join("/");
+    var options = {
+        method: method,
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, response) {
+        if (err && self._client.logging) {
+            console.log("There was an error with the connection call");
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ *  returns a unique identifier for an entity
+ *
+ *  @method connect
+ *  @public
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ *
+ */
+Usergrid.Entity.prototype.getEntityId = function(entity) {
+    var id;
+    if (isUUID(entity.get("uuid"))) {
+        id = entity.get("uuid");
+    } else if (this.get("type") === "users" || this.get("type") === "user") {
+        id = entity.get("username");
+    } else {
+        id = entity.get("name");
+    }
+    return id;
+};
+
+/*
+ *  gets an entities connections
+ *
+ *  @method getConnections
+ *  @public
+ *  @param {string} connection
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data, connections)
+ *
+ */
+Usergrid.Entity.prototype.getConnections = function(connection, callback) {
+    var self = this;
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        if (typeof callback === "function") {
+            var error = "Error in getConnections - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            doCallback(callback, [ true, error ], self);
+        }
+        return;
+    }
+    var endpoint = connectorType + "/" + connector + "/" + connection + "/";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be connected");
+        }
+        self[connection] = {};
+        var length = data && data.entities ? data.entities.length : 0;
+        for (var i = 0; i < length; i++) {
+            if (data.entities[i].type === "user") {
+                self[connection][data.entities[i].username] = data.entities[i];
+            } else {
+                self[connection][data.entities[i].name] = data.entities[i];
+            }
+        }
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Entity.prototype.getGroups = function(callback) {
+    var self = this;
+    var endpoint = "users" + "/" + this.get("uuid") + "/groups";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be connected");
+        }
+        self.groups = data.entities;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Entity.prototype.getActivities = function(callback) {
+    var self = this;
+    var endpoint = this.get("type") + "/" + this.get("uuid") + "/activities";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be connected");
+        }
+        for (var entity in data.entities) {
+            data.entities[entity].createdDate = new 
Date(data.entities[entity].created).toUTCString();
+        }
+        self.activities = data.entities;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Entity.prototype.getFollowing = function(callback) {
+    var self = this;
+    var endpoint = "users" + "/" + this.get("uuid") + "/following";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not get user following");
+        }
+        for (var entity in data.entities) {
+            data.entities[entity].createdDate = new 
Date(data.entities[entity].created).toUTCString();
+            var image = 
self._client.getDisplayImage(data.entities[entity].email, 
data.entities[entity].picture);
+            data.entities[entity]._portal_image_icon = image;
+        }
+        self.following = data.entities;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Entity.prototype.getFollowers = function(callback) {
+    var self = this;
+    var endpoint = "users" + "/" + this.get("uuid") + "/followers";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not get user followers");
+        }
+        for (var entity in data.entities) {
+            data.entities[entity].createdDate = new 
Date(data.entities[entity].created).toUTCString();
+            var image = 
self._client.getDisplayImage(data.entities[entity].email, 
data.entities[entity].picture);
+            data.entities[entity]._portal_image_icon = image;
+        }
+        self.followers = data.entities;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Client.prototype.createRole = function(roleName, permissions, 
callback) {
+    var options = {
+        type: "role",
+        name: roleName
+    };
+    this.createEntity(options, function(err, response, entity) {
+        if (err) {
+            doCallback(callback, [ err, response, self ]);
+        } else {
+            entity.assignPermissions(permissions, function(err, data) {
+                if (err) {
+                    doCallback(callback, [ err, response, self ]);
+                } else {
+                    doCallback(callback, [ err, data, data.data ], self);
+                }
+            });
+        }
+    });
+};
+
+Usergrid.Entity.prototype.getRoles = function(callback) {
+    var self = this;
+    var endpoint = this.get("type") + "/" + this.get("uuid") + "/roles";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not get user roles");
+        }
+        self.roles = data.entities;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+Usergrid.Entity.prototype.assignRole = function(roleName, callback) {
+    var self = this;
+    var type = self.get("type");
+    var collection = type + "s";
+    var entityID;
+    if (type == "user" && this.get("username") != null) {
+        entityID = self.get("username");
+    } else if (type == "group" && this.get("name") != null) {
+        entityID = self.get("name");
+    } else if (this.get("uuid") != null) {
+        entityID = self.get("uuid");
+    }
+    if (type != "users" && type != "groups") {
+        doCallback(callback, [ new UsergridError("entity must be a group or 
user", "invalid_entity_type"), null, this ], this);
+    }
+    var endpoint = "roles/" + roleName + "/" + collection + "/" + entityID;
+    var options = {
+        method: "POST",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, response) {
+        if (err) {
+            console.log("Could not assign role.");
+        }
+        doCallback(callback, [ err, response, self ]);
+    });
+};
+
+Usergrid.Entity.prototype.removeRole = function(roleName, callback) {
+    var self = this;
+    var type = self.get("type");
+    var collection = type + "s";
+    var entityID;
+    if (type == "user" && this.get("username") != null) {
+        entityID = this.get("username");
+    } else if (type == "group" && this.get("name") != null) {
+        entityID = this.get("name");
+    } else if (this.get("uuid") != null) {
+        entityID = this.get("uuid");
+    }
+    if (type != "users" && type != "groups") {
+        doCallback(callback, [ new UsergridError("entity must be a group or 
user", "invalid_entity_type"), null, this ], this);
+    }
+    var endpoint = "roles/" + roleName + "/" + collection + "/" + entityID;
+    var options = {
+        method: "DELETE",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, response) {
+        if (err) {
+            console.log("Could not assign role.");
+        }
+        doCallback(callback, [ err, response, self ]);
+    });
+};
+
+Usergrid.Entity.prototype.assignPermissions = function(permissions, callback) {
+    var self = this;
+    var entityID;
+    var type = this.get("type");
+    if (type != "user" && type != "users" && type != "group" && type != 
"groups" && type != "role" && type != "roles") {
+        doCallback(callback, [ new UsergridError("entity must be a group, 
user, or role", "invalid_entity_type"), null, this ], this);
+    }
+    if (type == "user" && this.get("username") != null) {
+        entityID = this.get("username");
+    } else if (type == "group" && this.get("name") != null) {
+        entityID = this.get("name");
+    } else if (this.get("uuid") != null) {
+        entityID = this.get("uuid");
+    }
+    var endpoint = type + "/" + entityID + "/permissions";
+    var options = {
+        method: "POST",
+        endpoint: endpoint,
+        body: {
+            permission: permissions
+        }
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not assign permissions");
+        }
+        doCallback(callback, [ err, data, data.data ], self);
+    });
+};
+
+Usergrid.Entity.prototype.removePermissions = function(permissions, callback) {
+    var self = this;
+    var entityID;
+    var type = this.get("type");
+    if (type != "user" && type != "users" && type != "group" && type != 
"groups" && type != "role" && type != "roles") {
+        doCallback(callback, [ new UsergridError("entity must be a group, 
user, or role", "invalid_entity_type"), null, this ], this);
+    }
+    if (type == "user" && this.get("username") != null) {
+        entityID = this.get("username");
+    } else if (type == "group" && this.get("name") != null) {
+        entityID = this.get("name");
+    } else if (this.get("uuid") != null) {
+        entityID = this.get("uuid");
+    }
+    var endpoint = type + "/" + entityID + "/permissions";
+    var options = {
+        method: "DELETE",
+        endpoint: endpoint,
+        qs: {
+            permission: permissions
+        }
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not remove permissions");
+        }
+        doCallback(callback, [ err, data, data.params.permission ], self);
+    });
+};
+
+Usergrid.Entity.prototype.getPermissions = function(callback) {
+    var self = this;
+    var endpoint = this.get("type") + "/" + this.get("uuid") + "/permissions";
+    var options = {
+        method: "GET",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("could not get user permissions");
+        }
+        var permissions = [];
+        if (data.data) {
+            var perms = data.data;
+            var count = 0;
+            for (var i in perms) {
+                count++;
+                var perm = perms[i];
+                var parts = perm.split(":");
+                var ops_part = "";
+                var path_part = parts[0];
+                if (parts.length > 1) {
+                    ops_part = parts[0];
+                    path_part = parts[1];
+                }
+                ops_part = ops_part.replace("*", "get,post,put,delete");
+                var ops = ops_part.split(",");
+                var ops_object = {};
+                ops_object.get = "no";
+                ops_object.post = "no";
+                ops_object.put = "no";
+                ops_object.delete = "no";
+                for (var j in ops) {
+                    ops_object[ops[j]] = "yes";
+                }
+                permissions.push({
+                    operations: ops_object,
+                    path: path_part,
+                    perm: perm
+                });
+            }
+        }
+        self.permissions = permissions;
+        doCallback(callback, [ err, data, data.entities ], self);
+    });
+};
+
+/*
+ *  The Collection class models Usergrid Collections.  It essentially
+ *  acts as a container for holding Entity objects, while providing
+ *  additional funcitonality such as paging, and saving
+ *
+ *  @constructor
+ *  @param {string} options - configuration object
+ *  @return {Collection} collection
+ */
+Usergrid.Collection = function(options) {
+    if (options) {
+        this._client = options.client;
+        this._type = options.type;
+        this.qs = options.qs || {};
+        this._list = options.list || [];
+        this._iterator = options.iterator || -1;
+        this._previous = options.previous || [];
+        this._next = options.next || null;
+        this._cursor = options.cursor || null;
+        if (options.list) {
+            var count = options.list.length;
+            for (var i = 0; i < count; i++) {
+                var entity = this._client.restoreEntity(options.list[i]);
+                this._list[i] = entity;
+            }
+        }
+    }
+};
+
+/*
+ *  method to determine whether or not the passed variable is a Usergrid 
Collection
+ *
+ *  @method isCollection
+ *  @public
+ *  @params {any} obj - any variable
+ *  @return {boolean} Returns true or false
+ */
+Usergrid.isCollection = function(obj) {
+    return obj && obj instanceof Usergrid.Collection;
+};
+
+/*
+ *  gets the data from the collection object for serialization
+ *
+ *  @method serialize
+ *  @return {object} data
+ */
+Usergrid.Collection.prototype.serialize = function() {
+    var data = {};
+    data.type = this._type;
+    data.qs = this.qs;
+    data.iterator = this._iterator;
+    data.previous = this._previous;
+    data.next = this._next;
+    data.cursor = this._cursor;
+    this.resetEntityPointer();
+    var i = 0;
+    data.list = [];
+    while (this.hasNextEntity()) {
+        var entity = this.getNextEntity();
+        data.list[i] = entity.serialize();
+        i++;
+    }
+    data = JSON.stringify(data);
+    return data;
+};
+
+/*Usergrid.Collection.prototype.addCollection = function (collectionName, 
options, callback) {
+  self = this;
+  options.client = this._client;
+  var collection = new Usergrid.Collection(options, function(err, data) {
+    if (typeof(callback) === 'function') {
+
+      collection.resetEntityPointer();
+      while(collection.hasNextEntity()) {
+        var user = collection.getNextEntity();
+        var email = user.get('email');
+        var image = self._client.getDisplayImage(user.get('email'), 
user.get('picture'));
+        user._portal_image_icon = image;
+      }
+
+      self[collectionName] = collection;
+      doCallback(callback, [err, collection], self);
+    }
+  });
+};*/
+/*
+ *  Populates the collection from the server
+ *
+ *  @method fetch
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection.prototype.fetch = function(callback) {
+    var self = this;
+    var qs = this.qs;
+    if (this._cursor) {
+        qs.cursor = this._cursor;
+    } else {
+        delete qs.cursor;
+    }
+    var options = {
+        method: "GET",
+        endpoint: this._type,
+        qs: this.qs
+    };
+    this._client.request(options, function(err, response) {
+        if (err && self._client.logging) {
+            console.log("error getting collection");
+        } else {
+            self.saveCursor(response.cursor || null);
+            self.resetEntityPointer();
+            self._list = response.getEntities().filter(function(entity) {
+                return isUUID(entity.uuid);
+            }).map(function(entity) {
+                var ent = new Usergrid.Entity({
+                    client: self._client
+                });
+                ent.set(entity);
+                ent.type = self._type;
+                return ent;
+            });
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ *  Adds a new Entity to the collection (saves, then adds to the local object)
+ *
+ *  @method addNewEntity
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data, entity)
+ */
+Usergrid.Collection.prototype.addEntity = function(entityObject, callback) {
+    var self = this;
+    entityObject.type = this._type;
+    this._client.createEntity(entityObject, function(err, response, entity) {
+        if (!err) {
+            self.addExistingEntity(entity);
+        }
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+Usergrid.Collection.prototype.addExistingEntity = function(entity) {
+    var count = this._list.length;
+    this._list[count] = entity;
+};
+
+/*
+ *  Removes the Entity from the collection, then destroys the object on the 
server
+ *
+ *  @method destroyEntity
+ *  @param {object} entity
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection.prototype.destroyEntity = function(entity, callback) {
+    var self = this;
+    entity.destroy(function(err, response) {
+        if (err) {
+            if (self._client.logging) {
+                console.log("could not destroy entity");
+            }
+            doCallback(callback, [ err, response, self ], self);
+        } else {
+            self.fetch(callback);
+        }
+        self.removeEntity(entity);
+    });
+};
+
+/*
+ * Filters the list of entities based on the supplied criteria function
+ * works like Array.prototype.filter
+ *
+ *  @method getEntitiesByCriteria
+ *  @param {function} criteria  A function that takes each entity as an 
argument and returns true or false
+ *  @return {Entity[]} returns a list of entities that caused the criteria 
function to return true
+ */
+Usergrid.Collection.prototype.getEntitiesByCriteria = function(criteria) {
+    return this._list.filter(criteria);
+};
+
+/*
+ * Returns the first entity from the list of entities based on the supplied 
criteria function
+ * works like Array.prototype.filter
+ *
+ *  @method getEntitiesByCriteria
+ *  @param {function} criteria  A function that takes each entity as an 
argument and returns true or false
+ *  @return {Entity[]} returns a list of entities that caused the criteria 
function to return true
+ */
+Usergrid.Collection.prototype.getEntityByCriteria = function(criteria) {
+    return this.getEntitiesByCriteria(criteria).shift();
+};
+
+/*
+ * Removed an entity from the collection without destroying it on the server
+ *
+ *  @method removeEntity
+ *  @param {object} entity
+ *  @return {Entity} returns the removed entity or undefined if it was not 
found
+ */
+Usergrid.Collection.prototype.removeEntity = function(entity) {
+    var removedEntity = this.getEntityByCriteria(function(item) {
+        return entity.uuid === item.get("uuid");
+    });
+    delete this._list[this._list.indexOf(removedEntity)];
+    return removedEntity;
+};
+
+/*
+ *  Looks up an Entity by UUID
+ *
+ *  @method getEntityByUUID
+ *  @param {string} UUID
+ *  @param {function} callback
+ *  @return {callback} callback(err, data, entity)
+ */
+Usergrid.Collection.prototype.getEntityByUUID = function(uuid, callback) {
+    var entity = this.getEntityByCriteria(function(item) {
+        return item.get("uuid") === uuid;
+    });
+    if (entity) {
+        doCallback(callback, [ null, entity, entity ], this);
+    } else {
+        var options = {
+            data: {
+                type: this._type,
+                uuid: uuid
+            },
+            client: this._client
+        };
+        entity = new Usergrid.Entity(options);
+        entity.fetch(callback);
+    }
+};
+
+/*
+ *  Returns the first Entity of the Entity list - does not affect the iterator
+ *
+ *  @method getFirstEntity
+ *  @return {object} returns an entity object
+ */
+Usergrid.Collection.prototype.getFirstEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[0];
+    }
+    return null;
+};
+
+/*
+ *  Returns the last Entity of the Entity list - does not affect the iterator
+ *
+ *  @method getLastEntity
+ *  @return {object} returns an entity object
+ */
+Usergrid.Collection.prototype.getLastEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[count - 1];
+    }
+    return null;
+};
+
+/*
+ *  Entity iteration -Checks to see if there is a "next" entity
+ *  in the list.  The first time this method is called on an entity
+ *  list, or after the resetEntityPointer method is called, it will
+ *  return true referencing the first entity in the list
+ *
+ *  @method hasNextEntity
+ *  @return {boolean} true if there is a next entity, false if not
+ */
+Usergrid.Collection.prototype.hasNextEntity = function() {
+    var next = this._iterator + 1;
+    var hasNextElement = next >= 0 && next < this._list.length;
+    if (hasNextElement) {
+        return true;
+    }
+    return false;
+};
+
+/*
+ *  Entity iteration - Gets the "next" entity in the list.  The first
+ *  time this method is called on an entity list, or after the method
+ *  resetEntityPointer is called, it will return the,
+ *  first entity in the list
+ *
+ *  @method hasNextEntity
+ *  @return {object} entity
+ */
+Usergrid.Collection.prototype.getNextEntity = function() {
+    this._iterator++;
+    var hasNextElement = this._iterator >= 0 && this._iterator <= 
this._list.length;
+    if (hasNextElement) {
+        return this._list[this._iterator];
+    }
+    return false;
+};
+
+/*
+ *  Entity iteration - Checks to see if there is a "previous"
+ *  entity in the list.
+ *
+ *  @method hasPrevEntity
+ *  @return {boolean} true if there is a previous entity, false if not
+ */
+Usergrid.Collection.prototype.hasPrevEntity = function() {
+    var previous = this._iterator - 1;
+    var hasPreviousElement = previous >= 0 && previous < this._list.length;
+    if (hasPreviousElement) {
+        return true;
+    }
+    return false;
+};
+
+/*
+ *  Entity iteration - Gets the "previous" entity in the list.
+ *
+ *  @method getPrevEntity
+ *  @return {object} entity
+ */
+Usergrid.Collection.prototype.getPrevEntity = function() {
+    this._iterator--;
+    var hasPreviousElement = this._iterator >= 0 && this._iterator <= 
this._list.length;
+    if (hasPreviousElement) {
+        return this._list[this._iterator];
+    }
+    return false;
+};
+
+/*
+ *  Entity iteration - Resets the iterator back to the beginning
+ *  of the list
+ *
+ *  @method resetEntityPointer
+ *  @return none
+ */
+Usergrid.Collection.prototype.resetEntityPointer = function() {
+    this._iterator = -1;
+};
+
+/*
+ * Method to save off the cursor just returned by the last API call
+ *
+ * @public
+ * @method saveCursor
+ * @return none
+ */
+Usergrid.Collection.prototype.saveCursor = function(cursor) {
+    if (this._next !== cursor) {
+        this._next = cursor;
+    }
+};
+
+/*
+ * Resets the paging pointer (back to original page)
+ *
+ * @public
+ * @method resetPaging
+ * @return none
+ */
+Usergrid.Collection.prototype.resetPaging = function() {
+    this._previous = [];
+    this._next = null;
+    this._cursor = null;
+};
+
+/*
+ *  Paging -  checks to see if there is a next page od data
+ *
+ *  @method hasNextPage
+ *  @return {boolean} returns true if there is a next page of data, false 
otherwise
+ */
+Usergrid.Collection.prototype.hasNextPage = function() {
+    return this._next;
+};
+
+/*
+ *  Paging - advances the cursor and gets the next
+ *  page of data from the API.  Stores returned entities
+ *  in the Entity list.
+ *
+ *  @method getNextPage
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection.prototype.getNextPage = function(callback) {
+    if (this.hasNextPage()) {
+        this._previous.push(this._cursor);
+        this._cursor = this._next;
+        this._list = [];
+        this.fetch(callback);
+    }
+};
+
+/*
+ *  Paging -  checks to see if there is a previous page od data
+ *
+ *  @method hasPreviousPage
+ *  @return {boolean} returns true if there is a previous page of data, false 
otherwise
+ */
+Usergrid.Collection.prototype.hasPreviousPage = function() {
+    return this._previous.length > 0;
+};
+
+/*
+ *  Paging - reverts the cursor and gets the previous
+ *  page of data from the API.  Stores returned entities
+ *  in the Entity list.
+ *
+ *  @method getPreviousPage
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection.prototype.getPreviousPage = function(callback) {
+    if (this.hasPreviousPage()) {
+        this._next = null;
+        this._cursor = this._previous.pop();
+        this._list = [];
+        this.fetch(callback);
+    }
+};
+
+/*
+ *  A class to model a Usergrid group.
+ *  Set the path in the options object.
+ *
+ *  @constructor
+ *  @param {object} options {client:client, data: {'key': 'value'}, 
path:'path'}
+ */
+Usergrid.Group = function(options, callback) {
+    this._path = options.path;
+    this._list = [];
+    this._client = options.client;
+    this._data = options.data || {};
+    this._data.type = "groups";
+};
+
+/*
+ *  Inherit from Usergrid.Entity.
+ *  Note: This only accounts for data on the group object itself.
+ *  You need to use add and remove to manipulate group membership.
+ */
+Usergrid.Group.prototype = new Usergrid.Entity();
+
+/*
+ *  Fetches current group data, and members.
+ *
+ *  @method fetch
+ *  @public
+ *  @param {function} callback
+ *  @returns {function} callback(err, data)
+ */
+Usergrid.Group.prototype.fetch = function(callback) {
+    var self = this;
+    var groupEndpoint = "groups/" + this._path;
+    var memberEndpoint = "groups/" + this._path + "/users";
+    var groupOptions = {
+        method: "GET",
+        endpoint: groupEndpoint
+    };
+    var memberOptions = {
+        method: "GET",
+        endpoint: memberEndpoint
+    };
+    this._client.request(groupOptions, function(err, response) {
+        if (err) {
+            if (self._client.logging) {
+                console.log("error getting group");
+            }
+            doCallback(callback, [ err, response ], self);
+        } else {
+            var entities = response.getEntities();
+            if (entities && entities.length) {
+                var groupresponse = entities.shift();
+                self._client.request(memberOptions, function(err, response) {
+                    if (err && self._client.logging) {
+                        console.log("error getting group users");
+                    } else {
+                        self._list = 
response.getEntities().filter(function(entity) {
+                            return isUUID(entity.uuid);
+                        }).map(function(entity) {
+                            return new Usergrid.Entity({
+                                type: entity.type,
+                                client: self._client,
+                                uuid: entity.uuid,
+                                response: entity
+                            });
+                        });
+                    }
+                    doCallback(callback, [ err, response, self ], self);
+                });
+            }
+        }
+    });
+};
+
+/*
+ *  Retrieves the members of a group.
+ *
+ *  @method members
+ *  @public
+ *  @param {function} callback
+ *  @return {function} callback(err, data);
+ */
+Usergrid.Group.prototype.members = function(callback) {
+    return this._list;
+};
+
+/*
+ *  Adds an existing user to the group, and refreshes the group object.
+ *
+ *  Options object: {user: user_entity}
+ *
+ *  @method add
+ *  @public
+ *  @params {object} options
+ *  @param {function} callback
+ *  @return {function} callback(err, data)
+ */
+Usergrid.Group.prototype.add = function(options, callback) {
+    var self = this;
+    if (options.user) {
+        options = {
+            method: "POST",
+            endpoint: "groups/" + this._path + "/users/" + 
options.user.get("username")
+        };
+        this._client.request(options, function(error, response) {
+            if (error) {
+                doCallback(callback, [ error, response, self ], self);
+            } else {
+                self.fetch(callback);
+            }
+        });
+    } else {
+        doCallback(callback, [ new UsergridError("no user specified", 
"no_user_specified"), null, this ], this);
+    }
+};
+
+/*
+ *  Removes a user from a group, and refreshes the group object.
+ *
+ *  Options object: {user: user_entity}
+ *
+ *  @method remove
+ *  @public
+ *  @params {object} options
+ *  @param {function} callback
+ *  @return {function} callback(err, data)
+ */
+Usergrid.Group.prototype.remove = function(options, callback) {
+    var self = this;
+    if (options.user) {
+        options = {
+            method: "DELETE",
+            endpoint: "groups/" + this._path + "/users/" + 
options.user.username
+        };
+        this._client.request(options, function(error, response) {
+            if (error) {
+                doCallback(callback, [ error, response, self ], self);
+            } else {
+                self.fetch(callback);
+            }
+        });
+    } else {
+        doCallback(callback, [ new UsergridError("no user specified", 
"no_user_specified"), null, this ], this);
+    }
+};
+
+/*
+ * Gets feed for a group.
+ *
+ * @public
+ * @method feed
+ * @param {function} callback
+ * @returns {callback} callback(err, data, activities)
+ */
+Usergrid.Group.prototype.feed = function(callback) {
+    var self = this;
+    var options = {
+        method: "GET",
+        endpoint: "groups/" + this._path + "/feed"
+    };
+    this._client.request(options, function(err, response) {
+        doCallback(callback, [ err, response, self ], self);
+    });
+};
+
+/*
+ * Creates activity and posts to group feed.
+ *
+ * options object: {user: user_entity, content: "activity content"}
+ *
+ * @public
+ * @method createGroupActivity
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, entity)
+ */
+Usergrid.Group.prototype.createGroupActivity = function(options, callback) {
+    var self = this;
+    var user = options.user;
+    var entity = new Usergrid.Entity({
+        client: this._client,
+        data: {
+            actor: {
+                displayName: user.get("username"),
+                uuid: user.get("uuid"),
+                username: user.get("username"),
+                email: user.get("email"),
+                picture: user.get("picture"),
+                image: {
+                    duration: 0,
+                    height: 80,
+                    url: user.get("picture"),
+                    width: 80
+                }
+            },
+            verb: "post",
+            content: options.content,
+            type: "groups/" + this._path + "/activities"
+        }
+    });
+    entity.save(function(err, response, entity) {
+        doCallback(callback, [ err, response, self ]);
+    });
+};
+
+/*
+ *  A class to model a Usergrid event.
+ *
+ *  @constructor
+ *  @param {object} options {timestamp:0, category:'value', counters:{name : 
value}}
+ *  @returns {callback} callback(err, event)
+ */
+Usergrid.Counter = function(options) {
+    this._client = options.client;
+    this._data = options.data || {};
+    this._data.category = options.category || "UNKNOWN";
+    this._data.timestamp = options.timestamp || 0;
+    this._data.type = "events";
+    this._data.counters = options.counters || {};
+};
+
+var COUNTER_RESOLUTIONS = [ "all", "minute", "five_minutes", "half_hour", 
"hour", "six_day", "day", "week", "month" ];
+
+/*
+ *  Inherit from Usergrid.Entity.
+ *  Note: This only accounts for data on the group object itself.
+ *  You need to use add and remove to manipulate group membership.
+ */
+Usergrid.Counter.prototype = new Usergrid.Entity();
+
+/*
+ * overrides Entity.prototype.fetch. Returns all data for counters
+ * associated with the object as specified in the constructor
+ *
+ * @public
+ * @method increment
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+Usergrid.Counter.prototype.fetch = function(callback) {
+    this.getData({}, callback);
+};
+
+/*
+ * increments the counter for a specific event
+ *
+ * options object: {name: counter_name}
+ *
+ * @public
+ * @method increment
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+Usergrid.Counter.prototype.increment = function(options, callback) {
+    var self = this, name = options.name, value = options.value;
+    if (!name) {
+        ret

<TRUNCATED>

Reply via email to