You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@usergrid.apache.org by sn...@apache.org on 2014/01/27 23:21:11 UTC

[25/27] git commit: Renamed the file. Changed method arity to be more consistent with the rest of the api. updated tests

Renamed the file. Changed method arity to be more consistent with the rest of the api. updated tests


Project: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/commit/31d481a9
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/31d481a9
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/31d481a9

Branch: refs/pull/34/merge
Commit: 31d481a9fbfd1e4bb9ecae621731c7cf4dbea616
Parents: 2c77ebf
Author: ryan bridges <rb...@apigee.com>
Authored: Mon Jan 27 17:11:16 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Mon Jan 27 17:11:16 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/Gruntfile.js        |   2 +-
 sdks/html5-javascript/lib/Counter.js      | 186 +++++++++++++++++++++++++
 sdks/html5-javascript/lib/Event.js        | 149 --------------------
 sdks/html5-javascript/tests/mocha/test.js |  34 ++---
 sdks/html5-javascript/usergrid.js         |  77 +++++++---
 sdks/html5-javascript/usergrid.min.js     |   4 +-
 6 files changed, 263 insertions(+), 189 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/Gruntfile.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/Gruntfile.js b/sdks/html5-javascript/Gruntfile.js
index e1d297a..703c6af 100644
--- a/sdks/html5-javascript/Gruntfile.js
+++ b/sdks/html5-javascript/Gruntfile.js
@@ -1,5 +1,5 @@
 module.exports = function(grunt) {
-  var files = ['lib/Usergrid.js', 'lib/Client.js', 'lib/Entity.js', 'lib/Collection.js', 'lib/Group.js', 'lib/Event.js'];
+  var files = ['lib/Usergrid.js', 'lib/Client.js', 'lib/Entity.js', 'lib/Collection.js', 'lib/Group.js', 'lib/Counter.js'];
   var tests = [ 'tests/mocha/index.html','tests/mocha/test_*.html' ];
    // Project configuration.
   grunt.initConfig({

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/lib/Counter.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Counter.js b/sdks/html5-javascript/lib/Counter.js
new file mode 100644
index 0000000..cb9c568
--- /dev/null
+++ b/sdks/html5-javascript/lib/Counter.js
@@ -0,0 +1,186 @@
+/*
+ *  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, callback) {
+  var self=this;
+  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||{};
+  if(typeof(callback) === 'function') {
+    callback.call(self, false, self);
+  }
+  //this.save(callback);
+};
+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){
+    if(typeof(callback) === 'function') {
+      return callback.call(self, true, "'value' for increment, decrement must be a number");
+    }
+  }else if(isNaN(value)){
+    if(typeof(callback) === 'function') {
+      return callback.call(self, true, "'value' for increment, decrement must be a number");
+    }
+  }else{
+    self._data.counters[name]=(parseInt(value))||1;
+    return self.save(callback);
+  }
+};
+/*
+ * decrements the counter for a specific event
+ *
+ * options object: {name: counter_name}
+ *
+ * @public
+ * @method decrement
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+
+Usergrid.Counter.prototype.decrement=function(options, callback){
+  var self=this,
+    name=options.name,
+    value=options.value;
+  self.increment({name:name, value:-((parseInt(value))||1)}, callback);
+};
+/*
+ * resets the counter for a specific event
+ *
+ * options object: {name: counter_name}
+ *
+ * @public
+ * @method reset
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+
+Usergrid.Counter.prototype.reset=function(options, callback){
+  var self=this,
+    name=options.name;
+  self.increment({name:name, value:0}, callback);
+};
+
+/*
+ * gets data for one or more counters over a given
+ * time period at a specified resolution
+ *
+ * options object: {
+ *                   counters: ['counter1', 'counter2', ...],
+ *                   start: epoch timestamp or ISO date string,
+ *                   end: epoch timestamp or ISO date string,
+ *                   resolution: one of ('all', 'minute', 'five_minutes', 'half_hour', 'hour', 'six_day', 'day', 'week', or 'month')
+ *                   }
+ *
+ * @public
+ * @method getData
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+Usergrid.Counter.prototype.getData=function(options, callback){
+  var start_time, 
+      end_time,
+      start=options.start||0,
+      end=options.end||Date.now(),
+      resolution=(options.resolution||'all').toLowerCase(),
+      counters=options.counters||Object.keys(this._data.counters),
+      res=(resolution||'all').toLowerCase();
+  if(COUNTER_RESOLUTIONS.indexOf(res)===-1){
+    res='all';
+  }
+  if(start){
+    switch(typeof start){
+      case "undefined":
+        start_time=0;
+        break;
+      case "number":
+        start_time=start;
+        break;
+      case "string":
+        start_time=(isNaN(start))?Date.parse(start):parseInt(start);
+        break;
+      default:
+        start_time=Date.parse(start.toString());
+    }
+  }
+  if(end){
+    switch(typeof end){
+      case "undefined":
+        end_time=Date.now();
+        break;
+      case "number":
+        end_time=end;
+        break;
+      case "string":
+        end_time=(isNaN(end))?Date.parse(end):parseInt(end);
+        break;
+      default:
+        end_time=Date.parse(end.toString());
+    }
+  }
+  var self=this;
+  //https://api.usergrid.com/yourorgname/sandbox/counters?counter=test_counter
+  var params=Object.keys(counters).map(function(counter){
+      return ["counter", encodeURIComponent(counters[counter])].join('=');
+    });
+  params.push('resolution='+res)
+  params.push('start_time='+String(start_time))
+  params.push('end_time='+String(end_time))
+    
+  var endpoint="counters?"+params.join('&');
+  this._client.request({endpoint:endpoint}, function(err, data){
+    if(data.counters && data.counters.length){
+      data.counters.forEach(function(counter){
+        self._data.counters[counter.name]=counter.value||counter.values;
+      })
+    }
+    if(typeof(callback) === 'function') {
+      callback.call(self, err, data);
+    }
+  })
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
deleted file mode 100644
index 74d019c..0000000
--- a/sdks/html5-javascript/lib/Event.js
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- *  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, callback) {
-  var self=this;
-  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||{};
-  if(typeof(callback) === 'function') {
-    callback.call(self, false, self);
-  }
-  //this.save(callback);
-};
-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();
-
-Usergrid.Counter.prototype.fetch=function(callback){
-  this.getData(null, null, null, null, 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(name, value, callback){
-  var self=this;
-  if(isNaN(value)){
-    if(typeof(callback) === 'function') {
-      return callback.call(self, true, "'value' for increment, decrement must be a number");
-    }
-  }
-  self._data.counters[name]=(parseInt(value))||1;
-  return self.save(callback);
-};
-/*
- * decrements the counter for a specific event
- *
- * options object: {name: counter_name}
- *
- * @public
- * @method decrement
- * @params {object} options
- * @param {function} callback
- * @returns {callback} callback(err, event)
- */
-
-Usergrid.Counter.prototype.decrement=function(name, value, callback){
-  this.increment(name, -((parseInt(value))||1), callback);
-};
-/*
- * resets the counter for a specific event
- *
- * options object: {name: counter_name}
- *
- * @public
- * @method reset
- * @params {object} options
- * @param {function} callback
- * @returns {callback} callback(err, event)
- */
-
-Usergrid.Counter.prototype.reset=function(name, callback){
-  this.increment(name, 0, callback);
-};
-
-Usergrid.Counter.prototype.getData=function(start, end, resolution, counters, callback){
-  var start_time, 
-      end_time,
-      res=(resolution||'all').toLowerCase();
-  if(COUNTER_RESOLUTIONS.indexOf(res)===-1){
-    res='all';
-  }
-  if(start){
-    switch(typeof start){
-      case "undefined":
-        start_time=0;
-        break;
-      case "number":
-        start_time=start;
-        break;
-      case "string":
-        start_time=(isNaN(start))?Date.parse(start):parseInt(start);
-        break;
-      default:
-        start_time=Date.parse(start.toString());
-    }
-  }
-  if(end){
-    switch(typeof end){
-      case "undefined":
-        end_time=Date.now();
-        break;
-      case "number":
-        end_time=end;
-        break;
-      case "string":
-        end_time=(isNaN(end))?Date.parse(end):parseInt(end);
-        break;
-      default:
-        end_time=Date.parse(end.toString());
-    }
-  }
-  var self=this;
-  //https://api.usergrid.com/yourorgname/sandbox/counters?counter=test_counter
-  if(counters===null || "undefined"===typeof counters)
-  counters=Object.keys(this._data.counters);
-  var params=Object.keys(counters).map(function(counter){
-      return ["counter", encodeURIComponent(counters[counter])].join('=');
-    });
-  params.push('resolution='+res)
-  params.push('start_time='+String(start_time))
-  params.push('end_time='+String(end_time))
-    
-  var endpoint="counters?"+params.join('&');
-  var options= {
-    endpoint:endpoint
-  };
-  this._client.request(options, function(err, data){
-    if(data.counters && data.counters.length){
-      data.counters.forEach(function(counter){
-        self._data.counters[counter.name]=counter.value||counter.values;
-      })
-    }
-    if(typeof(callback) === 'function') {
-      callback.call(self, err, data);
-    }
-  })
-};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/tests/mocha/test.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/mocha/test.js b/sdks/html5-javascript/tests/mocha/test.js
index 8034f06..b75f187 100644
--- a/sdks/html5-javascript/tests/mocha/test.js
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -248,21 +248,21 @@ describe('Usergrid', function(){
 			}
 		});
 	});
-	describe('Usergrid Events', function(){
-		var ev;
+	describe('Usergrid Counters', function(){
+		var counter;
 		var MINUTE=1000*60;
 		var HOUR=MINUTE*60;
 		var time=Date.now()-HOUR;
 
-		it('should CREATE an event', function(done){
-			ev = new Usergrid.Event({client:client, data:{category:'mocha_test', timestamp:time, name:"test", counters:{test:0,test_counter:0}}}, function(err, data){
+		it('should CREATE a counter', function(done){
+			counter = new Usergrid.Counter({client:client, data:{category:'mocha_test', timestamp:time, name:"test", counters:{test:0,test_counter:0}}}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				done();
 			});
 		});
-		it('should save an event', function(done){
-			ev.save(function(err, data){
+		it('should save a counter', function(done){
+			counter.save(function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				done();
@@ -270,8 +270,8 @@ describe('Usergrid', function(){
 		});
 		it('should reset a counter', function(done){
 			time+=MINUTE*10
-			ev.set("timestamp", time);
-			ev.reset('test', function(err, data){
+			counter.set("timestamp", time);
+			counter.reset({name:'test'}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				done();
@@ -279,8 +279,8 @@ describe('Usergrid', function(){
 		});
 		it("should increment 'test' counter", function(done){
 			time+=MINUTE*10
-			ev.set("timestamp", time);
-			ev.increment('test', 1, function(err, data){
+			counter.set("timestamp", time);
+			counter.increment({name:'test', value:1}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				done();
@@ -288,8 +288,8 @@ describe('Usergrid', function(){
 		});
 		it("should increment 'test_counter' counter by 4", function(done){
 			time+=MINUTE*10
-			ev.set("timestamp", time);
-			ev.increment('test_counter', 4, function(err, data){
+			counter.set("timestamp", time);
+			counter.increment({name:'test_counter', value:4}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(JSON.stringify(data,null,4));
 				done();
@@ -297,15 +297,15 @@ describe('Usergrid', function(){
 		});
 		it("should decrement 'test' counter", function(done){
 			time+=MINUTE*10
-			ev.set("timestamp", time);
-			ev.decrement('test', 1, function(err, data){
+			counter.set("timestamp", time);
+			counter.decrement({name:'test', value:1}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(JSON.stringify(data,null,4));
 				done();
 			});
 		});	
-		it('should fetch event', function(done){
-			ev.fetch(function(err, data){
+		it('should fetch the counter', function(done){
+			counter.fetch(function(err, data){
 				assert(!err, data.error_description);
 				console.log(JSON.stringify(data,null,4));
 				console.log(time, Date.now());
@@ -313,7 +313,7 @@ describe('Usergrid', function(){
 			});
 		});
 		it('should fetch counter data', function(done){
-			ev.getData('all', null, null, ['test', 'test_counter'], function(err, data){
+			counter.getData({resolution:'all', counters:['test', 'test_counter']}, function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				console.log(time, Date.now());

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
index 9fc9482..a7429a0 100644
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,4 +1,4 @@
-/*! usergrid@0.0.0 2014-01-21 */
+/*! usergrid@0.0.0 2014-01-27 */
 /*
  *  This module is a collection of classes designed to make working with
  *  the Appigee App Services API as easy as possible.
@@ -2169,7 +2169,7 @@ Usergrid.Group.prototype.createGroupActivity = function(options, callback) {
  *  @param {object} options {timestamp:0, category:'value', counters:{name : value}}
  *  @returns {callback} callback(err, event)
  */
-Usergrid.Event = function(options, callback) {
+Usergrid.Counter = function(options, callback) {
     var self = this;
     this._client = options.client;
     this._data = options.data || {};
@@ -2189,10 +2189,19 @@ var COUNTER_RESOLUTIONS = [ "all", "minute", "five_minutes", "half_hour", "hour"
  *  Note: This only accounts for data on the group object itself.
  *  You need to use add and remove to manipulate group membership.
  */
-Usergrid.Event.prototype = new Usergrid.Entity();
+Usergrid.Counter.prototype = new Usergrid.Entity();
 
-Usergrid.Event.prototype.fetch = function(callback) {
-    this.getData(null, null, null, null, callback);
+/*
+ * 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);
 };
 
 /*
@@ -2206,15 +2215,20 @@ Usergrid.Event.prototype.fetch = function(callback) {
  * @param {function} callback
  * @returns {callback} callback(err, event)
  */
-Usergrid.Event.prototype.increment = function(name, value, callback) {
-    var self = this;
-    if (isNaN(value)) {
+Usergrid.Counter.prototype.increment = function(options, callback) {
+    var self = this, name = options.name, value = options.value;
+    if (!name) {
+        if (typeof callback === "function") {
+            return callback.call(self, true, "'value' for increment, decrement must be a number");
+        }
+    } else if (isNaN(value)) {
         if (typeof callback === "function") {
             return callback.call(self, true, "'value' for increment, decrement must be a number");
         }
+    } else {
+        self._data.counters[name] = parseInt(value) || 1;
+        return self.save(callback);
     }
-    self._data.counters[name] = parseInt(value) || 1;
-    return self.save(callback);
 };
 
 /*
@@ -2228,8 +2242,12 @@ Usergrid.Event.prototype.increment = function(name, value, callback) {
  * @param {function} callback
  * @returns {callback} callback(err, event)
  */
-Usergrid.Event.prototype.decrement = function(name, value, callback) {
-    this.increment(name, -(parseInt(value) || 1), callback);
+Usergrid.Counter.prototype.decrement = function(options, callback) {
+    var self = this, name = options.name, value = options.value;
+    self.increment({
+        name: name,
+        value: -(parseInt(value) || 1)
+    }, callback);
 };
 
 /*
@@ -2243,12 +2261,33 @@ Usergrid.Event.prototype.decrement = function(name, value, callback) {
  * @param {function} callback
  * @returns {callback} callback(err, event)
  */
-Usergrid.Event.prototype.reset = function(name, callback) {
-    this.increment(name, 0, callback);
+Usergrid.Counter.prototype.reset = function(options, callback) {
+    var self = this, name = options.name;
+    self.increment({
+        name: name,
+        value: 0
+    }, callback);
 };
 
-Usergrid.Event.prototype.getData = function(start, end, resolution, counters, callback) {
-    var start_time, end_time, res = (resolution || "all").toLowerCase();
+/*
+ * gets data for one or more counters over a given
+ * time period at a specified resolution
+ *
+ * options object: {
+ *                   counters: ['counter1', 'counter2', ...],
+ *                   start: epoch timestamp or ISO date string,
+ *                   end: epoch timestamp or ISO date string,
+ *                   resolution: one of ('all', 'minute', 'five_minutes', 'half_hour', 'hour', 'six_day', 'day', 'week', or 'month')
+ *                   }
+ *
+ * @public
+ * @method getData
+ * @params {object} options
+ * @param {function} callback
+ * @returns {callback} callback(err, event)
+ */
+Usergrid.Counter.prototype.getData = function(options, callback) {
+    var start_time, end_time, start = options.start || 0, end = options.end || Date.now(), resolution = (options.resolution || "all").toLowerCase(), counters = options.counters || Object.keys(this._data.counters), res = (resolution || "all").toLowerCase();
     if (COUNTER_RESOLUTIONS.indexOf(res) === -1) {
         res = "all";
     }
@@ -2290,7 +2329,6 @@ Usergrid.Event.prototype.getData = function(start, end, resolution, counters, ca
     }
     var self = this;
     //https://api.usergrid.com/yourorgname/sandbox/counters?counter=test_counter
-    if (counters === null || "undefined" === typeof counters) counters = Object.keys(this._data.counters);
     var params = Object.keys(counters).map(function(counter) {
         return [ "counter", encodeURIComponent(counters[counter]) ].join("=");
     });
@@ -2298,10 +2336,9 @@ Usergrid.Event.prototype.getData = function(start, end, resolution, counters, ca
     params.push("start_time=" + String(start_time));
     params.push("end_time=" + String(end_time));
     var endpoint = "counters?" + params.join("&");
-    var options = {
+    this._client.request({
         endpoint: endpoint
-    };
-    this._client.request(options, function(err, data) {
+    }, function(err, data) {
         if (data.counters && data.counters.length) {
             data.counters.forEach(function(counter) {
                 self._data.counters[counter.name] = counter.value || counter.values;

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/31d481a9/sdks/html5-javascript/usergrid.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.min.js b/sdks/html5-javascript/usergrid.min.js
index 4d37d2d..f479995 100644
--- a/sdks/html5-javascript/usergrid.min.js
+++ b/sdks/html5-javascript/usergrid.min.js
@@ -1,2 +1,2 @@
-/*! usergrid@0.0.0 2014-01-21 */
-function isUUID(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}$/;return uuid?uuidValueRegex.test(uuid):!1}function encodeParams(params){var i,tail=[],item=[];if(params instanceof Array)for(i in params)item=params[i],item instanceof Array&&item.length>1&&tail.push(item[0]+"="+encodeURIComponent(item[1]));else for(var key in params)if(params.hasOwnProperty(key)){var value=params[key];if(value instanceof Array)for(i in value)item=value[i],tail.push(key+"="+encodeURIComponent(item));else tail.push(key+"="+encodeURIComponent(value))}return tail.join("&")}window.console=window.console||{},window.console.log=window.console.log||function(){},window.Usergrid=window.Usergrid||{},Usergrid=Usergrid||{},Usergrid.USERGRID_SDK_VERSION="0.10.07",Usergrid.Client=function(options){this.URI=options.URI||"https://api.usergrid.com",options.orgName&&this.set("orgName",options.orgName),options.appName&&this.set("appName",options.appName),this.buildCu
 rl=options.buildCurl||!1,this.logging=options.logging||!1,this._callTimeout=options.callTimeout||3e4,this._callTimeoutCallback=options.callTimeoutCallback||null,this.logoutCallback=options.logoutCallback||null},Usergrid.Client.prototype.request=function(options,callback){var uri,self=this,method=options.method||"GET",endpoint=options.endpoint,body=options.body||{},qs=options.qs||{},mQuery=options.mQuery||!1,orgName=this.get("orgName"),appName=this.get("appName");if(!mQuery&&!orgName&&!appName&&"function"==typeof this.logoutCallback)return this.logoutCallback(!0,"no_org_or_app_name_specified");uri=mQuery?this.URI+"/"+endpoint:this.URI+"/"+orgName+"/"+appName+"/"+endpoint,self.getToken()&&(qs.access_token=self.getToken());var encoded_params=encodeParams(qs);encoded_params&&(uri+="?"+encoded_params),body=JSON.stringify(body);var xhr=new XMLHttpRequest;xhr.open(method,uri,!0),body&&(xhr.setRequestHeader("Content-Type","application/json"),xhr.setRequestHeader("Accept","application/json")
 ),xhr.onerror=function(response){self._end=(new Date).getTime(),self.logging&&console.log("success (time: "+self.calcTimeDiff()+"): "+method+" "+uri),self.logging&&console.log("Error: API call failed at the network level."),clearTimeout(timeout);var err=!0;"function"==typeof callback&&callback(err,response)},xhr.onload=function(response){self._end=(new Date).getTime(),self.logging&&console.log("success (time: "+self.calcTimeDiff()+"): "+method+" "+uri),clearTimeout(timeout);try{response=JSON.parse(xhr.responseText)}catch(e){response={error:"unhandled_error",error_description:xhr.responseText},xhr.status=200===xhr.status?400:xhr.status,console.error(e)}if(200!=xhr.status){var error=response.error,error_description=response.error_description;if(self.logging&&console.log("Error ("+xhr.status+")("+error+"): "+error_description),("auth_expired_session_token"==error||"auth_missing_credentials"==error||"auth_unverified_oath"==error||"expired_token"==error||"unauthorized"==error||"auth_inva
 lid"==error)&&"function"==typeof self.logoutCallback)return self.logoutCallback(!0,response);"function"==typeof callback&&callback(!0,response)}else"function"==typeof callback&&callback(!1,response)};var timeout=setTimeout(function(){xhr.abort(),"function"===self._callTimeoutCallback?self._callTimeoutCallback("API CALL TIMEOUT"):self.callback("API CALL TIMEOUT")},self._callTimeout);if(this.logging&&console.log("calling: "+method+" "+uri),this.buildCurl){var curlOptions={uri:uri,body:body,method:method};this.buildCurlCall(curlOptions)}this._start=(new Date).getTime(),xhr.send(body)},Usergrid.Client.prototype.buildAssetURL=function(uuid){var self=this,qs={},assetURL=this.URI+"/"+this.orgName+"/"+this.appName+"/assets/"+uuid+"/data";self.getToken()&&(qs.access_token=self.getToken());var encoded_params=encodeParams(qs);return encoded_params&&(assetURL+="?"+encoded_params),assetURL},Usergrid.Client.prototype.createGroup=function(options,callback){var getOnExist=options.getOnExist||!1;opt
 ions={path:options.path,client:this,data:options};var group=new Usergrid.Group(options);group.fetch(function(err,data){var okToSave=err&&"service_resource_not_found"===data.error||"no_name_specified"===data.error||"null_pointer"===data.error||!err&&getOnExist;okToSave?group.save(function(err){"function"==typeof callback&&callback(err,group)}):"function"==typeof callback&&callback(err,group)})},Usergrid.Client.prototype.createEntity=function(options,callback){var getOnExist=options.getOnExist||!1,options={client:this,data:options},entity=new Usergrid.Entity(options);entity.fetch(function(err,data){var okToSave=err&&"service_resource_not_found"===data.error||"no_name_specified"===data.error||"null_pointer"===data.error||!err&&getOnExist;okToSave?(entity.set(options.data),entity.save(function(err,data){"function"==typeof callback&&callback(err,entity,data)})):"function"==typeof callback&&callback(err,entity,data)})},Usergrid.Client.prototype.getEntity=function(options,callback){var opt
 ions={client:this,data:options},entity=new Usergrid.Entity(options);entity.fetch(function(err,data){"function"==typeof callback&&callback(err,entity,data)})},Usergrid.Client.prototype.restoreEntity=function(serializedObject){var data=JSON.parse(serializedObject),options={client:this,data:data},entity=new Usergrid.Entity(options);return entity},Usergrid.Client.prototype.createCollection=function(options,callback){options.client=this;var collection=new Usergrid.Collection(options,function(err,data){"function"==typeof callback&&callback(err,collection,data)})},Usergrid.Client.prototype.restoreCollection=function(serializedObject){var data=JSON.parse(serializedObject);data.client=this;var collection=new Usergrid.Collection(data);return collection},Usergrid.Client.prototype.getFeedForUser=function(username,callback){var options={method:"GET",endpoint:"users/"+username+"/feed"};this.request(options,function(err,data){"function"==typeof callback&&(err?callback(err):callback(err,data,data.e
 ntities))})},Usergrid.Client.prototype.createUserActivity=function(user,options,callback){options.type="users/"+user+"/activities";var options={client:this,data:options},entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})},Usergrid.Client.prototype.createUserActivityWithEntity=function(user,content,callback){var username=user.get("username"),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)},Usergrid.Client.prototype.calcTimeDiff=function(){var seconds=0,time=this._end-this._start;try{seconds=(time/10/60).toFixed(2)}catch(e){return 0}return seconds},Usergrid.Client.prototype.setToken=function(token){this.set("token",token)},Usergrid.Client.prototype.getToken=function(){return this.get("token")},Usergrid.
 Client.prototype.setObject=function(key,value){value&&(value=JSON.stringify(value)),this.set(key,value)},Usergrid.Client.prototype.set=function(key,value){var keyStore="apigee_"+key;this[key]=value,"undefined"!=typeof Storage&&(value?localStorage.setItem(keyStore,value):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;return this[key]?this[key]:"undefined"!=typeof Storage?localStorage.getItem(keyStore):null},Usergrid.Client.prototype.signup=function(username,password,email,name,callback){var options={type:"users",username:username,password:password,email:email,name:name};this.createEntity(options,callback)},Usergrid.Client.prototype.login=function(username,password,callback){var self=this,options={method:"POST",endpoint:"token",body:{username:username,password:password,grant_type:"password"}};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)}"function"==typeof callback&&callback(err,data,user)})},Usergrid.Client.prototype.reAuthenticateLite=function(callback){var self=this,options={method:"GET",endpoint:"management/me",mQuery:!0};this.request(options,function(err,response){err&&self.logging?console.log("error trying to re-authenticate user"):self.setToken(response.access_token),"function"==typeof callback&&callback(err)})},Usergrid.Client.prototype.reAuthenticate=function(email,callback){var self=this,options={method:"GET",endpoint:"management/users/"+email,mQuery:!0};this.request(options,function(err,response){var data,organizations={},applications={},user={};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},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=!0,self.logging&&console.log("error selecting org")}applications=self.parseApplicationsArray(org),self.selectFirstApp(applications),self.setObject("organizations",organizations),self.setObject("applications",applications)}"function"==typeof callback&&callback(err,data,user,organizations,applications)})},Usergrid.Client.prototype.loginFacebook=function(facebookToken,callback){var self=this,options={method:"GET",endpoint:"auth/facebook",qs:{fb_access_token:facebookToken}};this.request(options,function(err,dat
 a){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)}"function"==typeof callback&&callback(err,data,user)})},Usergrid.Client.prototype.getLoggedInUser=function(callback){if(this.getToken()){var self=this,options={method:"GET",endpoint:"users/me"};this.request(options,function(err,data){if(err)self.logging&&console.log("error trying to log user in"),"function"==typeof callback&&callback(err,data,null);else{var options={client:self,data:data.entities[0]},user=new Usergrid.Entity(options);"function"==typeof callback&&callback(err,data,user)}})}else callback(!0,null,null)},Usergrid.Client.prototype.isLoggedIn=function(){return this.getToken()&&"null"!=this.getToken()?!0:!1},Usergrid.Client.prototype.logout=function(){this.setToken(null)},Usergrid.Client.prototype.buildCurlCall=function(options){var curl="curl",method=(options.method||"GET").toUpperCa
 se(),body=options.body||{},uri=options.uri;return curl+="POST"===method?" -X POST":"PUT"===method?" -X PUT":"DELETE"===method?" -X DELETE":" -X GET",curl+=" "+uri,"undefined"!=typeof window&&(body=JSON.stringify(body)),'"{}"'!==body&&"GET"!==method&&"DELETE"!==method&&(curl+=" -d '"+body+"'"),console.log(curl),curl},Usergrid.Client.prototype.getDisplayImage=function(email,picture,size){try{if(picture)return picture;var size=size||50;return email.length?"https://secure.gravatar.com/avatar/"+MD5(email)+"?s="+size+encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png"):"https://apigee.com/usergrid/images/user_profile.png"}catch(e){return"https://apigee.com/usergrid/images/user_profile.png"}},Usergrid.Entity=function(options){options&&(this._data=options.data||{},this._client=options.client||{})},Usergrid.Entity.prototype.serialize=function(){return JSON.stringify(this._data)},Usergrid.Entity.prototype.get=function(field){return field?this._data[field]:this._data},Usergrid.E
 ntity.prototype.set=function(key,value){if("object"==typeof key)for(var field in key)this._data[field]=key[field];else"string"==typeof key?null===value?delete this._data[key]:this._data[key]=value:this._data={}},Usergrid.Entity.prototype.save=function(callback){var type=this.get("type"),method="POST";isUUID(this.get("uuid"))&&(method="PUT",type+="/"+this.get("uuid"));var self=this,data={},entityData=this.get(),oldpassword=(this.get("password"),this.get("oldpassword")),newpassword=this.get("newpassword");for(var item in entityData)"metadata"!==item&&"created"!==item&&"modified"!==item&&"oldpassword"!==item&&"newpassword"!==item&&"type"!==item&&"activated"!==item&&"uuid"!==item&&(data[item]=entityData[item]);var options={method:method,endpoint:type,body:data};this._client.request(options,function(err,retdata){if(self.set("password",null),self.set("oldpassword",null),self.set("newpassword",null),err&&self._client.logging){if(console.log("could not save entity"),"function"==typeof callb
 ack)return callback(err,retdata,self)}else{if(retdata.entities&&retdata.entities.length){var entity=retdata.entities[0];self.set(entity);for(var path=retdata.path;"/"===path.substring(0,1);)path=path.substring(1);self.set("type",path)}var needPasswordChange=("user"===self.get("type")||"users"===self.get("type"))&&oldpassword&&newpassword;if(needPasswordChange){var pwdata={};pwdata.oldpassword=oldpassword,pwdata.newpassword=newpassword;var options={method:"PUT",endpoint:type+"/password",body:pwdata};self._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not update user"),self.set("oldpassword",null),self.set("newpassword",null),"function"==typeof callback&&callback(err,data,self)})}else"function"==typeof callback&&callback(err,retdata,self)}})},Usergrid.Entity.prototype.fetch=function(callback){var type=this.get("type"),self=this;try{if(void 0===type)throw"cannot fetch entity, no entity type specified";if(this.get("uuid"))type+="/"+this.get("uui
 d");else if("users"===type&&this.get("username"))type+="/"+this.get("username");else if(this.get("name"))type+="/"+encodeURIComponent(this.get("name"));else if("function"==typeof callback)throw"no_name_specified"}catch(e){return self._client.logging&&console.log(e),callback(!0,{error:e},self)}var options={method:"GET",endpoint:type};this._client.request(options,function(err,data){if(err&&self._client.logging)console.log("could not get entity");else if(data.user)self.set(data.user),self._json=JSON.stringify(data.user,null,2);else if(data.entities&&data.entities.length){var entity=data.entities[0];self.set(entity)}"function"==typeof callback&&callback(err,data,self)})},Usergrid.Entity.prototype.destroy=function(callback){var self=this,type=this.get("type");if(isUUID(this.get("uuid")))type+="/"+this.get("uuid");else if("function"==typeof callback){var error="Error trying to delete object - no uuid specified.";self._client.logging&&console.log(error),callback(!0,error)}var options={meth
 od:"DELETE",endpoint:type};this._client.request(options,function(err,data){err&&self._client.logging?console.log("entity could not be deleted"):self.set(null),"function"==typeof callback&&callback(err,data)})},Usergrid.Entity.prototype.connect=function(connection,entity,callback){var error,self=this,connecteeType=entity.get("type"),connectee=this.getEntityId(entity);if(!connectee)return void("function"==typeof callback&&(error="Error trying to delete object - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var connectorType=this.get("type"),connector=this.getEntityId(this);if(!connector)return void("function"==typeof callback&&(error="Error in connect - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var endpoint=connectorType+"/"+connector+"/"+connection+"/"+connecteeType+"/"+connectee,options={method:"POST",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("e
 ntity could not be connected"),"function"==typeof callback&&callback(err,data)})},Usergrid.Entity.prototype.getEntityId=function(entity){var id=!1;return isUUID(entity.get("uuid"))?id=entity.get("uuid"):"users"===type?id=entity.get("username"):entity.get("name")&&(id=entity.get("name")),id},Usergrid.Entity.prototype.getConnections=function(connection,callback){var self=this,connectorType=this.get("type"),connector=this.getEntityId(this);if(connector){var endpoint=connectorType+"/"+connector+"/"+connection+"/",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be connected"),self[connection]={};for(var length=data.entities.length,i=0;length>i;i++)"user"===data.entities[i].type?self[connection][data.entities[i].username]=data.entities[i]:self[connection][data.entities[i].name]=data.entities[i];"function"==typeof callback&&callback(err,data,data.entities)})}else if("function"==typeof callback
 ){var error="Error in getConnections - no uuid specified.";self._client.logging&&console.log(error),callback(!0,error)}},Usergrid.Entity.prototype.getGroups=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/groups",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be connected"),self.groups=data.entities,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getActivities=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/activities",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){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,"function"==typeof callback&&callback(err,data,data.entities)})},
 Usergrid.Entity.prototype.getFollowing=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/following",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getFollowers=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/followers",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user followers");for(var entity in data.entities){data.entities[entity].createdDate=new Date(d
 ata.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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getRoles=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/roles",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user roles"),self.roles=data.entities,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getPermissions=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/permissions",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user permissions");var permissions=[];if(data.data){var perms=dat
 a.data,count=0;for(var i in perms){count++;var perm=perms[i],parts=perm.split(":"),ops_part="",path_part=parts[0];parts.length>1&&(ops_part=parts[0],path_part=parts[1]),ops_part.replace("*","get,post,put,delete");var ops=ops_part.split(","),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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.disconnect=function(connection,entity,callback){var error,self=this,connecteeType=entity.get("type"),connectee=this.getEntityId(entity);if(!connectee)return void("function"==typeof callback&&(error="Error trying to delete object - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var connectorType=this.get("type"),connector=this.getEntityId(this);if(!connector)return void("function"==typeof ca
 llback&&(error="Error in connect - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var endpoint=connectorType+"/"+connector+"/"+connection+"/"+connecteeType+"/"+connectee,options={method:"DELETE",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be disconnected"),"function"==typeof callback&&callback(err,data)})},Usergrid.Collection=function(options,callback){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,options.list))for(var count=options.list.length,i=0;count>i;i++){var entity=this._client.restoreEntity(options.list[i]);this._list[i]=entity}callback&&this.fetch(callback)},Usergrid.Collection.prototype.serialize=function(){var data={};data.type=this._type,data.qs=this.qs,da
 ta.iterator=this._iterator,data.previous=this._previous,data.next=this._next,data.cursor=this._cursor,this.resetEntityPointer();var i=0;for(data.list=[];this.hasNextEntity();){var entity=this.getNextEntity();data.list[i]=entity.serialize(),i++}return data=JSON.stringify(data)},Usergrid.Collection.prototype.addCollection=function(collectionName,options,callback){self=this,options.client=this._client;var collection=new Usergrid.Collection(options,function(err){if("function"==typeof callback){for(collection.resetEntityPointer();collection.hasNextEntity();){var user=collection.getNextEntity(),image=(user.get("email"),self._client.getDisplayImage(user.get("email"),user.get("picture")));user._portal_image_icon=image}self[collectionName]=collection,callback(err,collection)}})},Usergrid.Collection.prototype.fetch=function(callback){var self=this,qs=this.qs;this._cursor?qs.cursor=this._cursor:delete qs.cursor;var options={method:"GET",endpoint:this._type,qs:this.qs};this._client.request(opti
 ons,function(err,data){if(err&&self._client.logging)console.log("error getting collection");else{var cursor=data.cursor||null;if(self.saveCursor(cursor),data.entities){self.resetEntityPointer();var count=data.entities.length;self._list=[];for(var i=0;count>i;i++){var uuid=data.entities[i].uuid;if(uuid){var entityData=data.entities[i]||{};self._baseType=data.entities[i].type,entityData.type=self._type;var entityOptions={type:self._type,client:self._client,uuid:uuid,data:entityData},ent=new Usergrid.Entity(entityOptions);ent._json=JSON.stringify(entityData,null,2);var ct=self._list.length;self._list[ct]=ent}}}}"function"==typeof callback&&callback(err,data)})},Usergrid.Collection.prototype.addEntity=function(options,callback){var self=this;options.type=this._type,this._client.createEntity(options,function(err,entity){if(!err){var count=self._list.length;self._list[count]=entity}"function"==typeof callback&&callback(err,entity)})},Usergrid.Collection.prototype.addExistingEntity=functio
 n(entity){var count=this._list.length;this._list[count]=entity},Usergrid.Collection.prototype.destroyEntity=function(entity,callback){var self=this;entity.destroy(function(err,data){err?(self._client.logging&&console.log("could not destroy entity"),"function"==typeof callback&&callback(err,data)):self.fetch(callback)}),this.removeEntity(entity)},Usergrid.Collection.prototype.removeEntity=function(entity){var uuid=entity.get("uuid");for(var key in this._list){var listItem=this._list[key];if(listItem.get("uuid")===uuid)return this._list.splice(key,1)}return!1},Usergrid.Collection.prototype.getEntityByUUID=function(uuid,callback){for(var key in this._list){var listItem=this._list[key];if(listItem.get("uuid")===uuid)return listItem}var options={data:{type:this._type,uuid:uuid},client:this._client},entity=new Usergrid.Entity(options);entity.fetch(callback)},Usergrid.Collection.prototype.getFirstEntity=function(){var count=this._list.length;return count>0?this._list[0]:null},Usergrid.Coll
 ection.prototype.getLastEntity=function(){var count=this._list.length;return count>0?this._list[count-1]:null},Usergrid.Collection.prototype.hasNextEntity=function(){var next=this._iterator+1,hasNextElement=next>=0&&next<this._list.length;return hasNextElement?!0:!1},Usergrid.Collection.prototype.getNextEntity=function(){this._iterator++;var hasNextElement=this._iterator>=0&&this._iterator<=this._list.length;return hasNextElement?this._list[this._iterator]:!1},Usergrid.Collection.prototype.hasPrevEntity=function(){var previous=this._iterator-1,hasPreviousElement=previous>=0&&previous<this._list.length;return hasPreviousElement?!0:!1},Usergrid.Collection.prototype.getPrevEntity=function(){this._iterator--;var hasPreviousElement=this._iterator>=0&&this._iterator<=this._list.length;return hasPreviousElement?this._list[this._iterator]:!1},Usergrid.Collection.prototype.resetEntityPointer=function(){this._iterator=-1},Usergrid.Collection.prototype.saveCursor=function(cursor){this._next!==
 cursor&&(this._next=cursor)},Usergrid.Collection.prototype.resetPaging=function(){this._previous=[],this._next=null,this._cursor=null},Usergrid.Collection.prototype.hasNextPage=function(){return this._next},Usergrid.Collection.prototype.getNextPage=function(callback){this.hasNextPage()&&(this._previous.push(this._cursor),this._cursor=this._next,this._list=[],this.fetch(callback))},Usergrid.Collection.prototype.hasPreviousPage=function(){return this._previous.length>0},Usergrid.Collection.prototype.getPreviousPage=function(callback){this.hasPreviousPage()&&(this._next=null,this._cursor=this._previous.pop(),this._list=[],this.fetch(callback))},Usergrid.Group=function(options){this._path=options.path,this._list=[],this._client=options.client,this._data=options.data||{},this._data.type="groups"},Usergrid.Group.prototype=new Usergrid.Entity,Usergrid.Group.prototype.fetch=function(callback){var self=this,groupEndpoint="groups/"+this._path,memberEndpoint="groups/"+this._path+"/users",group
 Options={method:"GET",endpoint:groupEndpoint},memberOptions={method:"GET",endpoint:memberEndpoint};this._client.request(groupOptions,function(err,data){if(err)self._client.logging&&console.log("error getting group"),"function"==typeof callback&&callback(err,data);else if(data.entities){var groupData=data.entities[0];self._data=groupData||{},self._client.request(memberOptions,function(err,data){if(err&&self._client.logging)console.log("error getting group users");else if(data.entities){var count=data.entities.length;self._list=[];for(var i=0;count>i;i++){var uuid=data.entities[i].uuid;if(uuid){var entityData=data.entities[i]||{},entityOptions={type:entityData.type,client:self._client,uuid:uuid,data:entityData},entity=new Usergrid.Entity(entityOptions);self._list.push(entity)}}}"function"==typeof callback&&callback(err,data,self._list)})}})},Usergrid.Group.prototype.members=function(callback){"function"==typeof callback&&callback(null,this._list)},Usergrid.Group.prototype.add=function
 (options,callback){var self=this,options={method:"POST",endpoint:"groups/"+this._path+"/users/"+options.user.get("username")};this._client.request(options,function(error,data){error?"function"==typeof callback&&callback(error,data,data.entities):self.fetch(callback)})},Usergrid.Group.prototype.remove=function(options,callback){var self=this,options={method:"DELETE",endpoint:"groups/"+this._path+"/users/"+options.user.get("username")};this._client.request(options,function(error,data){error?"function"==typeof callback&&callback(error,data):self.fetch(callback)})},Usergrid.Group.prototype.feed=function(callback){var self=this,endpoint="groups/"+this._path+"/feed",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self.logging&&console.log("error trying to log user in"),"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Group.prototype.createGroupActivity=function(options,callback){var user=options.user;options={client:th
 is._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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})},Usergrid.Event=function(options,callback){var self=this;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||{},"function"==typeof callback&&callback.call(self,!1,self)};var COUNTER_RESOLUTIONS=["all","minute","five_minutes","half_hour","hour","six_day","day","week","month"];Usergrid.Event.prototype=new Usergrid.Entity,Usergrid.Event.prototype.fetch=function(callback){this.getData(null,null,null,null,callback)},Userg
 rid.Event.prototype.increment=function(name,value,callback){var self=this;return isNaN(value)&&"function"==typeof callback?callback.call(self,!0,"'value' for increment, decrement must be a number"):(self._data.counters[name]=parseInt(value)||1,self.save(callback))},Usergrid.Event.prototype.decrement=function(name,value,callback){this.increment(name,-(parseInt(value)||1),callback)},Usergrid.Event.prototype.reset=function(name,callback){this.increment(name,0,callback)},Usergrid.Event.prototype.getData=function(start,end,resolution,counters,callback){var start_time,end_time,res=(resolution||"all").toLowerCase();if(-1===COUNTER_RESOLUTIONS.indexOf(res)&&(res="all"),start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(start)?Date.parse(start):parseInt(start);break;default:start_time=Date.parse(start.toString())}if(end)switch(typeof end){case"undefined":end_time=Date.now();break;case"number":end_time=end;break;case
 "string":end_time=isNaN(end)?Date.parse(end):parseInt(end);break;default:end_time=Date.parse(end.toString())}var self=this;(null===counters||"undefined"==typeof counters)&&(counters=Object.keys(this._data.counters));var params=Object.keys(counters).map(function(counter){return["counter",encodeURIComponent(counters[counter])].join("=")});params.push("resolution="+res),params.push("start_time="+String(start_time)),params.push("end_time="+String(end_time));var endpoint="counters?"+params.join("&"),options={endpoint:endpoint};this._client.request(options,function(err,data){data.counters&&data.counters.length&&data.counters.forEach(function(counter){self._data.counters[counter.name]=counter.value||counter.values}),"function"==typeof callback&&callback.call(self,err,data)})};
\ No newline at end of file
+/*! usergrid@0.0.0 2014-01-27 */
+function isUUID(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}$/;return uuid?uuidValueRegex.test(uuid):!1}function encodeParams(params){var i,tail=[],item=[];if(params instanceof Array)for(i in params)item=params[i],item instanceof Array&&item.length>1&&tail.push(item[0]+"="+encodeURIComponent(item[1]));else for(var key in params)if(params.hasOwnProperty(key)){var value=params[key];if(value instanceof Array)for(i in value)item=value[i],tail.push(key+"="+encodeURIComponent(item));else tail.push(key+"="+encodeURIComponent(value))}return tail.join("&")}window.console=window.console||{},window.console.log=window.console.log||function(){},window.Usergrid=window.Usergrid||{},Usergrid=Usergrid||{},Usergrid.USERGRID_SDK_VERSION="0.10.07",Usergrid.Client=function(options){this.URI=options.URI||"https://api.usergrid.com",options.orgName&&this.set("orgName",options.orgName),options.appName&&this.set("appName",options.appName),this.buildCu
 rl=options.buildCurl||!1,this.logging=options.logging||!1,this._callTimeout=options.callTimeout||3e4,this._callTimeoutCallback=options.callTimeoutCallback||null,this.logoutCallback=options.logoutCallback||null},Usergrid.Client.prototype.request=function(options,callback){var uri,self=this,method=options.method||"GET",endpoint=options.endpoint,body=options.body||{},qs=options.qs||{},mQuery=options.mQuery||!1,orgName=this.get("orgName"),appName=this.get("appName");if(!mQuery&&!orgName&&!appName&&"function"==typeof this.logoutCallback)return this.logoutCallback(!0,"no_org_or_app_name_specified");uri=mQuery?this.URI+"/"+endpoint:this.URI+"/"+orgName+"/"+appName+"/"+endpoint,self.getToken()&&(qs.access_token=self.getToken());var encoded_params=encodeParams(qs);encoded_params&&(uri+="?"+encoded_params),body=JSON.stringify(body);var xhr=new XMLHttpRequest;xhr.open(method,uri,!0),body&&(xhr.setRequestHeader("Content-Type","application/json"),xhr.setRequestHeader("Accept","application/json")
 ),xhr.onerror=function(response){self._end=(new Date).getTime(),self.logging&&console.log("success (time: "+self.calcTimeDiff()+"): "+method+" "+uri),self.logging&&console.log("Error: API call failed at the network level."),clearTimeout(timeout);var err=!0;"function"==typeof callback&&callback(err,response)},xhr.onload=function(response){self._end=(new Date).getTime(),self.logging&&console.log("success (time: "+self.calcTimeDiff()+"): "+method+" "+uri),clearTimeout(timeout);try{response=JSON.parse(xhr.responseText)}catch(e){response={error:"unhandled_error",error_description:xhr.responseText},xhr.status=200===xhr.status?400:xhr.status,console.error(e)}if(200!=xhr.status){var error=response.error,error_description=response.error_description;if(self.logging&&console.log("Error ("+xhr.status+")("+error+"): "+error_description),("auth_expired_session_token"==error||"auth_missing_credentials"==error||"auth_unverified_oath"==error||"expired_token"==error||"unauthorized"==error||"auth_inva
 lid"==error)&&"function"==typeof self.logoutCallback)return self.logoutCallback(!0,response);"function"==typeof callback&&callback(!0,response)}else"function"==typeof callback&&callback(!1,response)};var timeout=setTimeout(function(){xhr.abort(),"function"===self._callTimeoutCallback?self._callTimeoutCallback("API CALL TIMEOUT"):self.callback("API CALL TIMEOUT")},self._callTimeout);if(this.logging&&console.log("calling: "+method+" "+uri),this.buildCurl){var curlOptions={uri:uri,body:body,method:method};this.buildCurlCall(curlOptions)}this._start=(new Date).getTime(),xhr.send(body)},Usergrid.Client.prototype.buildAssetURL=function(uuid){var self=this,qs={},assetURL=this.URI+"/"+this.orgName+"/"+this.appName+"/assets/"+uuid+"/data";self.getToken()&&(qs.access_token=self.getToken());var encoded_params=encodeParams(qs);return encoded_params&&(assetURL+="?"+encoded_params),assetURL},Usergrid.Client.prototype.createGroup=function(options,callback){var getOnExist=options.getOnExist||!1;opt
 ions={path:options.path,client:this,data:options};var group=new Usergrid.Group(options);group.fetch(function(err,data){var okToSave=err&&"service_resource_not_found"===data.error||"no_name_specified"===data.error||"null_pointer"===data.error||!err&&getOnExist;okToSave?group.save(function(err){"function"==typeof callback&&callback(err,group)}):"function"==typeof callback&&callback(err,group)})},Usergrid.Client.prototype.createEntity=function(options,callback){var getOnExist=options.getOnExist||!1,options={client:this,data:options},entity=new Usergrid.Entity(options);entity.fetch(function(err,data){var okToSave=err&&"service_resource_not_found"===data.error||"no_name_specified"===data.error||"null_pointer"===data.error||!err&&getOnExist;okToSave?(entity.set(options.data),entity.save(function(err,data){"function"==typeof callback&&callback(err,entity,data)})):"function"==typeof callback&&callback(err,entity,data)})},Usergrid.Client.prototype.getEntity=function(options,callback){var opt
 ions={client:this,data:options},entity=new Usergrid.Entity(options);entity.fetch(function(err,data){"function"==typeof callback&&callback(err,entity,data)})},Usergrid.Client.prototype.restoreEntity=function(serializedObject){var data=JSON.parse(serializedObject),options={client:this,data:data},entity=new Usergrid.Entity(options);return entity},Usergrid.Client.prototype.createCollection=function(options,callback){options.client=this;var collection=new Usergrid.Collection(options,function(err,data){"function"==typeof callback&&callback(err,collection,data)})},Usergrid.Client.prototype.restoreCollection=function(serializedObject){var data=JSON.parse(serializedObject);data.client=this;var collection=new Usergrid.Collection(data);return collection},Usergrid.Client.prototype.getFeedForUser=function(username,callback){var options={method:"GET",endpoint:"users/"+username+"/feed"};this.request(options,function(err,data){"function"==typeof callback&&(err?callback(err):callback(err,data,data.e
 ntities))})},Usergrid.Client.prototype.createUserActivity=function(user,options,callback){options.type="users/"+user+"/activities";var options={client:this,data:options},entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})},Usergrid.Client.prototype.createUserActivityWithEntity=function(user,content,callback){var username=user.get("username"),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)},Usergrid.Client.prototype.calcTimeDiff=function(){var seconds=0,time=this._end-this._start;try{seconds=(time/10/60).toFixed(2)}catch(e){return 0}return seconds},Usergrid.Client.prototype.setToken=function(token){this.set("token",token)},Usergrid.Client.prototype.getToken=function(){return this.get("token")},Usergrid.
 Client.prototype.setObject=function(key,value){value&&(value=JSON.stringify(value)),this.set(key,value)},Usergrid.Client.prototype.set=function(key,value){var keyStore="apigee_"+key;this[key]=value,"undefined"!=typeof Storage&&(value?localStorage.setItem(keyStore,value):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;return this[key]?this[key]:"undefined"!=typeof Storage?localStorage.getItem(keyStore):null},Usergrid.Client.prototype.signup=function(username,password,email,name,callback){var options={type:"users",username:username,password:password,email:email,name:name};this.createEntity(options,callback)},Usergrid.Client.prototype.login=function(username,password,callback){var self=this,options={method:"POST",endpoint:"token",body:{username:username,password:password,grant_type:"password"}};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)}"function"==typeof callback&&callback(err,data,user)})},Usergrid.Client.prototype.reAuthenticateLite=function(callback){var self=this,options={method:"GET",endpoint:"management/me",mQuery:!0};this.request(options,function(err,response){err&&self.logging?console.log("error trying to re-authenticate user"):self.setToken(response.access_token),"function"==typeof callback&&callback(err)})},Usergrid.Client.prototype.reAuthenticate=function(email,callback){var self=this,options={method:"GET",endpoint:"management/users/"+email,mQuery:!0};this.request(options,function(err,response){var data,organizations={},applications={},user={};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},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=!0,self.logging&&console.log("error selecting org")}applications=self.parseApplicationsArray(org),self.selectFirstApp(applications),self.setObject("organizations",organizations),self.setObject("applications",applications)}"function"==typeof callback&&callback(err,data,user,organizations,applications)})},Usergrid.Client.prototype.loginFacebook=function(facebookToken,callback){var self=this,options={method:"GET",endpoint:"auth/facebook",qs:{fb_access_token:facebookToken}};this.request(options,function(err,dat
 a){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)}"function"==typeof callback&&callback(err,data,user)})},Usergrid.Client.prototype.getLoggedInUser=function(callback){if(this.getToken()){var self=this,options={method:"GET",endpoint:"users/me"};this.request(options,function(err,data){if(err)self.logging&&console.log("error trying to log user in"),"function"==typeof callback&&callback(err,data,null);else{var options={client:self,data:data.entities[0]},user=new Usergrid.Entity(options);"function"==typeof callback&&callback(err,data,user)}})}else callback(!0,null,null)},Usergrid.Client.prototype.isLoggedIn=function(){return this.getToken()&&"null"!=this.getToken()?!0:!1},Usergrid.Client.prototype.logout=function(){this.setToken(null)},Usergrid.Client.prototype.buildCurlCall=function(options){var curl="curl",method=(options.method||"GET").toUpperCa
 se(),body=options.body||{},uri=options.uri;return curl+="POST"===method?" -X POST":"PUT"===method?" -X PUT":"DELETE"===method?" -X DELETE":" -X GET",curl+=" "+uri,"undefined"!=typeof window&&(body=JSON.stringify(body)),'"{}"'!==body&&"GET"!==method&&"DELETE"!==method&&(curl+=" -d '"+body+"'"),console.log(curl),curl},Usergrid.Client.prototype.getDisplayImage=function(email,picture,size){try{if(picture)return picture;var size=size||50;return email.length?"https://secure.gravatar.com/avatar/"+MD5(email)+"?s="+size+encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png"):"https://apigee.com/usergrid/images/user_profile.png"}catch(e){return"https://apigee.com/usergrid/images/user_profile.png"}},Usergrid.Entity=function(options){options&&(this._data=options.data||{},this._client=options.client||{})},Usergrid.Entity.prototype.serialize=function(){return JSON.stringify(this._data)},Usergrid.Entity.prototype.get=function(field){return field?this._data[field]:this._data},Usergrid.E
 ntity.prototype.set=function(key,value){if("object"==typeof key)for(var field in key)this._data[field]=key[field];else"string"==typeof key?null===value?delete this._data[key]:this._data[key]=value:this._data={}},Usergrid.Entity.prototype.save=function(callback){var type=this.get("type"),method="POST";isUUID(this.get("uuid"))&&(method="PUT",type+="/"+this.get("uuid"));var self=this,data={},entityData=this.get(),oldpassword=(this.get("password"),this.get("oldpassword")),newpassword=this.get("newpassword");for(var item in entityData)"metadata"!==item&&"created"!==item&&"modified"!==item&&"oldpassword"!==item&&"newpassword"!==item&&"type"!==item&&"activated"!==item&&"uuid"!==item&&(data[item]=entityData[item]);var options={method:method,endpoint:type,body:data};this._client.request(options,function(err,retdata){if(self.set("password",null),self.set("oldpassword",null),self.set("newpassword",null),err&&self._client.logging){if(console.log("could not save entity"),"function"==typeof callb
 ack)return callback(err,retdata,self)}else{if(retdata.entities&&retdata.entities.length){var entity=retdata.entities[0];self.set(entity);for(var path=retdata.path;"/"===path.substring(0,1);)path=path.substring(1);self.set("type",path)}var needPasswordChange=("user"===self.get("type")||"users"===self.get("type"))&&oldpassword&&newpassword;if(needPasswordChange){var pwdata={};pwdata.oldpassword=oldpassword,pwdata.newpassword=newpassword;var options={method:"PUT",endpoint:type+"/password",body:pwdata};self._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not update user"),self.set("oldpassword",null),self.set("newpassword",null),"function"==typeof callback&&callback(err,data,self)})}else"function"==typeof callback&&callback(err,retdata,self)}})},Usergrid.Entity.prototype.fetch=function(callback){var type=this.get("type"),self=this;try{if(void 0===type)throw"cannot fetch entity, no entity type specified";if(this.get("uuid"))type+="/"+this.get("uui
 d");else if("users"===type&&this.get("username"))type+="/"+this.get("username");else if(this.get("name"))type+="/"+encodeURIComponent(this.get("name"));else if("function"==typeof callback)throw"no_name_specified"}catch(e){return self._client.logging&&console.log(e),callback(!0,{error:e},self)}var options={method:"GET",endpoint:type};this._client.request(options,function(err,data){if(err&&self._client.logging)console.log("could not get entity");else if(data.user)self.set(data.user),self._json=JSON.stringify(data.user,null,2);else if(data.entities&&data.entities.length){var entity=data.entities[0];self.set(entity)}"function"==typeof callback&&callback(err,data,self)})},Usergrid.Entity.prototype.destroy=function(callback){var self=this,type=this.get("type");if(isUUID(this.get("uuid")))type+="/"+this.get("uuid");else if("function"==typeof callback){var error="Error trying to delete object - no uuid specified.";self._client.logging&&console.log(error),callback(!0,error)}var options={meth
 od:"DELETE",endpoint:type};this._client.request(options,function(err,data){err&&self._client.logging?console.log("entity could not be deleted"):self.set(null),"function"==typeof callback&&callback(err,data)})},Usergrid.Entity.prototype.connect=function(connection,entity,callback){var error,self=this,connecteeType=entity.get("type"),connectee=this.getEntityId(entity);if(!connectee)return void("function"==typeof callback&&(error="Error trying to delete object - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var connectorType=this.get("type"),connector=this.getEntityId(this);if(!connector)return void("function"==typeof callback&&(error="Error in connect - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var endpoint=connectorType+"/"+connector+"/"+connection+"/"+connecteeType+"/"+connectee,options={method:"POST",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("e
 ntity could not be connected"),"function"==typeof callback&&callback(err,data)})},Usergrid.Entity.prototype.getEntityId=function(entity){var id=!1;return isUUID(entity.get("uuid"))?id=entity.get("uuid"):"users"===type?id=entity.get("username"):entity.get("name")&&(id=entity.get("name")),id},Usergrid.Entity.prototype.getConnections=function(connection,callback){var self=this,connectorType=this.get("type"),connector=this.getEntityId(this);if(connector){var endpoint=connectorType+"/"+connector+"/"+connection+"/",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be connected"),self[connection]={};for(var length=data.entities.length,i=0;length>i;i++)"user"===data.entities[i].type?self[connection][data.entities[i].username]=data.entities[i]:self[connection][data.entities[i].name]=data.entities[i];"function"==typeof callback&&callback(err,data,data.entities)})}else if("function"==typeof callback
 ){var error="Error in getConnections - no uuid specified.";self._client.logging&&console.log(error),callback(!0,error)}},Usergrid.Entity.prototype.getGroups=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/groups",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be connected"),self.groups=data.entities,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getActivities=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/activities",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){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,"function"==typeof callback&&callback(err,data,data.entities)})},
 Usergrid.Entity.prototype.getFollowing=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/following",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getFollowers=function(callback){var self=this,endpoint="users/"+this.get("uuid")+"/followers",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user followers");for(var entity in data.entities){data.entities[entity].createdDate=new Date(d
 ata.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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getRoles=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/roles",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user roles"),self.roles=data.entities,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.getPermissions=function(callback){var self=this,endpoint=this.get("type")+"/"+this.get("uuid")+"/permissions",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("could not get user permissions");var permissions=[];if(data.data){var perms=dat
 a.data,count=0;for(var i in perms){count++;var perm=perms[i],parts=perm.split(":"),ops_part="",path_part=parts[0];parts.length>1&&(ops_part=parts[0],path_part=parts[1]),ops_part.replace("*","get,post,put,delete");var ops=ops_part.split(","),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,"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Entity.prototype.disconnect=function(connection,entity,callback){var error,self=this,connecteeType=entity.get("type"),connectee=this.getEntityId(entity);if(!connectee)return void("function"==typeof callback&&(error="Error trying to delete object - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var connectorType=this.get("type"),connector=this.getEntityId(this);if(!connector)return void("function"==typeof ca
 llback&&(error="Error in connect - no uuid specified.",self._client.logging&&console.log(error),callback(!0,error)));var endpoint=connectorType+"/"+connector+"/"+connection+"/"+connecteeType+"/"+connectee,options={method:"DELETE",endpoint:endpoint};this._client.request(options,function(err,data){err&&self._client.logging&&console.log("entity could not be disconnected"),"function"==typeof callback&&callback(err,data)})},Usergrid.Collection=function(options,callback){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,options.list))for(var count=options.list.length,i=0;count>i;i++){var entity=this._client.restoreEntity(options.list[i]);this._list[i]=entity}callback&&this.fetch(callback)},Usergrid.Collection.prototype.serialize=function(){var data={};data.type=this._type,data.qs=this.qs,da
 ta.iterator=this._iterator,data.previous=this._previous,data.next=this._next,data.cursor=this._cursor,this.resetEntityPointer();var i=0;for(data.list=[];this.hasNextEntity();){var entity=this.getNextEntity();data.list[i]=entity.serialize(),i++}return data=JSON.stringify(data)},Usergrid.Collection.prototype.addCollection=function(collectionName,options,callback){self=this,options.client=this._client;var collection=new Usergrid.Collection(options,function(err){if("function"==typeof callback){for(collection.resetEntityPointer();collection.hasNextEntity();){var user=collection.getNextEntity(),image=(user.get("email"),self._client.getDisplayImage(user.get("email"),user.get("picture")));user._portal_image_icon=image}self[collectionName]=collection,callback(err,collection)}})},Usergrid.Collection.prototype.fetch=function(callback){var self=this,qs=this.qs;this._cursor?qs.cursor=this._cursor:delete qs.cursor;var options={method:"GET",endpoint:this._type,qs:this.qs};this._client.request(opti
 ons,function(err,data){if(err&&self._client.logging)console.log("error getting collection");else{var cursor=data.cursor||null;if(self.saveCursor(cursor),data.entities){self.resetEntityPointer();var count=data.entities.length;self._list=[];for(var i=0;count>i;i++){var uuid=data.entities[i].uuid;if(uuid){var entityData=data.entities[i]||{};self._baseType=data.entities[i].type,entityData.type=self._type;var entityOptions={type:self._type,client:self._client,uuid:uuid,data:entityData},ent=new Usergrid.Entity(entityOptions);ent._json=JSON.stringify(entityData,null,2);var ct=self._list.length;self._list[ct]=ent}}}}"function"==typeof callback&&callback(err,data)})},Usergrid.Collection.prototype.addEntity=function(options,callback){var self=this;options.type=this._type,this._client.createEntity(options,function(err,entity){if(!err){var count=self._list.length;self._list[count]=entity}"function"==typeof callback&&callback(err,entity)})},Usergrid.Collection.prototype.addExistingEntity=functio
 n(entity){var count=this._list.length;this._list[count]=entity},Usergrid.Collection.prototype.destroyEntity=function(entity,callback){var self=this;entity.destroy(function(err,data){err?(self._client.logging&&console.log("could not destroy entity"),"function"==typeof callback&&callback(err,data)):self.fetch(callback)}),this.removeEntity(entity)},Usergrid.Collection.prototype.removeEntity=function(entity){var uuid=entity.get("uuid");for(var key in this._list){var listItem=this._list[key];if(listItem.get("uuid")===uuid)return this._list.splice(key,1)}return!1},Usergrid.Collection.prototype.getEntityByUUID=function(uuid,callback){for(var key in this._list){var listItem=this._list[key];if(listItem.get("uuid")===uuid)return listItem}var options={data:{type:this._type,uuid:uuid},client:this._client},entity=new Usergrid.Entity(options);entity.fetch(callback)},Usergrid.Collection.prototype.getFirstEntity=function(){var count=this._list.length;return count>0?this._list[0]:null},Usergrid.Coll
 ection.prototype.getLastEntity=function(){var count=this._list.length;return count>0?this._list[count-1]:null},Usergrid.Collection.prototype.hasNextEntity=function(){var next=this._iterator+1,hasNextElement=next>=0&&next<this._list.length;return hasNextElement?!0:!1},Usergrid.Collection.prototype.getNextEntity=function(){this._iterator++;var hasNextElement=this._iterator>=0&&this._iterator<=this._list.length;return hasNextElement?this._list[this._iterator]:!1},Usergrid.Collection.prototype.hasPrevEntity=function(){var previous=this._iterator-1,hasPreviousElement=previous>=0&&previous<this._list.length;return hasPreviousElement?!0:!1},Usergrid.Collection.prototype.getPrevEntity=function(){this._iterator--;var hasPreviousElement=this._iterator>=0&&this._iterator<=this._list.length;return hasPreviousElement?this._list[this._iterator]:!1},Usergrid.Collection.prototype.resetEntityPointer=function(){this._iterator=-1},Usergrid.Collection.prototype.saveCursor=function(cursor){this._next!==
 cursor&&(this._next=cursor)},Usergrid.Collection.prototype.resetPaging=function(){this._previous=[],this._next=null,this._cursor=null},Usergrid.Collection.prototype.hasNextPage=function(){return this._next},Usergrid.Collection.prototype.getNextPage=function(callback){this.hasNextPage()&&(this._previous.push(this._cursor),this._cursor=this._next,this._list=[],this.fetch(callback))},Usergrid.Collection.prototype.hasPreviousPage=function(){return this._previous.length>0},Usergrid.Collection.prototype.getPreviousPage=function(callback){this.hasPreviousPage()&&(this._next=null,this._cursor=this._previous.pop(),this._list=[],this.fetch(callback))},Usergrid.Group=function(options){this._path=options.path,this._list=[],this._client=options.client,this._data=options.data||{},this._data.type="groups"},Usergrid.Group.prototype=new Usergrid.Entity,Usergrid.Group.prototype.fetch=function(callback){var self=this,groupEndpoint="groups/"+this._path,memberEndpoint="groups/"+this._path+"/users",group
 Options={method:"GET",endpoint:groupEndpoint},memberOptions={method:"GET",endpoint:memberEndpoint};this._client.request(groupOptions,function(err,data){if(err)self._client.logging&&console.log("error getting group"),"function"==typeof callback&&callback(err,data);else if(data.entities){var groupData=data.entities[0];self._data=groupData||{},self._client.request(memberOptions,function(err,data){if(err&&self._client.logging)console.log("error getting group users");else if(data.entities){var count=data.entities.length;self._list=[];for(var i=0;count>i;i++){var uuid=data.entities[i].uuid;if(uuid){var entityData=data.entities[i]||{},entityOptions={type:entityData.type,client:self._client,uuid:uuid,data:entityData},entity=new Usergrid.Entity(entityOptions);self._list.push(entity)}}}"function"==typeof callback&&callback(err,data,self._list)})}})},Usergrid.Group.prototype.members=function(callback){"function"==typeof callback&&callback(null,this._list)},Usergrid.Group.prototype.add=function
 (options,callback){var self=this,options={method:"POST",endpoint:"groups/"+this._path+"/users/"+options.user.get("username")};this._client.request(options,function(error,data){error?"function"==typeof callback&&callback(error,data,data.entities):self.fetch(callback)})},Usergrid.Group.prototype.remove=function(options,callback){var self=this,options={method:"DELETE",endpoint:"groups/"+this._path+"/users/"+options.user.get("username")};this._client.request(options,function(error,data){error?"function"==typeof callback&&callback(error,data):self.fetch(callback)})},Usergrid.Group.prototype.feed=function(callback){var self=this,endpoint="groups/"+this._path+"/feed",options={method:"GET",endpoint:endpoint};this._client.request(options,function(err,data){err&&self.logging&&console.log("error trying to log user in"),"function"==typeof callback&&callback(err,data,data.entities)})},Usergrid.Group.prototype.createGroupActivity=function(options,callback){var user=options.user;options={client:th
 is._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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})},Usergrid.Counter=function(options,callback){var self=this;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||{},"function"==typeof callback&&callback.call(self,!1,self)};var COUNTER_RESOLUTIONS=["all","minute","five_minutes","half_hour","hour","six_day","day","week","month"];Usergrid.Counter.prototype=new Usergrid.Entity,Usergrid.Counter.prototype.fetch=function(callback){this.getData({},callback)},Usergrid.Counter
 .prototype.increment=function(options,callback){var self=this,name=options.name,value=options.value;if(name){if(!isNaN(value))return self._data.counters[name]=parseInt(value)||1,self.save(callback);if("function"==typeof callback)return callback.call(self,!0,"'value' for increment, decrement must be a number")}else if("function"==typeof callback)return callback.call(self,!0,"'value' for increment, decrement must be a number")},Usergrid.Counter.prototype.decrement=function(options,callback){var self=this,name=options.name,value=options.value;self.increment({name:name,value:-(parseInt(value)||1)},callback)},Usergrid.Counter.prototype.reset=function(options,callback){var self=this,name=options.name;self.increment({name:name,value:0},callback)},Usergrid.Counter.prototype.getData=function(options,callback){var start_time,end_time,start=options.start||0,end=options.end||Date.now(),resolution=(options.resolution||"all").toLowerCase(),counters=options.counters||Object.keys(this._data.counter
 s),res=(resolution||"all").toLowerCase();if(-1===COUNTER_RESOLUTIONS.indexOf(res)&&(res="all"),start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(start)?Date.parse(start):parseInt(start);break;default:start_time=Date.parse(start.toString())}if(end)switch(typeof end){case"undefined":end_time=Date.now();break;case"number":end_time=end;break;case"string":end_time=isNaN(end)?Date.parse(end):parseInt(end);break;default:end_time=Date.parse(end.toString())}var self=this,params=Object.keys(counters).map(function(counter){return["counter",encodeURIComponent(counters[counter])].join("=")});params.push("resolution="+res),params.push("start_time="+String(start_time)),params.push("end_time="+String(end_time));var endpoint="counters?"+params.join("&");this._client.request({endpoint:endpoint},function(err,data){data.counters&&data.counters.length&&data.counters.forEach(function(counter){self._data.counters[counter.name]=c
 ounter.value||counter.values}),"function"==typeof callback&&callback.call(self,err,data)})};
\ No newline at end of file