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:20:47 UTC

[01/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Updated Branches:
  refs/pull/34/head [created] 31d481a9f
  refs/pull/34/merge [created] cc175edb0


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/test.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/test.html b/sdks/html5-javascript/tests/test.html
new file mode 100755
index 0000000..99525e2
--- /dev/null
+++ b/sdks/html5-javascript/tests/test.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+   <head>
+      <title>Readme File Tests</title>
+      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+      <link rel="stylesheet" href="resources/css/bootstrap-combined.min.css" />
+      <link rel="stylesheet" href="resources/css/styles.css" />
+      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
+      <script src="../usergrid.js" type="text/javascript"></script>
+      <script src="test.js" type="text/javascript"></script>
+      <script type="text/javascript">
+
+      </script>
+   </head>
+   <body>
+      <div class="header">
+         <img src="resources/images/apigee.png"> App Services (Usergrid) Javascript SDK
+      </div>
+      <div class="info">
+      This sample application runs tests on the sample code examples in the readme file.  Tests are run against App Services (Usergrid) using the Usergrid Javascript SDK.
+      </div>
+    <div id="main" class="main">
+      <div class="section-header">README sample code tests</div>
+      <div class="well">
+        <div id="name-control" class="control-group">
+          <div class="controls">
+            <button class="btn btn-primary" id="start-button" style="width: 90px;">Start</button>
+            <span style="clear: both;">&nbsp;</span>
+          </div>
+        </div>
+      </div>
+      <div class="section-header"><b>Test Output</b></div>
+      <div class="well">
+        <pre id="test-output">// Press Start button to begin</pre>
+      </div>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/test.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/test.js b/sdks/html5-javascript/tests/test.js
new file mode 100755
index 0000000..dcfd735
--- /dev/null
+++ b/sdks/html5-javascript/tests/test.js
@@ -0,0 +1,910 @@
+/**
+* Test suite for all the examples in the readme
+*
+* NOTE: No, this test suite doesn't use the traditional format for
+* a test suite.  This is because the goal is to require as little
+* alteration as possible during the copy / paste operation from this test
+* suite to the readme file.
+*
+* @author rod simpson (rod@apigee.com)
+*/
+
+$(document).ready(function () {
+
+//call the runner function to start the process
+$('#start-button').bind('click', function() {
+	$('#start-button').attr("disabled", "disabled");
+	$('#test-output').html('');
+	runner(0);
+});
+
+var logSuccess = true;
+var successCount = 0;
+var logError = true;
+var errorCount = 0;
+var logNotice = true;
+var _username = 'marty2';
+var _email = 'marty2@timetravel.com';
+var _password = 'password2';
+var _newpassword = 'password3';
+
+var client = new Usergrid.Client({
+	orgName:'yourorgname',
+	appName:'sandbox',
+	logging: true, //optional - turn on logging, off by default
+	buildCurl: true //optional - turn on curl commands, off by default
+});
+
+client.logout();
+
+function runner(step, arg, arg2){
+	step++;
+	switch(step)
+	{
+		case 1:
+			notice('-----running step '+step+': DELETE user from DB to prep test');
+			clearUser(step);
+			break;
+		case 2:
+			notice('-----running step '+step+': GET test');
+			testGET(step);
+			break;
+		case 3:
+			notice('-----running step '+step+': POST test');
+			testPOST(step);
+			break;
+		case 4:
+			notice('-----running step '+step+': PUT test');
+			testPUT(step);
+			break;
+		case 5:
+			notice('-----running step '+step+': DELETE test');
+			testDELETE(step);
+			break;
+		case 6:
+			notice('-----running step '+step+': prepare database - remove all dogs (no real dogs harmed here!!)');
+			cleanupAllDogs(step);
+			break;
+		case 7:
+			notice('-----running step '+step+': make a new dog');
+			makeNewDog(step);
+			break;
+		case 8:
+			notice('-----running step '+step+': update our dog');
+			updateDog(step, arg);
+			break;
+		case 9:
+			notice('-----running step '+step+': refresh our dog');
+			refreshDog(step, arg);
+			break;
+		case 10:
+			notice('-----running step '+step+': remove our dog from database (no real dogs harmed here!!)');
+			removeDogFromDatabase(step, arg);
+			break;
+		case 11:
+			notice('-----running step '+step+': make lots of dogs!');
+			makeSampleData(step, arg);
+			break;
+		case 12:
+			notice('-----running step '+step+': make a dogs collection and show each dog');
+			testDogsCollection(step);
+			break;
+		case 13:
+			notice('-----running step '+step+': get the next page of the dogs collection and show each dog');
+			getNextDogsPage(step, arg);
+			break;
+		case 14:
+			notice('-----running step '+step+': get the previous page of the dogs collection and show each dog');
+			getPreviousDogsPage(step, arg);
+			break;
+		case 15:
+			notice('-----running step '+step+': remove all dogs from the database (no real dogs harmed here!!)');
+			cleanupAllDogs(step);
+			break;
+		case 16:
+			notice('-----running step '+step+': prepare database (remove existing user if present)');
+			prepareDatabaseForNewUser(step);
+			break;
+		case 17:
+			notice('-----running step '+step+': create a new user');
+			createUser(step);
+			break;
+		case 18:
+			notice('-----running step '+step+': update the user');
+			updateUser(step, arg);
+			break;
+		case 19:
+			notice('-----running step '+step+': get the existing user');
+			getExistingUser(step, arg);
+			break;
+		case 20:
+			notice('-----running step '+step+': refresh the user from the database');
+			refreshUser(step, arg);
+			break;
+		case 21:
+			notice('-----running step '+step+': log user in');
+			loginUser(step, arg);
+			break;
+		case 22:
+			notice('-----running step '+step+': change users password');
+			changeUsersPassword(step, arg);
+			break;
+		case 23:
+			notice('-----running step '+step+': log user out');
+			logoutUser(step, arg);
+			break;
+		case 24:
+			notice('-----running step '+step+': relogin user');
+			reloginUser(step, arg);
+			break;
+		case 25:
+			notice('-----running step '+step+': logged in user creates dog');
+			createDog(step, arg);
+			break;
+		case 26:
+			notice('-----running step '+step+': logged in user likes dog');
+			userLikesDog(step, arg, arg2);
+			break;
+		case 27:
+			notice('-----running step '+step+': logged in user removes likes connection to dog');
+			removeUserLikesDog(step, arg, arg2);
+			break;
+		case 28:
+			notice('-----running step '+step+': user removes dog');
+			removeDog(step, arg, arg2);
+			break;
+		case 29:
+			notice('-----running step '+step+': log the user out');
+			logoutUser(step, arg);
+			break;
+		case 30:
+			notice('-----running step '+step+': remove the user from the database');
+			destroyUser(step, arg);
+			break;
+		case 31:
+			notice('-----running step '+step+': try to create existing entity');
+			createExistingEntity(step, arg);
+			break;
+		case 32:
+			notice('-----running step '+step+': try to create new entity with no name');
+			createNewEntityNoName(step, arg);
+			break;
+		default:
+			notice('-----test complete!-----');
+			notice('Success count= ' + successCount);
+			notice('Error count= ' + errorCount);
+			notice('-----thank you for playing!-----');
+			$('#start-button').removeAttr("disabled");
+	}
+}
+
+//logging functions
+function success(message){
+	successCount++;
+	if (logSuccess) {
+		console.log('SUCCESS: ' + message);
+		var html = $('#test-output').html();
+		html += ('SUCCESS: ' + message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+function error(message){
+	errorCount++
+	if (logError) {
+		console.log('ERROR: ' + message);
+		var html = $('#test-output').html();
+		html += ('ERROR: ' + message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+function notice(message){
+	if (logNotice) {
+		console.log('NOTICE: ' + message);
+		var html = $('#test-output').html();
+		html += (message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+//tests
+function clearUser(step) {
+  var options = {
+    method:'DELETE',
+    endpoint:'users/fred'
+  };
+  client.request(options, function (err, data) {
+    //data will contain raw results from API call
+    success('User cleared from DB');
+    runner(step);
+  });
+}
+
+function testGET(step) {
+	var options = {
+		method:'GET',
+		endpoint:'users'
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('GET failed');
+		} else {
+			//data will contain raw results from API call
+			success('GET worked');
+			runner(step);
+		}
+	});
+}
+
+function testPOST(step) {
+	var options = {
+		method:'POST',
+		endpoint:'users',
+		body:{ username:'fred', password:'secret' }
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('POST failed');
+		} else {
+			//data will contain raw results from API call
+			success('POST worked');
+			runner(step);
+		}
+	});
+}
+
+function testPUT(step) {
+	var options = {
+		method:'PUT',
+		endpoint:'users/fred',
+		body:{ newkey:'newvalue' }
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('PUT failed');
+		} else {
+			//data will contain raw results from API call
+			success('PUT worked');
+			runner(step);
+		}
+	});
+}
+
+function testDELETE(step) {
+	var options = {
+		method:'DELETE',
+		endpoint:'users/fred'
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('DELETE failed');
+		} else {
+			//data will contain raw results from API call
+			success('DELETE worked');
+			runner(step);
+		}
+	});
+}
+
+function makeNewDog(step) {
+
+	var options = {
+		type:'dogs',
+		name:'Rocky'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('dog not created');
+		} else {
+			success('dog is created');
+
+			//once the dog is created, you can set single properties:
+			dog.set('breed','Dinosaur');
+
+			//the set function can also take a JSON object:
+			var data = {
+				master:'Fred',
+				state:'hungry'
+			}
+			//set is additive, so previously set properties are not overwritten
+			dog.set(data);
+
+			//finally, call save on the object to save it back to the database
+			dog.save(function(err){
+				if (err){
+					error('dog not saved');
+				} else {
+					success('new dog is saved');
+					runner(step, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function updateDog(step, dog) {
+
+	//change a property in the object
+	dog.set("state", "fed");
+	//and save back to the database
+	dog.save(function(err){
+		if (err){
+			error('dog not saved');
+		} else {
+			success('dog is saved');
+			runner(step, dog);
+		}
+	});
+
+}
+
+function refreshDog(step, dog){
+
+	//call fetch to refresh the data from the server
+	dog.fetch(function(err){
+		if (err){
+			error('dog not refreshed from database');
+		} else {
+			//dog has been refreshed from the database
+			//will only work if the UUID for the entity is in the dog object
+			success('dog entity refreshed from database');
+			runner(step, dog);
+		}
+	});
+
+}
+
+function removeDogFromDatabase(step, dog){
+
+	//the destroy method will delete the entity from the database
+	dog.destroy(function(err){
+		if (err){
+			error('dog not removed from database');
+		} else {
+			success('dog removed from database'); // no real dogs were harmed!
+			dog = null; //no real dogs were harmed!
+			runner(step, 1);
+		}
+	});
+
+}
+
+function makeSampleData(step, i) {
+	notice('making dog '+i);
+
+	var options = {
+		type:'dogs',
+		name:'dog'+i,
+		index:i
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('dog ' + i + ' not created');
+		} else {
+			if (i >= 30) {
+				//data made, ready to go
+				success('all dogs made');
+				runner(step);
+			} else {
+				success('dog ' + i + ' made');
+				//keep making dogs
+				makeSampleData(step, ++i);
+			}
+		}
+	});
+}
+
+function testDogsCollection(step) {
+
+	var options = {
+		type:'dogs',
+		qs:{ql:'order by index'}
+	}
+
+	client.createCollection(options, function (err, dogs) {
+		if (err) {
+			error('could not make collection');
+		} else {
+
+			success('new Collection created');
+
+			//we got the dogs, now display the Entities:
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				dog = dogs.getNextEntity();
+				var name = dog.get('name');
+				notice('dog is called ' + name);
+			}
+
+			success('looped through dogs');
+
+			//create a new dog and add it to the collection
+			var options = {
+				name:'extra-dog',
+				fur:'shedding'
+			}
+			//just pass the options to the addEntity method
+			//to the collection and it is saved automatically
+			dogs.addEntity(options, function(err, dog, data) {
+				if (err) {
+					error('extra dog not saved or added to collection');
+				} else {
+					success('extra dog saved and added to collection');
+					runner(step, dogs);
+				}
+			});
+		}
+	});
+
+}
+
+function getNextDogsPage(step, dogs) {
+
+	if (dogs.hasNextPage()) {
+		//there is a next page, so get it from the server
+		dogs.getNextPage(function(err){
+			if (err) {
+				error('could not get next page of dogs');
+			} else {
+				success('got next page of dogs');
+				//we got the next page of data, so do something with it:
+				var i = 11;
+				while(dogs.hasNextEntity()) {
+					//get a reference to the dog
+					var dog = dogs.getNextEntity();
+					var index = dog.get('index');
+					if(i !== index) {
+						error('wrong dog loaded: wanted' + i + ', got ' + index);
+					}
+					notice('got dog ' + i);
+					i++
+				}
+				success('looped through dogs')
+				runner(step, dogs);
+			}
+		});
+	} else {
+		getPreviousDogsPage(dogs);
+	}
+
+}
+
+function getPreviousDogsPage(step, dogs) {
+
+	if (dogs.hasPreviousPage()) {
+		//there is a previous page, so get it from the server
+		dogs.getPreviousPage(function(err){
+			if(err) {
+				error('could not get previous page of dogs');
+			} else {
+				success('got next page of dogs');
+				//we got the previous page of data, so do something with it:
+				var i = 1;
+				while(dogs.hasNextEntity()) {
+					//get a reference to the dog
+					var dog = dogs.getNextEntity();
+					var index = dog.get('index');
+					if(i !== index) {
+						error('wrong dog loaded: wanted' + i + ', got ' + index);
+					}
+					notice('got dog ' + i);
+					i++
+				}
+				success('looped through dogs');
+				runner(step);
+			}
+		});
+	} else {
+		getAllDogs();
+	}
+}
+
+function cleanupAllDogs(step){
+
+	var options = {
+		type:'dogs',
+		qs:{limit:50} //limit statement set to 50
+	}
+
+	client.createCollection(options, function (err, dogs) {
+		if (err) {
+			error('could not get all dogs');
+		} else {
+			success('got at most 50 dogs');
+			//we got 50 dogs, now display the Entities:
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				var dog = dogs.getNextEntity();
+				var name = dog.get('name');
+				notice('dog is called ' + name);
+			}
+			dogs.resetEntityPointer();
+			//do doggy cleanup
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				var dog = dogs.getNextEntity();
+				var dogname = dog.get('name');
+				notice('removing dog ' + dogname + ' from database');
+				dog.destroy(function(err, data) {
+					if (err) {
+						error('dog not removed');
+					} else {
+						success('dog removed');
+					}
+				});
+			}
+
+			//no need to wait around for dogs to be removed, so go on to next test
+			runner(step);
+		}
+	});
+}
+
+
+function prepareDatabaseForNewUser(step) {
+	var options = {
+		method:'DELETE',
+		endpoint:'users/'+_username
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			notice('database ready - no user to delete');
+		runner(step);
+		} else {
+			//data will contain raw results from API call
+			success('database ready - user deleted worked');
+			runner(step);
+		}
+	});
+}
+
+
+function createUser(step) {
+	client.signup(_username, _password, _email, 'Marty McFly',
+		function (err, marty) {
+			if (err){
+				error('user not created');
+				runner(step, marty);
+			} else {
+				success('user created');
+				runner(step, marty);
+			}
+		}
+	);
+}
+
+function updateUser(step, marty) {
+
+	//add properties cumulatively
+	marty.set('state', 'California');
+	marty.set("girlfriend","Jennifer");
+	marty.save(function(err){
+		if (err){
+			error('user not updated');
+		} else {
+			success('user updated');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function getExistingUser(step, marty) {
+
+	var options = {
+		type:'users',
+		username:_username
+	}
+	client.getEntity(options, function(err, existingUser){
+		if (err){
+			error('existing user not retrieved');
+		} else {
+			success('existing user was retrieved');
+
+			var username = existingUser.get('username');
+			if (username === _username){
+				success('got existing user username');
+			} else {
+				error('could not get existing user username');
+			}
+			runner(step, marty);
+		}
+	});
+
+}
+
+
+function refreshUser(step, marty) {
+
+	marty.fetch(function(err){
+		if (err){
+			error('not refreshed');
+		} else {
+			success('user refreshed');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function loginUser(step, marty) {
+	username = _username;
+	password = _password;
+	client.login(username, password,
+		function (err) {
+			if (err) {
+				error('could not log user in');
+			} else {
+				success('user has been logged in');
+
+				//the login call will return an OAuth token, which is saved
+				//in the client. Any calls made now will use the token.
+				//once a user has logged in, their user object is stored
+				//in the client and you can access it this way:
+				var token = client.token;
+
+				//Then make calls against the API.  For example, you can
+				//get the user entity this way:
+				client.getLoggedInUser(function(err, data, user) {
+					if(err) {
+						error('could not get logged in user');
+					} else {
+						success('got logged in user');
+
+						//you can then get info from the user entity object:
+						var username = user.get('username');
+						notice('logged in user was: ' + username);
+
+						runner(step, user);
+					}
+				});
+
+			}
+		}
+	);
+}
+
+function changeUsersPassword(step, marty) {
+
+	marty.set('oldpassword', _password);
+	marty.set('newpassword', _newpassword);
+	marty.save(function(err){
+		if (err){
+			error('user password not updated');
+		} else {
+			success('user password updated');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function logoutUser(step, marty) {
+
+	//to log the user out, call the logout() method
+	client.logout();
+
+	//verify the logout worked
+	if (client.isLoggedIn()) {
+		error('logout failed');
+	} else {
+		success('user has been logged out');
+	}
+
+	runner(step, marty);
+}
+
+function reloginUser(step, marty) {
+
+	username = _username
+	password = _newpassword;
+	client.login(username, password,
+		function (err) {
+		if (err) {
+			error('could not relog user in');
+		} else {
+			success('user has been re-logged in');
+			runner(step, marty);
+		}
+		}
+	);
+}
+
+
+
+//TODO: currently, this code assumes permissions have been set to support user actions.  need to add code to show how to add new role and permission programatically
+//
+//first create a new permission on the default role:
+//POST "https://api.usergrid.com/yourorgname/yourappname/roles/default/permissions" -d '{"permission":"get,post,put,delete:/dogs/**"}'
+//then after user actions, delete the permission on the default role:
+//DELETE "https://api.usergrid.com/yourorgname/yourappname/roles/default/permissions?permission=get%2Cpost%2Cput%2Cdelete%3A%2Fdogs%2F**"
+
+
+function createDog(step, marty) {
+
+	var options = {
+		type:'dogs',
+		name:'einstein',
+		breed:'mutt'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('POST new dog by logged in user failed');
+		} else {
+			success('POST new dog by logged in user succeeded');
+			runner(step, marty, dog);
+		}
+	});
+
+}
+
+function userLikesDog(step, marty, dog) {
+
+	marty.connect('likes', dog, function (err, data) {
+		if (err) {
+			error('connection not created');
+			runner(step, marty);
+		} else {
+
+			//call succeeded, so pull the connections back down
+			marty.getConnections('likes', function (err, data) {
+				if (err) {
+						error('could not get connections');
+				} else {
+					//verify that connection exists
+					if (marty.likes.einstein) {
+						success('connection exists');
+					} else {
+						error('connection does not exist');
+					}
+
+					runner(step, marty, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function removeUserLikesDog(step, marty, dog) {
+
+	marty.disconnect('likes', dog, function (err, data) {
+		if (err) {
+			error('connection not deleted');
+			runner(step, marty);
+		} else {
+
+			//call succeeded, so pull the connections back down
+			marty.getConnections('likes', function (err, data) {
+				if (err) {
+					error('error getting connections');
+				} else {
+					//verify that connection exists
+					if (marty.likes.einstein) {
+						error('connection still exists');
+					} else {
+						success('connection deleted');
+					}
+
+					runner(step, marty, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function removeDog(step, marty, dog) {
+
+	//now delete the dog from the database
+	dog.destroy(function(err, data) {
+		if (err) {
+			error('dog not removed');
+		} else {
+			success('dog removed');
+		}
+	});
+	runner(step, marty);
+}
+
+function destroyUser(step, marty) {
+
+	marty.destroy(function(err){
+		if (err){
+			error('user not deleted from database');
+		} else {
+			success('user deleted from database');
+			marty = null; //blow away the local object
+			runner(step);
+		}
+	});
+
+}
+
+function createExistingEntity(step, marty) {
+
+	var options = {
+		type:'dogs',
+		name:'einstein'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('Create new entity to use for existing entity failed');
+		} else {
+			success('Create new entity to use for existing entity succeeded');
+
+			var uuid = dog.get('uuid');
+			//now create new entity, but use same entity name of einstein.  This means that
+			//the original einstein entity now exists.  Thus, the new einstein entity should
+			//be the same as the original + any data differences from the options var:
+
+			options = {
+				type:'dogs',
+				name:'einstein',
+				breed:'mutt'
+			}
+			client.createEntity(options, function (err, newdog) {
+				if (err) {
+					error('Create new entity to use for existing entity failed');
+				} else {
+					success('Create new entity to use for existing entity succeeded');
+
+					var newuuid = newdog.get('uuid');
+					if (newuuid === uuid) {
+						success('UUIDs of new and old entities match');
+					} else {
+						error('UUIDs of new and old entities do not match');
+					}
+
+					var breed = newdog.get('breed');
+					if (breed === 'mutt') {
+						success('attribute sucesfully set on new entity');
+					} else {
+						error('attribute not sucesfully set on new entity');
+					}
+
+					newdog.destroy(function(err){
+						if (err){
+							error('existing entity not deleted from database');
+						} else {
+							success('existing entity deleted from database');
+							dog = null; //blow away the local object
+							newdog = null; //blow away the local object
+							runner(step);
+						}
+					});
+
+				}
+			});
+		}
+	});
+
+}
+
+function createNewEntityNoName(step, marty) {
+
+	var options = {
+   type:"something",
+   othervalue:"something else"
+	}
+
+	client.createEntity(options, function (err, entity) {
+		if (err) {
+			error('Create new entity with no name failed');
+		} else {
+			success('Create new entity with no name succeeded');
+
+      entity.destroy();
+      runner(step);
+		}
+	});
+
+}
+
+});
\ No newline at end of file


[09/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/json2.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/json2.js b/sdks/html5-javascript/tests/resources/js/json2.js
new file mode 100755
index 0000000..c7745df
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/json2.js
@@ -0,0 +1,486 @@
+/*
+    json2.js
+    2012-10-08
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (typeof JSON !== 'object') {
+    JSON = {};
+}
+
+(function () {
+    'use strict';
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf())
+                ? this.getUTCFullYear()     + '-' +
+                    f(this.getUTCMonth() + 1) + '-' +
+                    f(this.getUTCDate())      + 'T' +
+                    f(this.getUTCHours())     + ':' +
+                    f(this.getUTCMinutes())   + ':' +
+                    f(this.getUTCSeconds())   + 'Z'
+                : null;
+        };
+
+        String.prototype.toJSON      =
+            Number.prototype.toJSON  =
+            Boolean.prototype.toJSON = function (key) {
+                return this.valueOf();
+            };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string'
+                ? c
+                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0
+                    ? '[]'
+                    : gap
+                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+                    : '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0
+                ? '{}'
+                : gap
+                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+                : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                    typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.prototype.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/
+                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function'
+                    ? walk({'': j}, '')
+                    : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());


[03/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/json2.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/json2.js b/sdks/html5-javascript/tests/resources/js/json2.js
new file mode 100755
index 0000000..c7745df
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/json2.js
@@ -0,0 +1,486 @@
+/*
+    json2.js
+    2012-10-08
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (typeof JSON !== 'object') {
+    JSON = {};
+}
+
+(function () {
+    'use strict';
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf())
+                ? this.getUTCFullYear()     + '-' +
+                    f(this.getUTCMonth() + 1) + '-' +
+                    f(this.getUTCDate())      + 'T' +
+                    f(this.getUTCHours())     + ':' +
+                    f(this.getUTCMinutes())   + ':' +
+                    f(this.getUTCSeconds())   + 'Z'
+                : null;
+        };
+
+        String.prototype.toJSON      =
+            Number.prototype.toJSON  =
+            Boolean.prototype.toJSON = function (key) {
+                return this.valueOf();
+            };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string'
+                ? c
+                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0
+                    ? '[]'
+                    : gap
+                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+                    : '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0
+                ? '{}'
+                : gap
+                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+                : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                    typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.prototype.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/
+                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function'
+                    ? walk({'': j}, '')
+                    : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());


[24/27] git commit: renaming 'Event' to 'Counter'

Posted by sn...@apache.org.
renaming 'Event' to 'Counter'


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

Branch: refs/pull/34/merge
Commit: 2c77ebf6ea06b293a7e219da3a7e654eb6334545
Parents: dc31ba5
Author: ryan bridges <rb...@apigee.com>
Authored: Mon Jan 27 16:22:54 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Mon Jan 27 16:22:54 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/lib/Event.js | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c77ebf6/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
index c39ec94..74d019c 100644
--- a/sdks/html5-javascript/lib/Event.js
+++ b/sdks/html5-javascript/lib/Event.js
@@ -5,7 +5,7 @@
  *  @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 || {};
@@ -27,9 +27,9 @@ var COUNTER_RESOLUTIONS=[
  *  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){
+Usergrid.Counter.prototype.fetch=function(callback){
   this.getData(null, null, null, null, callback);
 }
 /*
@@ -43,7 +43,7 @@ Usergrid.Event.prototype.fetch=function(callback){
  * @param {function} callback
  * @returns {callback} callback(err, event)
  */
-Usergrid.Event.prototype.increment=function(name, value, callback){
+Usergrid.Counter.prototype.increment=function(name, value, callback){
   var self=this;
   if(isNaN(value)){
     if(typeof(callback) === 'function') {
@@ -65,7 +65,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
  * @returns {callback} callback(err, event)
  */
 
-Usergrid.Event.prototype.decrement=function(name, value, callback){
+Usergrid.Counter.prototype.decrement=function(name, value, callback){
   this.increment(name, -((parseInt(value))||1), callback);
 };
 /*
@@ -80,11 +80,11 @@ Usergrid.Event.prototype.decrement=function(name, value, callback){
  * @returns {callback} callback(err, event)
  */
 
-Usergrid.Event.prototype.reset=function(name, callback){
+Usergrid.Counter.prototype.reset=function(name, callback){
   this.increment(name, 0, callback);
 };
 
-Usergrid.Event.prototype.getData=function(start, end, resolution, counters, callback){
+Usergrid.Counter.prototype.getData=function(start, end, resolution, counters, callback){
   var start_time, 
       end_time,
       res=(resolution||'all').toLowerCase();


[06/27] git commit: split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha 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/ef53b3b5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/ef53b3b5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/ef53b3b5

Branch: refs/pull/34/head
Commit: ef53b3b5f0e9469af4688991e5bb0bbd35e0fee4
Parents: 4def2d7
Author: ryan bridges <rb...@apigee.com>
Authored: Fri Jan 17 11:32:43 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Fri Jan 17 11:32:43 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/Gruntfile.js              |   83 +
 sdks/html5-javascript/lib/Client.js             |  864 +++
 sdks/html5-javascript/lib/Collection.js         |  446 ++
 sdks/html5-javascript/lib/Entity.js             |  646 +++
 sdks/html5-javascript/lib/Event.js              |  163 +
 sdks/html5-javascript/lib/Group.js              |  233 +
 sdks/html5-javascript/lib/Usergrid.js           |   87 +
 sdks/html5-javascript/package.json              |   22 +
 sdks/html5-javascript/tests/mocha/index.html    |   49 +
 sdks/html5-javascript/tests/mocha/test.js       |  348 ++
 .../tests/qunit/apigee_test.html                |   14 +
 sdks/html5-javascript/tests/qunit/tests.js      |    3 +
 .../resources/css/bootstrap-combined.min.css    |   18 +
 .../tests/resources/css/mocha.css               |  270 +
 .../tests/resources/css/styles.css              |   91 +
 .../tests/resources/images/apigee.png           |  Bin 0 -> 6010 bytes
 .../tests/resources/js/blanket_mocha.min.js     |    1 +
 .../tests/resources/js/json2.js                 |  486 ++
 .../tests/resources/js/mocha.js                 | 5341 ++++++++++++++++++
 sdks/html5-javascript/tests/test.html           |   37 +
 sdks/html5-javascript/tests/test.js             |  910 +++
 21 files changed, 10112 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/Gruntfile.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/Gruntfile.js b/sdks/html5-javascript/Gruntfile.js
new file mode 100644
index 0000000..e1d297a
--- /dev/null
+++ b/sdks/html5-javascript/Gruntfile.js
@@ -0,0 +1,83 @@
+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 tests = [ 'tests/mocha/index.html','tests/mocha/test_*.html' ];
+   // Project configuration.
+  grunt.initConfig({
+    //pkg: grunt.file.readJSON('package.json'),
+    meta: {
+      package: grunt.file.readJSON('package.json'),
+    },
+    clean: ['usergrid.js', 'usergrid.min.js'],
+    uglify: {
+      build: {
+        options: {
+          banner: '/*! <%= meta.package.name %>@<%= meta.package.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
+            mangle: false,
+            compress: false,
+            beautify: true,
+            preserveComments: "all"
+        },
+        files: {
+          'usergrid.js': files
+        }
+      },
+      buildmin: {
+        options: {
+          banner: '/*! <%= meta.package.name %>@<%= meta.package.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
+            mangle: false,
+            compress: true,
+            beautify: false,
+            preserveComments: "some"
+        },
+        files: {
+          'usergrid.min.js': files
+        }
+      }
+    },
+    connect: {
+      server: {
+        options: {
+          port: 3000,
+          base: '.'
+        }
+      },
+      test: {
+        options: {
+          port: 8000,
+          base: '.'
+        }
+      }
+    },
+    watch : {
+      files : files,
+      tasks : ['default']
+    },
+    blanket_mocha: {
+      all: tests,
+      //urls: [ 'http://localhost:8000/tests/mocha/index.html' ],
+      options: {
+          dest: 'report/coverage.html',
+          reporter: 'Spec',
+          threshold: 70
+      }
+    },
+  });
+  grunt.loadNpmTasks('grunt-contrib-clean');
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-watch'); 
+  grunt.loadNpmTasks('grunt-contrib-connect');
+  grunt.loadNpmTasks('grunt-blanket-mocha');
+grunt.registerTask('default', [
+    'clean',
+    'uglify'
+  ]);
+  grunt.registerTask('dev', [
+  	'connect:server',
+    'watch'
+  ]);
+  grunt.registerTask('test', [
+    'connect:test',
+    'blanket_mocha',
+  ]);
+};
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Client.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Client.js b/sdks/html5-javascript/lib/Client.js
new file mode 100644
index 0000000..3fc4338
--- /dev/null
+++ b/sdks/html5-javascript/lib/Client.js
@@ -0,0 +1,864 @@
+
+Usergrid.Client = function(options) {
+  //usergrid enpoint
+  this.URI = options.URI || 'https://api.usergrid.com';
+
+  //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
+  if (options.orgName) {
+    this.set('orgName', options.orgName);
+  }
+  if (options.appName) {
+    this.set('appName', options.appName);
+  }
+
+  //other options
+  this.buildCurl = options.buildCurl || false;
+  this.logging = options.logging || false;
+
+  //timeout and callbacks
+  this._callTimeout =  options.callTimeout || 30000; //default to 30 seconds
+  this._callTimeoutCallback =  options.callTimeoutCallback || null;
+  this.logoutCallback =  options.logoutCallback || null;
+};
+
+/*
+ *  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 self = this;
+  var method = options.method || 'GET';
+  var endpoint = options.endpoint;
+  var body = options.body || {};
+  var qs = options.qs || {};
+  var mQuery = options.mQuery || false; //is this a query to the management endpoint?
+  var orgName = this.get('orgName');
+  var appName = this.get('appName');
+  if(!mQuery && !orgName && !appName){
+    if (typeof(this.logoutCallback) === 'function') {
+      return this.logoutCallback(true, 'no_org_or_app_name_specified');
+    }
+  }
+  if (mQuery) {
+    uri = this.URI + '/' + endpoint;
+  } else {
+    uri = this.URI + '/' + orgName + '/' + appName + '/' + endpoint;
+  }
+
+  if (self.getToken()) {
+    qs.access_token = self.getToken();
+    /* //could also use headers for the token
+     xhr.setRequestHeader("Authorization", "Bearer " + self.getToken());
+     xhr.withCredentials = true;
+     */
+  }
+
+  //append params to the path
+  var encoded_params = encodeParams(qs);
+  if (encoded_params) {
+    uri += "?" + encoded_params;
+  }
+
+  //stringify the body object
+  body = JSON.stringify(body);
+
+  //so far so good, so run the query
+  var xhr = new XMLHttpRequest();
+  xhr.open(method, uri, true);
+  //add content type = json if there is a json payload
+  if (body) {
+    xhr.setRequestHeader("Content-Type", "application/json");
+    xhr.setRequestHeader("Accept", "application/json");
+  }
+
+  // Handle response.
+  xhr.onerror = function(response) {
+    self._end = new Date().getTime();
+    if (self.logging) {
+      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
+    }
+    if (self.logging) {
+      console.log('Error: API call failed at the network level.');
+    }
+    //network error
+    clearTimeout(timeout);
+    var err = true;
+    if (typeof(callback) === 'function') {
+      callback(err, response);
+    }
+  };
+
+  xhr.onload = function(response) {
+    //call timing, get time, then log the call
+    self._end = new Date().getTime();
+    if (self.logging) {
+      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
+    }
+    //call completed
+    clearTimeout(timeout);
+    //decode the response
+    try{
+      response = JSON.parse(xhr.responseText);
+    }catch (e){
+      response = {error:'unhandled_error',error_description:xhr.responseText};
+      xhr.status = xhr.status === 200 ? 400 : xhr.status;
+      console.error(e);
+    }
+    if (xhr.status != 200)   {
+      //there was an api error
+      var error = response.error;
+      var error_description = response.error_description;
+      if (self.logging) {
+        console.log('Error (' + xhr.status + ')(' + error + '): ' + error_description);
+      }
+      if ( (error == "auth_expired_session_token") ||
+        (error == "auth_missing_credentials")   ||
+        (error == "auth_unverified_oath")       ||
+        (error == "expired_token")              ||
+        (error == "unauthorized")               ||
+        (error == "auth_invalid")) {
+        //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
+        //if the user has specified a logout callback:
+        if (typeof(self.logoutCallback) === 'function') {
+          return self.logoutCallback(true, response);
+        }
+      }
+      if (typeof(callback) === 'function') {
+        callback(true, response);
+      }
+    } else {
+      if (typeof(callback) === 'function') {
+        callback(false, response);
+      }
+    }
+  };
+
+  var timeout = setTimeout(
+    function() {
+      xhr.abort();
+      if (self._callTimeoutCallback === 'function') {
+        self._callTimeoutCallback('API CALL TIMEOUT');
+      } else {
+        self.callback('API CALL TIMEOUT');
+      }
+    },
+    self._callTimeout); //set for 30 seconds
+
+  if (this.logging) {
+    console.log('calling: ' + method + ' ' + uri);
+  }
+  if (this.buildCurl) {
+    var curlOptions = {
+      uri:uri,
+      body:body,
+      method:method
+    }
+    this.buildCurlCall(curlOptions);
+  }
+  this._start = new Date().getTime();
+  xhr.send(body);
+}
+
+/*
+ *  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();
+  }
+
+  //append params to the path
+  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 getOnExist = options.getOnExist || false;
+
+  options = {
+    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);
+    if (okToSave) {
+      group.save(function(err, data){
+        if (typeof(callback) === 'function') {
+          callback(err, group);
+        }
+      });
+    } else {
+      if(typeof(callback) === 'function') {
+        callback(err, 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) {
+  // todo: replace the check for new / save on not found code with simple save
+  // when users PUT on no user fix is in place.
+  /*
+   var options = {
+   client:this,
+   data:options
+   }
+   var entity = new Usergrid.Entity(options);
+   entity.save(function(err, data) {
+   if (typeof(callback) === 'function') {
+   callback(err, entity);
+   }
+   });
+   */
+  var getOnExist = options.getOnExist || false; //if true, will return entity if one already exists
+  var options = {
+    client:this,
+    data:options
+  };
+  var entity = new Usergrid.Entity(options);
+  entity.fetch(function(err, data) {
+    //if the fetch doesn't find what we are looking for, or there is no error, do a save
+    var okToSave = (err && 'service_resource_not_found' === data.error || 'no_name_specified' === data.error || 'null_pointer' === data.error) || (!err && getOnExist);
+    if(okToSave) {
+      entity.set(options.data); //add the data again just in case
+      entity.save(function(err, data) {
+        if (typeof(callback) === 'function') {
+          callback(err, entity, data);
+        }
+      });
+    } else {
+      if (typeof(callback) === 'function') {
+        callback(err, entity, data);
+      }
+    }
+  });
+
+};
+
+/*
+ *  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 options = {
+    client:this,
+    data:options
+  }
+  var entity = new Usergrid.Entity(options);
+  entity.fetch(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, entity, data);
+    }
+  });
+};
+
+/*
+ *  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 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;
+  var collection = new Usergrid.Collection(options, function(err, data) {
+    if (typeof(callback) === 'function') {
+      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(typeof(callback) === "function") {
+      if(err) {
+        callback(err);
+      } else {
+        callback(err, data, data.entities);
+      }
+    }
+  });
+};
+
+/*
+ *  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';
+  var options = {
+    client:this,
+    data:options
+  }
+  var entity = new Usergrid.Entity(options);
+  entity.save(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, 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;
+  if (this[key]) {
+    return this[key];
+  } else if(typeof(Storage)!=="undefined") {
+    return localStorage.getItem(keyStore);
+  }
+  return null;
+};
+
+/*
+ * 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'
+    }
+  };
+  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);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, 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 {
+
+      //save the re-authed token and current email/username
+      self.setToken(response.access_token);
+
+    }
+    if (typeof(callback) === 'function') {
+      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);
+
+      //delete next block and corresponding function when iframes are refactored
+      localStorage.setItem('accessToken', data.token);
+      localStorage.setItem('userUUID', data.uuid);
+      localStorage.setItem('userEmail', data.email);
+      //end delete block
+
+
+      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 {
+        //if we have an org stored, then use that one. Otherwise, use the first one.
+        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');
+        }
+      } //should always be an org
+
+      applications = self.parseApplicationsArray(org);
+      self.selectFirstApp(applications);
+
+      self.setObject('organizations', organizations);
+      self.setObject('applications', applications);
+
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, user, organizations, applications);
+    }
+  });
+};
+
+/*
+ *  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);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, user);
+    }
+  });
+};
+
+/*
+ *  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) {
+  if (!this.getToken()) {
+    callback(true, null, null);
+  } else {
+    var self = this;
+    var options = {
+      method:'GET',
+      endpoint:'users/me'
+    };
+    this.request(options, function(err, data) {
+      if (err) {
+        if (self.logging) {
+          console.log('error trying to log user in');
+        }
+        if (typeof(callback) === 'function') {
+          callback(err, data, null);
+        }
+      } else {
+        var options = {
+          client:self,
+          data:data.entities[0]
+        };
+        var user = new Usergrid.Entity(options);
+        if (typeof(callback) === 'function') {
+          callback(err, data, user);
+        }
+      }
+    });
+  }
+};
+
+/*
+ *  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 () {
+  if (this.getToken() && this.getToken() != 'null') {
+    return true;
+  }
+  return false;
+};
+
+/*
+ *  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(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 - add the method to the command (no need to add anything for GET)
+  if (method === 'POST') {
+    curl += ' -X POST';
+  } else if (method === 'PUT') {
+    curl += ' -X PUT';
+  } else if (method === 'DELETE') {
+    curl += ' -X DELETE';
+  } else {
+    curl += ' -X GET';
+  }
+
+  //curl - append the path
+  curl += ' ' + uri;
+
+  //curl - add the body
+  if("undefined"!== typeof window){body = JSON.stringify(body);}//only in node module
+  if (body !== '"{}"' && method !== 'GET' && method !== 'DELETE') {
+    //curl - add in the json obj
+    curl += " -d '" + body + "'";
+  }
+
+  //log the curl command to the console
+  console.log(curl);
+
+  return curl;
+}
+
+Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
+  try {
+    if (picture) {
+      return picture;
+    }
+    var size = size || 50;
+    if (email.length) {
+      return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+    } else {
+      return 'https://apigee.com/usergrid/images/user_profile.png';
+    }
+  } catch(e) {
+    return 'https://apigee.com/usergrid/images/user_profile.png';
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Collection.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Collection.js b/sdks/html5-javascript/lib/Collection.js
new file mode 100644
index 0000000..57fdf06
--- /dev/null
+++ b/sdks/html5-javascript/lib/Collection.js
@@ -0,0 +1,446 @@
+
+/*
+ *  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
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection = function(options, callback) {
+
+  if (options) {
+    this._client = options.client;
+    this._type = options.type;
+    this.qs = options.qs || {};
+
+    //iteration
+    this._list = options.list || [];
+    this._iterator = options.iterator || -1; //first thing we do is increment, so set to -1
+
+    //paging
+    this._previous = options.previous || [];
+    this._next = options.next || null;
+    this._cursor = options.cursor || null;
+
+    //restore entities if available
+    if (options.list) {
+      var count = options.list.length;
+      for(var i=0;i<count;i++){
+        //make new entity with
+        var entity = this._client.restoreEntity(options.list[i]);
+        this._list[i] = entity;
+      }
+    }
+  }
+  if (callback) {
+    //populate the collection
+    this.fetch(callback);
+  }
+
+};
+
+
+/*
+ *  gets the data from the collection object for serialization
+ *
+ *  @method serialize
+ *  @return {object} data
+ */
+Usergrid.Collection.prototype.serialize = function () {
+
+  //pull out the state from this object and return it
+  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;
+      callback(err, collection);
+    }
+  });
+};
+
+/*
+ *  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;
+
+  //add in the cursor if one is available
+  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, data) {
+    if(err && self._client.logging) {
+      console.log('error getting collection');
+    } else {
+      //save the cursor if there is one
+      var cursor = data.cursor || null;
+      self.saveCursor(cursor);
+      if (data.entities) {
+        self.resetEntityPointer();
+        var count = data.entities.length;
+        //save entities locally
+        self._list = []; //clear the local list first
+        for (var i=0;i<count;i++) {
+          var uuid = data.entities[i].uuid;
+          if (uuid) {
+            var entityData = data.entities[i] || {};
+            self._baseType = data.entities[i].type; //store the base type in the collection
+            entityData.type = self._type;//make sure entities are same type (have same path) as parent collection.
+            var entityOptions = {
+              type:self._type,
+              client:self._client,
+              uuid:uuid,
+              data:entityData
+            };
+
+            var ent = new Usergrid.Entity(entityOptions);
+            ent._json = JSON.stringify(entityData, null, 2);
+            var ct = self._list.length;
+            self._list[ct] = ent;
+          }
+        }
+      }
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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 (options, callback) {
+  var self = this;
+  options.type = this._type;
+
+  //create the new entity
+  this._client.createEntity(options, function (err, entity) {
+    if (!err) {
+      //then add the entity to the list
+      var count = self._list.length;
+      self._list[count] = entity;
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, entity);
+    }
+  });
+};
+
+Usergrid.Collection.prototype.addExistingEntity = function (entity) {
+  //entity should already exist in the db, so just add it to the list
+  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, data) {
+    if (err) {
+      if (self._client.logging) {
+        console.log('could not destroy entity');
+      }
+      if (typeof(callback) === 'function') {
+        callback(err, data);
+      }
+    } else {
+      //destroy was good, so repopulate the collection
+      self.fetch(callback);
+    }
+  });
+  //remove entity from the local store
+  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 false;
+};
+
+/*
+ *  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) {
+
+  for (var key in this._list) {
+    var listItem = this._list[key];
+    if (listItem.get('uuid') === uuid) {
+      return listItem;
+    }
+  }
+
+  //get the entity from the database
+  var options = {
+    data: {
+      type: this._type,
+      uuid:uuid
+    },
+    client: this._client
+  }
+  var 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 current cursor is different, grab it for next 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()) {
+    //set the cursor to the next page of data
+    this._previous.push(this._cursor);
+    this._cursor = this._next;
+    //empty the list
+    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; //clear out next so the comparison will find the next item
+    this._cursor = this._previous.pop();
+    //empty the list
+    this._list = [];
+    this.fetch(callback);
+  }
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Entity.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Entity.js b/sdks/html5-javascript/lib/Entity.js
new file mode 100644
index 0000000..e070d8a
--- /dev/null
+++ b/sdks/html5-javascript/lib/Entity.js
@@ -0,0 +1,646 @@
+/*
+ *  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) {
+  if (options) {
+    this._data = options.data || {};
+    this._client = options.client || {};
+  }
+};
+
+/*
+ *  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 (field) {
+  if (field) {
+    return this._data[field];
+  } else {
+    return this._data;
+  }
+};
+
+/*
+ *  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 = {};
+  }
+};
+
+/*
+ *  Saves the entity back to the database
+ *
+ *  @method save
+ *  @public
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Entity.prototype.save = function (callback) {
+  var type = this.get('type');
+  var method = 'POST';
+  if (isUUID(this.get('uuid'))) {
+    method = 'PUT';
+    type += '/' + this.get('uuid');
+  }
+
+  //update the entity
+  var self = this;
+  var data = {};
+  var entityData = this.get();
+    var password = this.get('password');
+    var oldpassword = this.get('oldpassword');
+    var newpassword = this.get('newpassword');
+  //remove system specific properties
+  for (var item in entityData) {
+    if (item === 'metadata' || item === 'created' || item === 'modified' ||
+          item === 'oldpassword' || item === 'newpassword' || //old and new pw not added to data
+      item === 'type' || item === 'activated' || item === 'uuid') {
+      continue;
+    }
+    data[item] = entityData[item];
+  }
+  var options =  {
+    method:method,
+    endpoint:type,
+    body:data
+  };
+  //save the entity first
+  this._client.request(options, function (err, retdata) {
+      //clear out pw info if present
+      self.set('password', null);
+      self.set('oldpassword', null);
+      self.set('newpassword', null);
+    if (err && self._client.logging) {
+      console.log('could not save entity');
+      if (typeof(callback) === 'function') {
+        return callback(err, retdata, self);
+      }
+    } else {
+      if (retdata.entities) {
+        if (retdata.entities.length) {
+          var entity = retdata.entities[0];
+          self.set(entity);
+          var path = retdata.path;
+          //for connections, API returns type
+          while (path.substring(0, 1) === "/") {
+            path = path.substring(1);
+          }
+          self.set('type', path);
+        }
+      }
+      //if this is a user, update the password if it has been specified;
+        var needPasswordChange = ((self.get('type') === 'user' || self.get('type') === 'users') && oldpassword && newpassword);
+      if (needPasswordChange) {
+        //Note: we have a ticket in to change PUT calls to /users to accept the password change
+        //      once that is done, we will remove this call and merge it all into one
+        var pwdata = {};
+          pwdata.oldpassword = oldpassword;
+          pwdata.newpassword = newpassword;
+        var options = {
+          method:'PUT',
+          endpoint:type+'/password',
+          body:pwdata
+        }
+        self._client.request(options, function (err, data) {
+          if (err && self._client.logging) {
+            console.log('could not update user');
+          }
+          //remove old and new password fields so they don't end up as part of the entity object
+          self.set('oldpassword', null);
+          self.set('newpassword', null);
+          if (typeof(callback) === 'function') {
+            callback(err, data, self);
+          }
+        });
+      } else if (typeof(callback) === 'function') {
+        callback(err, retdata, self);
+      }
+    }
+  });
+};
+
+/*
+ *  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 type = this.get('type');
+  var self = this;
+
+  //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
+  try {
+    if (type === undefined) {
+      throw 'cannot fetch entity, no entity type specified'
+    } else if (this.get('uuid')) {
+      type += '/' + this.get('uuid');
+    } else if (type === 'users' && this.get('username')) {
+      type += '/' + this.get('username');
+    } else if (this.get('name')) {
+      type += '/' + encodeURIComponent(this.get('name'));
+    } else if (typeof(callback) === 'function') {
+      throw 'no_name_specified';
+    }
+  } catch (e) {
+    if (self._client.logging) {
+      console.log(e);
+    }
+    return callback(true, {
+      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) {
+        if (data.entities.length) {
+          var entity = data.entities[0];
+          self.set(entity);
+        }
+      }
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, 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 type = this.get('type');
+  if (isUUID(this.get('uuid'))) {
+    type += '/' + this.get('uuid');
+  } else {
+    if (typeof(callback) === 'function') {
+      var error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+  }
+  var options = {
+    method:'DELETE',
+    endpoint:type
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be deleted');
+    } else {
+      self.set(null);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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) {
+
+  var self = this;
+
+  var error;
+  //connectee info
+  var connecteeType = entity.get('type');
+  var connectee = this.getEntityId(entity);
+  if (!connectee) {
+    if (typeof(callback) === 'function') {
+      error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  //connector info
+  var connectorType = this.get('type');
+  var connector = this.getEntityId(this);
+  if (!connector) {
+    if (typeof(callback) === 'function') {
+      error = 'Error in connect - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
+  var options = {
+    method:'POST',
+    endpoint:endpoint
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be connected');
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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 = false;
+  if (isUUID(entity.get('uuid'))) {
+    id = entity.get('uuid');
+  } else {
+    if (type === 'users') {
+      id = entity.get('username');
+    } else if (entity.get('name')) {
+      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;
+
+  //connector info
+  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);
+      }
+      callback(true, error);
+    }
+    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.entities.length;
+    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]
+      }
+    }
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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.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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+/*
+ *  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) {
+
+  var self = this;
+
+  var error;
+  //connectee info
+  var connecteeType = entity.get('type');
+  var connectee = this.getEntityId(entity);
+  if (!connectee) {
+    if (typeof(callback) === 'function') {
+      error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  //connector info
+  var connectorType = this.get('type');
+  var connector = this.getEntityId(this);
+  if (!connector) {
+    if (typeof(callback) === 'function') {
+      error = 'Error in connect - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
+  var options = {
+    method:'DELETE',
+    endpoint:endpoint
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be disconnected');
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
new file mode 100644
index 0000000..789240f
--- /dev/null
+++ b/sdks/html5-javascript/lib/Event.js
@@ -0,0 +1,163 @@
+var COUNTER_RESOLUTIONS = {
+  'ALL': 'all',
+  'MINUTE': 'minute',
+  'FIVE_MINUTES': 'five_minutes',
+  'HALF_HOUR': 'half_hour',
+  'HOUR': 'hour',
+  'SIX_DAY': 'six_day',
+  'DAY': 'day',
+  'WEEK': 'week',
+  'MONTH': 'month'
+};
+COUNTER_RESOLUTIONS.valueOf=function(str){
+  Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){
+    if(COUNTER_RESOLUTIONS[res]===str){
+      return COUNTER_RESOLUTIONS[res];
+    }
+  });
+  return COUNTER_RESOLUTIONS.ALL;
+};
+
+/*
+ *  A class to model a Usergrid event.
+ *
+ *  @constructor
+ *  @param {object} options {timestamp:0, category:'value', counters:{name : value}}
+ *  @returns {callback} callback(err, event)
+ */
+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||{};
+  if(typeof(callback) === 'function') {
+    callback.call(self, false, self);
+  }
+  //this.save(callback);
+};
+
+/*
+ *  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.Event.prototype = new Usergrid.Entity();
+
+Usergrid.Event.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.Event.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);
+  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.Event.prototype.decrement=function(name, value, callback){
+  this.increment(name, -(value), 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.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=COUNTER_RESOLUTIONS.valueOf(resolution);
+  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/ef53b3b5/sdks/html5-javascript/lib/Group.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Group.js b/sdks/html5-javascript/lib/Group.js
new file mode 100644
index 0000000..2a853be
--- /dev/null
+++ b/sdks/html5-javascript/lib/Group.js
@@ -0,0 +1,233 @@
+/*
+ *  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, data){
+    if(err) {
+      if(self._client.logging) {
+        console.log('error getting group');
+      }
+      if(typeof(callback) === 'function') {
+        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; i < count; i++) {
+                var uuid = data.entities[i].uuid;
+                if(uuid) {
+                  var entityData = data.entities[i] || {};
+                  var entityOptions = {
+                    type: entityData.type,
+                    client: self._client,
+                    uuid:uuid,
+                    data:entityData
+                  };
+                  var entity = new Usergrid.Entity(entityOptions);
+                  self._list.push(entity);
+                }
+
+              }
+            }
+          }
+          if(typeof(callback) === 'function') {
+            callback(err, data, self._list);
+          }
+        });
+      }
+    }
+  });
+};
+
+/*
+ *  Retrieves the members of a group.
+ *
+ *  @method members
+ *  @public
+ *  @param {function} callback
+ *  @return {function} callback(err, data);
+ */
+Usergrid.Group.prototype.members = function(callback) {
+  if(typeof(callback) === 'function') {
+    callback(null, this._list);
+  }
+};
+
+/*
+ *  Adds a 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;
+  var options = {
+    method:"POST",
+    endpoint:"groups/"+this._path+"/users/"+options.user.get('username')
+  }
+
+  this._client.request(options, function(error, data){
+    if(error) {
+      if(typeof(callback) === 'function') {
+        callback(error, data, data.entities);
+      }
+    } else {
+      self.fetch(callback);
+    }
+  });
+}
+
+/*
+ *  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;
+
+  var options = {
+    method:"DELETE",
+    endpoint:"groups/"+this._path+"/users/"+options.user.get('username')
+  }
+
+  this._client.request(options, function(error, data){
+    if(error) {
+      if(typeof(callback) === 'function') {
+        callback(error, data);
+      }
+    } else {
+      self.fetch(callback);
+    }
+  });
+}
+
+/*
+ * 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 endpoint = "groups/"+this._path+"/feed";
+
+  var options = {
+    method:"GET",
+    endpoint:endpoint
+  }
+
+  this._client.request(options, function(err, data){
+    if (err && self.logging) {
+      console.log('error trying to log user in');
+    }
+    if(typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+}
+
+/*
+ * 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 user = options.user;
+  options = {
+    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'
+    }
+  }
+
+  var entity = new Usergrid.Entity(options);
+  entity.save(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, entity);
+    }
+  });
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Usergrid.js b/sdks/html5-javascript/lib/Usergrid.js
new file mode 100644
index 0000000..89507cf
--- /dev/null
+++ b/sdks/html5-javascript/lib/Usergrid.js
@@ -0,0 +1,87 @@
+/*
+ *  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://apigee.com/docs/usergrid
+ *
+ *   Copyright 2012 Apigee 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 (rod@apigee.com)
+ *  @author matt dobson (matt@apigee.com)
+ *  @author ryan bridges (rbridges@apigee.com)
+ */
+
+
+//Hack around IE console.log
+window.console = window.console || {};
+window.console.log = window.console.log || function() {};
+
+//Usergrid namespace encapsulates this SDK
+window.Usergrid = window.Usergrid || {};
+Usergrid = Usergrid || {};
+Usergrid.USERGRID_SDK_VERSION = '0.10.07';
+
+
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+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}$/;
+  if (!uuid) {
+    return false;
+  }
+  return 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 tail = [];
+  var item = [];
+  var i;
+  if (params instanceof Array) {
+    for (i in params) {
+      item = params[i];
+      if ((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("&");
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/package.json
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/package.json b/sdks/html5-javascript/package.json
new file mode 100644
index 0000000..a30f4e9
--- /dev/null
+++ b/sdks/html5-javascript/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "usergrid",
+  "version": "0.0.0",
+  "description": "Detailed instructions follow but if you just want a quick example of how to get started with this SDK, here’s a minimal HTML5 file that shows you how to include & initialize the SDK, as well as how to read & write data from Usergrid with it.",
+  "main": "usergrid.js",
+  "directories": {
+    "example": "examples"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt": "~0.4.2",
+    "grunt-contrib-clean": "~0.5.0",
+    "grunt-contrib-watch": "~0.5.3",
+    "grunt-contrib-uglify": "~0.2.7",
+    "grunt-blanket-mocha": "~0.3.3",
+    "grunt-contrib-connect": "~0.6.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/mocha/index.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/mocha/index.html b/sdks/html5-javascript/tests/mocha/index.html
new file mode 100644
index 0000000..f6d5c77
--- /dev/null
+++ b/sdks/html5-javascript/tests/mocha/index.html
@@ -0,0 +1,49 @@
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Mocha Tests</title>
+  <link rel="stylesheet" href="../resources/css/mocha.css" />
+
+
+
+
+
+
+
+  <script src="../resources/js/mocha.js"></script>
+  <script>mocha.setup('bdd')</script>
+  <script src="../resources/js/blanket_mocha.min.js"></script>
+  <script type="text/javascript" src="../../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
+	<script>
+      function assert(expr, msg) {
+        if (!expr) throw new Error(msg || 'failed');
+      }
+    </script>
+
+  <script src="../../usergrid.js" data-cover></script>
+  <script src="test.js"></script>
+<!-- run mocha -->
+    <script type="text/javascript" charset="utf-8">
+    	var _onload=onload||function(){};
+        onload = function(){
+        	_onload.apply(this, arguments);
+	        mocha.checkLeaks();
+	        mocha.globals(['']);
+	        var runner = mocha.run();
+	        /*runner.on('test end', function(test){
+	          console.log(test.fullTitle());
+	        });*/
+	      };
+    </script>
+
+  <script>
+    if (window.PHANTOMJS) {
+        blanket.options("reporter", "../../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
+    }
+  </script>
+
+</head>
+<body>
+	<div id="mocha"></div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/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
new file mode 100644
index 0000000..d74541c
--- /dev/null
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -0,0 +1,348 @@
+
+/*
+	Creates a generic usergrid client with logging and buildCurl disabled
+
+ */
+function getClient(){
+	return new Usergrid.Client({
+		orgName:'yourorgname',
+		appName:'sandbox',
+		logging: false, //optional - turn on logging, off by default
+		buildCurl: true //optional - turn on curl commands, off by default
+	});
+}
+/*
+	A convenience function that will test for the presence of an API error
+	and run any number of additional tests
+ */
+function usergridTestHarness(err, data, done, tests, ignoreError){
+	if(!ignoreError) assert(!err, data.error_description);
+	if(tests){
+		if("function"===typeof tests){
+			tests(err, data);
+		}else if(tests.length){
+			tests.forEach(function(test){
+				if("function"===typeof test){
+					test(err, data);
+				}
+			})
+		}
+	}	
+	done();
+}
+describe('Usergrid', function(){
+	var client = getClient();
+
+	before(function(done){
+    	//Make sure our dog doesn't already exist
+		client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
+			done();
+	    });
+  	});
+	describe('Usergrid CRUD', function(){
+		var options = {
+			method:'GET',
+			endpoint:'users'
+		};
+		it('should Create a new user', function(done){
+			client.request({method:'POST',endpoint:'users', body:{ username:'fred', password:'secret' }}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Retrieve an existing user', function(done){
+			client.request({method:'GET',endpoint:'users/fred', body:{}}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Update an existing user', function(done){
+			client.request({method:'PUT',endpoint:'users/fred', body:{ newkey:'newvalue' }}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Delete the user from the database', function(done){
+			client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+	});
+	describe('Usergrid REST', function(){
+		it('should return a list of users', function(done){
+			client.request({method:'GET',endpoint:'users'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(data.entities.length >=0)}
+				]);
+		    });
+		});
+		it('should return no entities when an endpoint does not exist', function(done){
+			client.request({method:'GET',endpoint:'nonexistantendpoint'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(data.entities.length === 0)}
+				]);
+		    });
+		});
+	});
+	describe('Usergrid Entity', function(){
+		var dog;
+		before(function(done){
+	    	//Make sure our dog doesn't already exist
+	    	client.request({method:'DELETE',endpoint:'dogs/Rocky'}, function (err, data) {
+	    		assert(true);
+	    		done();
+		    });
+	  	});
+		it('should create a new dog', function(done){
+			var options = {
+				type:'dogs',
+				name:'Rocky'
+			}
+
+			client.createEntity(options, function (err, data) {
+				assert(!err, "dog not created");
+				dog=data;
+				done();
+			});
+		});
+		it('should retrieve the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.fetch(function(err){
+				assert(!err, "dog not fetched");
+				done();
+			});
+		});
+		it('should update the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.set('breed','Dinosaur');
+
+			//the set function can also take a JSON object:
+			var data = {
+				master:'Fred',
+				state:'hungry'
+			}
+			//set is additive, so previously set properties are not overwritten
+			dog.set(data);
+
+			//finally, call save on the object to save it back to the database
+			dog.save(function(err){
+				assert(!err, "dog not saved");
+				done();
+			});
+		});
+		it('should remove the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.destroy(function(err){
+				assert(!err, "dog not removed");
+				done();
+			});
+		});
+
+	});
+	describe('Usergrid Collections', function(){
+		var client = getClient();
+		var dog, dogs={};
+		function loop(done){
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				dog = dogs.getNextEntity();
+				console.log(dog.get('name'));
+			}
+			if(done)done();
+		}
+		before(function(done){
+	    	//Make sure our dog doesn't already exist
+			var options = {
+				type:'dogs',
+				qs:{limit:50} //limit statement set to 50
+			}
+
+			client.createCollection(options, function (err, dogs) {
+				if (!err) {
+					assert(!err, "could not retrieve list of dogs: "+dogs.error_description);
+					//we got 50 dogs, now display the Entities:
+					//do doggy cleanup
+					if(dogs.hasNextEntity()){
+						while(dogs.hasNextEntity()) {
+							//get a reference to the dog
+							var dog = dogs.getNextEntity();
+							//notice('removing dog ' + dogname + ' from database');
+							dog.destroy(function(err, data) {
+								assert(!err, dog.get('name')+" not removed: "+data.error_description);
+								if(!dogs.hasNextEntity()){
+									done();
+								}
+							});
+						}
+					}else{
+						done();
+					}
+				}
+			});
+	  	});
+		before(function(done){
+			this.timeout(10000);
+			var totalDogs=30;
+			Array.apply(0, Array(totalDogs)).forEach(function (x, y) { 
+				var dogNum=y+1;
+				var options = {
+					type:'dogs',
+					name:'dog'+dogNum,
+					index:y
+				}
+				client.createEntity(options, function (err, dog) {
+					assert(!err, " not created: "+dog.error_description);
+					if(dogNum===totalDogs){
+						done();
+					}
+				});
+			})
+		});
+		it('should create a new dogs collection', function(done){
+			var options = {
+				type:'dogs',
+				qs:{ql:'order by index'}
+			}
+
+			client.createCollection(options, function (err, data) {
+				assert(!err, "could not create dogs collection: "+data.error_description);
+				dogs=data;
+				done();
+			});
+		});
+		it('should retrieve dogs from the collection', function(done){
+			loop(done);
+		});
+		it('should retrieve the next page of dogs from the collection', function(done){
+			if(dogs.hasNextPage()){
+				dogs.getNextPage(function(err){loop(done);});
+			}else{
+				done();
+			}
+		});
+		it('should retrieve the previous page of dogs from the collection', function(done){
+			if(dogs.hasPreviousPage()){
+				dogs.getPreviousPage(function(err){loop(done);});
+			}else{
+				done();
+			}
+		});
+		/*it('should retrieve the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+			}
+			dog.fetch(function(err){
+				assert(!err, "dog not fetched");
+				done();
+			});
+		});*/
+	});
+	describe('Usergrid Events', function(){
+		var ev;
+		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){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		it('should save an event', function(done){
+			ev.save(function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		/*it('should reset a counter', function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.reset('test', function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});*/
+		it("should increment 'test' counter", function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.increment('test', 1, function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		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){
+				assert(!err, data.error_description);
+				console.log(JSON.stringify(data,null,4));
+				done();
+			});
+		});
+		it("should decrement 'test' counter", function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.decrement('test', 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){
+				assert(!err, data.error_description);
+				console.log(JSON.stringify(data,null,4));
+				console.log(time, Date.now());
+				done();
+			});
+		});
+		/*it('should fetch counter data', function(done){
+			ev.getData('all', null, null, ['test', 'test_counter'], function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				console.log(time, Date.now());
+				done();
+			});
+		});*/
+	});
+	/*describe('Usergrid Counters', function(){
+		it('should create a counter', function(done){
+			var counter = new Apigee.Event({client:client, data:{category:"mocha_test", timestamp:28, name:'test'}}, function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+	});*/
+	describe('Usergrid extra', function(){
+		it('should not be phonegap', function(done){
+			
+		});
+	});
+});
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/qunit/apigee_test.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/qunit/apigee_test.html b/sdks/html5-javascript/tests/qunit/apigee_test.html
new file mode 100644
index 0000000..0975bbd
--- /dev/null
+++ b/sdks/html5-javascript/tests/qunit/apigee_test.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>QUnit Example</title>
+  <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <div id="qunit-fixture"></div>
+  <script src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
+  <script src="tests.js"></script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/qunit/tests.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/qunit/tests.js b/sdks/html5-javascript/tests/qunit/tests.js
new file mode 100644
index 0000000..67764a0
--- /dev/null
+++ b/sdks/html5-javascript/tests/qunit/tests.js
@@ -0,0 +1,3 @@
+test( "hello test", function() {
+  ok( 1 == "1", "Passed!" );
+});


[22/27] git commit: Prettying up the tests

Posted by sn...@apache.org.
Prettying up the 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/dc31ba57
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/dc31ba57
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/dc31ba57

Branch: refs/pull/34/merge
Commit: dc31ba575ab6811ba9816d9afaef23c8f649b9af
Parents: 2953c67
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 13:26:12 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 13:26:12 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/tests/mocha/test.js | 37 +++++++-------------------
 1 file changed, 9 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/dc31ba57/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 24d6530..8034f06 100644
--- a/sdks/html5-javascript/tests/mocha/test.js
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -218,7 +218,7 @@ describe('Usergrid', function(){
 				});
 			})
 		});
-		it('should create a new dogs collection', function(done){
+		it('should CREATE a new dogs collection', function(done){
 			var options = {
 				type:'dogs',
 				qs:{ql:'order by index'}
@@ -230,33 +230,23 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should retrieve dogs from the collection', function(done){
+		it('should RETRIEVE dogs from the collection', function(done){
 			loop(done);
 		});
-		it('should retrieve the next page of dogs from the collection', function(done){
+		it('should RETRIEVE the next page of dogs from the collection', function(done){
 			if(dogs.hasNextPage()){
 				dogs.getNextPage(function(err){loop(done);});
 			}else{
 				done();
 			}
 		});
-		it('should retrieve the previous page of dogs from the collection', function(done){
+		it('should RETRIEVE the previous page of dogs from the collection', function(done){
 			if(dogs.hasPreviousPage()){
 				dogs.getPreviousPage(function(err){loop(done);});
 			}else{
 				done();
 			}
 		});
-		/*it('should retrieve the dog', function(done){
-			if(!dog){
-				assert(false, "dog not created");
-				done();
-			}
-			dog.fetch(function(err){
-				assert(!err, "dog not fetched");
-				done();
-			});
-		});*/
 	});
 	describe('Usergrid Events', function(){
 		var ev;
@@ -264,7 +254,7 @@ describe('Usergrid', function(){
 		var HOUR=MINUTE*60;
 		var time=Date.now()-HOUR;
 
-		it('should create an event', function(done){
+		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){
 				assert(!err, data.error_description);
 				console.log(data);
@@ -278,7 +268,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		/*it('should reset a counter', function(done){
+		it('should reset a counter', function(done){
 			time+=MINUTE*10
 			ev.set("timestamp", time);
 			ev.reset('test', function(err, data){
@@ -286,7 +276,7 @@ describe('Usergrid', function(){
 				console.log(data);
 				done();
 			});
-		});*/
+		});
 		it("should increment 'test' counter", function(done){
 			time+=MINUTE*10
 			ev.set("timestamp", time);
@@ -322,23 +312,14 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		/*it('should fetch counter data', function(done){
+		it('should fetch counter data', function(done){
 			ev.getData('all', null, null, ['test', 'test_counter'], function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				console.log(time, Date.now());
 				done();
 			});
-		});*/
-	});
-	/*describe('Usergrid Counters', function(){
-		it('should create a counter', function(done){
-			var counter = new Apigee.Event({client:client, data:{category:"mocha_test", timestamp:28, name:'test'}}, function(err, data){
-				assert(!err, data.error_description);
-				console.log(data);
-				done();
-			});
 		});
-	});*/
+	});
 });
 


[12/27] git commit: split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha 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/ef53b3b5
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/ef53b3b5
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/ef53b3b5

Branch: refs/pull/34/merge
Commit: ef53b3b5f0e9469af4688991e5bb0bbd35e0fee4
Parents: 4def2d7
Author: ryan bridges <rb...@apigee.com>
Authored: Fri Jan 17 11:32:43 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Fri Jan 17 11:32:43 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/Gruntfile.js              |   83 +
 sdks/html5-javascript/lib/Client.js             |  864 +++
 sdks/html5-javascript/lib/Collection.js         |  446 ++
 sdks/html5-javascript/lib/Entity.js             |  646 +++
 sdks/html5-javascript/lib/Event.js              |  163 +
 sdks/html5-javascript/lib/Group.js              |  233 +
 sdks/html5-javascript/lib/Usergrid.js           |   87 +
 sdks/html5-javascript/package.json              |   22 +
 sdks/html5-javascript/tests/mocha/index.html    |   49 +
 sdks/html5-javascript/tests/mocha/test.js       |  348 ++
 .../tests/qunit/apigee_test.html                |   14 +
 sdks/html5-javascript/tests/qunit/tests.js      |    3 +
 .../resources/css/bootstrap-combined.min.css    |   18 +
 .../tests/resources/css/mocha.css               |  270 +
 .../tests/resources/css/styles.css              |   91 +
 .../tests/resources/images/apigee.png           |  Bin 0 -> 6010 bytes
 .../tests/resources/js/blanket_mocha.min.js     |    1 +
 .../tests/resources/js/json2.js                 |  486 ++
 .../tests/resources/js/mocha.js                 | 5341 ++++++++++++++++++
 sdks/html5-javascript/tests/test.html           |   37 +
 sdks/html5-javascript/tests/test.js             |  910 +++
 21 files changed, 10112 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/Gruntfile.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/Gruntfile.js b/sdks/html5-javascript/Gruntfile.js
new file mode 100644
index 0000000..e1d297a
--- /dev/null
+++ b/sdks/html5-javascript/Gruntfile.js
@@ -0,0 +1,83 @@
+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 tests = [ 'tests/mocha/index.html','tests/mocha/test_*.html' ];
+   // Project configuration.
+  grunt.initConfig({
+    //pkg: grunt.file.readJSON('package.json'),
+    meta: {
+      package: grunt.file.readJSON('package.json'),
+    },
+    clean: ['usergrid.js', 'usergrid.min.js'],
+    uglify: {
+      build: {
+        options: {
+          banner: '/*! <%= meta.package.name %>@<%= meta.package.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
+            mangle: false,
+            compress: false,
+            beautify: true,
+            preserveComments: "all"
+        },
+        files: {
+          'usergrid.js': files
+        }
+      },
+      buildmin: {
+        options: {
+          banner: '/*! <%= meta.package.name %>@<%= meta.package.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n',
+            mangle: false,
+            compress: true,
+            beautify: false,
+            preserveComments: "some"
+        },
+        files: {
+          'usergrid.min.js': files
+        }
+      }
+    },
+    connect: {
+      server: {
+        options: {
+          port: 3000,
+          base: '.'
+        }
+      },
+      test: {
+        options: {
+          port: 8000,
+          base: '.'
+        }
+      }
+    },
+    watch : {
+      files : files,
+      tasks : ['default']
+    },
+    blanket_mocha: {
+      all: tests,
+      //urls: [ 'http://localhost:8000/tests/mocha/index.html' ],
+      options: {
+          dest: 'report/coverage.html',
+          reporter: 'Spec',
+          threshold: 70
+      }
+    },
+  });
+  grunt.loadNpmTasks('grunt-contrib-clean');
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-watch'); 
+  grunt.loadNpmTasks('grunt-contrib-connect');
+  grunt.loadNpmTasks('grunt-blanket-mocha');
+grunt.registerTask('default', [
+    'clean',
+    'uglify'
+  ]);
+  grunt.registerTask('dev', [
+  	'connect:server',
+    'watch'
+  ]);
+  grunt.registerTask('test', [
+    'connect:test',
+    'blanket_mocha',
+  ]);
+};
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Client.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Client.js b/sdks/html5-javascript/lib/Client.js
new file mode 100644
index 0000000..3fc4338
--- /dev/null
+++ b/sdks/html5-javascript/lib/Client.js
@@ -0,0 +1,864 @@
+
+Usergrid.Client = function(options) {
+  //usergrid enpoint
+  this.URI = options.URI || 'https://api.usergrid.com';
+
+  //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
+  if (options.orgName) {
+    this.set('orgName', options.orgName);
+  }
+  if (options.appName) {
+    this.set('appName', options.appName);
+  }
+
+  //other options
+  this.buildCurl = options.buildCurl || false;
+  this.logging = options.logging || false;
+
+  //timeout and callbacks
+  this._callTimeout =  options.callTimeout || 30000; //default to 30 seconds
+  this._callTimeoutCallback =  options.callTimeoutCallback || null;
+  this.logoutCallback =  options.logoutCallback || null;
+};
+
+/*
+ *  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 self = this;
+  var method = options.method || 'GET';
+  var endpoint = options.endpoint;
+  var body = options.body || {};
+  var qs = options.qs || {};
+  var mQuery = options.mQuery || false; //is this a query to the management endpoint?
+  var orgName = this.get('orgName');
+  var appName = this.get('appName');
+  if(!mQuery && !orgName && !appName){
+    if (typeof(this.logoutCallback) === 'function') {
+      return this.logoutCallback(true, 'no_org_or_app_name_specified');
+    }
+  }
+  if (mQuery) {
+    uri = this.URI + '/' + endpoint;
+  } else {
+    uri = this.URI + '/' + orgName + '/' + appName + '/' + endpoint;
+  }
+
+  if (self.getToken()) {
+    qs.access_token = self.getToken();
+    /* //could also use headers for the token
+     xhr.setRequestHeader("Authorization", "Bearer " + self.getToken());
+     xhr.withCredentials = true;
+     */
+  }
+
+  //append params to the path
+  var encoded_params = encodeParams(qs);
+  if (encoded_params) {
+    uri += "?" + encoded_params;
+  }
+
+  //stringify the body object
+  body = JSON.stringify(body);
+
+  //so far so good, so run the query
+  var xhr = new XMLHttpRequest();
+  xhr.open(method, uri, true);
+  //add content type = json if there is a json payload
+  if (body) {
+    xhr.setRequestHeader("Content-Type", "application/json");
+    xhr.setRequestHeader("Accept", "application/json");
+  }
+
+  // Handle response.
+  xhr.onerror = function(response) {
+    self._end = new Date().getTime();
+    if (self.logging) {
+      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
+    }
+    if (self.logging) {
+      console.log('Error: API call failed at the network level.');
+    }
+    //network error
+    clearTimeout(timeout);
+    var err = true;
+    if (typeof(callback) === 'function') {
+      callback(err, response);
+    }
+  };
+
+  xhr.onload = function(response) {
+    //call timing, get time, then log the call
+    self._end = new Date().getTime();
+    if (self.logging) {
+      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
+    }
+    //call completed
+    clearTimeout(timeout);
+    //decode the response
+    try{
+      response = JSON.parse(xhr.responseText);
+    }catch (e){
+      response = {error:'unhandled_error',error_description:xhr.responseText};
+      xhr.status = xhr.status === 200 ? 400 : xhr.status;
+      console.error(e);
+    }
+    if (xhr.status != 200)   {
+      //there was an api error
+      var error = response.error;
+      var error_description = response.error_description;
+      if (self.logging) {
+        console.log('Error (' + xhr.status + ')(' + error + '): ' + error_description);
+      }
+      if ( (error == "auth_expired_session_token") ||
+        (error == "auth_missing_credentials")   ||
+        (error == "auth_unverified_oath")       ||
+        (error == "expired_token")              ||
+        (error == "unauthorized")               ||
+        (error == "auth_invalid")) {
+        //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
+        //if the user has specified a logout callback:
+        if (typeof(self.logoutCallback) === 'function') {
+          return self.logoutCallback(true, response);
+        }
+      }
+      if (typeof(callback) === 'function') {
+        callback(true, response);
+      }
+    } else {
+      if (typeof(callback) === 'function') {
+        callback(false, response);
+      }
+    }
+  };
+
+  var timeout = setTimeout(
+    function() {
+      xhr.abort();
+      if (self._callTimeoutCallback === 'function') {
+        self._callTimeoutCallback('API CALL TIMEOUT');
+      } else {
+        self.callback('API CALL TIMEOUT');
+      }
+    },
+    self._callTimeout); //set for 30 seconds
+
+  if (this.logging) {
+    console.log('calling: ' + method + ' ' + uri);
+  }
+  if (this.buildCurl) {
+    var curlOptions = {
+      uri:uri,
+      body:body,
+      method:method
+    }
+    this.buildCurlCall(curlOptions);
+  }
+  this._start = new Date().getTime();
+  xhr.send(body);
+}
+
+/*
+ *  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();
+  }
+
+  //append params to the path
+  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 getOnExist = options.getOnExist || false;
+
+  options = {
+    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);
+    if (okToSave) {
+      group.save(function(err, data){
+        if (typeof(callback) === 'function') {
+          callback(err, group);
+        }
+      });
+    } else {
+      if(typeof(callback) === 'function') {
+        callback(err, 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) {
+  // todo: replace the check for new / save on not found code with simple save
+  // when users PUT on no user fix is in place.
+  /*
+   var options = {
+   client:this,
+   data:options
+   }
+   var entity = new Usergrid.Entity(options);
+   entity.save(function(err, data) {
+   if (typeof(callback) === 'function') {
+   callback(err, entity);
+   }
+   });
+   */
+  var getOnExist = options.getOnExist || false; //if true, will return entity if one already exists
+  var options = {
+    client:this,
+    data:options
+  };
+  var entity = new Usergrid.Entity(options);
+  entity.fetch(function(err, data) {
+    //if the fetch doesn't find what we are looking for, or there is no error, do a save
+    var okToSave = (err && 'service_resource_not_found' === data.error || 'no_name_specified' === data.error || 'null_pointer' === data.error) || (!err && getOnExist);
+    if(okToSave) {
+      entity.set(options.data); //add the data again just in case
+      entity.save(function(err, data) {
+        if (typeof(callback) === 'function') {
+          callback(err, entity, data);
+        }
+      });
+    } else {
+      if (typeof(callback) === 'function') {
+        callback(err, entity, data);
+      }
+    }
+  });
+
+};
+
+/*
+ *  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 options = {
+    client:this,
+    data:options
+  }
+  var entity = new Usergrid.Entity(options);
+  entity.fetch(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, entity, data);
+    }
+  });
+};
+
+/*
+ *  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 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;
+  var collection = new Usergrid.Collection(options, function(err, data) {
+    if (typeof(callback) === 'function') {
+      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(typeof(callback) === "function") {
+      if(err) {
+        callback(err);
+      } else {
+        callback(err, data, data.entities);
+      }
+    }
+  });
+};
+
+/*
+ *  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';
+  var options = {
+    client:this,
+    data:options
+  }
+  var entity = new Usergrid.Entity(options);
+  entity.save(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, 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;
+  if (this[key]) {
+    return this[key];
+  } else if(typeof(Storage)!=="undefined") {
+    return localStorage.getItem(keyStore);
+  }
+  return null;
+};
+
+/*
+ * 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'
+    }
+  };
+  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);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, 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 {
+
+      //save the re-authed token and current email/username
+      self.setToken(response.access_token);
+
+    }
+    if (typeof(callback) === 'function') {
+      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);
+
+      //delete next block and corresponding function when iframes are refactored
+      localStorage.setItem('accessToken', data.token);
+      localStorage.setItem('userUUID', data.uuid);
+      localStorage.setItem('userEmail', data.email);
+      //end delete block
+
+
+      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 {
+        //if we have an org stored, then use that one. Otherwise, use the first one.
+        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');
+        }
+      } //should always be an org
+
+      applications = self.parseApplicationsArray(org);
+      self.selectFirstApp(applications);
+
+      self.setObject('organizations', organizations);
+      self.setObject('applications', applications);
+
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, user, organizations, applications);
+    }
+  });
+};
+
+/*
+ *  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);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, user);
+    }
+  });
+};
+
+/*
+ *  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) {
+  if (!this.getToken()) {
+    callback(true, null, null);
+  } else {
+    var self = this;
+    var options = {
+      method:'GET',
+      endpoint:'users/me'
+    };
+    this.request(options, function(err, data) {
+      if (err) {
+        if (self.logging) {
+          console.log('error trying to log user in');
+        }
+        if (typeof(callback) === 'function') {
+          callback(err, data, null);
+        }
+      } else {
+        var options = {
+          client:self,
+          data:data.entities[0]
+        };
+        var user = new Usergrid.Entity(options);
+        if (typeof(callback) === 'function') {
+          callback(err, data, user);
+        }
+      }
+    });
+  }
+};
+
+/*
+ *  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 () {
+  if (this.getToken() && this.getToken() != 'null') {
+    return true;
+  }
+  return false;
+};
+
+/*
+ *  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(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 - add the method to the command (no need to add anything for GET)
+  if (method === 'POST') {
+    curl += ' -X POST';
+  } else if (method === 'PUT') {
+    curl += ' -X PUT';
+  } else if (method === 'DELETE') {
+    curl += ' -X DELETE';
+  } else {
+    curl += ' -X GET';
+  }
+
+  //curl - append the path
+  curl += ' ' + uri;
+
+  //curl - add the body
+  if("undefined"!== typeof window){body = JSON.stringify(body);}//only in node module
+  if (body !== '"{}"' && method !== 'GET' && method !== 'DELETE') {
+    //curl - add in the json obj
+    curl += " -d '" + body + "'";
+  }
+
+  //log the curl command to the console
+  console.log(curl);
+
+  return curl;
+}
+
+Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
+  try {
+    if (picture) {
+      return picture;
+    }
+    var size = size || 50;
+    if (email.length) {
+      return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+    } else {
+      return 'https://apigee.com/usergrid/images/user_profile.png';
+    }
+  } catch(e) {
+    return 'https://apigee.com/usergrid/images/user_profile.png';
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Collection.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Collection.js b/sdks/html5-javascript/lib/Collection.js
new file mode 100644
index 0000000..57fdf06
--- /dev/null
+++ b/sdks/html5-javascript/lib/Collection.js
@@ -0,0 +1,446 @@
+
+/*
+ *  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
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Collection = function(options, callback) {
+
+  if (options) {
+    this._client = options.client;
+    this._type = options.type;
+    this.qs = options.qs || {};
+
+    //iteration
+    this._list = options.list || [];
+    this._iterator = options.iterator || -1; //first thing we do is increment, so set to -1
+
+    //paging
+    this._previous = options.previous || [];
+    this._next = options.next || null;
+    this._cursor = options.cursor || null;
+
+    //restore entities if available
+    if (options.list) {
+      var count = options.list.length;
+      for(var i=0;i<count;i++){
+        //make new entity with
+        var entity = this._client.restoreEntity(options.list[i]);
+        this._list[i] = entity;
+      }
+    }
+  }
+  if (callback) {
+    //populate the collection
+    this.fetch(callback);
+  }
+
+};
+
+
+/*
+ *  gets the data from the collection object for serialization
+ *
+ *  @method serialize
+ *  @return {object} data
+ */
+Usergrid.Collection.prototype.serialize = function () {
+
+  //pull out the state from this object and return it
+  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;
+      callback(err, collection);
+    }
+  });
+};
+
+/*
+ *  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;
+
+  //add in the cursor if one is available
+  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, data) {
+    if(err && self._client.logging) {
+      console.log('error getting collection');
+    } else {
+      //save the cursor if there is one
+      var cursor = data.cursor || null;
+      self.saveCursor(cursor);
+      if (data.entities) {
+        self.resetEntityPointer();
+        var count = data.entities.length;
+        //save entities locally
+        self._list = []; //clear the local list first
+        for (var i=0;i<count;i++) {
+          var uuid = data.entities[i].uuid;
+          if (uuid) {
+            var entityData = data.entities[i] || {};
+            self._baseType = data.entities[i].type; //store the base type in the collection
+            entityData.type = self._type;//make sure entities are same type (have same path) as parent collection.
+            var entityOptions = {
+              type:self._type,
+              client:self._client,
+              uuid:uuid,
+              data:entityData
+            };
+
+            var ent = new Usergrid.Entity(entityOptions);
+            ent._json = JSON.stringify(entityData, null, 2);
+            var ct = self._list.length;
+            self._list[ct] = ent;
+          }
+        }
+      }
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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 (options, callback) {
+  var self = this;
+  options.type = this._type;
+
+  //create the new entity
+  this._client.createEntity(options, function (err, entity) {
+    if (!err) {
+      //then add the entity to the list
+      var count = self._list.length;
+      self._list[count] = entity;
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, entity);
+    }
+  });
+};
+
+Usergrid.Collection.prototype.addExistingEntity = function (entity) {
+  //entity should already exist in the db, so just add it to the list
+  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, data) {
+    if (err) {
+      if (self._client.logging) {
+        console.log('could not destroy entity');
+      }
+      if (typeof(callback) === 'function') {
+        callback(err, data);
+      }
+    } else {
+      //destroy was good, so repopulate the collection
+      self.fetch(callback);
+    }
+  });
+  //remove entity from the local store
+  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 false;
+};
+
+/*
+ *  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) {
+
+  for (var key in this._list) {
+    var listItem = this._list[key];
+    if (listItem.get('uuid') === uuid) {
+      return listItem;
+    }
+  }
+
+  //get the entity from the database
+  var options = {
+    data: {
+      type: this._type,
+      uuid:uuid
+    },
+    client: this._client
+  }
+  var 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 current cursor is different, grab it for next 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()) {
+    //set the cursor to the next page of data
+    this._previous.push(this._cursor);
+    this._cursor = this._next;
+    //empty the list
+    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; //clear out next so the comparison will find the next item
+    this._cursor = this._previous.pop();
+    //empty the list
+    this._list = [];
+    this.fetch(callback);
+  }
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Entity.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Entity.js b/sdks/html5-javascript/lib/Entity.js
new file mode 100644
index 0000000..e070d8a
--- /dev/null
+++ b/sdks/html5-javascript/lib/Entity.js
@@ -0,0 +1,646 @@
+/*
+ *  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) {
+  if (options) {
+    this._data = options.data || {};
+    this._client = options.client || {};
+  }
+};
+
+/*
+ *  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 (field) {
+  if (field) {
+    return this._data[field];
+  } else {
+    return this._data;
+  }
+};
+
+/*
+ *  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 = {};
+  }
+};
+
+/*
+ *  Saves the entity back to the database
+ *
+ *  @method save
+ *  @public
+ *  @param {function} callback
+ *  @return {callback} callback(err, data)
+ */
+Usergrid.Entity.prototype.save = function (callback) {
+  var type = this.get('type');
+  var method = 'POST';
+  if (isUUID(this.get('uuid'))) {
+    method = 'PUT';
+    type += '/' + this.get('uuid');
+  }
+
+  //update the entity
+  var self = this;
+  var data = {};
+  var entityData = this.get();
+    var password = this.get('password');
+    var oldpassword = this.get('oldpassword');
+    var newpassword = this.get('newpassword');
+  //remove system specific properties
+  for (var item in entityData) {
+    if (item === 'metadata' || item === 'created' || item === 'modified' ||
+          item === 'oldpassword' || item === 'newpassword' || //old and new pw not added to data
+      item === 'type' || item === 'activated' || item === 'uuid') {
+      continue;
+    }
+    data[item] = entityData[item];
+  }
+  var options =  {
+    method:method,
+    endpoint:type,
+    body:data
+  };
+  //save the entity first
+  this._client.request(options, function (err, retdata) {
+      //clear out pw info if present
+      self.set('password', null);
+      self.set('oldpassword', null);
+      self.set('newpassword', null);
+    if (err && self._client.logging) {
+      console.log('could not save entity');
+      if (typeof(callback) === 'function') {
+        return callback(err, retdata, self);
+      }
+    } else {
+      if (retdata.entities) {
+        if (retdata.entities.length) {
+          var entity = retdata.entities[0];
+          self.set(entity);
+          var path = retdata.path;
+          //for connections, API returns type
+          while (path.substring(0, 1) === "/") {
+            path = path.substring(1);
+          }
+          self.set('type', path);
+        }
+      }
+      //if this is a user, update the password if it has been specified;
+        var needPasswordChange = ((self.get('type') === 'user' || self.get('type') === 'users') && oldpassword && newpassword);
+      if (needPasswordChange) {
+        //Note: we have a ticket in to change PUT calls to /users to accept the password change
+        //      once that is done, we will remove this call and merge it all into one
+        var pwdata = {};
+          pwdata.oldpassword = oldpassword;
+          pwdata.newpassword = newpassword;
+        var options = {
+          method:'PUT',
+          endpoint:type+'/password',
+          body:pwdata
+        }
+        self._client.request(options, function (err, data) {
+          if (err && self._client.logging) {
+            console.log('could not update user');
+          }
+          //remove old and new password fields so they don't end up as part of the entity object
+          self.set('oldpassword', null);
+          self.set('newpassword', null);
+          if (typeof(callback) === 'function') {
+            callback(err, data, self);
+          }
+        });
+      } else if (typeof(callback) === 'function') {
+        callback(err, retdata, self);
+      }
+    }
+  });
+};
+
+/*
+ *  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 type = this.get('type');
+  var self = this;
+
+  //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
+  try {
+    if (type === undefined) {
+      throw 'cannot fetch entity, no entity type specified'
+    } else if (this.get('uuid')) {
+      type += '/' + this.get('uuid');
+    } else if (type === 'users' && this.get('username')) {
+      type += '/' + this.get('username');
+    } else if (this.get('name')) {
+      type += '/' + encodeURIComponent(this.get('name'));
+    } else if (typeof(callback) === 'function') {
+      throw 'no_name_specified';
+    }
+  } catch (e) {
+    if (self._client.logging) {
+      console.log(e);
+    }
+    return callback(true, {
+      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) {
+        if (data.entities.length) {
+          var entity = data.entities[0];
+          self.set(entity);
+        }
+      }
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data, 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 type = this.get('type');
+  if (isUUID(this.get('uuid'))) {
+    type += '/' + this.get('uuid');
+  } else {
+    if (typeof(callback) === 'function') {
+      var error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+  }
+  var options = {
+    method:'DELETE',
+    endpoint:type
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be deleted');
+    } else {
+      self.set(null);
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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) {
+
+  var self = this;
+
+  var error;
+  //connectee info
+  var connecteeType = entity.get('type');
+  var connectee = this.getEntityId(entity);
+  if (!connectee) {
+    if (typeof(callback) === 'function') {
+      error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  //connector info
+  var connectorType = this.get('type');
+  var connector = this.getEntityId(this);
+  if (!connector) {
+    if (typeof(callback) === 'function') {
+      error = 'Error in connect - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
+  var options = {
+    method:'POST',
+    endpoint:endpoint
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be connected');
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};
+
+/*
+ *  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 = false;
+  if (isUUID(entity.get('uuid'))) {
+    id = entity.get('uuid');
+  } else {
+    if (type === 'users') {
+      id = entity.get('username');
+    } else if (entity.get('name')) {
+      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;
+
+  //connector info
+  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);
+      }
+      callback(true, error);
+    }
+    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.entities.length;
+    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]
+      }
+    }
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+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.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;
+
+    if (typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+
+};
+
+/*
+ *  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) {
+
+  var self = this;
+
+  var error;
+  //connectee info
+  var connecteeType = entity.get('type');
+  var connectee = this.getEntityId(entity);
+  if (!connectee) {
+    if (typeof(callback) === 'function') {
+      error = 'Error trying to delete object - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  //connector info
+  var connectorType = this.get('type');
+  var connector = this.getEntityId(this);
+  if (!connector) {
+    if (typeof(callback) === 'function') {
+      error = 'Error in connect - no uuid specified.';
+      if (self._client.logging) {
+        console.log(error);
+      }
+      callback(true, error);
+    }
+    return;
+  }
+
+  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
+  var options = {
+    method:'DELETE',
+    endpoint:endpoint
+  };
+  this._client.request(options, function (err, data) {
+    if (err && self._client.logging) {
+      console.log('entity could not be disconnected');
+    }
+    if (typeof(callback) === 'function') {
+      callback(err, data);
+    }
+  });
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
new file mode 100644
index 0000000..789240f
--- /dev/null
+++ b/sdks/html5-javascript/lib/Event.js
@@ -0,0 +1,163 @@
+var COUNTER_RESOLUTIONS = {
+  'ALL': 'all',
+  'MINUTE': 'minute',
+  'FIVE_MINUTES': 'five_minutes',
+  'HALF_HOUR': 'half_hour',
+  'HOUR': 'hour',
+  'SIX_DAY': 'six_day',
+  'DAY': 'day',
+  'WEEK': 'week',
+  'MONTH': 'month'
+};
+COUNTER_RESOLUTIONS.valueOf=function(str){
+  Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){
+    if(COUNTER_RESOLUTIONS[res]===str){
+      return COUNTER_RESOLUTIONS[res];
+    }
+  });
+  return COUNTER_RESOLUTIONS.ALL;
+};
+
+/*
+ *  A class to model a Usergrid event.
+ *
+ *  @constructor
+ *  @param {object} options {timestamp:0, category:'value', counters:{name : value}}
+ *  @returns {callback} callback(err, event)
+ */
+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||{};
+  if(typeof(callback) === 'function') {
+    callback.call(self, false, self);
+  }
+  //this.save(callback);
+};
+
+/*
+ *  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.Event.prototype = new Usergrid.Entity();
+
+Usergrid.Event.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.Event.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);
+  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.Event.prototype.decrement=function(name, value, callback){
+  this.increment(name, -(value), 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.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=COUNTER_RESOLUTIONS.valueOf(resolution);
+  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/ef53b3b5/sdks/html5-javascript/lib/Group.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Group.js b/sdks/html5-javascript/lib/Group.js
new file mode 100644
index 0000000..2a853be
--- /dev/null
+++ b/sdks/html5-javascript/lib/Group.js
@@ -0,0 +1,233 @@
+/*
+ *  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, data){
+    if(err) {
+      if(self._client.logging) {
+        console.log('error getting group');
+      }
+      if(typeof(callback) === 'function') {
+        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; i < count; i++) {
+                var uuid = data.entities[i].uuid;
+                if(uuid) {
+                  var entityData = data.entities[i] || {};
+                  var entityOptions = {
+                    type: entityData.type,
+                    client: self._client,
+                    uuid:uuid,
+                    data:entityData
+                  };
+                  var entity = new Usergrid.Entity(entityOptions);
+                  self._list.push(entity);
+                }
+
+              }
+            }
+          }
+          if(typeof(callback) === 'function') {
+            callback(err, data, self._list);
+          }
+        });
+      }
+    }
+  });
+};
+
+/*
+ *  Retrieves the members of a group.
+ *
+ *  @method members
+ *  @public
+ *  @param {function} callback
+ *  @return {function} callback(err, data);
+ */
+Usergrid.Group.prototype.members = function(callback) {
+  if(typeof(callback) === 'function') {
+    callback(null, this._list);
+  }
+};
+
+/*
+ *  Adds a 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;
+  var options = {
+    method:"POST",
+    endpoint:"groups/"+this._path+"/users/"+options.user.get('username')
+  }
+
+  this._client.request(options, function(error, data){
+    if(error) {
+      if(typeof(callback) === 'function') {
+        callback(error, data, data.entities);
+      }
+    } else {
+      self.fetch(callback);
+    }
+  });
+}
+
+/*
+ *  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;
+
+  var options = {
+    method:"DELETE",
+    endpoint:"groups/"+this._path+"/users/"+options.user.get('username')
+  }
+
+  this._client.request(options, function(error, data){
+    if(error) {
+      if(typeof(callback) === 'function') {
+        callback(error, data);
+      }
+    } else {
+      self.fetch(callback);
+    }
+  });
+}
+
+/*
+ * 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 endpoint = "groups/"+this._path+"/feed";
+
+  var options = {
+    method:"GET",
+    endpoint:endpoint
+  }
+
+  this._client.request(options, function(err, data){
+    if (err && self.logging) {
+      console.log('error trying to log user in');
+    }
+    if(typeof(callback) === 'function') {
+      callback(err, data, data.entities);
+    }
+  });
+}
+
+/*
+ * 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 user = options.user;
+  options = {
+    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'
+    }
+  }
+
+  var entity = new Usergrid.Entity(options);
+  entity.save(function(err, data) {
+    if (typeof(callback) === 'function') {
+      callback(err, entity);
+    }
+  });
+};

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/lib/Usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Usergrid.js b/sdks/html5-javascript/lib/Usergrid.js
new file mode 100644
index 0000000..89507cf
--- /dev/null
+++ b/sdks/html5-javascript/lib/Usergrid.js
@@ -0,0 +1,87 @@
+/*
+ *  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://apigee.com/docs/usergrid
+ *
+ *   Copyright 2012 Apigee 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 (rod@apigee.com)
+ *  @author matt dobson (matt@apigee.com)
+ *  @author ryan bridges (rbridges@apigee.com)
+ */
+
+
+//Hack around IE console.log
+window.console = window.console || {};
+window.console.log = window.console.log || function() {};
+
+//Usergrid namespace encapsulates this SDK
+window.Usergrid = window.Usergrid || {};
+Usergrid = Usergrid || {};
+Usergrid.USERGRID_SDK_VERSION = '0.10.07';
+
+
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+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}$/;
+  if (!uuid) {
+    return false;
+  }
+  return 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 tail = [];
+  var item = [];
+  var i;
+  if (params instanceof Array) {
+    for (i in params) {
+      item = params[i];
+      if ((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("&");
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/package.json
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/package.json b/sdks/html5-javascript/package.json
new file mode 100644
index 0000000..a30f4e9
--- /dev/null
+++ b/sdks/html5-javascript/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "usergrid",
+  "version": "0.0.0",
+  "description": "Detailed instructions follow but if you just want a quick example of how to get started with this SDK, here’s a minimal HTML5 file that shows you how to include & initialize the SDK, as well as how to read & write data from Usergrid with it.",
+  "main": "usergrid.js",
+  "directories": {
+    "example": "examples"
+  },
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "Apache 2.0",
+  "devDependencies": {
+    "grunt": "~0.4.2",
+    "grunt-contrib-clean": "~0.5.0",
+    "grunt-contrib-watch": "~0.5.3",
+    "grunt-contrib-uglify": "~0.2.7",
+    "grunt-blanket-mocha": "~0.3.3",
+    "grunt-contrib-connect": "~0.6.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/mocha/index.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/mocha/index.html b/sdks/html5-javascript/tests/mocha/index.html
new file mode 100644
index 0000000..f6d5c77
--- /dev/null
+++ b/sdks/html5-javascript/tests/mocha/index.html
@@ -0,0 +1,49 @@
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Mocha Tests</title>
+  <link rel="stylesheet" href="../resources/css/mocha.css" />
+
+
+
+
+
+
+
+  <script src="../resources/js/mocha.js"></script>
+  <script>mocha.setup('bdd')</script>
+  <script src="../resources/js/blanket_mocha.min.js"></script>
+  <script type="text/javascript" src="../../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
+	<script>
+      function assert(expr, msg) {
+        if (!expr) throw new Error(msg || 'failed');
+      }
+    </script>
+
+  <script src="../../usergrid.js" data-cover></script>
+  <script src="test.js"></script>
+<!-- run mocha -->
+    <script type="text/javascript" charset="utf-8">
+    	var _onload=onload||function(){};
+        onload = function(){
+        	_onload.apply(this, arguments);
+	        mocha.checkLeaks();
+	        mocha.globals(['']);
+	        var runner = mocha.run();
+	        /*runner.on('test end', function(test){
+	          console.log(test.fullTitle());
+	        });*/
+	      };
+    </script>
+
+  <script>
+    if (window.PHANTOMJS) {
+        blanket.options("reporter", "../../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
+    }
+  </script>
+
+</head>
+<body>
+	<div id="mocha"></div>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/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
new file mode 100644
index 0000000..d74541c
--- /dev/null
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -0,0 +1,348 @@
+
+/*
+	Creates a generic usergrid client with logging and buildCurl disabled
+
+ */
+function getClient(){
+	return new Usergrid.Client({
+		orgName:'yourorgname',
+		appName:'sandbox',
+		logging: false, //optional - turn on logging, off by default
+		buildCurl: true //optional - turn on curl commands, off by default
+	});
+}
+/*
+	A convenience function that will test for the presence of an API error
+	and run any number of additional tests
+ */
+function usergridTestHarness(err, data, done, tests, ignoreError){
+	if(!ignoreError) assert(!err, data.error_description);
+	if(tests){
+		if("function"===typeof tests){
+			tests(err, data);
+		}else if(tests.length){
+			tests.forEach(function(test){
+				if("function"===typeof test){
+					test(err, data);
+				}
+			})
+		}
+	}	
+	done();
+}
+describe('Usergrid', function(){
+	var client = getClient();
+
+	before(function(done){
+    	//Make sure our dog doesn't already exist
+		client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
+			done();
+	    });
+  	});
+	describe('Usergrid CRUD', function(){
+		var options = {
+			method:'GET',
+			endpoint:'users'
+		};
+		it('should Create a new user', function(done){
+			client.request({method:'POST',endpoint:'users', body:{ username:'fred', password:'secret' }}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Retrieve an existing user', function(done){
+			client.request({method:'GET',endpoint:'users/fred', body:{}}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Update an existing user', function(done){
+			client.request({method:'PUT',endpoint:'users/fred', body:{ newkey:'newvalue' }}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+		it('should Delete the user from the database', function(done){
+			client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(true)}
+				]);
+		    });
+		});
+	});
+	describe('Usergrid REST', function(){
+		it('should return a list of users', function(done){
+			client.request({method:'GET',endpoint:'users'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(data.entities.length >=0)}
+				]);
+		    });
+		});
+		it('should return no entities when an endpoint does not exist', function(done){
+			client.request({method:'GET',endpoint:'nonexistantendpoint'}, function (err, data) {
+				usergridTestHarness(err, data, done, [
+					function(err, data){assert(data.entities.length === 0)}
+				]);
+		    });
+		});
+	});
+	describe('Usergrid Entity', function(){
+		var dog;
+		before(function(done){
+	    	//Make sure our dog doesn't already exist
+	    	client.request({method:'DELETE',endpoint:'dogs/Rocky'}, function (err, data) {
+	    		assert(true);
+	    		done();
+		    });
+	  	});
+		it('should create a new dog', function(done){
+			var options = {
+				type:'dogs',
+				name:'Rocky'
+			}
+
+			client.createEntity(options, function (err, data) {
+				assert(!err, "dog not created");
+				dog=data;
+				done();
+			});
+		});
+		it('should retrieve the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.fetch(function(err){
+				assert(!err, "dog not fetched");
+				done();
+			});
+		});
+		it('should update the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.set('breed','Dinosaur');
+
+			//the set function can also take a JSON object:
+			var data = {
+				master:'Fred',
+				state:'hungry'
+			}
+			//set is additive, so previously set properties are not overwritten
+			dog.set(data);
+
+			//finally, call save on the object to save it back to the database
+			dog.save(function(err){
+				assert(!err, "dog not saved");
+				done();
+			});
+		});
+		it('should remove the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+				return;
+			}
+			//once the dog is created, you can set single properties:
+			dog.destroy(function(err){
+				assert(!err, "dog not removed");
+				done();
+			});
+		});
+
+	});
+	describe('Usergrid Collections', function(){
+		var client = getClient();
+		var dog, dogs={};
+		function loop(done){
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				dog = dogs.getNextEntity();
+				console.log(dog.get('name'));
+			}
+			if(done)done();
+		}
+		before(function(done){
+	    	//Make sure our dog doesn't already exist
+			var options = {
+				type:'dogs',
+				qs:{limit:50} //limit statement set to 50
+			}
+
+			client.createCollection(options, function (err, dogs) {
+				if (!err) {
+					assert(!err, "could not retrieve list of dogs: "+dogs.error_description);
+					//we got 50 dogs, now display the Entities:
+					//do doggy cleanup
+					if(dogs.hasNextEntity()){
+						while(dogs.hasNextEntity()) {
+							//get a reference to the dog
+							var dog = dogs.getNextEntity();
+							//notice('removing dog ' + dogname + ' from database');
+							dog.destroy(function(err, data) {
+								assert(!err, dog.get('name')+" not removed: "+data.error_description);
+								if(!dogs.hasNextEntity()){
+									done();
+								}
+							});
+						}
+					}else{
+						done();
+					}
+				}
+			});
+	  	});
+		before(function(done){
+			this.timeout(10000);
+			var totalDogs=30;
+			Array.apply(0, Array(totalDogs)).forEach(function (x, y) { 
+				var dogNum=y+1;
+				var options = {
+					type:'dogs',
+					name:'dog'+dogNum,
+					index:y
+				}
+				client.createEntity(options, function (err, dog) {
+					assert(!err, " not created: "+dog.error_description);
+					if(dogNum===totalDogs){
+						done();
+					}
+				});
+			})
+		});
+		it('should create a new dogs collection', function(done){
+			var options = {
+				type:'dogs',
+				qs:{ql:'order by index'}
+			}
+
+			client.createCollection(options, function (err, data) {
+				assert(!err, "could not create dogs collection: "+data.error_description);
+				dogs=data;
+				done();
+			});
+		});
+		it('should retrieve dogs from the collection', function(done){
+			loop(done);
+		});
+		it('should retrieve the next page of dogs from the collection', function(done){
+			if(dogs.hasNextPage()){
+				dogs.getNextPage(function(err){loop(done);});
+			}else{
+				done();
+			}
+		});
+		it('should retrieve the previous page of dogs from the collection', function(done){
+			if(dogs.hasPreviousPage()){
+				dogs.getPreviousPage(function(err){loop(done);});
+			}else{
+				done();
+			}
+		});
+		/*it('should retrieve the dog', function(done){
+			if(!dog){
+				assert(false, "dog not created");
+				done();
+			}
+			dog.fetch(function(err){
+				assert(!err, "dog not fetched");
+				done();
+			});
+		});*/
+	});
+	describe('Usergrid Events', function(){
+		var ev;
+		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){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		it('should save an event', function(done){
+			ev.save(function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		/*it('should reset a counter', function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.reset('test', function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});*/
+		it("should increment 'test' counter", function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.increment('test', 1, function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+		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){
+				assert(!err, data.error_description);
+				console.log(JSON.stringify(data,null,4));
+				done();
+			});
+		});
+		it("should decrement 'test' counter", function(done){
+			time+=MINUTE*10
+			ev.set("timestamp", time);
+			ev.decrement('test', 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){
+				assert(!err, data.error_description);
+				console.log(JSON.stringify(data,null,4));
+				console.log(time, Date.now());
+				done();
+			});
+		});
+		/*it('should fetch counter data', function(done){
+			ev.getData('all', null, null, ['test', 'test_counter'], function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				console.log(time, Date.now());
+				done();
+			});
+		});*/
+	});
+	/*describe('Usergrid Counters', function(){
+		it('should create a counter', function(done){
+			var counter = new Apigee.Event({client:client, data:{category:"mocha_test", timestamp:28, name:'test'}}, function(err, data){
+				assert(!err, data.error_description);
+				console.log(data);
+				done();
+			});
+		});
+	});*/
+	describe('Usergrid extra', function(){
+		it('should not be phonegap', function(done){
+			
+		});
+	});
+});
+

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/qunit/apigee_test.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/qunit/apigee_test.html b/sdks/html5-javascript/tests/qunit/apigee_test.html
new file mode 100644
index 0000000..0975bbd
--- /dev/null
+++ b/sdks/html5-javascript/tests/qunit/apigee_test.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>QUnit Example</title>
+  <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
+</head>
+<body>
+  <div id="qunit"></div>
+  <div id="qunit-fixture"></div>
+  <script src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
+  <script src="tests.js"></script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/qunit/tests.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/qunit/tests.js b/sdks/html5-javascript/tests/qunit/tests.js
new file mode 100644
index 0000000..67764a0
--- /dev/null
+++ b/sdks/html5-javascript/tests/qunit/tests.js
@@ -0,0 +1,3 @@
+test( "hello test", function() {
+  ok( 1 == "1", "Passed!" );
+});


[15/27] git commit: built with the new Events module included

Posted by sn...@apache.org.
built with the new Events module included


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

Branch: refs/pull/34/head
Commit: 8367ea49bb900444556d9ea1c41758bb8b58dcfd
Parents: ef53b3b
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 11:14:16 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 11:14:16 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/usergrid.js     | 3056 ++++++++++++++--------------
 sdks/html5-javascript/usergrid.min.js |    3 +-
 2 files changed, 1556 insertions(+), 1503 deletions(-)
----------------------------------------------------------------------



[19/27] git commit: fixed issue with counter resolutions. Fixed global scope leak in client.

Posted by sn...@apache.org.
fixed issue with counter resolutions. Fixed global scope leak in client.


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

Branch: refs/pull/34/head
Commit: 2953c67dd5f40adf1568c543fa40cc6406dc11ea
Parents: 8367ea4
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 13:21:39 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 13:21:39 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/lib/Client.js       |  1 +
 sdks/html5-javascript/lib/Event.js        | 34 ++++++++-----------------
 sdks/html5-javascript/tests/mocha/test.js | 24 ++++++++----------
 sdks/html5-javascript/usergrid.js         | 35 ++++++++------------------
 sdks/html5-javascript/usergrid.min.js     |  4 +--
 5 files changed, 33 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/lib/Client.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Client.js b/sdks/html5-javascript/lib/Client.js
index 3fc4338..c6fb550 100644
--- a/sdks/html5-javascript/lib/Client.js
+++ b/sdks/html5-javascript/lib/Client.js
@@ -46,6 +46,7 @@ Usergrid.Client.prototype.request = function (options, callback) {
   var mQuery = options.mQuery || false; //is this a query to the management endpoint?
   var orgName = this.get('orgName');
   var appName = this.get('appName');
+  var uri;
   if(!mQuery && !orgName && !appName){
     if (typeof(this.logoutCallback) === 'function') {
       return this.logoutCallback(true, 'no_org_or_app_name_specified');

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
index 789240f..c39ec94 100644
--- a/sdks/html5-javascript/lib/Event.js
+++ b/sdks/html5-javascript/lib/Event.js
@@ -1,23 +1,3 @@
-var COUNTER_RESOLUTIONS = {
-  'ALL': 'all',
-  'MINUTE': 'minute',
-  'FIVE_MINUTES': 'five_minutes',
-  'HALF_HOUR': 'half_hour',
-  'HOUR': 'hour',
-  'SIX_DAY': 'six_day',
-  'DAY': 'day',
-  'WEEK': 'week',
-  'MONTH': 'month'
-};
-COUNTER_RESOLUTIONS.valueOf=function(str){
-  Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){
-    if(COUNTER_RESOLUTIONS[res]===str){
-      return COUNTER_RESOLUTIONS[res];
-    }
-  });
-  return COUNTER_RESOLUTIONS.ALL;
-};
-
 /*
  *  A class to model a Usergrid event.
  *
@@ -38,7 +18,10 @@ Usergrid.Event = function(options, callback) {
   }
   //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.
@@ -67,7 +50,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
       return callback.call(self, true, "'value' for increment, decrement must be a number");
     }
   }
-  self._data.counters[name]=parseInt(value);
+  self._data.counters[name]=(parseInt(value))||1;
   return self.save(callback);
 };
 /*
@@ -83,7 +66,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
  */
 
 Usergrid.Event.prototype.decrement=function(name, value, callback){
-  this.increment(name, -(value), callback);
+  this.increment(name, -((parseInt(value))||1), callback);
 };
 /*
  * resets the counter for a specific event
@@ -104,7 +87,10 @@ Usergrid.Event.prototype.reset=function(name, callback){
 Usergrid.Event.prototype.getData=function(start, end, resolution, counters, callback){
   var start_time, 
       end_time,
-      res=COUNTER_RESOLUTIONS.valueOf(resolution);
+      res=(resolution||'all').toLowerCase();
+  if(COUNTER_RESOLUTIONS.indexOf(res)===-1){
+    res='all';
+  }
   if(start){
     switch(typeof start){
       case "undefined":

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/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 d74541c..24d6530 100644
--- a/sdks/html5-javascript/tests/mocha/test.js
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -44,28 +44,28 @@ describe('Usergrid', function(){
 			method:'GET',
 			endpoint:'users'
 		};
-		it('should Create a new user', function(done){
+		it('should CREATE a new user', function(done){
 			client.request({method:'POST',endpoint:'users', body:{ username:'fred', password:'secret' }}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Retrieve an existing user', function(done){
+		it('should RETRIEVE an existing user', function(done){
 			client.request({method:'GET',endpoint:'users/fred', body:{}}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Update an existing user', function(done){
+		it('should UPDATE an existing user', function(done){
 			client.request({method:'PUT',endpoint:'users/fred', body:{ newkey:'newvalue' }}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Delete the user from the database', function(done){
+		it('should DELETE the user from the database', function(done){
 			client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
@@ -98,7 +98,7 @@ describe('Usergrid', function(){
 	    		done();
 		    });
 	  	});
-		it('should create a new dog', function(done){
+		it('should CREATE a new dog', function(done){
 			var options = {
 				type:'dogs',
 				name:'Rocky'
@@ -110,7 +110,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should retrieve the dog', function(done){
+		it('should RETRIEVE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -122,7 +122,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should update the dog', function(done){
+		it('should UPDATE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -145,7 +145,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should remove the dog', function(done){
+		it('should DELETE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -263,6 +263,7 @@ describe('Usergrid', function(){
 		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){
 				assert(!err, data.error_description);
@@ -312,7 +313,7 @@ describe('Usergrid', function(){
 				console.log(JSON.stringify(data,null,4));
 				done();
 			});
-		});
+		});	
 		it('should fetch event', function(done){
 			ev.fetch(function(err, data){
 				assert(!err, data.error_description);
@@ -339,10 +340,5 @@ describe('Usergrid', function(){
 			});
 		});
 	});*/
-	describe('Usergrid extra', function(){
-		it('should not be phonegap', function(done){
-			
-		});
-	});
 });
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
index 96dbbe8..9fc9482 100644
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,4 +1,4 @@
-/*! usergrid@0.0.0 2014-01-16 */
+/*! usergrid@0.0.0 2014-01-21 */
 /*
  *  This module is a collection of classes designed to make working with
  *  the Appigee App Services API as easy as possible.
@@ -133,6 +133,7 @@ Usergrid.Client.prototype.request = function(options, callback) {
     //is this a query to the management endpoint?
     var orgName = this.get("orgName");
     var appName = this.get("appName");
+    var uri;
     if (!mQuery && !orgName && !appName) {
         if (typeof this.logoutCallback === "function") {
             return this.logoutCallback(true, "no_org_or_app_name_specified");
@@ -2161,27 +2162,6 @@ Usergrid.Group.prototype.createGroupActivity = function(options, callback) {
     });
 };
 
-var COUNTER_RESOLUTIONS = {
-    ALL: "all",
-    MINUTE: "minute",
-    FIVE_MINUTES: "five_minutes",
-    HALF_HOUR: "half_hour",
-    HOUR: "hour",
-    SIX_DAY: "six_day",
-    DAY: "day",
-    WEEK: "week",
-    MONTH: "month"
-};
-
-COUNTER_RESOLUTIONS.valueOf = function(str) {
-    Object.keys(COUNTER_RESOLUTIONS).forEach(function(res) {
-        if (COUNTER_RESOLUTIONS[res] === str) {
-            return COUNTER_RESOLUTIONS[res];
-        }
-    });
-    return COUNTER_RESOLUTIONS.ALL;
-};
-
 /*
  *  A class to model a Usergrid event.
  *
@@ -2202,6 +2182,8 @@ Usergrid.Event = function(options, 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.
@@ -2231,7 +2213,7 @@ Usergrid.Event.prototype.increment = function(name, value, callback) {
             return callback.call(self, true, "'value' for increment, decrement must be a number");
         }
     }
-    self._data.counters[name] = parseInt(value);
+    self._data.counters[name] = parseInt(value) || 1;
     return self.save(callback);
 };
 
@@ -2247,7 +2229,7 @@ Usergrid.Event.prototype.increment = function(name, value, callback) {
  * @returns {callback} callback(err, event)
  */
 Usergrid.Event.prototype.decrement = function(name, value, callback) {
-    this.increment(name, -value, callback);
+    this.increment(name, -(parseInt(value) || 1), callback);
 };
 
 /*
@@ -2266,7 +2248,10 @@ Usergrid.Event.prototype.reset = function(name, callback) {
 };
 
 Usergrid.Event.prototype.getData = function(start, end, resolution, counters, callback) {
-    var start_time, end_time, res = COUNTER_RESOLUTIONS.valueOf(resolution);
+    var start_time, end_time, res = (resolution || "all").toLowerCase();
+    if (COUNTER_RESOLUTIONS.indexOf(res) === -1) {
+        res = "all";
+    }
     if (start) {
         switch (typeof start) {
           case "undefined":

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/usergrid.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.min.js b/sdks/html5-javascript/usergrid.min.js
index c701528..4d37d2d 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-16 */
-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 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")),xh
 r.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_invalid"
 ==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;options
 ={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 options
 ={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.entit
 ies))})},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.Clie
 nt.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",dat
 a.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,data){v
 ar 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").toUpperCase()
 ,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.Entit
 y.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 callback)
 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("uuid");
 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={method:"
 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("entit
 y 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){va
 r 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)})},User
 grid.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(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,"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=data.da
 ta,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 callba
 ck&&(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,data.i
 terator=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(options,
 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=function(en
 tity){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.Collecti
 on.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!==curs
 or&&(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",groupOpti
 ons={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(opt
 ions,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: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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})};var COUNTER_RESOLUTIONS={ALL:"all",MINUTE:"minute",FIVE_MINUTES:"five_minutes",HALF_HOUR:"half_hour",HOUR:"hour",SIX_DAY:"six_day",DAY:"day",WEEK:"week",MONTH:"month"};COUNTER_RESOLUTIONS.valueOf=function(str){return Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){return COUNTER_RESOLUTIONS[res]===str?COUNTER_RESOLUTIONS[res]:void 0}),COUNTER_RESOLUTIONS.ALL},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._dat
 a.type="events",this._data.counters=options.counters||{},"function"==typeof callback&&callback.call(self,!1,self)},Usergrid.Event.prototype=new Usergrid.Entity,Usergrid.Event.prototype.fetch=function(callback){this.getData(null,null,null,null,callback)},Usergrid.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),self.save(callback))},Usergrid.Event.prototype.decrement=function(name,value,callback){this.increment(name,-value,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=COUNTER_RESOLUTIONS.valueOf(resolution);if(start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(sta
 rt)?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-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


[10/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/mocha.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/mocha.css b/sdks/html5-javascript/tests/resources/css/mocha.css
new file mode 100644
index 0000000..42b9798
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/mocha.css
@@ -0,0 +1,270 @@
+@charset "utf-8";
+
+body {
+  margin:0;
+}
+
+#mocha {
+  font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
+  margin: 60px 50px;
+}
+
+#mocha ul,
+#mocha li {
+  margin: 0;
+  padding: 0;
+}
+
+#mocha ul {
+  list-style: none;
+}
+
+#mocha h1,
+#mocha h2 {
+  margin: 0;
+}
+
+#mocha h1 {
+  margin-top: 15px;
+  font-size: 1em;
+  font-weight: 200;
+}
+
+#mocha h1 a {
+  text-decoration: none;
+  color: inherit;
+}
+
+#mocha h1 a:hover {
+  text-decoration: underline;
+}
+
+#mocha .suite .suite h1 {
+  margin-top: 0;
+  font-size: .8em;
+}
+
+#mocha .hidden {
+  display: none;
+}
+
+#mocha h2 {
+  font-size: 12px;
+  font-weight: normal;
+  cursor: pointer;
+}
+
+#mocha .suite {
+  margin-left: 15px;
+}
+
+#mocha .test {
+  margin-left: 15px;
+  overflow: hidden;
+}
+
+#mocha .test.pending:hover h2::after {
+  content: '(pending)';
+  font-family: arial, sans-serif;
+}
+
+#mocha .test.pass.medium .duration {
+  background: #c09853;
+}
+
+#mocha .test.pass.slow .duration {
+  background: #b94a48;
+}
+
+#mocha .test.pass::before {
+  content: '✓';
+  font-size: 12px;
+  display: block;
+  float: left;
+  margin-right: 5px;
+  color: #00d6b2;
+}
+
+#mocha .test.pass .duration {
+  font-size: 9px;
+  margin-left: 5px;
+  padding: 2px 5px;
+  color: #fff;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  -ms-border-radius: 5px;
+  -o-border-radius: 5px;
+  border-radius: 5px;
+}
+
+#mocha .test.pass.fast .duration {
+  display: none;
+}
+
+#mocha .test.pending {
+  color: #0b97c4;
+}
+
+#mocha .test.pending::before {
+  content: 'â—¦';
+  color: #0b97c4;
+}
+
+#mocha .test.fail {
+  color: #c00;
+}
+
+#mocha .test.fail pre {
+  color: black;
+}
+
+#mocha .test.fail::before {
+  content: '✖';
+  font-size: 12px;
+  display: block;
+  float: left;
+  margin-right: 5px;
+  color: #c00;
+}
+
+#mocha .test pre.error {
+  color: #c00;
+  max-height: 300px;
+  overflow: auto;
+}
+
+/**
+ * (1): approximate for browsers not supporting calc
+ * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
+ *      ^^ seriously
+ */
+#mocha .test pre {
+  display: block;
+  float: left;
+  clear: left;
+  font: 12px/1.5 monaco, monospace;
+  margin: 5px;
+  padding: 15px;
+  border: 1px solid #eee;
+  max-width: 85%; /*(1)*/
+  max-width: calc(100% - 42px); /*(2)*/
+  word-wrap: break-word;
+  border-bottom-color: #ddd;
+  -webkit-border-radius: 3px;
+  -webkit-box-shadow: 0 1px 3px #eee;
+  -moz-border-radius: 3px;
+  -moz-box-shadow: 0 1px 3px #eee;
+  border-radius: 3px;
+}
+
+#mocha .test h2 {
+  position: relative;
+}
+
+#mocha .test a.replay {
+  position: absolute;
+  top: 3px;
+  right: 0;
+  text-decoration: none;
+  vertical-align: middle;
+  display: block;
+  width: 15px;
+  height: 15px;
+  line-height: 15px;
+  text-align: center;
+  background: #eee;
+  font-size: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+  -webkit-transition: opacity 200ms;
+  -moz-transition: opacity 200ms;
+  transition: opacity 200ms;
+  opacity: 0.3;
+  color: #888;
+}
+
+#mocha .test:hover a.replay {
+  opacity: 1;
+}
+
+#mocha-report.pass .test.fail {
+  display: none;
+}
+
+#mocha-report.fail .test.pass {
+  display: none;
+}
+
+#mocha-report.pending .test.pass,
+#mocha-report.pending .test.fail {
+  display: none;
+}
+#mocha-report.pending .test.pass.pending {
+  display: block;
+}
+
+#mocha-error {
+  color: #c00;
+  font-size: 1.5em;
+  font-weight: 100;
+  letter-spacing: 1px;
+}
+
+#mocha-stats {
+  position: fixed;
+  top: 15px;
+  right: 10px;
+  font-size: 12px;
+  margin: 0;
+  color: #888;
+  z-index: 1;
+}
+
+#mocha-stats .progress {
+  float: right;
+  padding-top: 0;
+}
+
+#mocha-stats em {
+  color: black;
+}
+
+#mocha-stats a {
+  text-decoration: none;
+  color: inherit;
+}
+
+#mocha-stats a:hover {
+  border-bottom: 1px solid #eee;
+}
+
+#mocha-stats li {
+  display: inline-block;
+  margin: 0 5px;
+  list-style: none;
+  padding-top: 11px;
+}
+
+#mocha-stats canvas {
+  width: 40px;
+  height: 40px;
+}
+
+#mocha code .comment { color: #ddd; }
+#mocha code .init { color: #2f6fad; }
+#mocha code .string { color: #5890ad; }
+#mocha code .keyword { color: #8a6343; }
+#mocha code .number { color: #2f6fad; }
+
+@media screen and (max-device-width: 480px) {
+  #mocha {
+    margin: 60px 0px;
+  }
+
+  #mocha #stats {
+    position: absolute;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/styles.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/styles.css b/sdks/html5-javascript/tests/resources/css/styles.css
new file mode 100755
index 0000000..7492f93
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/styles.css
@@ -0,0 +1,91 @@
+/**
+*  All Calls is a Node.js sample app that is powered by Usergrid
+*  This app shows how to make the 4 REST calls (GET, POST,
+*  PUT, DELETE) against the usergrid API.
+*
+*  Learn more at http://Usergrid.com/docs
+*
+*   Copyright 2012 Apigee 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.
+*/
+
+/**
+*  @file styles.css
+*  @author Rod Simpson (rod@apigee.com)
+*
+*/
+
+body {
+  background-color: #fff;
+  min-height: 800px;
+}
+
+/* buttons ================================================================= */
+.btn-primary{border-color:#1455ab #1455ab #0c3367;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);background-color:#146cab;background-image:-moz-linear-gradient(top, #147bab, #1455ab);background-image:-ms-linear-gradient(top, #147bab, #1455ab);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#147bab), to(#1455ab));background-image:-webkit-linear-gradient(top, #147bab, #1455ab);background-image:-o-linear-gradient(top, #147bab, #1455ab);background-image:linear-gradient(top, #147bab, #1455ab);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#147bab', endColorstr='#1455ab', GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#1455ab;}
+
+.header{
+   padding: 10px;
+   width: 100%;
+   height: 40px;
+   background-color: #ff4200;
+   color: #fff;
+   text-align: left;
+   font-size: 16px;
+   font-weight: 800;
+}
+.breadcrumb{
+  font-size: 16px;
+}
+.info{
+  padding: 0px 30px 30px 30px;
+  font-size: 16px;
+}
+h3{
+ padding-bottom: 20px;
+}
+.main{
+   display: block;
+   padding: 0 30px 30px 30px ;
+   background-color: #fff;
+}
+.form-block{
+  display: block;
+  display: none;
+  padding: 10px 0;
+  min-height: 210px;
+  background-color: #fff;
+}
+.section-header{
+  font-size: 20px;
+  font-weight: 200;
+  padding-bottom: 20px;
+}
+.note {
+   padding-bottom: 20px;
+}
+.response-box{
+   margin: 0 auto;
+   padding: 10px;
+   width: 640px;
+   border: 1px solid silver;
+   background-color: #ddd;
+   font-weight: bold;
+}
+pre{
+   border: none;
+   padding: 0;
+}
+.left{
+   float: left;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/images/apigee.png
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/images/apigee.png b/sdks/html5-javascript/tests/resources/images/apigee.png
new file mode 100755
index 0000000..c0d0f84
Binary files /dev/null and b/sdks/html5-javascript/tests/resources/images/apigee.png differ

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js b/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
new file mode 100644
index 0000000..74368f0
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
@@ -0,0 +1 @@
+(function(e){(function(t,n){"use strict";typeof e=="function"&&e.amd?e(["exports"],n):typeof exports!="undefined"?n(exports):n(t.esprima={})})(this,function(e){"use strict";function m(e,t){if(!e)throw new Error("ASSERT: "+t)}function g(e,t){return u.slice(e,t)}function y(e){return"0123456789".indexOf(e)>=0}function b(e){return"0123456789abcdefABCDEF".indexOf(e)>=0}function w(e){return"01234567".indexOf(e)>=0}function E(e){return e===" "||e===" "||e===""||e==="\f"||e==="\u00a0"||e.charCodeAt(0)>=5760&&"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff".indexOf(e)>=0}function S(e){return e==="\n"||e==="\r"||e==="\u2028"||e==="\u2029"}function x(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierStart.test(e)}function T(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e>="0"&&e<="9"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierPart.test(e)}function N(e){
 switch(e){case"class":case"enum":case"export":case"extends":case"import":case"super":return!0}return!1}function C(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0}return!1}function k(e){return e==="eval"||e==="arguments"}function L(e){var t=!1;switch(e.length){case 2:t=e==="if"||e==="in"||e==="do";break;case 3:t=e==="var"||e==="for"||e==="new"||e==="try";break;case 4:t=e==="this"||e==="else"||e==="case"||e==="void"||e==="with";break;case 5:t=e==="while"||e==="break"||e==="catch"||e==="throw";break;case 6:t=e==="return"||e==="typeof"||e==="delete"||e==="switch";break;case 7:t=e==="default"||e==="finally";break;case 8:t=e==="function"||e==="continue"||e==="debugger";break;case 10:t=e==="instanceof"}if(t)return!0;switch(e){case"const":return!0;case"yield":case"let":return!0}return a&&C(e)?!0:N(e)}function A(){var e,t,n;t=!1,n=!1;while(f<h){e=u[f];if(n)e=u[f++],S(e)&&(n=!1,e==="\r"&&u[f]===
 "\n"&&++f,++l,c=f);else if(t)S(e)?(e==="\r"&&u[f+1]==="\n"&&++f,++l,++f,c=f,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")):(e=u[f++],f>=h&&R({},s.UnexpectedToken,"ILLEGAL"),e==="*"&&(e=u[f],e==="/"&&(++f,t=!1)));else if(e==="/"){e=u[f+1];if(e==="/")f+=2,n=!0;else{if(e!=="*")break;f+=2,t=!0,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")}}else if(E(e))++f;else{if(!S(e))break;++f,e==="\r"&&u[f]==="\n"&&++f,++l,c=f}}}function O(e){var t,n,r,i=0;n=e==="u"?4:2;for(t=0;t<n;++t){if(!(f<h&&b(u[f])))return"";r=u[f++],i=i*16+"0123456789abcdef".indexOf(r.toLowerCase())}return String.fromCharCode(i)}function M(){var e,n,r,i;e=u[f];if(!x(e))return;n=f;if(e==="\\"){++f;if(u[f]!=="u")return;++f,i=f,e=O("u");if(e){if(e==="\\"||!x(e))return;r=e}else f=i,r="u"}else r=u[f++];while(f<h){e=u[f];if(!T(e))break;if(e==="\\"){++f;if(u[f]!=="u")return;++f,i=f,e=O("u");if(e){if(e==="\\"||!T(e))return;r+=e}else f=i,r+="u"}else r+=u[f++]}return r.length===1?{type:t.Identifier,value:r,lineNumber:l,lineStart:c,range:[n,f]}:L(r
 )?{type:t.Keyword,value:r,lineNumber:l,lineStart:c,range:[n,f]}:r==="null"?{type:t.NullLiteral,value:r,lineNumber:l,lineStart:c,range:[n,f]}:r==="true"||r==="false"?{type:t.BooleanLiteral,value:r,lineNumber:l,lineStart:c,range:[n,f]}:{type:t.Identifier,value:r,lineNumber:l,lineStart:c,range:[n,f]}}function _(){var e=f,n=u[f],r,i,s;if(n===";"||n==="{"||n==="}")return++f,{type:t.Punctuator,value:n,lineNumber:l,lineStart:c,range:[e,f]};if(n===","||n==="("||n===")")return++f,{type:t.Punctuator,value:n,lineNumber:l,lineStart:c,range:[e,f]};r=u[f+1];if(n==="."&&!y(r))return{type:t.Punctuator,value:u[f++],lineNumber:l,lineStart:c,range:[e,f]};i=u[f+2],s=u[f+3];if(n===">"&&r===">"&&i===">"&&s==="=")return f+=4,{type:t.Punctuator,value:">>>=",lineNumber:l,lineStart:c,range:[e,f]};if(n==="="&&r==="="&&i==="=")return f+=3,{type:t.Punctuator,value:"===",lineNumber:l,lineStart:c,range:[e,f]};if(n==="!"&&r==="="&&i==="=")return f+=3,{type:t.Punctuator,value:"!==",lineNumber:l,lineStart:c,range:[e
 ,f]};if(n===">"&&r===">"&&i===">")return f+=3,{type:t.Punctuator,value:">>>",lineNumber:l,lineStart:c,range:[e,f]};if(n==="<"&&r==="<"&&i==="=")return f+=3,{type:t.Punctuator,value:"<<=",lineNumber:l,lineStart:c,range:[e,f]};if(n===">"&&r===">"&&i==="=")return f+=3,{type:t.Punctuator,value:">>=",lineNumber:l,lineStart:c,range:[e,f]};if(r==="="&&"<>=!+-*%&|^/".indexOf(n)>=0)return f+=2,{type:t.Punctuator,value:n+r,lineNumber:l,lineStart:c,range:[e,f]};if(n===r&&"+-<>&|".indexOf(n)>=0&&"+-<>&|".indexOf(r)>=0)return f+=2,{type:t.Punctuator,value:n+r,lineNumber:l,lineStart:c,range:[e,f]};if("[]<>+-*%&|^!~?:=/".indexOf(n)>=0)return{type:t.Punctuator,value:u[f++],lineNumber:l,lineStart:c,range:[e,f]}}function D(){var e,n,r;r=u[f],m(y(r)||r===".","Numeric literal must start with a decimal digit or a decimal point"),n=f,e="";if(r!=="."){e=u[f++],r=u[f];if(e==="0"){if(r==="x"||r==="X"){e+=u[f++];while(f<h){r=u[f];if(!b(r))break;e+=u[f++]}return e.length<=2&&R({},s.UnexpectedToken,"ILLEGAL"),
 f<h&&(r=u[f],x(r)&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseInt(e,16),lineNumber:l,lineStart:c,range:[n,f]}}if(w(r)){e+=u[f++];while(f<h){r=u[f];if(!w(r))break;e+=u[f++]}return f<h&&(r=u[f],(x(r)||y(r))&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseInt(e,8),octal:!0,lineNumber:l,lineStart:c,range:[n,f]}}y(r)&&R({},s.UnexpectedToken,"ILLEGAL")}while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}if(r==="."){e+=u[f++];while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}if(r==="e"||r==="E"){e+=u[f++],r=u[f];if(r==="+"||r==="-")e+=u[f++];r=u[f];if(y(r)){e+=u[f++];while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}else r="character "+r,f>=h&&(r="<end>"),R({},s.UnexpectedToken,"ILLEGAL")}return f<h&&(r=u[f],x(r)&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseFloat(e),lineNumber:l,lineStart:c,range:[n,f]}}function P(){var e="",n,r,i,o,a,p,d=!1;n=u[f],m(n==="'"||n==='"',"String literal must starts with a quote"),r=f,++f;while(f<h){i=u[f++];
 if(i===n){n="";break}if(i==="\\"){i=u[f++];if(!S(i))switch(i){case"n":e+="\n";break;case"r":e+="\r";break;case"t":e+="  ";break;case"u":case"x":p=f,a=O(i),a?e+=a:(f=p,e+=i);break;case"b":e+="\b";break;case"f":e+="\f";break;case"v":e+="";break;default:w(i)?(o="01234567".indexOf(i),o!==0&&(d=!0),f<h&&w(u[f])&&(d=!0,o=o*8+"01234567".indexOf(u[f++]),"0123".indexOf(i)>=0&&f<h&&w(u[f])&&(o=o*8+"01234567".indexOf(u[f++]))),e+=String.fromCharCode(o)):e+=i}else++l,i==="\r"&&u[f]==="\n"&&++f}else{if(S(i))break;e+=i}}return n!==""&&R({},s.UnexpectedToken,"ILLEGAL"),{type:t.StringLiteral,value:e,octal:d,lineNumber:l,lineStart:c,range:[r,f]}}function H(){var e,t,n,r,i,o,a=!1,l,c=!1;p=null,A(),n=f,t=u[f],m(t==="/","Regular expression literal must start with a slash"),e=u[f++];while(f<h){t=u[f++],e+=t;if(t==="\\")t=u[f++],S(t)&&R({},s.UnterminatedRegExp),e+=t;else if(a)t==="]"&&(a=!1);else{if(t==="/"){c=!0;break}t==="["?a=!0:S(t)&&R({},s.UnterminatedRegExp)}}c||R({},s.UnterminatedRegExp),r=e.subs
 tr(1,e.length-2),i="";while(f<h){t=u[f];if(!T(t))break;++f;if(t==="\\"&&f<h){t=u[f];if(t==="u"){++f,l=f,t=O("u");if(t){i+=t,e+="\\u";for(;l<f;++l)e+=u[l]}else f=l,i+="u",e+="\\u"}else e+="\\"}else i+=t,e+=t}try{o=new RegExp(r,i)}catch(d){R({},s.InvalidRegExp)}return{literal:e,value:o,range:[n,f]}}function B(e){return e.type===t.Identifier||e.type===t.Keyword||e.type===t.BooleanLiteral||e.type===t.NullLiteral}function j(){var e,n;A();if(f>=h)return{type:t.EOF,lineNumber:l,lineStart:c,range:[f,f]};n=_();if(typeof n!="undefined")return n;e=u[f];if(e==="'"||e==='"')return P();if(e==="."||y(e))return D();n=M();if(typeof n!="undefined")return n;R({},s.UnexpectedToken,"ILLEGAL")}function F(){var e;return p?(f=p.range[1],l=p.lineNumber,c=p.lineStart,e=p,p=null,e):(p=null,j())}function I(){var e,t,n;return p!==null?p:(e=f,t=l,n=c,p=j(),f=e,l=t,c=n,p)}function q(){var e,t,n,r;return e=f,t=l,n=c,A(),r=l!==t,f=e,l=t,c=n,r}function R(e,t){var n,r=Array.prototype.slice.call(arguments,2),i=t.repla
 ce(/%(\d)/g,function(e,t){return r[t]||""});throw typeof e.lineNumber=="number"?(n=new Error("Line "+e.lineNumber+": "+i),n.index=e.range[0],n.lineNumber=e.lineNumber,n.column=e.range[0]-c+1):(n=new Error("Line "+l+": "+i),n.index=f,n.lineNumber=l,n.column=f-c+1),n}function U(){try{R.apply(null,arguments)}catch(e){if(!v.errors)throw e;v.errors.push(e)}}function z(e){e.type===t.EOF&&R(e,s.UnexpectedEOS),e.type===t.NumericLiteral&&R(e,s.UnexpectedNumber),e.type===t.StringLiteral&&R(e,s.UnexpectedString),e.type===t.Identifier&&R(e,s.UnexpectedIdentifier);if(e.type===t.Keyword){if(N(e.value))R(e,s.UnexpectedReserved);else if(a&&C(e.value)){U(e,s.StrictReservedWord);return}R(e,s.UnexpectedToken,e.value)}R(e,s.UnexpectedToken,e.value)}function W(e){var n=F();(n.type!==t.Punctuator||n.value!==e)&&z(n)}function X(e){var n=F();(n.type!==t.Keyword||n.value!==e)&&z(n)}function V(e){var n=I();return n.type===t.Punctuator&&n.value===e}function $(e){var n=I();return n.type===t.Keyword&&n.value===
 e}function J(){var e=I(),n=e.value;return e.type!==t.Punctuator?!1:n==="="||n==="*="||n==="/="||n==="%="||n==="+="||n==="-="||n==="<<="||n===">>="||n===">>>="||n==="&="||n==="^="||n==="|="}function K(){var e,n;if(u[f]===";"){F();return}n=l,A();if(l!==n)return;if(V(";")){F();return}e=I(),e.type!==t.EOF&&!V("}")&&z(e)}function Q(e){return e.type===r.Identifier||e.type===r.MemberExpression}function G(){var e=[];W("[");while(!V("]"))V(",")?(F(),e.push(null)):(e.push(Tt()),V("]")||W(","));return W("]"),{type:r.ArrayExpression,elements:e}}function Y(e,t){var n,i;return n=a,i=Gt(),t&&a&&k(e[0].name)&&U(t,s.StrictParamName),a=n,{type:r.FunctionExpression,id:null,params:e,defaults:[],body:i,rest:null,generator:!1,expression:!1}}function Z(){var e=F();return e.type===t.StringLiteral||e.type===t.NumericLiteral?(a&&e.octal&&U(e,s.StrictOctalLiteral),ln(e)):{type:r.Identifier,name:e.value}}function et(){var e,n,i,o;e=I();if(e.type===t.Identifier)return i=Z(),e.value==="get"&&!V(":")?(n=Z(),W("("
 ),W(")"),{type:r.Property,key:n,value:Y([]),kind:"get"}):e.value==="set"&&!V(":")?(n=Z(),W("("),e=I(),e.type!==t.Identifier?(W(")"),U(e,s.UnexpectedToken,e.value),{type:r.Property,key:n,value:Y([]),kind:"set"}):(o=[Lt()],W(")"),{type:r.Property,key:n,value:Y(o,e),kind:"set"})):(W(":"),{type:r.Property,key:i,value:Tt(),kind:"init"});if(e.type!==t.EOF&&e.type!==t.Punctuator)return n=Z(),W(":"),{type:r.Property,key:n,value:Tt(),kind:"init"};z(e)}function tt(){var e=[],t,n,o,u={},f=String;W("{");while(!V("}"))t=et(),t.key.type===r.Identifier?n=t.key.name:n=f(t.key.value),o=t.kind==="init"?i.Data:t.kind==="get"?i.Get:i.Set,Object.prototype.hasOwnProperty.call(u,n)?(u[n]===i.Data?a&&o===i.Data?U({},s.StrictDuplicateProperty):o!==i.Data&&U({},s.AccessorDataProperty):o===i.Data?U({},s.AccessorDataProperty):u[n]&o&&U({},s.AccessorGetSet),u[n]|=o):u[n]=o,e.push(t),V("}")||W(",");return W("}"),{type:r.ObjectExpression,properties:e}}function nt(){var e;return W("("),e=Nt(),W(")"),e}function rt(
 ){var e=I(),n=e.type;if(n===t.Identifier)return{type:r.Identifier,name:F().value};if(n===t.StringLiteral||n===t.NumericLiteral)return a&&e.octal&&U(e,s.StrictOctalLiteral),ln(F());if(n===t.Keyword){if($("this"))return F(),{type:r.ThisExpression};if($("function"))return Zt()}return n===t.BooleanLiteral?(F(),e.value=e.value==="true",ln(e)):n===t.NullLiteral?(F(),e.value=null,ln(e)):V("[")?G():V("{")?tt():V("(")?nt():V("/")||V("/=")?ln(H()):z(F())}function it(){var e=[];W("(");if(!V(")"))while(f<h){e.push(Tt());if(V(")"))break;W(",")}return W(")"),e}function st(){var e=F();return B(e)||z(e),{type:r.Identifier,name:e.value}}function ot(){return W("."),st()}function ut(){var e;return W("["),e=Nt(),W("]"),e}function at(){var e;return X("new"),e={type:r.NewExpression,callee:lt(),arguments:[]},V("(")&&(e.arguments=it()),e}function ft(){var e;e=$("new")?at():rt();while(V(".")||V("[")||V("("))V("(")?e={type:r.CallExpression,callee:e,arguments:it()}:V("[")?e={type:r.MemberExpression,computed:!
 0,object:e,property:ut()}:e={type:r.MemberExpression,computed:!1,object:e,property:ot()};return e}function lt(){var e;e=$("new")?at():rt();while(V(".")||V("["))V("[")?e={type:r.MemberExpression,computed:!0,object:e,property:ut()}:e={type:r.MemberExpression,computed:!1,object:e,property:ot()};return e}function ct(){var e=ft(),n;return n=I(),n.type!==t.Punctuator?e:((V("++")||V("--"))&&!q()&&(a&&e.type===r.Identifier&&k(e.name)&&U({},s.StrictLHSPostfix),Q(e)||U({},s.InvalidLHSInAssignment),e={type:r.UpdateExpression,operator:F().value,argument:e,prefix:!1}),e)}function ht(){var e,n;return e=I(),e.type!==t.Punctuator&&e.type!==t.Keyword?ct():V("++")||V("--")?(e=F(),n=ht(),a&&n.type===r.Identifier&&k(n.name)&&U({},s.StrictLHSPrefix),Q(n)||U({},s.InvalidLHSInAssignment),n={type:r.UpdateExpression,operator:e.value,argument:n,prefix:!0},n):V("+")||V("-")||V("~")||V("!")?(n={type:r.UnaryExpression,operator:F().value,argument:ht(),prefix:!0},n):$("delete")||$("void")||$("typeof")?(n={type:r.
 UnaryExpression,operator:F().value,argument:ht(),prefix:!0},a&&n.operator==="delete"&&n.argument.type===r.Identifier&&U({},s.StrictDelete),n):ct()}function pt(){var e=ht();while(V("*")||V("/")||V("%"))e={type:r.BinaryExpression,operator:F().value,left:e,right:ht()};return e}function dt(){var e=pt();while(V("+")||V("-"))e={type:r.BinaryExpression,operator:F().value,left:e,right:pt()};return e}function vt(){var e=dt();while(V("<<")||V(">>")||V(">>>"))e={type:r.BinaryExpression,operator:F().value,left:e,right:dt()};return e}function mt(){var e,t;t=d.allowIn,d.allowIn=!0,e=vt();while(V("<")||V(">")||V("<=")||V(">=")||t&&$("in")||$("instanceof"))e={type:r.BinaryExpression,operator:F().value,left:e,right:vt()};return d.allowIn=t,e}function gt(){var e=mt();while(V("==")||V("!=")||V("===")||V("!=="))e={type:r.BinaryExpression,operator:F().value,left:e,right:mt()};return e}function yt(){var e=gt();while(V("&"))F(),e={type:r.BinaryExpression,operator:"&",left:e,right:gt()};return e}function b
 t(){var e=yt();while(V("^"))F(),e={type:r.BinaryExpression,operator:"^",left:e,right:yt()};return e}function wt(){var e=bt();while(V("|"))F(),e={type:r.BinaryExpression,operator:"|",left:e,right:bt()};return e}function Et(){var e=wt();while(V("&&"))F(),e={type:r.LogicalExpression,operator:"&&",left:e,right:wt()};return e}function St(){var e=Et();while(V("||"))F(),e={type:r.LogicalExpression,operator:"||",left:e,right:Et()};return e}function xt(){var e,t,n;return e=St(),V("?")&&(F(),t=d.allowIn,d.allowIn=!0,n=Tt(),d.allowIn=t,W(":"),e={type:r.ConditionalExpression,test:e,consequent:n,alternate:Tt()}),e}function Tt(){var e,t;return e=I(),t=xt(),J()&&(Q(t)||U({},s.InvalidLHSInAssignment),a&&t.type===r.Identifier&&k(t.name)&&U(e,s.StrictLHSAssignment),t={type:r.AssignmentExpression,operator:F().value,left:t,right:Tt()}),t}function Nt(){var e=Tt();if(V(",")){e={type:r.SequenceExpression,expressions:[e]};while(f<h){if(!V(","))break;F(),e.expressions.push(Tt())}}return e}function Ct(){var 
 e=[],t;while(f<h){if(V("}"))break;t=en();if(typeof t=="undefined")break;e.push(t)}return e}function kt(){var e;return W("{"),e=Ct(),W("}"),{type:r.BlockStatement,body:e}}function Lt(){var e=F();return e.type!==t.Identifier&&z(e),{type:r.Identifier,name:e.value}}function At(e){var t=Lt(),n=null;return a&&k(t.name)&&U({},s.StrictVarName),e==="const"?(W("="),n=Tt()):V("=")&&(F(),n=Tt()),{type:r.VariableDeclarator,id:t,init:n}}function Ot(e){var t=[];do{t.push(At(e));if(!V(","))break;F()}while(f<h);return t}function Mt(){var e;return X("var"),e=Ot(),K(),{type:r.VariableDeclaration,declarations:e,kind:"var"}}function _t(e){var t;return X(e),t=Ot(e),K(),{type:r.VariableDeclaration,declarations:t,kind:e}}function Dt(){return W(";"),{type:r.EmptyStatement}}function Pt(){var e=Nt();return K(),{type:r.ExpressionStatement,expression:e}}function Ht(){var e,t,n;return X("if"),W("("),e=Nt(),W(")"),t=Qt(),$("else")?(F(),n=Qt()):n=null,{type:r.IfStatement,test:e,consequent:t,alternate:n}}function B
 t(){var e,t,n;return X("do"),n=d.inIteration,d.inIteration=!0,e=Qt(),d.inIteration=n,X("while"),W("("),t=Nt(),W(")"),V(";")&&F(),{type:r.DoWhileStatement,body:e,test:t}}function jt(){var e,t,n;return X("while"),W("("),e=Nt(),W(")"),n=d.inIteration,d.inIteration=!0,t=Qt(),d.inIteration=n,{type:r.WhileStatement,test:e,body:t}}function Ft(){var e=F();return{type:r.VariableDeclaration,declarations:Ot(),kind:e.value}}function It(){var e,t,n,i,o,u,a;return e=t=n=null,X("for"),W("("),V(";")?F():($("var")||$("let")?(d.allowIn=!1,e=Ft(),d.allowIn=!0,e.declarations.length===1&&$("in")&&(F(),i=e,o=Nt(),e=null)):(d.allowIn=!1,e=Nt(),d.allowIn=!0,$("in")&&(Q(e)||U({},s.InvalidLHSInForIn),F(),i=e,o=Nt(),e=null)),typeof i=="undefined"&&W(";")),typeof i=="undefined"&&(V(";")||(t=Nt()),W(";"),V(")")||(n=Nt())),W(")"),a=d.inIteration,d.inIteration=!0,u=Qt(),d.inIteration=a,typeof i=="undefined"?{type:r.ForStatement,init:e,test:t,update:n,body:u}:{type:r.ForInStatement,left:i,right:o,body:u,each:!1}}f
 unction qt(){var e,n=null;return X("continue"),u[f]===";"?(F(),d.inIteration||R({},s.IllegalContinue),{type:r.ContinueStatement,label:null}):q()?(d.inIteration||R({},s.IllegalContinue),{type:r.ContinueStatement,label:null}):(e=I(),e.type===t.Identifier&&(n=Lt(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)||R({},s.UnknownLabel,n.name)),K(),n===null&&!d.inIteration&&R({},s.IllegalContinue),{type:r.ContinueStatement,label:n})}function Rt(){var e,n=null;return X("break"),u[f]===";"?(F(),!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:null}):q()?(!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:null}):(e=I(),e.type===t.Identifier&&(n=Lt(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)||R({},s.UnknownLabel,n.name)),K(),n===null&&!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:n})}function Ut(){var e,n=null;return X("return"),d.inFunctionBody||U({},s.IllegalReturn),u[f]===" "&&x(
 u[f+1])?(n=Nt(),K(),{type:r.ReturnStatement,argument:n}):q()?{type:r.ReturnStatement,argument:null}:(V(";")||(e=I(),!V("}")&&e.type!==t.EOF&&(n=Nt())),K(),{type:r.ReturnStatement,argument:n})}function zt(){var e,t;return a&&U({},s.StrictModeWith),X("with"),W("("),e=Nt(),W(")"),t=Qt(),{type:r.WithStatement,object:e,body:t}}function Wt(){var e,t=[],n;$("default")?(F(),e=null):(X("case"),e=Nt()),W(":");while(f<h){if(V("}")||$("default")||$("case"))break;n=Qt();if(typeof n=="undefined")break;t.push(n)}return{type:r.SwitchCase,test:e,consequent:t}}function Xt(){var e,t,n,i,o;X("switch"),W("("),e=Nt(),W(")"),W("{"),t=[];if(V("}"))return F(),{type:r.SwitchStatement,discriminant:e,cases:t};i=d.inSwitch,d.inSwitch=!0,o=!1;while(f<h){if(V("}"))break;n=Wt(),n.test===null&&(o&&R({},s.MultipleDefaultsInSwitch),o=!0),t.push(n)}return d.inSwitch=i,W("}"),{type:r.SwitchStatement,discriminant:e,cases:t}}function Vt(){var e;return X("throw"),q()&&R({},s.NewlineAfterThrow),e=Nt(),K(),{type:r.ThrowStat
 ement,argument:e}}function $t(){var e;return X("catch"),W("("),V(")")&&z(I()),e=Lt(),a&&k(e.name)&&U({},s.StrictCatchVariable),W(")"),{type:r.CatchClause,param:e,body:kt()}}function Jt(){var e,t=[],n=null;return X("try"),e=kt(),$("catch")&&t.push($t()),$("finally")&&(F(),n=kt()),t.length===0&&!n&&R({},s.NoCatchOrFinally),{type:r.TryStatement,block:e,guardedHandlers:[],handlers:t,finalizer:n}}function Kt(){return X("debugger"),K(),{type:r.DebuggerStatement}}function Qt(){var e=I(),n,i;e.type===t.EOF&&z(e);if(e.type===t.Punctuator)switch(e.value){case";":return Dt();case"{":return kt();case"(":return Pt();default:}if(e.type===t.Keyword)switch(e.value){case"break":return Rt();case"continue":return qt();case"debugger":return Kt();case"do":return Bt();case"for":return It();case"function":return Yt();case"if":return Ht();case"return":return Ut();case"switch":return Xt();case"throw":return Vt();case"try":return Jt();case"var":return Mt();case"while":return jt();case"with":return zt();defau
 lt:}return n=Nt(),n.type===r.Identifier&&V(":")?(F(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)&&R({},s.Redeclaration,"Label",n.name),d.labelSet[n.name]=!0,i=Qt(),delete d.labelSet[n.name],{type:r.LabeledStatement,label:n,body:i}):(K(),{type:r.ExpressionStatement,expression:n})}function Gt(){var e,n=[],i,o,u,l,c,p,v;W("{");while(f<h){i=I();if(i.type!==t.StringLiteral)break;e=en(),n.push(e);if(e.expression.type!==r.Literal)break;o=g(i.range[0]+1,i.range[1]-1),o==="use strict"?(a=!0,u&&U(u,s.StrictOctalLiteral)):!u&&i.octal&&(u=i)}l=d.labelSet,c=d.inIteration,p=d.inSwitch,v=d.inFunctionBody,d.labelSet={},d.inIteration=!1,d.inSwitch=!1,d.inFunctionBody=!0;while(f<h){if(V("}"))break;e=en();if(typeof e=="undefined")break;n.push(e)}return W("}"),d.labelSet=l,d.inIteration=c,d.inSwitch=p,d.inFunctionBody=v,{type:r.BlockStatement,body:n}}function Yt(){var e,t,n=[],i,o,u,l,c,p,d;X("function"),o=I(),e=Lt(),a?k(o.value)&&U(o,s.StrictFunctionName):k(o.value)?(l=o,c=s.StrictFunction
 Name):C(o.value)&&(l=o,c=s.StrictReservedWord),W("(");if(!V(")")){d={};while(f<h){o=I(),t=Lt(),a?(k(o.value)&&(u=o,c=s.StrictParamName),Object.prototype.hasOwnProperty.call(d,o.value)&&(u=o,c=s.StrictParamDupe)):l||(k(o.value)?(l=o,c=s.StrictParamName):C(o.value)?(l=o,c=s.StrictReservedWord):Object.prototype.hasOwnProperty.call(d,o.value)&&(l=o,c=s.StrictParamDupe)),n.push(t),d[t.name]=!0;if(V(")"))break;W(",")}}return W(")"),p=a,i=Gt(),a&&l&&R(l,c),a&&u&&U(u,c),a=p,{type:r.FunctionDeclaration,id:e,params:n,defaults:[],body:i,rest:null,generator:!1,expression:!1}}function Zt(){var e,t=null,n,i,o,u,l=[],c,p,d;X("function"),V("(")||(e=I(),t=Lt(),a?k(e.value)&&U(e,s.StrictFunctionName):k(e.value)?(i=e,o=s.StrictFunctionName):C(e.value)&&(i=e,o=s.StrictReservedWord)),W("(");if(!V(")")){d={};while(f<h){e=I(),u=Lt(),a?(k(e.value)&&(n=e,o=s.StrictParamName),Object.prototype.hasOwnProperty.call(d,e.value)&&(n=e,o=s.StrictParamDupe)):i||(k(e.value)?(i=e,o=s.StrictParamName):C(e.value)?(i=e,o
 =s.StrictReservedWord):Object.prototype.hasOwnProperty.call(d,e.value)&&(i=e,o=s.StrictParamDupe)),l.push(u),d[u.name]=!0;if(V(")"))break;W(",")}}return W(")"),p=a,c=Gt(),a&&i&&R(i,o),a&&n&&U(n,o),a=p,{type:r.FunctionExpression,id:t,params:l,defaults:[],body:c,rest:null,generator:!1,expression:!1}}function en(){var e=I();if(e.type===t.Keyword)switch(e.value){case"const":case"let":return _t(e.value);case"function":return Yt();default:return Qt()}if(e.type!==t.EOF)return Qt()}function tn(){var e,n=[],i,o,u;while(f<h){i=I();if(i.type!==t.StringLiteral)break;e=en(),n.push(e);if(e.expression.type!==r.Literal)break;o=g(i.range[0]+1,i.range[1]-1),o==="use strict"?(a=!0,u&&U(u,s.StrictOctalLiteral)):!u&&i.octal&&(u=i)}while(f<h){e=en();if(typeof e=="undefined")break;n.push(e)}return n}function nn(){var e;return a=!1,e={type:r.Program,body:tn()},e}function rn(e,t,n,r,i){m(typeof n=="number","Comment must have valid position");if(v.comments.length>0&&v.comments[v.comments.length-1].range[1]>n
 )return;v.comments.push({type:e,value:t,range:[n,r],loc:i})}function sn(){var e,t,n,r,i,o;e="",i=!1,o=!1;while(f<h){t=u[f];if(o)t=u[f++],S(t)?(n.end={line:l,column:f-c-1},o=!1,rn("Line",e,r,f-1,n),t==="\r"&&u[f]==="\n"&&++f,++l,c=f,e=""):f>=h?(o=!1,e+=t,n.end={line:l,column:h-c},rn("Line",e,r,h,n)):e+=t;else if(i)S(t)?(t==="\r"&&u[f+1]==="\n"?(++f,e+="\r\n"):e+=t,++l,++f,c=f,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")):(t=u[f++],f>=h&&R({},s.UnexpectedToken,"ILLEGAL"),e+=t,t==="*"&&(t=u[f],t==="/"&&(e=e.substr(0,e.length-1),i=!1,++f,n.end={line:l,column:f-c},rn("Block",e,r,f,n),e="")));else if(t==="/"){t=u[f+1];if(t==="/")n={start:{line:l,column:f-c}},r=f,f+=2,o=!0,f>=h&&(n.end={line:l,column:f-c},o=!1,rn("Line",e,r,f,n));else{if(t!=="*")break;r=f,f+=2,i=!0,n={start:{line:l,column:f-c-2}},f>=h&&R({},s.UnexpectedToken,"ILLEGAL")}}else if(E(t))++f;else{if(!S(t))break;++f,t==="\r"&&u[f]==="\n"&&++f,++l,c=f}}}function on(){var e,t,n,r=[];for(e=0;e<v.comments.length;++e)t=v.comments[e],n={ty
 pe:t.type,value:t.value},v.range&&(n.range=t.range),v.loc&&(n.loc=t.loc),r.push(n);v.comments=r}function un(){var e,r,i,s,o;return A(),e=f,r={start:{line:l,column:f-c}},i=v.advance(),r.end={line:l,column:f-c},i.type!==t.EOF&&(s=[i.range[0],i.range[1]],o=g(i.range[0],i.range[1]),v.tokens.push({type:n[i.type],value:o,range:s,loc:r})),i}function an(){var e,t,n,r;return A(),e=f,t={start:{line:l,column:f-c}},n=v.scanRegExp(),t.end={line:l,column:f-c},v.tokens.length>0&&(r=v.tokens[v.tokens.length-1],r.range[0]===e&&r.type==="Punctuator"&&(r.value==="/"||r.value==="/=")&&v.tokens.pop()),v.tokens.push({type:"RegularExpression",value:n.literal,range:[e,f],loc:t}),n}function fn(){var e,t,n,r=[];for(e=0;e<v.tokens.length;++e)t=v.tokens[e],n={type:t.type,value:t.value},v.range&&(n.range=t.range),v.loc&&(n.loc=t.loc),r.push(n);v.tokens=r}function ln(e){return{type:r.Literal,value:e.value}}function cn(e){return{type:r.Literal,value:e.value,raw:g(e.range[0],e.range[1])}}function hn(){var e={};ret
 urn e.range=[f,f],e.loc={start:{line:l,column:f-c},end:{line:l,column:f-c}},e.end=function(){this.range[1]=f,this.loc.end.line=l,this.loc.end.column=f-c},e.applyGroup=function(e){v.range&&(e.groupRange=[this.range[0],this.range[1]]),v.loc&&(e.groupLoc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e.apply=function(e){v.range&&(e.range=[this.range[0],this.range[1]]),v.loc&&(e.loc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e}function pn(){var e,t;return A(),e=hn(),W("("),t=Nt(),W(")"),e.end(),e.applyGroup(t),t}function dn(){var e,t;A(),e=hn(),t=$("new")?at():rt();while(V(".")||V("["))V("[")?(t={type:r.MemberExpression,computed:!0,object:t,property:ut()},e.end(),e.apply(t)):(t={type:r.MemberExpression,computed:!1,object:t,property:ot()},e.end(),e.apply(t));return t}function vn(){var e,t;A(),e=hn(),t=$("new")?at():rt();while(V(".")||V(
 "[")||V("("))V("(")?(t={type:r.CallExpression,callee:t,arguments:it()},e.end(),e.apply(t)):V("[")?(t={type:r.MemberExpression,computed:!0,object:t,property:ut()},e.end(),e.apply(t)):(t={type:r.MemberExpression,computed:!1,object:t,property:ot()},e.end(),e.apply(t));return t}function mn(e){var t,n,r;t=Object.prototype.toString.apply(e)==="[object Array]"?[]:{};for(n in e)e.hasOwnProperty(n)&&n!=="groupRange"&&n!=="groupLoc"&&(r=e[n],r===null||typeof r!="object"||r instanceof RegExp?t[n]=r:t[n]=mn(r));return t}function gn(e,t){return function(n){function i(e){return e.type===r.LogicalExpression||e.type===r.BinaryExpression}function s(n){var r,o;i(n.left)&&s(n.left),i(n.right)&&s(n.right),e&&(n.left.groupRange||n.right.groupRange?(r=n.left.groupRange?n.left.groupRange[0]:n.left.range[0],o=n.right.groupRange?n.right.groupRange[1]:n.right.range[1],n.range=[r,o]):typeof n.range=="undefined"&&(r=n.left.range[0],o=n.right.range[1],n.range=[r,o])),t&&(n.left.groupLoc||n.right.groupLoc?(r=n.l
 eft.groupLoc?n.left.groupLoc.start:n.left.loc.start,o=n.right.groupLoc?n.right.groupLoc.end:n.right.loc.end,n.loc={start:r,end:o}):typeof n.loc=="undefined"&&(n.loc={start:n.left.loc.start,end:n.right.loc.end}))}return function(){var r,o;return A(),r=hn(),o=n.apply(null,arguments),r.end(),e&&typeof o.range=="undefined"&&r.apply(o),t&&typeof o.loc=="undefined"&&r.apply(o),i(o)&&s(o),o}}}function yn(){var e;v.comments&&(v.skipComment=A,A=sn),v.raw&&(v.createLiteral=ln,ln=cn);if(v.range||v.loc)v.parseGroupExpression=nt,v.parseLeftHandSideExpression=lt,v.parseLeftHandSideExpressionAllowCall=ft,nt=pn,lt=dn,ft=vn,e=gn(v.range,v.loc),v.parseAdditiveExpression=dt,v.parseAssignmentExpression=Tt,v.parseBitwiseANDExpression=yt,v.parseBitwiseORExpression=wt,v.parseBitwiseXORExpression=bt,v.parseBlock=kt,v.parseFunctionSourceElements=Gt,v.parseCatchClause=$t,v.parseComputedMember=ut,v.parseConditionalExpression=xt,v.parseConstLetDeclaration=_t,v.parseEqualityExpression=gt,v.parseExpression=Nt,v.
 parseForVariableDeclaration=Ft,v.parseFunctionDeclaration=Yt,v.parseFunctionExpression=Zt,v.parseLogicalANDExpression=Et,v.parseLogicalORExpression=St,v.parseMultiplicativeExpression=pt,v.parseNewExpression=at,v.parseNonComputedProperty=st,v.parseObjectProperty=et,v.parseObjectPropertyKey=Z,v.parsePostfixExpression=ct,v.parsePrimaryExpression=rt,v.parseProgram=nn,v.parsePropertyFunction=Y,v.parseRelationalExpression=mt,v.parseStatement=Qt,v.parseShiftExpression=vt,v.parseSwitchCase=Wt,v.parseUnaryExpression=ht,v.parseVariableDeclaration=At,v.parseVariableIdentifier=Lt,dt=e(v.parseAdditiveExpression),Tt=e(v.parseAssignmentExpression),yt=e(v.parseBitwiseANDExpression),wt=e(v.parseBitwiseORExpression),bt=e(v.parseBitwiseXORExpression),kt=e(v.parseBlock),Gt=e(v.parseFunctionSourceElements),$t=e(v.parseCatchClause),ut=e(v.parseComputedMember),xt=e(v.parseConditionalExpression),_t=e(v.parseConstLetDeclaration),gt=e(v.parseEqualityExpression),Nt=e(v.parseExpression),Ft=e(v.parseForVariable
 Declaration),Yt=e(v.parseFunctionDeclaration),Zt=e(v.parseFunctionExpression),lt=e(lt),Et=e(v.parseLogicalANDExpression),St=e(v.parseLogicalORExpression),pt=e(v.parseMultiplicativeExpression),at=e(v.parseNewExpression),st=e(v.parseNonComputedProperty),et=e(v.parseObjectProperty),Z=e(v.parseObjectPropertyKey),ct=e(v.parsePostfixExpression),rt=e(v.parsePrimaryExpression),nn=e(v.parseProgram),Y=e(v.parsePropertyFunction),mt=e(v.parseRelationalExpression),Qt=e(v.parseStatement),vt=e(v.parseShiftExpression),Wt=e(v.parseSwitchCase),ht=e(v.parseUnaryExpression),At=e(v.parseVariableDeclaration),Lt=e(v.parseVariableIdentifier);typeof v.tokens!="undefined"&&(v.advance=j,v.scanRegExp=H,j=un,H=an)}function bn(){typeof v.skipComment=="function"&&(A=v.skipComment),v.raw&&(ln=v.createLiteral);if(v.range||v.loc)dt=v.parseAdditiveExpression,Tt=v.parseAssignmentExpression,yt=v.parseBitwiseANDExpression,wt=v.parseBitwiseORExpression,bt=v.parseBitwiseXORExpression,kt=v.parseBlock,Gt=v.parseFunctionSour
 ceElements,$t=v.parseCatchClause,ut=v.parseComputedMember,xt=v.parseConditionalExpression,_t=v.parseConstLetDeclaration,gt=v.parseEqualityExpression,Nt=v.parseExpression,Ft=v.parseForVariableDeclaration,Yt=v.parseFunctionDeclaration,Zt=v.parseFunctionExpression,nt=v.parseGroupExpression,lt=v.parseLeftHandSideExpression,ft=v.parseLeftHandSideExpressionAllowCall,Et=v.parseLogicalANDExpression,St=v.parseLogicalORExpression,pt=v.parseMultiplicativeExpression,at=v.parseNewExpression,st=v.parseNonComputedProperty,et=v.parseObjectProperty,Z=v.parseObjectPropertyKey,rt=v.parsePrimaryExpression,ct=v.parsePostfixExpression,nn=v.parseProgram,Y=v.parsePropertyFunction,mt=v.parseRelationalExpression,Qt=v.parseStatement,vt=v.parseShiftExpression,Wt=v.parseSwitchCase,ht=v.parseUnaryExpression,At=v.parseVariableDeclaration,Lt=v.parseVariableIdentifier;typeof v.scanRegExp=="function"&&(j=v.advance,H=v.scanRegExp)}function wn(e){var t=e.length,n=[],r;for(r=0;r<t;++r)n[r]=e.charAt(r);return n}function
  En(e,t){var n,r;r=String,typeof e!="string"&&!(e instanceof String)&&(e=r(e)),u=e,f=0,l=u.length>0?1:0,c=0,h=u.length,p=null,d={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1},v={},typeof t!="undefined"&&(v.range=typeof t.range=="boolean"&&t.range,v.loc=typeof t.loc=="boolean"&&t.loc,v.raw=typeof t.raw=="boolean"&&t.raw,typeof t.tokens=="boolean"&&t.tokens&&(v.tokens=[]),typeof t.comment=="boolean"&&t.comment&&(v.comments=[]),typeof t.tolerant=="boolean"&&t.tolerant&&(v.errors=[])),h>0&&typeof u[0]=="undefined"&&(e instanceof String&&(u=e.valueOf()),typeof u[0]=="undefined"&&(u=wn(e))),yn();try{n=nn(),typeof v.comments!="undefined"&&(on(),n.comments=v.comments),typeof v.tokens!="undefined"&&(fn(),n.tokens=v.tokens),typeof v.errors!="undefined"&&(n.errors=v.errors);if(v.range||v.loc)n.body=mn(n.body)}catch(i){throw i}finally{bn(),v={}}return n}var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v;t={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctu
 ator:7,StringLiteral:8},n={},n[t.BooleanLiteral]="Boolean",n[t.EOF]="<end>",n[t.Identifier]="Identifier",n[t.Keyword]="Keyword",n[t.NullLiteral]="Null",n[t.NumericLiteral]="Numeric",n[t.Punctuator]="Punctuator",n[t.StringLiteral]="String",r={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",Mem
 berExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},i={Data:1,Get:2,Set:4},s={UnexpectedToken:"Unexpected token %0",UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",In
 validLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictDelete:"D
 elete of an unqualified identifier in strict mode.",StrictDuplicateProperty:"Duplicate data property in object literal not allowed in strict mode",AccessorDataProperty:"Object literal may not have data and accessor property with the same name",AccessorGetSet:"Object literal may not have multiple get/set accessors with the same name",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictReservedWord:"Use of future reserved word in strict mode"},o={NonAsciiIdentifierStart:new RegExp("[\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u062
 0-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\
 u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18
 f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0
 -\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]"),NonAsciiIdentifierPart:new RegExp("[\u00aa\u0
 0b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9
 \u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0
 dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u
 1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u30
 9a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-
 \uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]")},typeof "esprima"[0]=="undefined"&&(g=function(t,n){return u.slice(t,n).join("")}),e.version="1.0.4",e.parse=En,e.Syntax=function(){var e,t={};typeof Object.create=="function"&&(t=Object.create(null));for(e in r)r.hasOwnProperty(e)&&(t[e]=r[e]);return typeof Object.freeze=="function"&&Object.freeze(t),t}()})})(null),function(e,t){function o(e,t,n){function o(t){n[e.range[0]]=t;for(var r=e.range[0]+1;r<e.range[1];r++)n[r]=""}if(!e.range)return;e.parent=t,e.source=function(){return n.slice(e.range[0],e.range[1]).join("")};if(e.update&&typeof e.update=="object"){var s=e.update;i(r(s),function(e){o[e]=s[e]}),e.update=o}else e.update=o}var n=e("esprima").parse,r=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t},i=function(e,t){if(e.forEach)return e.forEach(t);for(var n=0;n<e.length;n++)t.call(e,e[n],n,e)},s=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"};t.exports=func
 tion(e,t,u){typeof t=="function"&&(u=t,t={}),typeof e=="object"&&(t=e,e=t.source,delete t.source),e=e===undefined?t.source:e,t.range=!0,typeof e!="string"&&(e=String(e));var a=n(e,t),f={chunks:e.split(""),toString:function(){return f.chunks.join("")},inspect:function(){return f.toString()}},l=0;return function c(e,t){o(e,t,f.chunks),i(r(e),function(t){if(t==="parent")return;var n=e[t];s(n)?i(n,function(t){t&&typeof t.type=="string"&&c(t,e)}):n&&typeof n.type=="string"&&(o(n,e,f.chunks),c(n,e))}),u(e)}(a,undefined),f},window.falafel=t.exports}(function(){return{parse:esprima.parse}},{exports:{}});var inBrowser=typeof window!="undefined"&&this===window,parseAndModify=inBrowser?window.falafel:require("falafel");(inBrowser?window:exports).blanket=function(){var e=["ExpressionStatement","BreakStatement","ContinueStatement","VariableDeclaration","ReturnStatement","ThrowStatement","TryStatement","FunctionDeclaration","IfStatement","WhileStatement","DoWhileStatement","ForStatement","ForInSt
 atement","SwitchStatement","WithStatement"],t=["IfStatement","WhileStatement","DoWhileStatement","ForStatement","ForInStatement","WithStatement"],n,r=Math.floor(Math.random()*1e3),i={},s={reporter:null,adapter:null,filter:null,customVariable:null,loader:null,ignoreScriptError:!1,existingRequireJS:!1,autoStart:!1,timeout:180,ignoreCors:!1,branchTracking:!1,sourceURL:!1,debug:!1,engineOnly:!1,testReadyCallback:null,commonJS:!1,instrumentCache:!1,modulePattern:null};return inBrowser&&typeof window.blanket!="undefined"&&(n=window.blanket.noConflict()),_blanket={noConflict:function(){return n?n:_blanket},_getCopyNumber:function(){return r},extend:function(e){_blanket._extend(_blanket,e)},_extend:function(e,t){if(t)for(var n in t)e[n]instanceof Object&&typeof e[n]!="function"?_blanket._extend(e[n],t[n]):e[n]=t[n]},getCovVar:function(){var e=_blanket.options("customVariable");return e?(_blanket.options("debug")&&console.log("BLANKET-Using custom tracking variable:",e),inBrowser?"window."+e
 :e):inBrowser?"window._$blanket":"_$jscoverage"},options:function(e,t){if(typeof e!="string")_blanket._extend(s,e);else{if(typeof t=="undefined")return s[e];s[e]=t}},instrument:function(e,t){var n=e.inputFile,r=e.inputFileName;if(_blanket.options("instrumentCache")&&sessionStorage&&sessionStorage.getItem("blanket_instrument_store-"+r))_blanket.options("debug")&&console.log("BLANKET-Reading instrumentation from cache: ",r),t(sessionStorage.getItem("blanket_instrument_store-"+r));else{var i=_blanket._prepareSource(n);_blanket._trackingArraySetup=[];var s=parseAndModify(n,{loc:!0,comment:!0},_blanket._addTracking(r));s=_blanket._trackingSetup(r,i)+s,_blanket.options("sourceURL")&&(s+="\n//@ sourceURL="+r.replace("http://","")),_blanket.options("debug")&&console.log("BLANKET-Instrumented file: ",r),_blanket.options("instrumentCache")&&sessionStorage&&(_blanket.options("debug")&&console.log("BLANKET-Saving instrumentation to cache: ",r),sessionStorage.setItem("blanket_instrument_store-"+
 r,s)),t(s)}},_trackingArraySetup:[],_branchingArraySetup:[],_prepareSource:function(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/(\r\n|\n|\r)/gm,"\n").split("\n")},_trackingSetup:function(e,t){var n=_blanket.options("branchTracking"),r=t.join("',\n'"),i="",s=_blanket.getCovVar();return i+="if (typeof "+s+" === 'undefined') "+s+" = {};\n",n&&(i+="var _$branchFcn=function(f,l,c,r){ ",i+="if (!!r) { ",i+=s+"[f].branchData[l][c][0] = "+s+"[f].branchData[l][c][0] || [];",i+=s+"[f].branchData[l][c][0].push(r); }",i+="else { ",i+=s+"[f].branchData[l][c][1] = "+s+"[f].branchData[l][c][1] || [];",i+=s+"[f].branchData[l][c][1].push(r); }",i+="return r;};\n"),i+="if (typeof "+s+"['"+e+"'] === 'undefined'){",i+=s+"['"+e+"']=[];\n",n&&(i+=s+"['"+e+"'].branchData=[];\n"),i+=s+"['"+e+"'].source=['"+r+"'];\n",_blanket._trackingArraySetup.sort(function(e,t){return parseInt(e,10)>parseInt(t,10)}).forEach(function(t){i+=s+"['"+e+"']["+t+"]=0;\n"}),n&&_blanket._branchingArraySetup.sor
 t(function(e,t){return e.line>t.line}).sort(function(e,t){return e.column>t.column}).forEach(function(t){t.file===e&&(i+="if (typeof "+s+"['"+e+"'].branchData["+t.line+"] === 'undefined'){\n",i+=s+"['"+e+"'].branchData["+t.line+"]=[];\n",i+="}",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"] = [];\n",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"].consequent = "+JSON.stringify(t.consequent)+";\n",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"].alternate = "+JSON.stringify(t.alternate)+";\n")}),i+="}",i},_blockifyIf:function(e){if(t.indexOf(e.type)>-1){var n=e.consequent||e.body,r=e.alternate;r&&r.type!=="BlockStatement"&&r.update("{\n"+r.source()+"}\n"),n&&n.type!=="BlockStatement"&&n.update("{\n"+n.source()+"}\n")}},_trackBranch:function(e,t){var n=e.loc.start.line,r=e.loc.start.column;_blanket._branchingArraySetup.push({line:n,column:r,file:t,consequent:e.consequent.loc,alternate:e.alternate.loc});var i="_$branchFcn('"+t+"',"+n+","+r+","+e.test.source()+")?"+e.conse
 quent.source()+":"+e.alternate.source();e.update(i)},_addTracking:function(t){var n=_blanket.getCovVar();return function(r){_blanket._blockifyIf(r);if(e.indexOf(r.type)>-1&&r.parent.type!=="LabeledStatement"){_blanket._checkDefs(r,t);if(r.type==="VariableDeclaration"&&(r.parent.type==="ForStatement"||r.parent.type==="ForInStatement"))return;if(!r.loc||!r.loc.start)throw new Error("The instrumenter encountered a node with no location: "+Object.keys(r));r.update(n+"['"+t+"']["+r.loc.start.line+"]++;\n"+r.source()),_blanket._trackingArraySetup.push(r.loc.start.line)}else _blanket.options("branchTracking")&&r.type==="ConditionalExpression"&&_blanket._trackBranch(r,t)}},_checkDefs:function(e,t){if(inBrowser){e.type==="VariableDeclaration"&&e.declarations&&e.declarations.forEach(function(n){if(n.id.name==="window")throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  "+t+":"+e.loc.start.line)}),e.type==="FunctionDeclaration"&&e.params&&e.params.forEach(func
 tion(n){if(n.name==="window")throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  "+t+":"+e.loc.start.line)});if(e.type==="ExpressionStatement"&&e.expression&&e.expression.left&&e.expression.left.object&&e.expression.left.property&&e.expression.left.object.name+"."+e.expression.left.property.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in  "+t+":"+e.loc.start.line)}else if(e.type==="ExpressionStatement"&&e.expression&&e.expression.left&&!e.expression.left.object&&!e.expression.left.property&&e.expression.left.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in  "+t+":"+e.loc.start.line)},setupCoverage:function(){i.instrumentation="blanket",i.stats={suites:0,tests:0,passes:0,pending:0,failures:0,start:new Date}},_checkIfSetup:function(){if(!i.stats)throw new Error("You must call blanket.setupCoverage() first.")},onTestStart:fun
 ction(){_blanket.options("debug")&&console.log("BLANKET-Test event started"),this._checkIfSetup(),i.stats.tests++,i.stats.pending++},onTestDone:function(e,t){this._checkIfSetup(),t===e?i.stats.passes++:i.stats.failures++,i.stats.pending--},onModuleStart:function(){this._checkIfSetup(),i.stats.suites++},onTestsDone:function(){_blanket.options("debug")&&console.log("BLANKET-Test event done"),this._checkIfSetup(),i.stats.end=new Date,inBrowser?this.report(i):(_blanket.options("branchTracking")||delete (inBrowser?window:global)[_blanket.getCovVar()].branchFcn,this.options("reporter").call(this,i))}},_blanket}(),function(e){var t=e.options;e.extend({outstandingRequireFiles:[],options:function(n,r){var i={};if(typeof n!="string")t(n),i=n;else{if(typeof r=="undefined")return t(n);t(n,r),i[n]=r}i.adapter&&e._loadFile(i.adapter),i.loader&&e._loadFile(i.loader)},requiringFile:function(t,n){typeof t=="undefined"?e.outstandingRequireFiles=[]:typeof n=="undefined"?e.outstandingRequireFiles.push(
 t):e.outstandingRequireFiles.splice(e.outstandingRequireFiles.indexOf(t),1)},requireFilesLoaded:function(){return e.outstandingRequireFiles.length===0},showManualLoader:function(){if(document.getElementById("blanketLoaderDialog"))return;var e="<div class='blanketDialogOverlay'>";e+="&nbsp;</div>",e+="<div class='blanketDialogVerticalOffset'>",e+="<div class='blanketDialogBox'>",e+="<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files.  ",e+="<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ",e+="<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari).",e+="<br>",typeof FileReader!="undefin
 ed"&&(e+="<br>Or, try the experimental loader.  When prompted, simply click on the directory containing all the source files you want covered.",e+="<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>",e+="<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>"),e+="<br><span style='float:right;cursor:pointer;'  onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>",e+="<div style='clear:both'></div>",e+="</div></div>";var t=".blanketDialogWrapper {";t+="display:block;",t+="position:fixed;",t+="z-index:40001; }",t+=".blanketDialogOverlay {",t+="position:fixed;",t+="width:100%;",t+="height:100%;",t+="background-color:black;",t+="opacity:.5; ",t+="-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ",t+="filter:alpha(o
 pacity=50); ",t+="z-index:40001; }",t+=".blanketDialogVerticalOffset { ",t+="position:fixed;",t+="top:30%;",t+="width:100%;",t+="z-index:40002; }",t+=".blanketDialogBox { ",t+="width:405px; ",t+="position:relative;",t+="margin:0 auto;",t+="background-color:white;",t+="padding:10px;",t+="border:1px solid black; }";var n=document.createElement("style");n.innerHTML=t,document.head.appendChild(n);var r=document.createElement("div");r.id="blanketLoaderDialog",r.className="blanketDialogWrapper",r.innerHTML=e,document.body.insertBefore(r,document.body.firstChild)},manualFileLoader:function(e){function o(e){var t=new FileReader;t.onload=s,t.readAsText(e)}var t=Array.prototype.slice;e=t.call(e).filter(function(e){return e.type!==""});var n=e.length-1,r=0,i={};sessionStorage.blanketSessionLoader&&(i=JSON.parse(sessionStorage.blanketSessionLoader));var s=function(t){var s=t.currentTarget.result,u=e[r],a=u.webkitRelativePath&&u.webkitRelativePath!==""?u.webkitRelativePath:u.name;i[a]=s,r++,r===
 n?(sessionStorage.setItem("blanketSessionLoader",JSON.stringify(i)),document.location.reload()):o(e[r])};o(e[r])},_loadFile:function(t){if(typeof t!="undefined"){var n=new XMLHttpRequest;n.open("GET",t,!1),n.send(),e._addScript(n.responseText)}},_addScript:function(e){var t=document.createElement("script");t.type="text/javascript",t.text=e,(document.body||document.getElementsByTagName("head")[0]).appendChild(t)},hasAdapter:function(t){return e.options("adapter")!==null},report:function(t){document.getElementById("blanketLoaderDialog")||(e.blanketSession=null),t.files=window._$blanket;var n=blanket.options("commonJS")?blanket._commonjs.require:window.require;if(!t.files||!Object.keys(t.files).length){e.options("debug")&&console.log("BLANKET-Reporting No files were instrumented.");return}typeof t.files.branchFcn!="undefined"&&delete t.files.branchFcn;if(typeof e.options("reporter")=="string")e._loadFile(e.options("reporter")),e.customReporter(t,e.options("reporter_options"));else if(t
 ypeof e.options("reporter")=="function")e.options("reporter")(t,e.options("reporter_options"));else{if(typeof e.defaultReporter!="function")throw new Error("no reporter defined.");e.defaultReporter(t,e.options("reporter_options"))}},_bindStartTestRunner:function(e,t){e?e(t):window.addEventListener("load",t,!1)},_loadSourceFiles:function(t){function r(e){var t=Object.create(Object.getPrototypeOf(e)),n=Object.getOwnPropertyNames(e);return n.forEach(function(n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r)}),t}var n=blanket.options("commonJS")?blanket._commonjs.require:window.require;e.options("debug")&&console.log("BLANKET-Collecting page scripts");var i=e.utils.collectPageScripts();if(i.length===0)t();else{sessionStorage.blanketSessionLoader&&(e.blanketSession=JSON.parse(sessionStorage.blanketSessionLoader)),i.forEach(function(t,n){e.utils.cache[t]={loaded:!1}});var s=-1;e.utils.loadAll(function(e){return e?typeof i[s+1]!="undefined":(s++,s>=i.length?null:i[
 s])},t)}},beforeStartTestRunner:function(t){t=t||{},t.checkRequirejs=typeof t.checkRequirejs=="undefined"?!0:t.checkRequirejs,t.callback=t.callback||function(){},t.coverage=typeof t.coverage=="undefined"?!0:t.coverage,t.coverage?e._bindStartTestRunner(t.bindEvent,function(){e._loadSourceFiles(function(){var n=function(){return t.condition?t.condition():e.requireFilesLoaded()},r=function(){if(n()){e.options("debug")&&console.log("BLANKET-All files loaded, init start test runner callback.");var i=e.options("testReadyCallback");i?typeof i=="function"?i(t.callback):typeof i=="string"&&(e._addScript(i),t.callback()):t.callback()}else setTimeout(r,13)};r()})}):t.callback()},utils:{qualifyURL:function(e){var t=document.createElement("a");return t.href=e,t.href}}})}(blanket),blanket.defaultReporter=function(e){function l(e){var t=document.getElementById(e);t.style.display==="block"?t.style.display="none":t.style.display="block"}function d(e){return e.replace(/\&/g,"&amp;").replace(/</g,"&lt
 ;").replace(/\>/g,"&gt;").replace(/\"/g,"&quot;").replace(/\'/g,"&apos;")}function v(e,t){var n=t?0:1;return typeof e=="undefined"||typeof e===null||typeof e[n]=="undefined"?!1:e[n].length>0}function g(e,t,n,r,i){var s="",o="";if(m.length>0){s+="<span class='"+(v(m[0][1],m[0][1].consequent===m[0][0])?"branchOkay":"branchWarning")+"'>";if(m[0][0].end.line===i){s+=d(t.slice(0,m[0][0].end.column))+"</span>",t=t.slice(m[0][0].end.column),m.shift();if(m.length>0){s+="<span class='"+(v(m[0][1],!1)?"branchOkay":"branchWarning")+"'>";if(m[0][0].end.line===i){s+=d(t.slice(0,m[0][0].end.column))+"</span>",t=t.slice(m[0][0].end.column),m.shift();if(!n)return{src:s+d(t),cols:n}}else{if(!n)return{src:s+d(t)+"</span>",cols:n};o="</span>"}}else if(!n)return{src:s+d(t),cols:n}}else{if(!n)return{src:s+d(t)+"</span>",cols:n};o="</span>"}}var u=n[e],a=u.consequent;if(a.start.line>i)m.unshift([u.alternate,u]),m.unshift([a,u]),t=d(t);else{var f="<span class='"+(v(u,!0)?"branchOkay":"branchWarning")+"'>"
 ;s+=d(t.slice(0,a.start.column-r))+f;if(n.length>e+1&&n[e+1].consequent.start.line===i&&n[e+1].consequent.start.column-r<n[e].consequent.end.column-r){var l=g(e+1,t.slice(a.start.column-r,a.end.column-r),n,a.start.column-r,i);s+=l.src,n=l.cols,n[e+1]=n[e+2],n.length--}else s+=d(t.slice(a.start.column-r,a.end.column-r));s+="</span>";var c=u.alternate;if(c.start.line>i)s+=d(t.slice(a.end.column-r)),m.unshift([c,u]);else{s+=d(t.slice(a.end.column-r,c.start.column-r)),f="<span class='"+(v(u,!1)?"branchOkay":"branchWarning")+"'>",s+=f;if(n.length>e+1&&n[e+1].consequent.start.line===i&&n[e+1].consequent.start.column-r<n[e].alternate.end.column-r){var h=g(e+1,t.slice(c.start.column-r,c.end.column-r),n,c.start.column-r,i);s+=h.src,n=h.cols,n[e+1]=n[e+2],n.length--}else s+=d(t.slice(c.start.column-r,c.end.column-r));s+="</span>",s+=d(t.slice(c.end.column-r)),t=s}}return{src:t+o,cols:n}}var t="#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 
 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;}  #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:y
 ellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",n=60,r=document.head,i=0,s=document.body,o,u=Object.keys(e.files).some(function(t){return typeof e.files[t].branchData!="undefined"}),a="<div id='blanket-main'><div class='blanket bl-title'><div class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</div><div class='bl-cl rs'>Coverage (%)</div><div class='bl-cl rs'>Covered/Total Smts.</div>"+(u?"<div class='bl-cl rs'>Covered/Total Branches</div>":"")+"<div style='clear:both;'></div></div>",f="<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{file}}</a></div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+(u?"<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>":"")+"<div id='file-{{fileNumber}}'
  class='bl-source' style='display:none;'>{{source}}</div><div style='clear:both;'></div></div>";grandTotalTemplate="<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>{{rowTitle}}</div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+(u?"<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>":"")+"<div style='clear:both;'></div></div>";var c=document.createElement("script");c.type="text/javascript",c.text=l.toString().replace("function "+l.name,"function blanket_toggleSource"),s.appendChild(c);var h=function(e,t){return Math.round(e/t*100*100)/100},p=function(e,t,n){var r=document.createElement(e);r.innerHTML=n,t.appendChild(r)},m=[],y=function(e){return typeof e!="undefined"},b=e.files,w={totalSmts:0,numberOfFilesCovered:0,passedBranches:0,totalBranches:0,moduleTotalStatements:{},moduleTotalCoveredStatements:{},moduleTotalBranches:{},moduleTotalCoveredBranches:{}},E=_blanket.options("modulePattern"),
 S=E?new RegExp(E):null;for(var x in b){i++;var T=b[x],N=0,C=0,k=[],L,A=[];for(L=0;L<T.source.length;L+=1){var O=T.source[L];if(m.length>0||typeof T.branchData!="undefined")if(typeof T.branchData[L+1]!="undefined"){var M=T.branchData[L+1].filter(y),_=0;O=g(_,O,M,0,L+1).src}else m.length?O=g(0,O,null,0,L+1).src:O=d(O);else O=d(O);var D="";T[L+1]?(C+=1,N+=1,D="hit"):T[L+1]===0&&(N++,D="miss"),k[L+1]="<div class='"+D+"'><span class=''>"+(L+1)+"</span>"+O+"</div>"}w.totalSmts+=N,w.numberOfFilesCovered+=C;var P=0,H=0;if(typeof T.branchData!="undefined")for(var B=0;B<T.branchData.length;B++)if(typeof T.branchData[B]!="undefined")for(var j=0;j<T.branchData[B].length;j++)typeof T.branchData[B][j]!="undefined"&&(P++,typeof T.branchData[B][j][0]!="undefined"&&T.branchData[B][j][0].length>0&&typeof T.branchData[B][j][1]!="undefined"&&T.branchData[B][j][1].length>0&&H++);w.passedBranches+=H,w.totalBranches+=P;if(S){var F=x.match(S)[1];w.moduleTotalStatements.hasOwnProperty(F)||(w.moduleTotalStat
 ements[F]=0,w.moduleTotalCoveredStatements[F]=0),w.moduleTotalStatements[F]+=N,w.moduleTotalCoveredStatements[F]+=C,w.moduleTotalBranches.hasOwnProperty(F)||(w.moduleTotalBranches[F]=0,w.moduleTotalCoveredBranches[F]=0),w.moduleTotalBranches[F]+=P,w.moduleTotalCoveredBranches[F]+=H}var I=h(C,N),q=f.replace("{{file}}",x).replace("{{percentage}}",I).replace("{{numberCovered}}",C).replace(/\{\{fileNumber\}\}/g,i).replace("{{totalSmts}}",N).replace("{{totalBranches}}",P).replace("{{passedBranches}}",H).replace("{{source}}",k.join(" "));I<n?q=q.replace("{{statusclass}}","bl-error"):q=q.replace("{{statusclass}}","bl-success"),a+=q}var R=function(e,t,r,i,s){var o=h(t,e),u=o<n?"bl-error":"bl-success",f=s?"Total for module: "+s:"Global total",l=grandTotalTemplate.replace("{{rowTitle}}",f).replace("{{percentage}}",o).replace("{{numberCovered}}",t).replace("{{totalSmts}}",e).replace("{{passedBranches}}",i).replace("{{totalBranches}}",r).replace("{{statusclass}}",u);a+=l};if(S)for(var U in w.mo
 duleTotalStatements)if(w.moduleTotalStatements.hasOwnProperty(U)){var z=w.moduleTotalStatements[U],W=w.moduleTotalCoveredStatements[U],X=w.moduleTotalBranches[U],V=w.moduleTotalCoveredBranches[U];R(z,W,X,V,U)}R(w.totalSmts,w.numberOfFilesCovered,w.totalBranches,w.passedBranches,null),a+="</div>",p("style",r,t),document.getElementById("blanket-main")?document.getElementById("blanket-main").innerHTML=a.slice(23,-6):p("div",s,a)},function(){var e={},t=Array.prototype.slice,n=t.call(document.scripts);t.call(n[n.length-1].attributes).forEach(function(t){t.nodeName==="data-cover-only"&&(e.filter=t.nodeValue),t.nodeName==="data-cover-never"&&(e.antifilter=t.nodeValue),t.nodeName==="data-cover-reporter"&&(e.reporter=t.nodeValue),t.nodeName==="data-cover-adapter"&&(e.adapter=t.nodeValue),t.nodeName==="data-cover-loader"&&(e.loader=t.nodeValue),t.nodeName==="data-cover-timeout"&&(e.timeout=t.nodeValue),t.nodeName==="data-cover-modulepattern"&&(e.modulePattern=t.nodeValue);if(t.nodeName==="dat
 a-cover-reporter-options")try{e.reporter_options=JSON.parse(t.nodeValue)}catch(n){if(blanket.options("debug"))throw new Error("Invalid reporter options.  Must be a valid stringified JSON object.")}t.nodeName==="data-cover-testReadyCallback"&&(e.testReadyCallback=t.nodeValue),t.nodeName==="data-cover-customVariable"&&(e.customVariable=t.nodeValue);if(t.nodeName==="data-cover-flags"){var r=" "+t.nodeValue+" ";r.indexOf(" ignoreError ")>-1&&(e.ignoreScriptError=!0),r.indexOf(" autoStart ")>-1&&(e.autoStart=!0),r.indexOf(" ignoreCors ")>-1&&(e.ignoreCors=!0),r.indexOf(" branchTracking ")>-1&&(e.branchTracking=!0),r.indexOf(" sourceURL ")>-1&&(e.sourceURL=!0),r.indexOf(" debug ")>-1&&(e.debug=!0),r.indexOf(" engineOnly ")>-1&&(e.engineOnly=!0),r.indexOf(" commonJS ")>-1&&(e.commonJS=!0),r.indexOf(" instrumentCache ")>-1&&(e.instrumentCache=!0)}}),blanket.options(e),typeof requirejs!="undefined"&&blanket.options("existingRequireJS",!0),blanket.options("commonJS")&&(blanket._commonjs={})}(
 ),function(e){e.extend({utils:{normalizeBackslashes:function(e){return e.replace(/\\/g,"/")},matchPatternAttribute:function(t,n){if(typeof n=="string"){if(n.indexOf("[")===0){var r=n.slice(1,n.length-1).split(",");return r.some(function(n){return e.utils.matchPatternAttribute(t,e.utils.normalizeBackslashes(n.slice(1,-1)))})}if(n.indexOf("//")===0){var i=n.slice(2,n.lastIndexOf("/")),s=n.slice(n.lastIndexOf("/")+1),o=new RegExp(i,s);return o.test(t)}return n.indexOf("#")===0?window[n.slice(1)].call(window,t):t.indexOf(e.utils.normalizeBackslashes(n))>-1}if(n instanceof Array)return n.some(function(n){return e.utils.matchPatternAttribute(t,n)});if(n instanceof RegExp)return n.test(t);if(typeof n=="function")return n.call(window,t)},blanketEval:function(t){e._addScript(t)},collectPageScripts:function(){var t=Array.prototype.slice,n=t.call(document.scripts),r=[],i=[],s=e.options("filter");if(s!=null){var o=e.options("antifilter");r=t.call(document.scripts).filter(function(n){return t.ca
 ll(n.attributes).filter(function(t){return t.nodeName==="src"&&e.utils.matchPatternAttribute(t.nodeValue,s)&&(typeof o=="undefined"||!e.utils.matchPatternAttribute(t.nodeValue,o))}).length===1})}else r=t.call(document.querySelectorAll("script[data-cover]"));return i=r.map(function(n){return e.utils.qualifyURL(t.call(n.attributes).filter(function(e){return e.nodeName==="src"})[0].nodeValue)}),s||e.options("filter","['"+i.join("','")+"']"),i},loadAll:function(t,n,r){var i=t(),s=e.utils.scriptIsLoaded(i,e.utils.ifOrdered,t,n);if(!e.utils.cache[i]||!e.utils.cache[i].loaded){var o=function(){e.options("debug")&&console.log("BLANKET-Mark script:"+i+", as loaded and move to next script."),s()},u=function(t){e.options("debug")&&console.log("BLANKET-File loading finished"),typeof t!="undefined"&&(e.options("debug")&&console.log("BLANKET-Add file to DOM."),e._addScript(t)),o()};e.utils.attachScript({url:i},function(t){e.utils.processFile(t,i,u,u)})}else s()},attachScript:function(t,n){var r=e
 .options("timeout")||3e3;setTimeout(function(){if(!e.utils.cache[t.url].loaded)throw new Error("error loading source script")},r),e.utils.getFile(t.url,n,function(){throw new Error("error loading source script")})},ifOrdered:function(t,n){var r=t(!0);r?e.utils.loadAll(t,n):n(new Error("Error in loading chain."))},scriptIsLoaded:function(t,n,r,i){return e.options("debug")&&console.log("BLANKET-Returning function"),function(){e.options("debug")&&console.log("BLANKET-Marking file as loaded: "+t),e.utils.cache[t].loaded=!0,e.utils.allLoaded()?(e.options("debug")&&console.log("BLANKET-All files loaded"),i()):n&&(e.options("debug")&&console.log("BLANKET-Load next file."),n(r,i))}},cache:{},allLoaded:function(){var t=Object.keys(e.utils.cache);for(var n=0;n<t.length;n++)if(!e.utils.cache[t[n]].loaded)return!1;return!0},processFile:function(t,n,r,i){var s=e.options("filter"),o=e.options("antifilter");typeof o!="undefined"&&e.utils.matchPatternAttribute(n,o)?(i(t),e.options("debug")&&console
 .log("BLANKET-File will never be instrumented:"+n),e.requiringFile(n,!0)):e.utils.matchPatternAttribute(n,s)?(e.options("debug")&&console.log("BLANKET-Attempting instrument of:"+n),e.instrument({inputFile:t,inputFileName:n},function(i){try{e.options("debug")&&console.log("BLANKET-instrument of:"+n+" was successfull."),e.utils.blanketEval(i),r(),e.requiringFile(n,!0)}catch(s){if(!e.options("ignoreScriptError"))throw new Error("Error parsing instrumented code: "+s);e.options("debug")&&console.log("BLANKET-There was an error loading the file:"+n),r(t),e.requiringFile(n,!0)}})):(e.options("debug")&&console.log("BLANKET-Loading (without instrumenting) the file:"+n),i(t),e.requiringFile(n,!0))},cacheXhrConstructor:function(){var e,t,n,r;if(typeof XMLHttpRequest!="undefined")e=XMLHttpRequest,this.createXhr=function(){return new e};else if(typeof ActiveXObject!="undefined"){e=ActiveXObject;for(n=0;n<3;n+=1){r=progIds[n];try{new ActiveXObject(r);break}catch(i){}}this.createXhr=function(){ret
 urn new e(r)}}},craeteXhr:function(){throw new Error("cacheXhrConstructor is supposed to overwrite this function.")},getFile:function(t,n,r,i){var s=!1;if(e.blanketSession){var o=Object.keys(e.blanketSession);for(var u=0;u<o.length;u++){var a=o[u];if(t.indexOf(a)>-1){n(e.blanketSession[a]),s=!0;return}}}if(!s){var f=e.utils.createXhr();f.open("GET",t,!0),i&&i(f,t),f.onreadystatechange=function(e){var i,s;f.readyState===4&&(i=f.status,i>399&&i<600?(s=new Error(t+" HTTP status: "+i),s.xhr=f,r(s)):n(f.responseText))};try{f.send(null)}catch(l){if(!l.code||l.code!==101&&l.code!==1012||e.options("ignoreCors")!==!1)throw l;e.showManualLoader()}}}}}),function(){var t=blanket.options("commonJS")?blanket._commonjs.require:window.require,n=blanket.options("commonJS")?blanket._commonjs.requirejs:window.requirejs;!e.options("engineOnly")&&e.options("existingRequireJS")&&(e.utils.oldloader=n.load,n.load=function(t,n,r){e.requiringFile(r),e.utils.getFile(r,function(i){e.utils.processFile(i,r,funct
 ion(){t.completeLoad(n)},function(){e.utils.oldloader(t,n,r)})},function(t){throw e.requiringFile(),t})}),e.utils.cacheXhrConstructor()}()}(blanket),function(){if(!mocha)throw new Exception("mocha library does not exist in global namespace!");var e=mocha._reporter,t=function(t){t.on("start",function(){blanket.setupCoverage()}),t.on("end",function(){blanket.onTestsDone()}),t.on("suite",function(){blanket.onModuleStart()}),t.on("test",function(){blanket.onTestStart()}),t.on("test end",function(e){blanket.onTestDone(e.parent.tests.length,e.state==="passed")}),e.apply(this,arguments)};mocha.reporter(t);var n=mocha.run,r=null;mocha.run=function(e){r=e,console.log("waiting for blanket...")},blanket.beforeStartTestRunner({callback:function(){blanket.options("existingRequireJS")||n(r),mocha.run=n}})}();


[02/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/mocha.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/mocha.js b/sdks/html5-javascript/tests/resources/js/mocha.js
new file mode 100644
index 0000000..00dcda1
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/mocha.js
@@ -0,0 +1,5341 @@
+;(function(){
+
+
+// CommonJS require()
+
+function require(p){
+    var path = require.resolve(p)
+      , mod = require.modules[path];
+    if (!mod) throw new Error('failed to require "' + p + '"');
+    if (!mod.exports) {
+      mod.exports = {};
+      mod.call(mod.exports, mod, mod.exports, require.relative(path));
+    }
+    return mod.exports;
+  }
+
+require.modules = {};
+
+require.resolve = function (path){
+    var orig = path
+      , reg = path + '.js'
+      , index = path + '/index.js';
+    return require.modules[reg] && reg
+      || require.modules[index] && index
+      || orig;
+  };
+
+require.register = function (path, fn){
+    require.modules[path] = fn;
+  };
+
+require.relative = function (parent) {
+    return function(p){
+      if ('.' != p.charAt(0)) return require(p);
+      
+      var path = parent.split('/')
+        , segs = p.split('/');
+      path.pop();
+      
+      for (var i = 0; i < segs.length; i++) {
+        var seg = segs[i];
+        if ('..' == seg) path.pop();
+        else if ('.' != seg) path.push(seg);
+      }
+
+      return require(path.join('/'));
+    };
+  };
+
+
+require.register("browser/debug.js", function(module, exports, require){
+
+module.exports = function(type){
+  return function(){
+    
+  }
+};
+}); // module: browser/debug.js
+
+require.register("browser/diff.js", function(module, exports, require){
+/* See license.txt for terms of usage */
+
+/*
+ * Text diff implementation.
+ * 
+ * This library supports the following APIS:
+ * JsDiff.diffChars: Character by character diff
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
+ * JsDiff.diffLines: Line based diff
+ * 
+ * JsDiff.diffCss: Diff targeted at CSS content
+ * 
+ * These methods are based on the implementation proposed in
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
+ */
+var JsDiff = (function() {
+  function clonePath(path) {
+    return { newPos: path.newPos, components: path.components.slice(0) };
+  }
+  function removeEmpty(array) {
+    var ret = [];
+    for (var i = 0; i < array.length; i++) {
+      if (array[i]) {
+        ret.push(array[i]);
+      }
+    }
+    return ret;
+  }
+  function escapeHTML(s) {
+    var n = s;
+    n = n.replace(/&/g, "&amp;");
+    n = n.replace(/</g, "&lt;");
+    n = n.replace(/>/g, "&gt;");
+    n = n.replace(/"/g, "&quot;");
+
+    return n;
+  }
+
+
+  var fbDiff = function(ignoreWhitespace) {
+    this.ignoreWhitespace = ignoreWhitespace;
+  };
+  fbDiff.prototype = {
+      diff: function(oldString, newString) {
+        // Handle the identity case (this is due to unrolling editLength == 0
+        if (newString == oldString) {
+          return [{ value: newString }];
+        }
+        if (!newString) {
+          return [{ value: oldString, removed: true }];
+        }
+        if (!oldString) {
+          return [{ value: newString, added: true }];
+        }
+
+        newString = this.tokenize(newString);
+        oldString = this.tokenize(oldString);
+
+        var newLen = newString.length, oldLen = oldString.length;
+        var maxEditLength = newLen + oldLen;
+        var bestPath = [{ newPos: -1, components: [] }];
+
+        // Seed editLength = 0
+        var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
+        if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
+          return bestPath[0].components;
+        }
+
+        for (var editLength = 1; editLength <= maxEditLength; editLength++) {
+          for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
+            var basePath;
+            var addPath = bestPath[diagonalPath-1],
+                removePath = bestPath[diagonalPath+1];
+            oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
+            if (addPath) {
+              // No one else is going to attempt to use this value, clear it
+              bestPath[diagonalPath-1] = undefined;
+            }
+
+            var canAdd = addPath && addPath.newPos+1 < newLen;
+            var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
+            if (!canAdd && !canRemove) {
+              bestPath[diagonalPath] = undefined;
+              continue;
+            }
+
+            // Select the diagonal that we want to branch from. We select the prior
+            // path whose position in the new string is the farthest from the origin
+            // and does not pass the bounds of the diff graph
+            if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
+              basePath = clonePath(removePath);
+              this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
+            } else {
+              basePath = clonePath(addPath);
+              basePath.newPos++;
+              this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
+            }
+
+            var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
+
+            if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
+              return basePath.components;
+            } else {
+              bestPath[diagonalPath] = basePath;
+            }
+          }
+        }
+      },
+
+      pushComponent: function(components, value, added, removed) {
+        var last = components[components.length-1];
+        if (last && last.added === added && last.removed === removed) {
+          // We need to clone here as the component clone operation is just
+          // as shallow array clone
+          components[components.length-1] =
+            {value: this.join(last.value, value), added: added, removed: removed };
+        } else {
+          components.push({value: value, added: added, removed: removed });
+        }
+      },
+      extractCommon: function(basePath, newString, oldString, diagonalPath) {
+        var newLen = newString.length,
+            oldLen = oldString.length,
+            newPos = basePath.newPos,
+            oldPos = newPos - diagonalPath;
+        while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
+          newPos++;
+          oldPos++;
+          
+          this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
+        }
+        basePath.newPos = newPos;
+        return oldPos;
+      },
+
+      equals: function(left, right) {
+        var reWhitespace = /\S/;
+        if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
+          return true;
+        } else {
+          return left == right;
+        }
+      },
+      join: function(left, right) {
+        return left + right;
+      },
+      tokenize: function(value) {
+        return value;
+      }
+  };
+  
+  var CharDiff = new fbDiff();
+  
+  var WordDiff = new fbDiff(true);
+  WordDiff.tokenize = function(value) {
+    return removeEmpty(value.split(/(\s+|\b)/));
+  };
+  
+  var CssDiff = new fbDiff(true);
+  CssDiff.tokenize = function(value) {
+    return removeEmpty(value.split(/([{}:;,]|\s+)/));
+  };
+  
+  var LineDiff = new fbDiff();
+  LineDiff.tokenize = function(value) {
+    return value.split(/^/m);
+  };
+  
+  return {
+    diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
+    diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
+    diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
+
+    diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
+
+    createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
+      var ret = [];
+
+      ret.push("Index: " + fileName);
+      ret.push("===================================================================");
+      ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
+      ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
+
+      var diff = LineDiff.diff(oldStr, newStr);
+      if (!diff[diff.length-1].value) {
+        diff.pop();   // Remove trailing newline add
+      }
+      diff.push({value: "", lines: []});   // Append an empty value to make cleanup easier
+
+      function contextLines(lines) {
+        return lines.map(function(entry) { return ' ' + entry; });
+      }
+      function eofNL(curRange, i, current) {
+        var last = diff[diff.length-2],
+            isLast = i === diff.length-2,
+            isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
+
+        // Figure out if this is the last line for the given file and missing NL
+        if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
+          curRange.push('\\ No newline at end of file');
+        }
+      }
+
+      var oldRangeStart = 0, newRangeStart = 0, curRange = [],
+          oldLine = 1, newLine = 1;
+      for (var i = 0; i < diff.length; i++) {
+        var current = diff[i],
+            lines = current.lines || current.value.replace(/\n$/, "").split("\n");
+        current.lines = lines;
+
+        if (current.added || current.removed) {
+          if (!oldRangeStart) {
+            var prev = diff[i-1];
+            oldRangeStart = oldLine;
+            newRangeStart = newLine;
+            
+            if (prev) {
+              curRange = contextLines(prev.lines.slice(-4));
+              oldRangeStart -= curRange.length;
+              newRangeStart -= curRange.length;
+            }
+          }
+          curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
+          eofNL(curRange, i, current);
+
+          if (current.added) {
+            newLine += lines.length;
+          } else {
+            oldLine += lines.length;
+          }
+        } else {
+          if (oldRangeStart) {
+            // Close out any changes that have been output (or join overlapping)
+            if (lines.length <= 8 && i < diff.length-2) {
+              // Overlapping
+              curRange.push.apply(curRange, contextLines(lines));
+            } else {
+              // end the range and output
+              var contextSize = Math.min(lines.length, 4);
+              ret.push(
+                  "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
+                  + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
+                  + " @@");
+              ret.push.apply(ret, curRange);
+              ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
+              if (lines.length <= 4) {
+                eofNL(ret, i, current);
+              }
+
+              oldRangeStart = 0;  newRangeStart = 0; curRange = [];
+            }
+          }
+          oldLine += lines.length;
+          newLine += lines.length;
+        }
+      }
+
+      return ret.join('\n') + '\n';
+    },
+
+    convertChangesToXML: function(changes){
+      var ret = [];
+      for ( var i = 0; i < changes.length; i++) {
+        var change = changes[i];
+        if (change.added) {
+          ret.push("<ins>");
+        } else if (change.removed) {
+          ret.push("<del>");
+        }
+
+        ret.push(escapeHTML(change.value));
+
+        if (change.added) {
+          ret.push("</ins>");
+        } else if (change.removed) {
+          ret.push("</del>");
+        }
+      }
+      return ret.join("");
+    }
+  };
+})();
+
+if (typeof module !== "undefined") {
+    module.exports = JsDiff;
+}
+
+}); // module: browser/diff.js
+
+require.register("browser/events.js", function(module, exports, require){
+
+/**
+ * Module exports.
+ */
+
+exports.EventEmitter = EventEmitter;
+
+/**
+ * Check if `obj` is an array.
+ */
+
+function isArray(obj) {
+  return '[object Array]' == {}.toString.call(obj);
+}
+
+/**
+ * Event emitter constructor.
+ *
+ * @api public
+ */
+
+function EventEmitter(){};
+
+/**
+ * Adds a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.on = function (name, fn) {
+  if (!this.$events) {
+    this.$events = {};
+  }
+
+  if (!this.$events[name]) {
+    this.$events[name] = fn;
+  } else if (isArray(this.$events[name])) {
+    this.$events[name].push(fn);
+  } else {
+    this.$events[name] = [this.$events[name], fn];
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+/**
+ * Adds a volatile listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.once = function (name, fn) {
+  var self = this;
+
+  function on () {
+    self.removeListener(name, on);
+    fn.apply(this, arguments);
+  };
+
+  on.listener = fn;
+  this.on(name, on);
+
+  return this;
+};
+
+/**
+ * Removes a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeListener = function (name, fn) {
+  if (this.$events && this.$events[name]) {
+    var list = this.$events[name];
+
+    if (isArray(list)) {
+      var pos = -1;
+
+      for (var i = 0, l = list.length; i < l; i++) {
+        if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
+          pos = i;
+          break;
+        }
+      }
+
+      if (pos < 0) {
+        return this;
+      }
+
+      list.splice(pos, 1);
+
+      if (!list.length) {
+        delete this.$events[name];
+      }
+    } else if (list === fn || (list.listener && list.listener === fn)) {
+      delete this.$events[name];
+    }
+  }
+
+  return this;
+};
+
+/**
+ * Removes all listeners for an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeAllListeners = function (name) {
+  if (name === undefined) {
+    this.$events = {};
+    return this;
+  }
+
+  if (this.$events && this.$events[name]) {
+    this.$events[name] = null;
+  }
+
+  return this;
+};
+
+/**
+ * Gets all listeners for a certain event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.listeners = function (name) {
+  if (!this.$events) {
+    this.$events = {};
+  }
+
+  if (!this.$events[name]) {
+    this.$events[name] = [];
+  }
+
+  if (!isArray(this.$events[name])) {
+    this.$events[name] = [this.$events[name]];
+  }
+
+  return this.$events[name];
+};
+
+/**
+ * Emits an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.emit = function (name) {
+  if (!this.$events) {
+    return false;
+  }
+
+  var handler = this.$events[name];
+
+  if (!handler) {
+    return false;
+  }
+
+  var args = [].slice.call(arguments, 1);
+
+  if ('function' == typeof handler) {
+    handler.apply(this, args);
+  } else if (isArray(handler)) {
+    var listeners = handler.slice();
+
+    for (var i = 0, l = listeners.length; i < l; i++) {
+      listeners[i].apply(this, args);
+    }
+  } else {
+    return false;
+  }
+
+  return true;
+};
+}); // module: browser/events.js
+
+require.register("browser/fs.js", function(module, exports, require){
+
+}); // module: browser/fs.js
+
+require.register("browser/path.js", function(module, exports, require){
+
+}); // module: browser/path.js
+
+require.register("browser/progress.js", function(module, exports, require){
+
+/**
+ * Expose `Progress`.
+ */
+
+module.exports = Progress;
+
+/**
+ * Initialize a new `Progress` indicator.
+ */
+
+function Progress() {
+  this.percent = 0;
+  this.size(0);
+  this.fontSize(11);
+  this.font('helvetica, arial, sans-serif');
+}
+
+/**
+ * Set progress size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.size = function(n){
+  this._size = n;
+  return this;
+};
+
+/**
+ * Set text to `str`.
+ *
+ * @param {String} str
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.text = function(str){
+  this._text = str;
+  return this;
+};
+
+/**
+ * Set font size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.fontSize = function(n){
+  this._fontSize = n;
+  return this;
+};
+
+/**
+ * Set font `family`.
+ *
+ * @param {String} family
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.font = function(family){
+  this._font = family;
+  return this;
+};
+
+/**
+ * Update percentage to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.update = function(n){
+  this.percent = n;
+  return this;
+};
+
+/**
+ * Draw on `ctx`.
+ *
+ * @param {CanvasRenderingContext2d} ctx
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.draw = function(ctx){
+  var percent = Math.min(this.percent, 100)
+    , size = this._size
+    , half = size / 2
+    , x = half
+    , y = half
+    , rad = half - 1
+    , fontSize = this._fontSize;
+
+  ctx.font = fontSize + 'px ' + this._font;
+
+  var angle = Math.PI * 2 * (percent / 100);
+  ctx.clearRect(0, 0, size, size);
+
+  // outer circle
+  ctx.strokeStyle = '#9f9f9f';
+  ctx.beginPath();
+  ctx.arc(x, y, rad, 0, angle, false);
+  ctx.stroke();
+
+  // inner circle
+  ctx.strokeStyle = '#eee';
+  ctx.beginPath();
+  ctx.arc(x, y, rad - 1, 0, angle, true);
+  ctx.stroke();
+
+  // text
+  var text = this._text || (percent | 0) + '%'
+    , w = ctx.measureText(text).width;
+
+  ctx.fillText(
+      text
+    , x - w / 2 + 1
+    , y + fontSize / 2 - 1);
+
+  return this;
+};
+
+}); // module: browser/progress.js
+
+require.register("browser/tty.js", function(module, exports, require){
+
+exports.isatty = function(){
+  return true;
+};
+
+exports.getWindowSize = function(){
+  return [window.innerHeight, window.innerWidth];
+};
+}); // module: browser/tty.js
+
+require.register("context.js", function(module, exports, require){
+
+/**
+ * Expose `Context`.
+ */
+
+module.exports = Context;
+
+/**
+ * Initialize a new `Context`.
+ *
+ * @api private
+ */
+
+function Context(){}
+
+/**
+ * Set or get the context `Runnable` to `runnable`.
+ *
+ * @param {Runnable} runnable
+ * @return {Context}
+ * @api private
+ */
+
+Context.prototype.runnable = function(runnable){
+  if (0 == arguments.length) return this._runnable;
+  this.test = this._runnable = runnable;
+  return this;
+};
+
+/**
+ * Set test timeout `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.timeout = function(ms){
+  this.runnable().timeout(ms);
+  return this;
+};
+
+/**
+ * Set test slowness threshold `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.slow = function(ms){
+  this.runnable().slow(ms);
+  return this;
+};
+
+/**
+ * Inspect the context void of `._runnable`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Context.prototype.inspect = function(){
+  return JSON.stringify(this, function(key, val){
+    if ('_runnable' == key) return;
+    if ('test' == key) return;
+    return val;
+  }, 2);
+};
+
+}); // module: context.js
+
+require.register("hook.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+
+/**
+ * Expose `Hook`.
+ */
+
+module.exports = Hook;
+
+/**
+ * Initialize a new `Hook` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Hook(title, fn) {
+  Runnable.call(this, title, fn);
+  this.type = 'hook';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+
+function F(){};
+F.prototype = Runnable.prototype;
+Hook.prototype = new F;
+Hook.prototype.constructor = Hook;
+
+
+/**
+ * Get or set the test `err`.
+ *
+ * @param {Error} err
+ * @return {Error}
+ * @api public
+ */
+
+Hook.prototype.error = function(err){
+  if (0 == arguments.length) {
+    var err = this._error;
+    this._error = null;
+    return err;
+  }
+
+  this._error = err;
+};
+
+
+}); // module: hook.js
+
+require.register("interfaces/bdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * BDD-style interface:
+ * 
+ *      describe('Array', function(){
+ *        describe('#indexOf()', function(){
+ *          it('should return -1 when not present', function(){
+ *
+ *          });
+ *
+ *          it('should return the index when present', function(){
+ *
+ *          });
+ *        });
+ *      });
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context, file, mocha){
+
+    /**
+     * Execute before running tests.
+     */
+
+    context.before = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after running tests.
+     */
+
+    context.after = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.beforeEach = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.afterEach = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`
+     * and callback `fn` containing nested suites
+     * and/or tests.
+     */
+  
+    context.describe = context.context = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+      return suite;
+    };
+
+    /**
+     * Pending describe.
+     */
+
+    context.xdescribe =
+    context.xcontext =
+    context.describe.skip = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suite.pending = true;
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+    };
+
+    /**
+     * Exclusive suite.
+     */
+
+    context.describe.only = function(title, fn){
+      var suite = context.describe(title, fn);
+      mocha.grep(suite.fullTitle());
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.it = context.specify = function(title, fn){
+      var suite = suites[0];
+      if (suite.pending) var fn = null;
+      var test = new Test(title, fn);
+      suite.addTest(test);
+      return test;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.it.only = function(title, fn){
+      var test = context.it(title, fn);
+      mocha.grep(test.fullTitle());
+    };
+
+    /**
+     * Pending test case.
+     */
+
+    context.xit =
+    context.xspecify =
+    context.it.skip = function(title){
+      context.it(title);
+    };
+  });
+};
+
+}); // module: interfaces/bdd.js
+
+require.register("interfaces/exports.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ * 
+ *     exports.Array = {
+ *       '#indexOf()': {
+ *         'should return -1 when the value is not present': function(){
+ *           
+ *         },
+ *
+ *         'should return the correct index when the value is present': function(){
+ *           
+ *         }
+ *       }
+ *     };
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('require', visit);
+
+  function visit(obj) {
+    var suite;
+    for (var key in obj) {
+      if ('function' == typeof obj[key]) {
+        var fn = obj[key];
+        switch (key) {
+          case 'before':
+            suites[0].beforeAll(fn);
+            break;
+          case 'after':
+            suites[0].afterAll(fn);
+            break;
+          case 'beforeEach':
+            suites[0].beforeEach(fn);
+            break;
+          case 'afterEach':
+            suites[0].afterEach(fn);
+            break;
+          default:
+            suites[0].addTest(new Test(key, fn));
+        }
+      } else {
+        var suite = Suite.create(suites[0], key);
+        suites.unshift(suite);
+        visit(obj[key]);
+        suites.shift();
+      }
+    }
+  }
+};
+}); // module: interfaces/exports.js
+
+require.register("interfaces/index.js", function(module, exports, require){
+
+exports.bdd = require('./bdd');
+exports.tdd = require('./tdd');
+exports.qunit = require('./qunit');
+exports.exports = require('./exports');
+
+}); // module: interfaces/index.js
+
+require.register("interfaces/qunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * QUnit-style interface:
+ * 
+ *     suite('Array');
+ *     
+ *     test('#length', function(){
+ *       var arr = [1,2,3];
+ *       ok(arr.length == 3);
+ *     });
+ *     
+ *     test('#indexOf()', function(){
+ *       var arr = [1,2,3];
+ *       ok(arr.indexOf(1) == 0);
+ *       ok(arr.indexOf(2) == 1);
+ *       ok(arr.indexOf(3) == 2);
+ *     });
+ *     
+ *     suite('String');
+ *     
+ *     test('#length', function(){
+ *       ok('foo'.length == 3);
+ *     });
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context){
+
+    /**
+     * Execute before running tests.
+     */
+
+    context.before = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after running tests.
+     */
+
+    context.after = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.beforeEach = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.afterEach = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`.
+     */
+  
+    context.suite = function(title){
+      if (suites.length > 1) suites.shift();
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.test = function(title, fn){
+      suites[0].addTest(new Test(title, fn));
+    };
+  });
+};
+
+}); // module: interfaces/qunit.js
+
+require.register("interfaces/tdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ *
+ *      suite('Array', function(){
+ *        suite('#indexOf()', function(){
+ *          suiteSetup(function(){
+ *
+ *          });
+ *          
+ *          test('should return -1 when not present', function(){
+ *
+ *          });
+ *
+ *          test('should return the index when present', function(){
+ *
+ *          });
+ *
+ *          suiteTeardown(function(){
+ *
+ *          });
+ *        });
+ *      });
+ *
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context, file, mocha){
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.setup = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.teardown = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Execute before the suite.
+     */
+
+    context.suiteSetup = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after the suite.
+     */
+
+    context.suiteTeardown = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`
+     * and callback `fn` containing nested suites
+     * and/or tests.
+     */
+
+    context.suite = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+      return suite;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.suite.only = function(title, fn){
+      var suite = context.suite(title, fn);
+      mocha.grep(suite.fullTitle());
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.test = function(title, fn){
+      var test = new Test(title, fn);
+      suites[0].addTest(test);
+      return test;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.test.only = function(title, fn){
+      var test = context.test(title, fn);
+      mocha.grep(test.fullTitle());
+    };
+
+    /**
+     * Pending test case.
+     */
+
+    context.test.skip = function(title){
+      context.test(title);
+    };
+  });
+};
+
+}); // module: interfaces/tdd.js
+
+require.register("mocha.js", function(module, exports, require){
+/*!
+ * mocha
+ * Copyright(c) 2011 TJ Holowaychuk <tj...@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var path = require('browser/path')
+  , utils = require('./utils');
+
+/**
+ * Expose `Mocha`.
+ */
+
+exports = module.exports = Mocha;
+
+/**
+ * Expose internals.
+ */
+
+exports.utils = utils;
+exports.interfaces = require('./interfaces');
+exports.reporters = require('./reporters');
+exports.Runnable = require('./runnable');
+exports.Context = require('./context');
+exports.Runner = require('./runner');
+exports.Suite = require('./suite');
+exports.Hook = require('./hook');
+exports.Test = require('./test');
+
+/**
+ * Return image `name` path.
+ *
+ * @param {String} name
+ * @return {String}
+ * @api private
+ */
+
+function image(name) {
+  return __dirname + '/../images/' + name + '.png';
+}
+
+/**
+ * Setup mocha with `options`.
+ *
+ * Options:
+ *
+ *   - `ui` name "bdd", "tdd", "exports" etc
+ *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
+ *   - `globals` array of accepted globals
+ *   - `timeout` timeout in milliseconds
+ *   - `bail` bail on the first test failure
+ *   - `slow` milliseconds to wait before considering a test slow
+ *   - `ignoreLeaks` ignore global leaks
+ *   - `grep` string or regexp to filter tests with
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+function Mocha(options) {
+  options = options || {};
+  this.files = [];
+  this.options = options;
+  this.grep(options.grep);
+  this.suite = new exports.Suite('', new exports.Context);
+  this.ui(options.ui);
+  this.bail(options.bail);
+  this.reporter(options.reporter);
+  if (options.timeout) this.timeout(options.timeout);
+  if (options.slow) this.slow(options.slow);
+}
+
+/**
+ * Enable or disable bailing on the first failure.
+ *
+ * @param {Boolean} [bail]
+ * @api public
+ */
+
+Mocha.prototype.bail = function(bail){
+  if (0 == arguments.length) bail = true;
+  this.suite.bail(bail);
+  return this;
+};
+
+/**
+ * Add test `file`.
+ *
+ * @param {String} file
+ * @api public
+ */
+
+Mocha.prototype.addFile = function(file){
+  this.files.push(file);
+  return this;
+};
+
+/**
+ * Set reporter to `reporter`, defaults to "dot".
+ *
+ * @param {String|Function} reporter name or constructor
+ * @api public
+ */
+
+Mocha.prototype.reporter = function(reporter){
+  if ('function' == typeof reporter) {
+    this._reporter = reporter;
+  } else {
+    reporter = reporter || 'dot';
+    try {
+      this._reporter = require('./reporters/' + reporter);
+    } catch (err) {
+      this._reporter = require(reporter);
+    }
+    if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
+  }
+  return this;
+};
+
+/**
+ * Set test UI `name`, defaults to "bdd".
+ *
+ * @param {String} bdd
+ * @api public
+ */
+
+Mocha.prototype.ui = function(name){
+  name = name || 'bdd';
+  this._ui = exports.interfaces[name];
+  if (!this._ui) throw new Error('invalid interface "' + name + '"');
+  this._ui = this._ui(this.suite);
+  return this;
+};
+
+/**
+ * Load registered files.
+ *
+ * @api private
+ */
+
+Mocha.prototype.loadFiles = function(fn){
+  var self = this;
+  var suite = this.suite;
+  var pending = this.files.length;
+  this.files.forEach(function(file){
+    file = path.resolve(file);
+    suite.emit('pre-require', global, file, self);
+    suite.emit('require', require(file), file, self);
+    suite.emit('post-require', global, file, self);
+    --pending || (fn && fn());
+  });
+};
+
+/**
+ * Enable growl support.
+ *
+ * @api private
+ */
+
+Mocha.prototype._growl = function(runner, reporter) {
+  var notify = require('growl');
+
+  runner.on('end', function(){
+    var stats = reporter.stats;
+    if (stats.failures) {
+      var msg = stats.failures + ' of ' + runner.total + ' tests failed';
+      notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
+    } else {
+      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
+          name: 'mocha'
+        , title: 'Passed'
+        , image: image('ok')
+      });
+    }
+  });
+};
+
+/**
+ * Add regexp to grep, if `re` is a string it is escaped.
+ *
+ * @param {RegExp|String} re
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.grep = function(re){
+  this.options.grep = 'string' == typeof re
+    ? new RegExp(utils.escapeRegexp(re))
+    : re;
+  return this;
+};
+
+/**
+ * Invert `.grep()` matches.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.invert = function(){
+  this.options.invert = true;
+  return this;
+};
+
+/**
+ * Ignore global leaks.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.ignoreLeaks = function(){
+  this.options.ignoreLeaks = true;
+  return this;
+};
+
+/**
+ * Enable global leak checking.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.checkLeaks = function(){
+  this.options.ignoreLeaks = false;
+  return this;
+};
+
+/**
+ * Enable growl support.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.growl = function(){
+  this.options.growl = true;
+  return this;
+};
+
+/**
+ * Ignore `globals` array or string.
+ *
+ * @param {Array|String} globals
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.globals = function(globals){
+  this.options.globals = (this.options.globals || []).concat(globals);
+  return this;
+};
+
+/**
+ * Set the timeout in milliseconds.
+ *
+ * @param {Number} timeout
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.timeout = function(timeout){
+  this.suite.timeout(timeout);
+  return this;
+};
+
+/**
+ * Set slowness threshold in milliseconds.
+ *
+ * @param {Number} slow
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.slow = function(slow){
+  this.suite.slow(slow);
+  return this;
+};
+
+/**
+ * Makes all tests async (accepting a callback)
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.asyncOnly = function(){
+  this.options.asyncOnly = true;
+  return this;
+};
+
+/**
+ * Run tests and invoke `fn()` when complete.
+ *
+ * @param {Function} fn
+ * @return {Runner}
+ * @api public
+ */
+
+Mocha.prototype.run = function(fn){
+  if (this.files.length) this.loadFiles();
+  var suite = this.suite;
+  var options = this.options;
+  var runner = new exports.Runner(suite);
+  var reporter = new this._reporter(runner);
+  runner.ignoreLeaks = options.ignoreLeaks;
+  runner.asyncOnly = options.asyncOnly;
+  if (options.grep) runner.grep(options.grep, options.invert);
+  if (options.globals) runner.globals(options.globals);
+  if (options.growl) this._growl(runner, reporter);
+  return runner.run(fn);
+};
+
+}); // module: blanket_mocha.js
+
+require.register("ms.js", function(module, exports, require){
+
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * @param {String|Number} val
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val){
+  if ('string' == typeof val) return parse(val);
+  return format(val);
+}
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
+  if (!m) return;
+  var n = parseFloat(m[1]);
+  var type = (m[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'y':
+      return n * 31557600000;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * 86400000;
+    case 'hours':
+    case 'hour':
+    case 'h':
+      return n * 3600000;
+    case 'minutes':
+    case 'minute':
+    case 'm':
+      return n * 60000;
+    case 'seconds':
+    case 'second':
+    case 's':
+      return n * 1000;
+    case 'ms':
+      return n;
+  }
+}
+
+/**
+ * Format the given `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api public
+ */
+
+function format(ms) {
+  if (ms == d) return Math.round(ms / d) + ' day';
+  if (ms > d) return Math.round(ms / d) + ' days';
+  if (ms == h) return Math.round(ms / h) + ' hour';
+  if (ms > h) return Math.round(ms / h) + ' hours';
+  if (ms == m) return Math.round(ms / m) + ' minute';
+  if (ms > m) return Math.round(ms / m) + ' minutes';
+  if (ms == s) return Math.round(ms / s) + ' second';
+  if (ms > s) return Math.round(ms / s) + ' seconds';
+  return ms + ' ms';
+}
+}); // module: ms.js
+
+require.register("reporters/base.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var tty = require('browser/tty')
+  , diff = require('browser/diff')
+  , ms = require('../ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Check if both stdio streams are associated with a tty.
+ */
+
+var isatty = tty.isatty(1) && tty.isatty(2);
+
+/**
+ * Expose `Base`.
+ */
+
+exports = module.exports = Base;
+
+/**
+ * Enable coloring by default.
+ */
+
+exports.useColors = isatty;
+
+/**
+ * Default color map.
+ */
+
+exports.colors = {
+    'pass': 90
+  , 'fail': 31
+  , 'bright pass': 92
+  , 'bright fail': 91
+  , 'bright yellow': 93
+  , 'pending': 36
+  , 'suite': 0
+  , 'error title': 0
+  , 'error message': 31
+  , 'error stack': 90
+  , 'checkmark': 32
+  , 'fast': 90
+  , 'medium': 33
+  , 'slow': 31
+  , 'green': 32
+  , 'light': 90
+  , 'diff gutter': 90
+  , 'diff added': 42
+  , 'diff removed': 41
+};
+
+/**
+ * Default symbol map.
+ */
+ 
+exports.symbols = {
+  ok: '✓',
+  err: '✖',
+  dot: '․'
+};
+
+// With node.js on Windows: use symbols available in terminal default fonts
+if ('win32' == process.platform) {
+  exports.symbols.ok = '\u221A';
+  exports.symbols.err = '\u00D7';
+  exports.symbols.dot = '.';
+}
+
+/**
+ * Color `str` with the given `type`,
+ * allowing colors to be disabled,
+ * as well as user-defined color
+ * schemes.
+ *
+ * @param {String} type
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+var color = exports.color = function(type, str) {
+  if (!exports.useColors) return str;
+  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Expose term window size, with some
+ * defaults for when stderr is not a tty.
+ */
+
+exports.window = {
+  width: isatty
+    ? process.stdout.getWindowSize
+      ? process.stdout.getWindowSize(1)[0]
+      : tty.getWindowSize()[1]
+    : 75
+};
+
+/**
+ * Expose some basic cursor interactions
+ * that are common among reporters.
+ */
+
+exports.cursor = {
+  hide: function(){
+    process.stdout.write('\u001b[?25l');
+  },
+
+  show: function(){
+    process.stdout.write('\u001b[?25h');
+  },
+
+  deleteLine: function(){
+    process.stdout.write('\u001b[2K');
+  },
+
+  beginningOfLine: function(){
+    process.stdout.write('\u001b[0G');
+  },
+
+  CR: function(){
+    exports.cursor.deleteLine();
+    exports.cursor.beginningOfLine();
+  }
+};
+
+/**
+ * Outut the given `failures` as a list.
+ *
+ * @param {Array} failures
+ * @api public
+ */
+
+exports.list = function(failures){
+  console.error();
+  failures.forEach(function(test, i){
+    // format
+    var fmt = color('error title', '  %s) %s:\n')
+      + color('error message', '     %s')
+      + color('error stack', '\n%s\n');
+
+    // msg
+    var err = test.err
+      , message = err.message || ''
+      , stack = err.stack || message
+      , index = stack.indexOf(message) + message.length
+      , msg = stack.slice(0, index)
+      , actual = err.actual
+      , expected = err.expected
+      , escape = true;
+
+    // explicitly show diff
+    if (err.showDiff) {
+      escape = false;
+      err.actual = actual = JSON.stringify(actual, null, 2);
+      err.expected = expected = JSON.stringify(expected, null, 2);
+    }
+
+    // actual / expected diff
+    if ('string' == typeof actual && 'string' == typeof expected) {
+      var len = Math.max(actual.length, expected.length);
+
+      if (len < 20) msg = errorDiff(err, 'Chars', escape);
+      else msg = errorDiff(err, 'Words', escape);
+
+      // linenos
+      var lines = msg.split('\n');
+      if (lines.length > 4) {
+        var width = String(lines.length).length;
+        msg = lines.map(function(str, i){
+          return pad(++i, width) + ' |' + ' ' + str;
+        }).join('\n');
+      }
+
+      // legend
+      msg = '\n'
+        + color('diff removed', 'actual')
+        + ' '
+        + color('diff added', 'expected')
+        + '\n\n'
+        + msg
+        + '\n';
+
+      // indent
+      msg = msg.replace(/^/gm, '      ');
+
+      fmt = color('error title', '  %s) %s:\n%s')
+        + color('error stack', '\n%s\n');
+    }
+
+    // indent stack trace without msg
+    stack = stack.slice(index ? index + 1 : index)
+      .replace(/^/gm, '  ');
+
+    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+  });
+};
+
+/**
+ * Initialize a new `Base` reporter.
+ *
+ * All other reporters generally
+ * inherit from this reporter, providing
+ * stats such as test duration, number
+ * of tests passed / failed etc.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Base(runner) {
+  var self = this
+    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
+    , failures = this.failures = [];
+
+  if (!runner) return;
+  this.runner = runner;
+
+  runner.stats = stats;
+
+  runner.on('start', function(){
+    stats.start = new Date;
+  });
+
+  runner.on('suite', function(suite){
+    stats.suites = stats.suites || 0;
+    suite.root || stats.suites++;
+  });
+
+  runner.on('test end', function(test){
+    stats.tests = stats.tests || 0;
+    stats.tests++;
+  });
+
+  runner.on('pass', function(test){
+    stats.passes = stats.passes || 0;
+
+    var medium = test.slow() / 2;
+    test.speed = test.duration > test.slow()
+      ? 'slow'
+      : test.duration > medium
+        ? 'medium'
+        : 'fast';
+
+    stats.passes++;
+  });
+
+  runner.on('fail', function(test, err){
+    stats.failures = stats.failures || 0;
+    stats.failures++;
+    test.err = err;
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    stats.end = new Date;
+    stats.duration = new Date - stats.start;
+  });
+
+  runner.on('pending', function(){
+    stats.pending++;
+  });
+}
+
+/**
+ * Output common epilogue used by many of
+ * the bundled reporters.
+ *
+ * @api public
+ */
+
+Base.prototype.epilogue = function(){
+  var stats = this.stats
+    , fmt
+    , tests;
+
+  console.log();
+
+  function pluralize(n) {
+    return 1 == n ? 'test' : 'tests';
+  }
+
+  // failure
+  if (stats.failures) {
+    fmt = color('bright fail', '  ' + exports.symbols.err)
+      + color('fail', ' %d of %d %s failed')
+      + color('light', ':')
+
+    console.error(fmt,
+      stats.failures,
+      this.runner.total,
+      pluralize(this.runner.total));
+
+    Base.list(this.failures);
+    console.error();
+    return;
+  }
+
+  // pass
+  fmt = color('bright pass', ' ')
+    + color('green', ' %d %s complete')
+    + color('light', ' (%s)');
+
+  console.log(fmt,
+    stats.tests || 0,
+    pluralize(stats.tests),
+    ms(stats.duration));
+
+  // pending
+  if (stats.pending) {
+    fmt = color('pending', ' ')
+      + color('pending', ' %d %s pending');
+
+    console.log(fmt, stats.pending, pluralize(stats.pending));
+  }
+
+  console.log();
+};
+
+/**
+ * Pad the given `str` to `len`.
+ *
+ * @param {String} str
+ * @param {String} len
+ * @return {String}
+ * @api private
+ */
+
+function pad(str, len) {
+  str = String(str);
+  return Array(len - str.length + 1).join(' ') + str;
+}
+
+/**
+ * Return a character diff for `err`.
+ *
+ * @param {Error} err
+ * @return {String}
+ * @api private
+ */
+
+function errorDiff(err, type, escape) {
+  return diff['diff' + type](err.actual, err.expected).map(function(str){
+    if (escape) {
+      str.value = str.value
+        .replace(/\t/g, '<tab>')
+        .replace(/\r/g, '<CR>')
+        .replace(/\n/g, '<LF>\n');
+    }
+    if (str.added) return colorLines('diff added', str.value);
+    if (str.removed) return colorLines('diff removed', str.value);
+    return str.value;
+  }).join('');
+}
+
+/**
+ * Color lines for `str`, using the color `name`.
+ *
+ * @param {String} name
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function colorLines(name, str) {
+  return str.split('\n').map(function(str){
+    return color(name, str);
+  }).join('\n');
+}
+
+}); // module: reporters/base.js
+
+require.register("reporters/doc.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils');
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = Doc;
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Doc(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total
+    , indents = 2;
+
+  function indent() {
+    return Array(indents).join('  ');
+  }
+
+  runner.on('suite', function(suite){
+    if (suite.root) return;
+    ++indents;
+    console.log('%s<section class="suite">', indent());
+    ++indents;
+    console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
+    console.log('%s<dl>', indent());
+  });
+
+  runner.on('suite end', function(suite){
+    if (suite.root) return;
+    console.log('%s</dl>', indent());
+    --indents;
+    console.log('%s</section>', indent());
+    --indents;
+  });
+
+  runner.on('pass', function(test){
+    console.log('%s  <dt>%s</dt>', indent(), utils.escape(test.title));
+    var code = utils.escape(utils.clean(test.fn.toString()));
+    console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);
+  });
+}
+
+}); // module: reporters/doc.js
+
+require.register("reporters/dot.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = Dot;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Dot(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , n = 0;
+
+  runner.on('start', function(){
+    process.stdout.write('\n  ');
+  });
+
+  runner.on('pending', function(test){
+    process.stdout.write(color('pending', Base.symbols.dot));
+  });
+
+  runner.on('pass', function(test){
+    if (++n % width == 0) process.stdout.write('\n  ');
+    if ('slow' == test.speed) {
+      process.stdout.write(color('bright yellow', Base.symbols.dot));
+    } else {
+      process.stdout.write(color(test.speed, Base.symbols.dot));
+    }
+  });
+
+  runner.on('fail', function(test, err){
+    if (++n % width == 0) process.stdout.write('\n  ');
+    process.stdout.write(color('fail', Base.symbols.dot));
+  });
+
+  runner.on('end', function(){
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Dot.prototype = new F;
+Dot.prototype.constructor = Dot;
+
+}); // module: reporters/dot.js
+
+require.register("reporters/html-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var JSONCov = require('./json-cov')
+  , fs = require('browser/fs');
+
+/**
+ * Expose `HTMLCov`.
+ */
+
+exports = module.exports = HTMLCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTMLCov(runner) {
+  var jade = require('jade')
+    , file = __dirname + '/templates/coverage.jade'
+    , str = fs.readFileSync(file, 'utf8')
+    , fn = jade.compile(str, { filename: file })
+    , self = this;
+
+  JSONCov.call(this, runner, false);
+
+  runner.on('end', function(){
+    process.stdout.write(fn({
+        cov: self.cov
+      , coverageClass: coverageClass
+    }));
+  });
+}
+
+/**
+ * Return coverage class for `n`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+function coverageClass(n) {
+  if (n >= 75) return 'high';
+  if (n >= 50) return 'medium';
+  if (n >= 25) return 'low';
+  return 'terrible';
+}
+}); // module: reporters/html-cov.js
+
+require.register("reporters/html.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils')
+  , Progress = require('../browser/progress')
+  , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = HTML;
+
+/**
+ * Stats template.
+ */
+
+var statsTemplate = '<ul id="mocha-stats">'
+  + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
+  + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>'
+  + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>'
+  + '<li class="duration">duration: <em>0</em>s</li>'
+  + '</ul>';
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTML(runner, root) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total
+    , stat = fragment(statsTemplate)
+    , items = stat.getElementsByTagName('li')
+    , passes = items[1].getElementsByTagName('em')[0]
+    , passesLink = items[1].getElementsByTagName('a')[0]
+    , failures = items[2].getElementsByTagName('em')[0]
+    , failuresLink = items[2].getElementsByTagName('a')[0]
+    , duration = items[3].getElementsByTagName('em')[0]
+    , canvas = stat.getElementsByTagName('canvas')[0]
+    , report = fragment('<ul id="mocha-report"></ul>')
+    , stack = [report]
+    , progress
+    , ctx
+
+  root = root || document.getElementById('mocha');
+
+  if (canvas.getContext) {
+    var ratio = window.devicePixelRatio || 1;
+    canvas.style.width = canvas.width;
+    canvas.style.height = canvas.height;
+    canvas.width *= ratio;
+    canvas.height *= ratio;
+    ctx = canvas.getContext('2d');
+    ctx.scale(ratio, ratio);
+    progress = new Progress;
+  }
+
+  if (!root) return error('#mocha div missing, add it to your document');
+
+  // pass toggle
+  on(passesLink, 'click', function(){
+    unhide();
+    var name = /pass/.test(report.className) ? '' : ' pass';
+    report.className = report.className.replace(/fail|pass/g, '') + name;
+    if (report.className.trim()) hideSuitesWithout('test pass');
+  });
+
+  // failure toggle
+  on(failuresLink, 'click', function(){
+    unhide();
+    var name = /fail/.test(report.className) ? '' : ' fail';
+    report.className = report.className.replace(/fail|pass/g, '') + name;
+    if (report.className.trim()) hideSuitesWithout('test fail');
+  });
+
+  root.appendChild(stat);
+  root.appendChild(report);
+
+  if (progress) progress.size(40);
+
+  runner.on('suite', function(suite){
+    if (suite.root) return;
+
+    // suite
+    var url = '?grep=' + encodeURIComponent(suite.fullTitle());
+    var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
+
+    // container
+    stack[0].appendChild(el);
+    stack.unshift(document.createElement('ul'));
+    el.appendChild(stack[0]);
+  });
+
+  runner.on('suite end', function(suite){
+    if (suite.root) return;
+    stack.shift();
+  });
+
+  runner.on('fail', function(test, err){
+    if ('hook' == test.type) runner.emit('test end', test);
+  });
+
+  runner.on('test end', function(test){
+    window.scrollTo(0, document.body.scrollHeight);
+
+    // TODO: add to stats
+    var percent = stats.tests / this.total * 100 | 0;
+    if (progress) progress.update(percent).draw(ctx);
+
+    // update stats
+    var ms = new Date - stats.start;
+    text(passes, stats.passes);
+    text(failures, stats.failures);
+    text(duration, (ms / 1000).toFixed(2));
+
+    // test
+    if ('passed' == test.state) {
+      var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="?grep=%e" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));
+    } else if (test.pending) {
+      var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
+    } else {
+      var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
+      var str = test.err.stack || test.err.toString();
+
+      // FF / Opera do not add the message
+      if (!~str.indexOf(test.err.message)) {
+        str = test.err.message + '\n' + str;
+      }
+
+      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
+      // check for the result of the stringifying.
+      if ('[object Error]' == str) str = test.err.message;
+
+      // Safari doesn't give you a stack. Let's at least provide a source line.
+      if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
+        str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
+      }
+
+      el.appendChild(fragment('<pre class="error">%e</pre>', str));
+    }
+
+    // toggle code
+    // TODO: defer
+    if (!test.pending) {
+      var h2 = el.getElementsByTagName('h2')[0];
+
+      on(h2, 'click', function(){
+        pre.style.display = 'none' == pre.style.display
+          ? 'block'
+          : 'none';
+      });
+
+      var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));
+      el.appendChild(pre);
+      pre.style.display = 'none';
+    }
+
+    // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
+    if (stack[0]) stack[0].appendChild(el);
+  });
+}
+
+/**
+ * Display error `msg`.
+ */
+
+function error(msg) {
+  document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
+}
+
+/**
+ * Return a DOM fragment from `html`.
+ */
+
+function fragment(html) {
+  var args = arguments
+    , div = document.createElement('div')
+    , i = 1;
+
+  div.innerHTML = html.replace(/%([se])/g, function(_, type){
+    switch (type) {
+      case 's': return String(args[i++]);
+      case 'e': return escape(args[i++]);
+    }
+  });
+
+  return div.firstChild;
+}
+
+/**
+ * Check for suites that do not have elements
+ * with `classname`, and hide them.
+ */
+
+function hideSuitesWithout(classname) {
+  var suites = document.getElementsByClassName('suite');
+  for (var i = 0; i < suites.length; i++) {
+    var els = suites[i].getElementsByClassName(classname);
+    if (0 == els.length) suites[i].className += ' hidden';
+  }
+}
+
+/**
+ * Unhide .hidden suites.
+ */
+
+function unhide() {
+  var els = document.getElementsByClassName('suite hidden');
+  for (var i = 0; i < els.length; ++i) {
+    els[i].className = els[i].className.replace('suite hidden', 'suite');
+  }
+}
+
+/**
+ * Set `el` text to `str`.
+ */
+
+function text(el, str) {
+  if (el.textContent) {
+    el.textContent = str;
+  } else {
+    el.innerText = str;
+  }
+}
+
+/**
+ * Listen on `event` with callback `fn`.
+ */
+
+function on(el, event, fn) {
+  if (el.addEventListener) {
+    el.addEventListener(event, fn, false);
+  } else {
+    el.attachEvent('on' + event, fn);
+  }
+}
+
+}); // module: reporters/html.js
+
+require.register("reporters/index.js", function(module, exports, require){
+
+exports.Base = require('./base');
+exports.Dot = require('./dot');
+exports.Doc = require('./doc');
+exports.TAP = require('./tap');
+exports.JSON = require('./json');
+exports.HTML = require('./html');
+exports.List = require('./list');
+exports.Min = require('./min');
+exports.Spec = require('./spec');
+exports.Nyan = require('./nyan');
+exports.XUnit = require('./xunit');
+exports.Markdown = require('./markdown');
+exports.Progress = require('./progress');
+exports.Landing = require('./landing');
+exports.JSONCov = require('./json-cov');
+exports.HTMLCov = require('./html-cov');
+exports.JSONStream = require('./json-stream');
+exports.Teamcity = require('./teamcity');
+
+}); // module: reporters/index.js
+
+require.register("reporters/json-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `JSONCov`.
+ */
+
+exports = module.exports = JSONCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @param {Boolean} output
+ * @api public
+ */
+
+function JSONCov(runner, output) {
+  var self = this
+    , output = 1 == arguments.length ? true : output;
+
+  Base.call(this, runner);
+
+  var tests = []
+    , failures = []
+    , passes = [];
+
+  runner.on('test end', function(test){
+    tests.push(test);
+  });
+
+  runner.on('pass', function(test){
+    passes.push(test);
+  });
+
+  runner.on('fail', function(test){
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    var cov = global._$jscoverage || {};
+    var result = self.cov = map(cov);
+    result.stats = self.stats;
+    result.tests = tests.map(clean);
+    result.failures = failures.map(clean);
+    result.passes = passes.map(clean);
+    if (!output) return;
+    process.stdout.write(JSON.stringify(result, null, 2 ));
+  });
+}
+
+/**
+ * Map jscoverage data to a JSON structure
+ * suitable for reporting.
+ *
+ * @param {Object} cov
+ * @return {Object}
+ * @api private
+ */
+
+function map(cov) {
+  var ret = {
+      instrumentation: 'node-jscoverage'
+    , sloc: 0
+    , hits: 0
+    , misses: 0
+    , coverage: 0
+    , files: []
+  };
+
+  for (var filename in cov) {
+    var data = coverage(filename, cov[filename]);
+    ret.files.push(data);
+    ret.hits += data.hits;
+    ret.misses += data.misses;
+    ret.sloc += data.sloc;
+  }
+
+  ret.files.sort(function(a, b) {
+    return a.filename.localeCompare(b.filename);
+  });
+
+  if (ret.sloc > 0) {
+    ret.coverage = (ret.hits / ret.sloc) * 100;
+  }
+
+  return ret;
+};
+
+/**
+ * Map jscoverage data for a single source file
+ * to a JSON structure suitable for reporting.
+ *
+ * @param {String} filename name of the source file
+ * @param {Object} data jscoverage coverage data
+ * @return {Object}
+ * @api private
+ */
+
+function coverage(filename, data) {
+  var ret = {
+    filename: filename,
+    coverage: 0,
+    hits: 0,
+    misses: 0,
+    sloc: 0,
+    source: {}
+  };
+
+  data.source.forEach(function(line, num){
+    num++;
+
+    if (data[num] === 0) {
+      ret.misses++;
+      ret.sloc++;
+    } else if (data[num] !== undefined) {
+      ret.hits++;
+      ret.sloc++;
+    }
+
+    ret.source[num] = {
+        source: line
+      , coverage: data[num] === undefined
+        ? ''
+        : data[num]
+    };
+  });
+
+  ret.coverage = ret.hits / ret.sloc * 100;
+
+  return ret;
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+
+}); // module: reporters/json-cov.js
+
+require.register("reporters/json-stream.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total;
+
+  runner.on('start', function(){
+    console.log(JSON.stringify(['start', { total: total }]));
+  });
+
+  runner.on('pass', function(test){
+    console.log(JSON.stringify(['pass', clean(test)]));
+  });
+
+  runner.on('fail', function(test, err){
+    console.log(JSON.stringify(['fail', clean(test)]));
+  });
+
+  runner.on('end', function(){
+    process.stdout.write(JSON.stringify(['end', self.stats]));
+  });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+}); // module: reporters/json-stream.js
+
+require.register("reporters/json.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `JSON`.
+ */
+
+exports = module.exports = JSONReporter;
+
+/**
+ * Initialize a new `JSON` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function JSONReporter(runner) {
+  var self = this;
+  Base.call(this, runner);
+
+  var tests = []
+    , failures = []
+    , passes = [];
+
+  runner.on('test end', function(test){
+    tests.push(test);
+  });
+
+  runner.on('pass', function(test){
+    passes.push(test);
+  });
+
+  runner.on('fail', function(test){
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    var obj = {
+        stats: self.stats
+      , tests: tests.map(clean)
+      , failures: failures.map(clean)
+      , passes: passes.map(clean)
+    };
+
+    process.stdout.write(JSON.stringify(obj, null, 2));
+  });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+}); // module: reporters/json.js
+
+require.register("reporters/landing.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Landing`.
+ */
+
+exports = module.exports = Landing;
+
+/**
+ * Airplane color.
+ */
+
+Base.colors.plane = 0;
+
+/**
+ * Airplane crash color.
+ */
+
+Base.colors['plane crash'] = 31;
+
+/**
+ * Runway color.
+ */
+
+Base.colors.runway = 90;
+
+/**
+ * Initialize a new `Landing` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Landing(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , total = runner.total
+    , stream = process.stdout
+    , plane = color('plane', '✈')
+    , crashed = -1
+    , n = 0;
+
+  function runway() {
+    var buf = Array(width).join('-');
+    return '  ' + color('runway', buf);
+  }
+
+  runner.on('start', function(){
+    stream.write('\n  ');
+    cursor.hide();
+  });
+
+  runner.on('test end', function(test){
+    // check if the plane crashed
+    var col = -1 == crashed
+      ? width * ++n / total | 0
+      : crashed;
+
+    // show the crash
+    if ('failed' == test.state) {
+      plane = color('plane crash', '✈');
+      crashed = col;
+    }
+
+    // render landing strip
+    stream.write('\u001b[4F\n\n');
+    stream.write(runway());
+    stream.write('\n  ');
+    stream.write(color('runway', Array(col).join('â‹…')));
+    stream.write(plane)
+    stream.write(color('runway', Array(width - col).join('â‹…') + '\n'));
+    stream.write(runway());
+    stream.write('\u001b[0m');
+  });
+
+  runner.on('end', function(){
+    cursor.show();
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Landing.prototype = new F;
+Landing.prototype.constructor = Landing;
+
+}); // module: reporters/landing.js
+
+require.register("reporters/list.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , n = 0;
+
+  runner.on('start', function(){
+    console.log();
+  });
+
+  runner.on('test', function(test){
+    process.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));
+  });
+
+  runner.on('pending', function(test){
+    var fmt = color('checkmark', '  -')
+      + color('pending', ' %s');
+    console.log(fmt, test.fullTitle());
+  });
+
+  runner.on('pass', function(test){
+    var fmt = color('checkmark', '  '+Base.symbols.dot)
+      + color('pass', ' %s: ')
+      + color(test.speed, '%dms');
+    cursor.CR();
+    console.log(fmt, test.fullTitle(), test.duration);
+  });
+
+  runner.on('fail', function(test, err){
+    cursor.CR();
+    console.log(color('fail', '  %d) %s'), ++n, test.fullTitle());
+  });
+
+  runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+List.prototype = new F;
+List.prototype.constructor = List;
+
+
+}); // module: reporters/list.js
+
+require.register("reporters/markdown.js", function(module, exports, require){
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils');
+
+/**
+ * Expose `Markdown`.
+ */
+
+exports = module.exports = Markdown;
+
+/**
+ * Initialize a new `Markdown` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Markdown(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , level = 0
+    , buf = '';
+
+  function title(str) {
+    return Array(level).join('#') + ' ' + str;
+  }
+
+  function indent() {
+    return Array(level).join('  ');
+  }
+
+  function mapTOC(suite, obj) {
+    var ret = obj;
+    obj = obj[suite.title] = obj[suite.title] || { suite: suite };
+    suite.suites.forEach(function(suite){
+      mapTOC(suite, obj);
+    });
+    return ret;
+  }
+
+  function stringifyTOC(obj, level) {
+    ++level;
+    var buf = '';
+    var link;
+    for (var key in obj) {
+      if ('suite' == key) continue;
+      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+      if (key) buf += Array(level).join('  ') + link;
+      buf += stringifyTOC(obj[key], level);
+    }
+    --level;
+    return buf;
+  }
+
+  function generateTOC(suite) {
+    var obj = mapTOC(suite, {});
+    return stringifyTOC(obj, 0);
+  }
+
+  generateTOC(runner.suite);
+
+  runner.on('suite', function(suite){
+    ++level;
+    var slug = utils.slug(suite.fullTitle());
+    buf += '<a name="' + slug + '"></a>' + '\n';
+    buf += title(suite.title) + '\n';
+  });
+
+  runner.on('suite end', function(suite){
+    --level;
+  });
+
+  runner.on('pass', function(test){
+    var code = utils.clean(test.fn.toString());
+    buf += test.title + '.\n';
+    buf += '\n```js\n';
+    buf += code + '\n';
+    buf += '```\n\n';
+  });
+
+  runner.on('end', function(){
+    process.stdout.write('# TOC\n');
+    process.stdout.write(generateTOC(runner.suite));
+    process.stdout.write(buf);
+  });
+}
+}); // module: reporters/markdown.js
+
+require.register("reporters/min.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Min`.
+ */
+
+exports = module.exports = Min;
+
+/**
+ * Initialize a new `Min` minimal test reporter (best used with --watch).
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Min(runner) {
+  Base.call(this, runner);
+  
+  runner.on('start', function(){
+    // clear screen
+    process.stdout.write('\u001b[2J');
+    // set cursor position
+    process.stdout.write('\u001b[1;3H');
+  });
+
+  runner.on('end', this.epilogue.bind(this));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Min.prototype = new F;
+Min.prototype.constructor = Min;
+
+}); // module: reporters/min.js
+
+require.register("reporters/nyan.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = NyanCat;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function NyanCat(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , rainbowColors = this.rainbowColors = self.generateColors()
+    , colorIndex = this.colorIndex = 0
+    , numerOfLines = this.numberOfLines = 4
+    , trajectories = this.trajectories = [[], [], [], []]
+    , nyanCatWidth = this.nyanCatWidth = 11
+    , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)
+    , scoreboardWidth = this.scoreboardWidth = 5
+    , tick = this.tick = 0
+    , n = 0;
+
+  runner.on('start', function(){
+    Base.cursor.hide();
+    self.draw('start');
+  });
+
+  runner.on('pending', function(test){
+    self.draw('pending');
+  });
+
+  runner.on('pass', function(test){
+    self.draw('pass');
+  });
+
+  runner.on('fail', function(test, err){
+    self.draw('fail');
+  });
+
+  runner.on('end', function(){
+    Base.cursor.show();
+    for (var i = 0; i < self.numberOfLines; i++) write('\n');
+    self.epilogue();
+  });
+}
+
+/**
+ * Draw the nyan cat with runner `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.draw = function(status){
+  this.appendRainbow();
+  this.drawScoreboard();
+  this.drawRainbow();
+  this.drawNyanCat(status);
+  this.tick = !this.tick;
+};
+
+/**
+ * Draw the "scoreboard" showing the number
+ * of passes, failures and pending tests.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawScoreboard = function(){
+  var stats = this.stats;
+  var colors = Base.colors;
+
+  function draw(color, n) {
+    write(' ');
+    write('\u001b[' + color + 'm' + n + '\u001b[0m');
+    write('\n');
+  }
+
+  draw(colors.green, stats.passes);
+  draw(colors.fail, stats.failures);
+  draw(colors.pending, stats.pending);
+  write('\n');
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Append the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.appendRainbow = function(){
+  var segment = this.tick ? '_' : '-';
+  var rainbowified = this.rainbowify(segment);
+
+  for (var index = 0; index < this.numberOfLines; index++) {
+    var trajectory = this.trajectories[index];
+    if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();
+    trajectory.push(rainbowified);
+  }
+};
+
+/**
+ * Draw the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawRainbow = function(){
+  var self = this;
+
+  this.trajectories.forEach(function(line, index) {
+    write('\u001b[' + self.scoreboardWidth + 'C');
+    write(line.join(''));
+    write('\n');
+  });
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw the nyan cat with `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.drawNyanCat = function(status) {
+  var self = this;
+  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
+
+  [0, 1, 2, 3].forEach(function(index) {
+    write('\u001b[' + startWidth + 'C');
+
+    switch (index) {
+      case 0:
+        write('_,------,');
+        write('\n');
+        break;
+      case 1:
+        var padding = self.tick ? '  ' : '   ';
+        write('_|' + padding + '/\\_/\\ ');
+        write('\n');
+        break;
+      case 2:
+        var padding = self.tick ? '_' : '__';
+        var tail = self.tick ? '~' : '^';
+        var face;
+        switch (status) {
+          case 'pass':
+            face = '( ^ .^)';
+            break;
+          case 'fail':
+            face = '( o .o)';
+            break;
+          default:
+            face = '( - .-)';
+        }
+        write(tail + '|' + padding + face + ' ');
+        write('\n');
+        break;
+      case 3:
+        var padding = self.tick ? ' ' : '  ';
+        write(padding + '""  "" ');
+        write('\n');
+        break;
+    }
+  });
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Move cursor up `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorUp = function(n) {
+  write('\u001b[' + n + 'A');
+};
+
+/**
+ * Move cursor down `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorDown = function(n) {
+  write('\u001b[' + n + 'B');
+};
+
+/**
+ * Generate rainbow colors.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+NyanCat.prototype.generateColors = function(){
+  var colors = [];
+
+  for (var i = 0; i < (6 * 7); i++) {
+    var pi3 = Math.floor(Math.PI / 3);
+    var n = (i * (1.0 / 6));
+    var r = Math.floor(3 * Math.sin(n) + 3);
+    var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
+    var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
+    colors.push(36 * r + 6 * g + b + 16);
+  }
+
+  return colors;
+};
+
+/**
+ * Apply rainbow to the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+NyanCat.prototype.rainbowify = function(str){
+  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
+  this.colorIndex += 1;
+  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Stdout helper.
+ */
+
+function write(string) {
+  process.stdout.write(string);
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+NyanCat.prototype = new F;
+NyanCat.prototype.constructor = NyanCat;
+
+
+}); // module: reporters/nyan.js
+
+require.register("reporters/progress.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Progress`.
+ */
+
+exports = module.exports = Progress;
+
+/**
+ * General progress bar color.
+ */
+
+Base.colors.progress = 90;
+
+/**
+ * Initialize a new `Progress` bar test reporter.
+ *
+ * @param {Runner} runner
+ * @param {Object} options
+ * @api public
+ */
+
+function Progress(runner, options) {
+  Base.call(this, runner);
+
+  var self = this
+    , options = options || {}
+    , stats = this.stats
+    , width = Base.window.width * .50 | 0
+    , total = runner.total
+    , complete = 0
+    , max = Math.max;
+
+  // default chars
+  options.open = options.open || '[';
+  options.complete = options.complete || 'â–¬';
+  options.incomplete = options.incomplete || Base.symbols.dot;
+  options.close = options.close || ']';
+  options.verbose = false;
+
+  // tests started
+  runner.on('start', function(){
+    console.log();
+    cursor.hide();
+  });
+
+  // tests complete
+  runner.on('test end', function(){
+    complete++;
+    var incomplete = total - complete
+      , percent = complete / total
+      , n = width * percent | 0
+      , i = width - n;
+
+    cursor.CR();
+    process.stdout.write('\u001b[J');
+    process.stdout.write(color('progress', '  ' + options.open));
+    process.stdout.write(Array(n).join(options.complete));
+    process.stdout.write(Array(i).join(options.incomplete));
+    process.stdout.write(color('progress', options.close));
+    if (options.verbose) {
+      process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
+    }
+  });
+
+  // tests are complete, output some stats
+  // and the failures if any
+  runner.on('end', function(){
+    cursor.show();
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Progress.prototype = new F;
+Progress.prototype.constructor = Progress;
+
+
+}); // module: reporters/progress.js
+
+require.register("reporters/spec.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Spec`.
+ */
+
+exports = module.exports = Spec;
+
+/**
+ * Initialize a new `Spec` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Spec(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , indents = 0
+    , n = 0;
+
+  function indent() {
+    return Array(indents).join('  ')
+  }
+
+  runner.on('start', function(){
+    console.log();
+  });
+
+  runner.on('suite', function(suite){
+    ++indents;
+    console.log(color('suite', '%s%s'), indent(), suite.title);
+  });
+
+  runner.on('suite end', function(suite){
+    --indents;
+    if (1 == indents) console.log();
+  });
+
+  runner.on('test', function(test){
+    process.stdout.write(indent() + color('pass', '  â—¦ ' + test.title + ': '));
+  });
+
+  runner.on('pending', function(test){
+    var fmt = indent() + color('pending', '  - %s');
+    console.log(fmt, test.title);
+  });
+
+  runner.on('pass', function(test){
+    if ('fast' == test.speed) {
+      var fmt = indent()
+        + color('checkmark', '  ' + Base.symbols.ok)
+        + color('pass', ' %s ');
+      cursor.CR();
+      console.log(fmt, test.title);
+    } else {
+      var fmt = indent()
+        + color('checkmark', '  ' + Base.symbols.ok)
+        + color('pass', ' %s ')
+        + color(test.speed, '(%dms)');
+      cursor.CR();
+      console.log(fmt, test.title, test.duration);
+    }
+  });
+
+  runner.on('fail', function(test, err){
+    cursor.CR();
+    console.log(indent() + color('fail', '  %d) %s'), ++n, test.title);
+  });
+
+  runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Spec.prototype = new F;
+Spec.prototype.constructor = Spec;
+
+
+}); // module: reporters/spec.js
+
+require.register("reporters/tap.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `TAP`.
+ */
+
+exports = module.exports = TAP;
+
+/**
+ * Initialize a new `TAP` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function TAP(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , n = 1
+    , passes = 0
+    , failures = 0;
+
+  runner.on('start', function(){
+    var total = runner.grepTotal(runner.suite);
+    console.log('%d..%d', 1, total);
+  });
+
+  runner.on('test end', function(){
+    ++n;
+  });
+
+  runner.on('pending', function(test){
+    console.log('ok %d %s # SKIP -', n, title(test));
+  });
+
+  runner.on('pass', function(test){
+    passes++;
+    console.log('ok %d %s', n, title(test));
+  });
+
+  runner.on('fail', function(test, err){
+    failures++;
+    console.log('not ok %d %s', n, title(test));
+    if (err.stack) console.log(err.stack.replace(/^/gm, '  '));
+  });
+
+  runner.on('end', function(){
+    console.log('# tests ' + (passes + failures));
+    console.log('# pass ' + passes);
+    console.log('# fail ' + failures);
+  });
+}
+
+/**
+ * Return a TAP-safe title of `test`
+ *
+ * @param {Object} test
+ * @return {String}
+ * @api private
+ */
+
+function title(test) {
+  return test.fullTitle().replace(/#/g, '');
+}
+
+}); // module: reporters/tap.js
+
+require.register("reporters/teamcity.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Teamcity`.
+ */
+
+exports = module.exports = Teamcity;
+
+/**
+ * Initialize a new `Teamcity` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Teamcity(runner) {
+  Base.call(this, runner);
+  var stats = this.stats;
+
+  runner.on('start', function() {
+    console.log("##teamcity[testSuiteStarted name='mocha.suite']");
+  });
+
+  runner.on('test', function(test) {
+    console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
+  });
+
+  runner.on('fail', function(test, err) {
+    console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
+  });
+
+  runner.on('pending', function(test) {
+    console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
+  });
+
+  runner.on('test end', function(test) {
+    console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
+  });
+
+  runner.on('end', function() {
+    console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
+  });
+}
+
+/**
+ * Escape the given `str`.
+ */
+
+function escape(str) {
+  return str
+    .replace(/\|/g, "||")
+    .replace(/\n/g, "|n")
+    .replace(/\r/g, "|r")
+    .replace(/\[/g, "|[")
+    .replace(/\]/g, "|]")
+    .replace(/\u0085/g, "|x")
+    .replace(/\u2028/g, "|l")
+    .replace(/\u2029/g, "|p")
+    .replace(/'/g, "|'");
+}
+
+}); // module: reporters/teamcity.js
+
+require.register("reporters/xunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils')
+  , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Expose `XUnit`.
+ */
+
+exports = module.exports = XUnit;
+
+/**
+ * Initialize a new `XUnit` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function XUnit(runner) {
+  Base.call(this, runner);
+  var stats = this.stats
+    , tests = []
+    , self = this;
+
+  runner.on('pass', function(test){
+    tests.push(test);
+  });
+  
+  runner.on('fail', function(test){
+    tests.push(test);
+  });
+
+  runner.on('end', function(){
+    console.log(tag('testsuite', {
+        name: 'Mocha Tests'
+      , tests: stats.tests
+      , failures: stats.failures
+      , errors: stats.failures
+      , skip: stats.tests - stats.failures - stats.passes
+      , timestamp: (new Date).toUTCString()
+      , time: stats.duration / 1000
+    }, false));
+
+    tests.forEach(test);
+    console.log('</testsuite>');    
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+XUnit.prototype = new F;
+XUnit.prototype.constructor = XUnit;
+
+
+/**
+ * Output tag for the given `test.`
+ */
+
+function test(test) {
+  var attrs = {
+      classname: test.parent.fullTitle()
+    , name: test.title
+    , time: test.duration / 1000
+  };
+
+  if ('failed' == test.state) {
+    var err = test.err;
+    attrs.message = escape(err.message);
+    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
+  } else if (test.pending) {
+    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
+  } else {
+    console.log(tag('testcase', attrs, true) );
+  }
+}
+
+/**
+ * HTML tag helper.
+ */
+
+function tag(name, attrs, close, content) {
+  var end = close ? '/>' : '>'
+    , pairs = []
+    , tag;
+
+  for (var key in attrs) {
+    pairs.push(key + '="' + escape(attrs[key]) + '"');
+  }
+
+  tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
+  if (content) tag += content + '</' + name + end;
+  return tag;
+}
+
+/**
+ * Return cdata escaped CDATA `str`.
+ */
+
+function cdata(str) {
+  return '<![CDATA[' + escape(str) + ']]>';
+}
+
+}); // module: reporters/xunit.js
+
+require.register("runnable.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('browser/events').EventEmitter
+  , debug = require('browser/debug')('mocha:runnable')
+  , milliseconds = require('./ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Object#toString().
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Expose `Runnable`.
+ */
+
+module.exports = Runnable;
+
+/**
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Runnable(title, fn) {
+  this.title = title;
+  this.fn = fn;
+  this.async = fn && fn.length;
+  this.sync = ! this.async;
+  this._timeout = 2000;
+  this._slow = 75;
+  this.timedOut = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+
+function F(){};
+F.prototype = EventEmitter.prototype;
+Runnable.prototype = new F;
+Runnable.prototype.constructor = Runnable;
+
+
+/**
+ * Set & get timeout `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.timeout = function(ms){
+  if (0 == arguments.length) return this._timeout;
+  if ('string' == typeof ms) ms = milliseconds(ms);
+  debug('timeout %d', ms);
+  this._timeout = ms;
+  if (this.timer) this.resetTimeout();
+  return this;
+};
+
+/**
+ * Set & get slow `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.slow = function(ms){
+  if (0 === arguments.length) return this._slow;
+  if ('string' == typeof ms) ms = milliseconds(ms);
+  debug('timeout %d', ms);
+  this._slow = ms;
+  return this;
+};
+
+/**
+ * Return the full title generated by recursively
+ * concatenating the parent's full title.
+ *
+ * @return {String}
+ * @api public
+ */
+
+Runnable.prototype.fullTitle = function(){
+  return this.parent.fullTitle() + ' ' + this.title;
+};
+
+/**
+ * Clear the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.clearTimeout = function(){
+  clearTimeout(this.timer);
+};
+
+/**
+ * Inspect the runnable void of private properties.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Runnable.prototype.inspect = function(){
+  return JSON.stringify(this, function(key, val){
+    if ('_' == key[0]) return;
+    if ('parent' == key) return '#<Suite>';
+    if ('ctx' == key) return '#<Context>';
+    return val;
+  }, 2);
+};
+
+/**
+ * Reset the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.resetTimeout = function(){
+  var self = this
+    , ms = this.timeout();
+
+  this.clearTimeout();
+  if (ms) {
+    this.timer = setTimeout(function(){
+      self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+      self.timedOut = true;
+    }, ms);
+  }
+};
+
+/**
+ * Run the test and invoke `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+
+Runnable.prototype.run = function(fn){
+  var self = this
+    , ms = this.timeout()
+    , start = new Date
+    , ctx = this.ctx
+    , finished
+    , emitted;
+
+  if (ctx) ctx.runnable(this);
+
+  // timeout
+  if (this.async) {
+    if (ms) {
+      this.timer = setTimeout(function(){
+        done(new Error('timeout of ' + ms + 'ms exceeded'));
+        self.timedOut = true;
+      }, ms);
+    }
+  }
+
+  // called multiple times
+  function multiple(err) {
+    if (emitted) return;
+    emitted = true;
+    self.emit('error', err || new Error('done() called multiple times'));
+  }
+
+  // finished
+  function done(err) {
+    if (self.timedOut) return;
+    if (finished) return multiple(err);
+    self.clearTimeout();
+    self.duration = new Date - start;
+    finished = true;
+    fn(err);
+  }
+
+  // for .resetTimeout()
+  this.callback = done;
+
+  // async
+  if (this.async) {
+    try {
+      this

<TRUNCATED>

[14/27] built with the new Events module included

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8367ea49/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
old mode 100755
new mode 100644
index 948238b..96dbbe8
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,3 +1,4 @@
+/*! usergrid@0.0.0 2014-01-16 */
 /*
  *  This module is a collection of classes designed to make working with
  *  the Appigee App Services API as easy as possible.
@@ -21,37 +22,89 @@
  *  @author matt dobson (matt@apigee.com)
  *  @author ryan bridges (rbridges@apigee.com)
  */
-
-
 //Hack around IE console.log
 window.console = window.console || {};
+
 window.console.log = window.console.log || function() {};
 
 //Usergrid namespace encapsulates this SDK
 window.Usergrid = window.Usergrid || {};
+
 Usergrid = Usergrid || {};
-Usergrid.USERGRID_SDK_VERSION = '0.10.07';
 
-Usergrid.Client = function(options) {
-  //usergrid enpoint
-  this.URI = options.URI || 'https://api.usergrid.com';
+Usergrid.USERGRID_SDK_VERSION = "0.10.07";
 
-  //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
-  if (options.orgName) {
-    this.set('orgName', options.orgName);
-  }
-  if (options.appName) {
-    this.set('appName', options.appName);
-  }
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+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}$/;
+    if (!uuid) {
+        return false;
+    }
+    return uuidValueRegex.test(uuid);
+}
 
-  //other options
-  this.buildCurl = options.buildCurl || false;
-  this.logging = options.logging || false;
+/*
+ *  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 tail = [];
+    var item = [];
+    var i;
+    if (params instanceof Array) {
+        for (i in params) {
+            item = params[i];
+            if (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("&");
+}
 
-  //timeout and callbacks
-  this._callTimeout =  options.callTimeout || 30000; //default to 30 seconds
-  this._callTimeoutCallback =  options.callTimeoutCallback || null;
-  this.logoutCallback =  options.logoutCallback || null;
+Usergrid.Client = function(options) {
+    //usergrid enpoint
+    this.URI = options.URI || "https://api.usergrid.com";
+    //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
+    if (options.orgName) {
+        this.set("orgName", options.orgName);
+    }
+    if (options.appName) {
+        this.set("appName", options.appName);
+    }
+    //other options
+    this.buildCurl = options.buildCurl || false;
+    this.logging = options.logging || false;
+    //timeout and callbacks
+    this._callTimeout = options.callTimeout || 3e4;
+    //default to 30 seconds
+    this._callTimeoutCallback = options.callTimeoutCallback || null;
+    this.logoutCallback = options.logoutCallback || null;
 };
 
 /*
@@ -70,139 +123,125 @@ Usergrid.Client = function(options) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.request = function (options, callback) {
-  var self = this;
-  var method = options.method || 'GET';
-  var endpoint = options.endpoint;
-  var body = options.body || {};
-  var qs = options.qs || {};
-  var mQuery = options.mQuery || false; //is this a query to the management endpoint?
-  var orgName = this.get('orgName');
-  var appName = this.get('appName');
-  if(!mQuery && !orgName && !appName){
-    if (typeof(this.logoutCallback) === 'function') {
-      return this.logoutCallback(true, 'no_org_or_app_name_specified');
-    }
-  }
-  if (mQuery) {
-    uri = this.URI + '/' + endpoint;
-  } else {
-    uri = this.URI + '/' + orgName + '/' + appName + '/' + endpoint;
-  }
-
-  if (self.getToken()) {
-    qs.access_token = self.getToken();
-    /* //could also use headers for the token
-     xhr.setRequestHeader("Authorization", "Bearer " + self.getToken());
-     xhr.withCredentials = true;
-     */
-  }
-
-  //append params to the path
-  var encoded_params = encodeParams(qs);
-  if (encoded_params) {
-    uri += "?" + encoded_params;
-  }
-
-  //stringify the body object
-  body = JSON.stringify(body);
-
-  //so far so good, so run the query
-  var xhr = new XMLHttpRequest();
-  xhr.open(method, uri, true);
-  //add content type = json if there is a json payload
-  if (body) {
-    xhr.setRequestHeader("Content-Type", "application/json");
-    xhr.setRequestHeader("Accept", "application/json");
-  }
-
-  // Handle response.
-  xhr.onerror = function(response) {
-    self._end = new Date().getTime();
-    if (self.logging) {
-      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
-    }
-    if (self.logging) {
-      console.log('Error: API call failed at the network level.');
-    }
-    //network error
-    clearTimeout(timeout);
-    var err = true;
-    if (typeof(callback) === 'function') {
-      callback(err, response);
-    }
-  };
-
-  xhr.onload = function(response) {
-    //call timing, get time, then log the call
-    self._end = new Date().getTime();
-    if (self.logging) {
-      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
-    }
-    //call completed
-    clearTimeout(timeout);
-    //decode the response
-    try{
-      response = JSON.parse(xhr.responseText);
-    }catch (e){
-      response = {error:'unhandled_error',error_description:xhr.responseText};
-      xhr.status = xhr.status === 200 ? 400 : xhr.status;
-      console.error(e);
+Usergrid.Client.prototype.request = function(options, callback) {
+    var self = this;
+    var method = options.method || "GET";
+    var endpoint = options.endpoint;
+    var body = options.body || {};
+    var qs = options.qs || {};
+    var mQuery = options.mQuery || false;
+    //is this a query to the management endpoint?
+    var orgName = this.get("orgName");
+    var appName = this.get("appName");
+    if (!mQuery && !orgName && !appName) {
+        if (typeof this.logoutCallback === "function") {
+            return this.logoutCallback(true, "no_org_or_app_name_specified");
+        }
     }
-    if (xhr.status != 200)   {
-      //there was an api error
-      var error = response.error;
-      var error_description = response.error_description;
-      if (self.logging) {
-        console.log('Error (' + xhr.status + ')(' + error + '): ' + error_description);
-      }
-      if ( (error == "auth_expired_session_token") ||
-        (error == "auth_missing_credentials")   ||
-        (error == "auth_unverified_oath")       ||
-        (error == "expired_token")              ||
-        (error == "unauthorized")               ||
-        (error == "auth_invalid")) {
-        //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
-        //if the user has specified a logout callback:
-        if (typeof(self.logoutCallback) === 'function') {
-          return self.logoutCallback(true, response);
-        }
-      }
-      if (typeof(callback) === 'function') {
-        callback(true, response);
-      }
+    if (mQuery) {
+        uri = this.URI + "/" + endpoint;
     } else {
-      if (typeof(callback) === 'function') {
-        callback(false, response);
-      }
-    }
-  };
-
-  var timeout = setTimeout(
-    function() {
-      xhr.abort();
-      if (self._callTimeoutCallback === 'function') {
-        self._callTimeoutCallback('API CALL TIMEOUT');
-      } else {
-        self.callback('API CALL TIMEOUT');
-      }
-    },
-    self._callTimeout); //set for 30 seconds
-
-  if (this.logging) {
-    console.log('calling: ' + method + ' ' + uri);
-  }
-  if (this.buildCurl) {
-    var curlOptions = {
-      uri:uri,
-      body:body,
-      method:method
+        uri = this.URI + "/" + orgName + "/" + appName + "/" + endpoint;
+    }
+    if (self.getToken()) {
+        qs.access_token = self.getToken();
+    }
+    //append params to the path
+    var encoded_params = encodeParams(qs);
+    if (encoded_params) {
+        uri += "?" + encoded_params;
+    }
+    //stringify the body object
+    body = JSON.stringify(body);
+    //so far so good, so run the query
+    var xhr = new XMLHttpRequest();
+    xhr.open(method, uri, true);
+    //add content type = json if there is a json payload
+    if (body) {
+        xhr.setRequestHeader("Content-Type", "application/json");
+        xhr.setRequestHeader("Accept", "application/json");
+    }
+    // Handle response.
+    xhr.onerror = function(response) {
+        self._end = new Date().getTime();
+        if (self.logging) {
+            console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
+        }
+        if (self.logging) {
+            console.log("Error: API call failed at the network level.");
+        }
+        //network error
+        clearTimeout(timeout);
+        var err = true;
+        if (typeof callback === "function") {
+            callback(err, response);
+        }
+    };
+    xhr.onload = function(response) {
+        //call timing, get time, then log the call
+        self._end = new Date().getTime();
+        if (self.logging) {
+            console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
+        }
+        //call completed
+        clearTimeout(timeout);
+        //decode the response
+        try {
+            response = JSON.parse(xhr.responseText);
+        } catch (e) {
+            response = {
+                error: "unhandled_error",
+                error_description: xhr.responseText
+            };
+            xhr.status = xhr.status === 200 ? 400 : xhr.status;
+            console.error(e);
+        }
+        if (xhr.status != 200) {
+            //there was an api error
+            var error = response.error;
+            var error_description = response.error_description;
+            if (self.logging) {
+                console.log("Error (" + xhr.status + ")(" + error + "): " + error_description);
+            }
+            if (error == "auth_expired_session_token" || error == "auth_missing_credentials" || error == "auth_unverified_oath" || error == "expired_token" || error == "unauthorized" || error == "auth_invalid") {
+                //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
+                //if the user has specified a logout callback:
+                if (typeof self.logoutCallback === "function") {
+                    return self.logoutCallback(true, response);
+                }
+            }
+            if (typeof callback === "function") {
+                callback(true, response);
+            }
+        } else {
+            if (typeof callback === "function") {
+                callback(false, response);
+            }
+        }
+    };
+    var timeout = setTimeout(function() {
+        xhr.abort();
+        if (self._callTimeoutCallback === "function") {
+            self._callTimeoutCallback("API CALL TIMEOUT");
+        } else {
+            self.callback("API CALL TIMEOUT");
+        }
+    }, self._callTimeout);
+    //set for 30 seconds
+    if (this.logging) {
+        console.log("calling: " + method + " " + uri);
+    }
+    if (this.buildCurl) {
+        var curlOptions = {
+            uri: uri,
+            body: body,
+            method: method
+        };
+        this.buildCurlCall(curlOptions);
     }
-    this.buildCurlCall(curlOptions);
-  }
-  this._start = new Date().getTime();
-  xhr.send(body);
-}
+    this._start = new Date().getTime();
+    xhr.send(body);
+};
 
 /*
  *  function for building asset urls
@@ -213,21 +252,18 @@ Usergrid.Client.prototype.request = function (options, callback) {
  *  @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();
-  }
-
-  //append params to the path
-  var encoded_params = encodeParams(qs);
-  if (encoded_params) {
-    assetURL += "?" + encoded_params;
-  }
-
-  return assetURL;
+    var self = this;
+    var qs = {};
+    var assetURL = this.URI + "/" + this.orgName + "/" + this.appName + "/assets/" + uuid + "/data";
+    if (self.getToken()) {
+        qs.access_token = self.getToken();
+    }
+    //append params to the path
+    var encoded_params = encodeParams(qs);
+    if (encoded_params) {
+        assetURL += "?" + encoded_params;
+    }
+    return assetURL;
 };
 
 /*
@@ -240,29 +276,27 @@ Usergrid.Client.prototype.buildAssetURL = function(uuid) {
  *  @return {callback} callback(err, data)
  */
 Usergrid.Client.prototype.createGroup = function(options, callback) {
-  var getOnExist = options.getOnExist || false;
-
-  options = {
-    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);
-    if (okToSave) {
-      group.save(function(err, data){
-        if (typeof(callback) === 'function') {
-          callback(err, group);
-        }
-      });
-    } else {
-      if(typeof(callback) === 'function') {
-        callback(err, group);
-      }
-    }
-  });
+    var getOnExist = options.getOnExist || false;
+    options = {
+        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;
+        if (okToSave) {
+            group.save(function(err, data) {
+                if (typeof callback === "function") {
+                    callback(err, group);
+                }
+            });
+        } else {
+            if (typeof callback === "function") {
+                callback(err, group);
+            }
+        }
+    });
 };
 
 /*
@@ -276,10 +310,10 @@ Usergrid.Client.prototype.createGroup = function(options, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createEntity = function (options, callback) {
-  // todo: replace the check for new / save on not found code with simple save
-  // when users PUT on no user fix is in place.
-  /*
+Usergrid.Client.prototype.createEntity = function(options, callback) {
+    // todo: replace the check for new / save on not found code with simple save
+    // when users PUT on no user fix is in place.
+    /*
    var options = {
    client:this,
    data:options
@@ -291,29 +325,30 @@ Usergrid.Client.prototype.createEntity = function (options, callback) {
    }
    });
    */
-  var getOnExist = options.getOnExist || false; //if true, will return entity if one already exists
-  var options = {
-    client:this,
-    data:options
-  };
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(function(err, data) {
-    //if the fetch doesn't find what we are looking for, or there is no error, do a save
-    var okToSave = (err && 'service_resource_not_found' === data.error || 'no_name_specified' === data.error || 'null_pointer' === data.error) || (!err && getOnExist);
-    if(okToSave) {
-      entity.set(options.data); //add the data again just in case
-      entity.save(function(err, data) {
-        if (typeof(callback) === 'function') {
-          callback(err, entity, data);
-        }
-      });
-    } else {
-      if (typeof(callback) === 'function') {
-        callback(err, entity, data);
-      }
-    }
-  });
-
+    var getOnExist = options.getOnExist || false;
+    //if true, will return entity if one already exists
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(function(err, data) {
+        //if the fetch doesn't find what we are looking for, or there is no error, do a save
+        var okToSave = err && "service_resource_not_found" === data.error || "no_name_specified" === data.error || "null_pointer" === data.error || !err && getOnExist;
+        if (okToSave) {
+            entity.set(options.data);
+            //add the data again just in case
+            entity.save(function(err, data) {
+                if (typeof callback === "function") {
+                    callback(err, entity, data);
+                }
+            });
+        } else {
+            if (typeof callback === "function") {
+                callback(err, entity, data);
+            }
+        }
+    });
 };
 
 /*
@@ -330,17 +365,17 @@ Usergrid.Client.prototype.createEntity = function (options, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.getEntity = function (options, callback) {
-  var options = {
-    client:this,
-    data:options
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, entity, data);
-    }
-  });
+Usergrid.Client.prototype.getEntity = function(options, callback) {
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, entity, data);
+        }
+    });
 };
 
 /*
@@ -353,14 +388,14 @@ Usergrid.Client.prototype.getEntity = function (options, callback) {
  *  @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;
+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;
 };
 
 /*
@@ -374,13 +409,13 @@ Usergrid.Client.prototype.restoreEntity = function (serializedObject) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createCollection = function (options, callback) {
-  options.client = this;
-  var collection = new Usergrid.Collection(options, function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, collection, data);
-    }
-  });
+Usergrid.Client.prototype.createCollection = function(options, callback) {
+    options.client = this;
+    var collection = new Usergrid.Collection(options, function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, collection, data);
+        }
+    });
 };
 
 /*
@@ -393,11 +428,11 @@ Usergrid.Client.prototype.createCollection = function (options, callback) {
  *  @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;
+Usergrid.Client.prototype.restoreCollection = function(serializedObject) {
+    var data = JSON.parse(serializedObject);
+    data.client = this;
+    var collection = new Usergrid.Collection(data);
+    return collection;
 };
 
 /*
@@ -410,20 +445,19 @@ Usergrid.Client.prototype.restoreCollection = function (serializedObject) {
  *  @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(typeof(callback) === "function") {
-      if(err) {
-        callback(err);
-      } else {
-        callback(err, data, data.entities);
-      }
-    }
-  });
+    var options = {
+        method: "GET",
+        endpoint: "users/" + username + "/feed"
+    };
+    this.request(options, function(err, data) {
+        if (typeof callback === "function") {
+            if (err) {
+                callback(err);
+            } else {
+                callback(err, data, data.entities);
+            }
+        }
+    });
 };
 
 /*
@@ -461,18 +495,18 @@ Usergrid.Client.prototype.getFeedForUser = function(username, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createUserActivity = function (user, options, callback) {
-  options.type = 'users/'+user+'/activities';
-  var options = {
-    client:this,
-    data:options
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.save(function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, entity);
-    }
-  });
+Usergrid.Client.prototype.createUserActivity = function(user, options, callback) {
+    options.type = "users/" + user + "/activities";
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.save(function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, entity);
+        }
+    });
 };
 
 /*
@@ -489,41 +523,39 @@ Usergrid.Client.prototype.createUserActivity = function (user, options, 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);
-
+    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;
+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;
 };
 
 /*
@@ -534,8 +566,8 @@ Usergrid.Client.prototype.calcTimeDiff = function () {
  *  @params {string} token
  *  @return none
  */
-Usergrid.Client.prototype.setToken = function (token) {
-  this.set('token', token);
+Usergrid.Client.prototype.setToken = function(token) {
+    this.set("token", token);
 };
 
 /*
@@ -545,41 +577,41 @@ Usergrid.Client.prototype.setToken = function (token) {
  *  @public
  *  @return {string} token
  */
-Usergrid.Client.prototype.getToken = function () {
-  return this.get('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);
+    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.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));
+    return JSON.parse(this.get(key));
 };
 
-Usergrid.Client.prototype.get = function (key) {
-  var keyStore = 'apigee_' + key;
-  if (this[key]) {
-    return this[key];
-  } else if(typeof(Storage)!=="undefined") {
-    return localStorage.getItem(keyStore);
-  }
-  return null;
+Usergrid.Client.prototype.get = function(key) {
+    var keyStore = "apigee_" + key;
+    if (this[key]) {
+        return this[key];
+    } else if (typeof Storage !== "undefined") {
+        return localStorage.getItem(keyStore);
+    }
+    return null;
 };
 
 /*
@@ -595,16 +627,15 @@ Usergrid.Client.prototype.get = function (key) {
  * @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);
+    var self = this;
+    var options = {
+        type: "users",
+        username: username,
+        password: password,
+        email: email,
+        name: name
+    };
+    this.createEntity(options, callback);
 };
 
 /*
@@ -618,122 +649,112 @@ Usergrid.Client.prototype.signup = function(username, password, email, name, cal
  *  @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'
-    }
-  };
-  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);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user);
-    }
-  });
+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"
+        }
+    };
+    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);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, 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 {
-
-      //save the re-authed token and current email/username
-      self.setToken(response.access_token);
-
-    }
-    if (typeof(callback) === 'function') {
-      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);
-
-      //delete next block and corresponding function when iframes are refactored
-      localStorage.setItem('accessToken', data.token);
-      localStorage.setItem('userUUID', data.uuid);
-      localStorage.setItem('userEmail', data.email);
-      //end delete block
-
-
-      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 {
-        //if we have an org stored, then use that one. Otherwise, use the first one.
-        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');
+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 {
+            //save the re-authed token and current email/username
+            self.setToken(response.access_token);
         }
-      } //should always be an org
-
-      applications = self.parseApplicationsArray(org);
-      self.selectFirstApp(applications);
-
-      self.setObject('organizations', organizations);
-      self.setObject('applications', applications);
+        if (typeof callback === "function") {
+            callback(err);
+        }
+    });
+};
 
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user, organizations, applications);
-    }
-  });
+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);
+            //delete next block and corresponding function when iframes are refactored
+            localStorage.setItem("accessToken", data.token);
+            localStorage.setItem("userUUID", data.uuid);
+            localStorage.setItem("userEmail", data.email);
+            //end delete block
+            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 {
+                //if we have an org stored, then use that one. Otherwise, use the first one.
+                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");
+                }
+            }
+            //should always be an org
+            applications = self.parseApplicationsArray(org);
+            self.selectFirstApp(applications);
+            self.setObject("organizations", organizations);
+            self.setObject("applications", applications);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, user, organizations, applications);
+        }
+    });
 };
 
 /*
@@ -746,31 +767,31 @@ Usergrid.Client.prototype.reAuthenticate = function (email, callback) {
  *  @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);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user);
-    }
-  });
+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);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, user);
+        }
+    });
 };
 
 /*
@@ -781,35 +802,35 @@ Usergrid.Client.prototype.loginFacebook = function (facebookToken, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.getLoggedInUser = function (callback) {
-  if (!this.getToken()) {
-    callback(true, null, null);
-  } else {
-    var self = this;
-    var options = {
-      method:'GET',
-      endpoint:'users/me'
-    };
-    this.request(options, function(err, data) {
-      if (err) {
-        if (self.logging) {
-          console.log('error trying to log user in');
-        }
-        if (typeof(callback) === 'function') {
-          callback(err, data, null);
-        }
-      } else {
+Usergrid.Client.prototype.getLoggedInUser = function(callback) {
+    if (!this.getToken()) {
+        callback(true, null, null);
+    } else {
+        var self = this;
         var options = {
-          client:self,
-          data:data.entities[0]
+            method: "GET",
+            endpoint: "users/me"
         };
-        var user = new Usergrid.Entity(options);
-        if (typeof(callback) === 'function') {
-          callback(err, data, user);
-        }
-      }
-    });
-  }
+        this.request(options, function(err, data) {
+            if (err) {
+                if (self.logging) {
+                    console.log("error trying to log user in");
+                }
+                if (typeof callback === "function") {
+                    callback(err, data, null);
+                }
+            } else {
+                var options = {
+                    client: self,
+                    data: data.entities[0]
+                };
+                var user = new Usergrid.Entity(options);
+                if (typeof callback === "function") {
+                    callback(err, data, user);
+                }
+            }
+        });
+    }
 };
 
 /*
@@ -820,11 +841,11 @@ Usergrid.Client.prototype.getLoggedInUser = function (callback) {
  *  @public
  *  @return {boolean} Returns true the user is logged in (has token and uuid), false if not
  */
-Usergrid.Client.prototype.isLoggedIn = function () {
-  if (this.getToken() && this.getToken() != 'null') {
-    return true;
-  }
-  return false;
+Usergrid.Client.prototype.isLoggedIn = function() {
+    if (this.getToken() && this.getToken() != "null") {
+        return true;
+    }
+    return false;
 };
 
 /*
@@ -834,8 +855,8 @@ Usergrid.Client.prototype.isLoggedIn = function () {
  *  @public
  *  @return none
  */
-Usergrid.Client.prototype.logout = function () {
-  this.setToken(null);
+Usergrid.Client.prototype.logout = function() {
+    this.setToken(null);
 };
 
 /*
@@ -846,54 +867,52 @@ Usergrid.Client.prototype.logout = function () {
  *  @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 - add the method to the command (no need to add anything for GET)
-  if (method === 'POST') {
-    curl += ' -X POST';
-  } else if (method === 'PUT') {
-    curl += ' -X PUT';
-  } else if (method === 'DELETE') {
-    curl += ' -X DELETE';
-  } else {
-    curl += ' -X GET';
-  }
-
-  //curl - append the path
-  curl += ' ' + uri;
-
-  //curl - add the body
-  if("undefined"!== typeof window){body = JSON.stringify(body);}//only in node module
-  if (body !== '"{}"' && method !== 'GET' && method !== 'DELETE') {
-    //curl - add in the json obj
-    curl += " -d '" + body + "'";
-  }
-
-  //log the curl command to the console
-  console.log(curl);
-
-  return curl;
-}
-
-Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
-  try {
-    if (picture) {
-      return picture;
-    }
-    var size = size || 50;
-    if (email.length) {
-      return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+Usergrid.Client.prototype.buildCurlCall = function(options) {
+    var curl = "curl";
+    var method = (options.method || "GET").toUpperCase();
+    var body = options.body || {};
+    var uri = options.uri;
+    //curl - add the method to the command (no need to add anything for GET)
+    if (method === "POST") {
+        curl += " -X POST";
+    } else if (method === "PUT") {
+        curl += " -X PUT";
+    } else if (method === "DELETE") {
+        curl += " -X DELETE";
     } else {
-      return 'https://apigee.com/usergrid/images/user_profile.png';
+        curl += " -X GET";
     }
-  } catch(e) {
-    return 'https://apigee.com/usergrid/images/user_profile.png';
-  }
-}
+    //curl - append the path
+    curl += " " + uri;
+    //curl - add the body
+    if ("undefined" !== typeof window) {
+        body = JSON.stringify(body);
+    }
+    //only in node module
+    if (body !== '"{}"' && method !== "GET" && method !== "DELETE") {
+        //curl - add in the json obj
+        curl += " -d '" + body + "'";
+    }
+    //log the curl command to the console
+    console.log(curl);
+    return curl;
+};
+
+Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) {
+    try {
+        if (picture) {
+            return picture;
+        }
+        var size = size || 50;
+        if (email.length) {
+            return "https://secure.gravatar.com/avatar/" + MD5(email) + "?s=" + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+        } else {
+            return "https://apigee.com/usergrid/images/user_profile.png";
+        }
+    } catch (e) {
+        return "https://apigee.com/usergrid/images/user_profile.png";
+    }
+};
 
 /*
  *  A class to Model a Usergrid Entity.
@@ -903,10 +922,10 @@ Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
  *  @param {object} options {client:client, data:{'type':'collection_type', uuid:'uuid', 'key':'value'}}
  */
 Usergrid.Entity = function(options) {
-  if (options) {
-    this._data = options.data || {};
-    this._client = options.client || {};
-  }
+    if (options) {
+        this._data = options.data || {};
+        this._client = options.client || {};
+    }
 };
 
 /*
@@ -917,8 +936,8 @@ Usergrid.Entity = function(options) {
  *  @method serialize
  *  @return {string} data
  */
-Usergrid.Entity.prototype.serialize = function () {
-  return JSON.stringify(this._data);
+Usergrid.Entity.prototype.serialize = function() {
+    return JSON.stringify(this._data);
 };
 
 /*
@@ -929,12 +948,12 @@ Usergrid.Entity.prototype.serialize = function () {
  *  @param {string} field
  *  @return {string} || {object} data
  */
-Usergrid.Entity.prototype.get = function (field) {
-  if (field) {
-    return this._data[field];
-  } else {
-    return this._data;
-  }
+Usergrid.Entity.prototype.get = function(field) {
+    if (field) {
+        return this._data[field];
+    } else {
+        return this._data;
+    }
 };
 
 /*
@@ -947,20 +966,20 @@ Usergrid.Entity.prototype.get = function (field) {
  *  @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];
+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[key] = value;
+        this._data = {};
     }
-  } else {
-    this._data = {};
-  }
 };
 
 /*
@@ -971,88 +990,86 @@ Usergrid.Entity.prototype.set = function (key, value) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Entity.prototype.save = function (callback) {
-  var type = this.get('type');
-  var method = 'POST';
-  if (isUUID(this.get('uuid'))) {
-    method = 'PUT';
-    type += '/' + this.get('uuid');
-  }
-
-  //update the entity
-  var self = this;
-  var data = {};
-  var entityData = this.get();
-    var password = this.get('password');
-    var oldpassword = this.get('oldpassword');
-    var newpassword = this.get('newpassword');
-  //remove system specific properties
-  for (var item in entityData) {
-    if (item === 'metadata' || item === 'created' || item === 'modified' ||
-          item === 'oldpassword' || item === 'newpassword' || //old and new pw not added to data
-      item === 'type' || item === 'activated' || item === 'uuid') {
-      continue;
-    }
-    data[item] = entityData[item];
-  }
-  var options =  {
-    method:method,
-    endpoint:type,
-    body:data
-  };
-  //save the entity first
-  this._client.request(options, function (err, retdata) {
-      //clear out pw info if present
-      self.set('password', null);
-      self.set('oldpassword', null);
-      self.set('newpassword', null);
-    if (err && self._client.logging) {
-      console.log('could not save entity');
-      if (typeof(callback) === 'function') {
-        return callback(err, retdata, self);
-      }
-    } else {
-      if (retdata.entities) {
-        if (retdata.entities.length) {
-          var entity = retdata.entities[0];
-          self.set(entity);
-          var path = retdata.path;
-          //for connections, API returns type
-          while (path.substring(0, 1) === "/") {
-            path = path.substring(1);
-          }
-          self.set('type', path);
-        }
-      }
-      //if this is a user, update the password if it has been specified;
-        var needPasswordChange = ((self.get('type') === 'user' || self.get('type') === 'users') && oldpassword && newpassword);
-      if (needPasswordChange) {
-        //Note: we have a ticket in to change PUT calls to /users to accept the password change
-        //      once that is done, we will remove this call and merge it all into one
-        var pwdata = {};
-          pwdata.oldpassword = oldpassword;
-          pwdata.newpassword = newpassword;
-        var options = {
-          method:'PUT',
-          endpoint:type+'/password',
-          body:pwdata
-        }
-        self._client.request(options, function (err, data) {
-          if (err && self._client.logging) {
-            console.log('could not update user');
-          }
-          //remove old and new password fields so they don't end up as part of the entity object
-          self.set('oldpassword', null);
-          self.set('newpassword', null);
-          if (typeof(callback) === 'function') {
-            callback(err, data, self);
-          }
-        });
-      } else if (typeof(callback) === 'function') {
-        callback(err, retdata, self);
-      }
+Usergrid.Entity.prototype.save = function(callback) {
+    var type = this.get("type");
+    var method = "POST";
+    if (isUUID(this.get("uuid"))) {
+        method = "PUT";
+        type += "/" + this.get("uuid");
+    }
+    //update the entity
+    var self = this;
+    var data = {};
+    var entityData = this.get();
+    var password = this.get("password");
+    var oldpassword = this.get("oldpassword");
+    var newpassword = this.get("newpassword");
+    //remove system specific properties
+    for (var item in entityData) {
+        if (item === "metadata" || item === "created" || item === "modified" || item === "oldpassword" || item === "newpassword" || //old and new pw not added to data
+        item === "type" || item === "activated" || item === "uuid") {
+            continue;
+        }
+        data[item] = entityData[item];
     }
-  });
+    var options = {
+        method: method,
+        endpoint: type,
+        body: data
+    };
+    //save the entity first
+    this._client.request(options, function(err, retdata) {
+        //clear out pw info if present
+        self.set("password", null);
+        self.set("oldpassword", null);
+        self.set("newpassword", null);
+        if (err && self._client.logging) {
+            console.log("could not save entity");
+            if (typeof callback === "function") {
+                return callback(err, retdata, self);
+            }
+        } else {
+            if (retdata.entities) {
+                if (retdata.entities.length) {
+                    var entity = retdata.entities[0];
+                    self.set(entity);
+                    var path = retdata.path;
+                    //for connections, API returns type
+                    while (path.substring(0, 1) === "/") {
+                        path = path.substring(1);
+                    }
+                    self.set("type", path);
+                }
+            }
+            //if this is a user, update the password if it has been specified;
+            var needPasswordChange = (self.get("type") === "user" || self.get("type") === "users") && oldpassword && newpassword;
+            if (needPasswordChange) {
+                //Note: we have a ticket in to change PUT calls to /users to accept the password change
+                //      once that is done, we will remove this call and merge it all into one
+                var pwdata = {};
+                pwdata.oldpassword = oldpassword;
+                pwdata.newpassword = newpassword;
+                var options = {
+                    method: "PUT",
+                    endpoint: type + "/password",
+                    body: pwdata
+                };
+                self._client.request(options, function(err, data) {
+                    if (err && self._client.logging) {
+                        console.log("could not update user");
+                    }
+                    //remove old and new password fields so they don't end up as part of the entity object
+                    self.set("oldpassword", null);
+                    self.set("newpassword", null);
+                    if (typeof callback === "function") {
+                        callback(err, data, self);
+                    }
+                });
+            } else if (typeof callback === "function") {
+                callback(err, retdata, self);
+            }
+        }
+    });
 };
 
 /*
@@ -1063,93 +1080,92 @@ Usergrid.Entity.prototype.save = function (callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Entity.prototype.fetch = function (callback) {
-  var type = this.get('type');
-  var self = this;
-
-  //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
-  try {
-    if (type === undefined) {
-      throw 'cannot fetch entity, no entity type specified'
-    } else if (this.get('uuid')) {
-      type += '/' + this.get('uuid');
-    } else if (type === 'users' && this.get('username')) {
-      type += '/' + this.get('username');
-    } else if (this.get('name')) {
-      type += '/' + encodeURIComponent(this.get('name'));
-    } else if (typeof(callback) === 'function') {
-      throw 'no_name_specified';
-    }
-  } catch (e) {
-    if (self._client.logging) {
-      console.log(e);
-    }
-    return callback(true, {
-      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) {
-        if (data.entities.length) {
-          var entity = data.entities[0];
-          self.set(entity);
-        }
-      }
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, self);
+Usergrid.Entity.prototype.fetch = function(callback) {
+    var type = this.get("type");
+    var self = this;
+    //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
+    try {
+        if (type === undefined) {
+            throw "cannot fetch entity, no entity type specified";
+        } else if (this.get("uuid")) {
+            type += "/" + this.get("uuid");
+        } else if (type === "users" && this.get("username")) {
+            type += "/" + this.get("username");
+        } else if (this.get("name")) {
+            type += "/" + encodeURIComponent(this.get("name"));
+        } else if (typeof callback === "function") {
+            throw "no_name_specified";
+        }
+    } catch (e) {
+        if (self._client.logging) {
+            console.log(e);
+        }
+        return callback(true, {
+            error: e
+        }, self);
     }
-  });
-};
-
-/*
- *  deletes the entity from the database - will only delete
- *  if the object has a valid uuid
- *
- *  @method destroy
+    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) {
+                if (data.entities.length) {
+                    var entity = data.entities[0];
+                    self.set(entity);
+                }
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data, 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 type = this.get('type');
-  if (isUUID(this.get('uuid'))) {
-    type += '/' + this.get('uuid');
-  } else {
-    if (typeof(callback) === 'function') {
-      var error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-  }
-  var options = {
-    method:'DELETE',
-    endpoint:type
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be deleted');
+Usergrid.Entity.prototype.destroy = function(callback) {
+    var self = this;
+    var type = this.get("type");
+    if (isUUID(this.get("uuid"))) {
+        type += "/" + this.get("uuid");
     } else {
-      self.set(null);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+        if (typeof callback === "function") {
+            var error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
     }
-  });
+    var options = {
+        method: "DELETE",
+        endpoint: type
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be deleted");
+        } else {
+            self.set(null);
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1163,52 +1179,48 @@ Usergrid.Entity.prototype.destroy = function (callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.connect = function (connection, entity, callback) {
-
-  var self = this;
-
-  var error;
-  //connectee info
-  var connecteeType = entity.get('type');
-  var connectee = this.getEntityId(entity);
-  if (!connectee) {
-    if (typeof(callback) === 'function') {
-      error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  //connector info
-  var connectorType = this.get('type');
-  var connector = this.getEntityId(this);
-  if (!connector) {
-    if (typeof(callback) === 'function') {
-      error = 'Error in connect - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
-  var options = {
-    method:'POST',
-    endpoint:endpoint
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be connected');
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+Usergrid.Entity.prototype.connect = function(connection, entity, callback) {
+    var self = this;
+    var error;
+    //connectee info
+    var connecteeType = entity.get("type");
+    var connectee = this.getEntityId(entity);
+    if (!connectee) {
+        if (typeof callback === "function") {
+            error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
+    }
+    //connector info
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        if (typeof callback === "function") {
+            error = "Error in connect - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
     }
-  });
+    var endpoint = connectorType + "/" + connector + "/" + connection + "/" + connecteeType + "/" + connectee;
+    var options = {
+        method: "POST",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be connected");
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1221,18 +1233,18 @@ Usergrid.Entity.prototype.connect = function (connection, entity, callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.getEntityId = function (entity) {
-  var id = false;
-  if (isUUID(entity.get('uuid'))) {
-    id = entity.get('uuid');
-  } else {
-    if (type === 'users') {
-      id = entity.get('username');
-    } else if (entity.get('name')) {
-      id = entity.get('name');
+Usergrid.Entity.prototype.getEntityId = function(entity) {
+    var id = false;
+    if (isUUID(entity.get("uuid"))) {
+        id = entity.get("uuid");
+    } else {
+        if (type === "users") {
+            id = entity.get("username");
+        } else if (entity.get("name")) {
+            id = entity.get("name");
+        }
     }
-  }
-  return id;
+    return id;
 };
 
 /*
@@ -1246,241 +1258,195 @@ Usergrid.Entity.prototype.getEntityId = function (entity) {
  *  @return {callback} callback(err, data, connections)
  *
  */
-Usergrid.Entity.prototype.getConnections = function (connection, callback) {
-
-  var self = this;
-
-  //connector info
-  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);
-      }
-      callback(true, error);
-    }
-    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.entities.length;
-    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]
-      }
-    }
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
+Usergrid.Entity.prototype.getConnections = function(connection, callback) {
+    var self = this;
+    //connector info
+    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);
+            }
+            callback(true, error);
+        }
+        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.entities.length;
+        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];
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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.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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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.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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
 /*
@@ -1494,52 +1460,48 @@ Usergrid.Entity.prototype.getPermissions = function (callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.disconnect = function (connection, entity, callback) {
-
-  var self = this;
-
-  var error;
-  //connectee info
-  var connecteeType = entity.get('type');
-  var connectee = this.getEntityId(entity);
-  if (!connectee) {
-    if (typeof(callback) === 'function') {
-      error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  //connector info
-  var connectorType = this.get('type');
-  var connector = this.getEntityId(this);
-  if (!connector) {
-    if (typeof(callback) === 'function') {
-      error = 'Error in connect - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
-  var options = {
-    method:'DELETE',
-    endpoint:endpoint
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be disconnected');
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+Usergrid.Entity.prototype.disconnect = function(connection, entity, callback) {
+    var self = this;
+    var error;
+    //connectee info
+    var connecteeType = entity.get("type");
+    var connectee = this.getEntityId(entity);
+    if (!connectee) {
+        if (typeof callback === "function") {
+            error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
+    }
+    //connector info
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        if (typeof callback === "function") {
+            error = "Error in connect - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
     }
-  });
+    var endpoint = connectorType + "/" + connector + "/" + connection + "/" + connecteeType + "/" + connectee;
+    var options = {
+        method: "DELETE",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be disconnected");
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1553,87 +1515,77 @@ Usergrid.Entity.prototype.disconnect = function (connection, entity, callback) {
  *  @return {callback} callback(err, data)
  */
 Usergrid.Collection = function(options, callback) {
-
-  if (options) {
-    this._client = options.client;
-    this._type = options.type;
-    this.qs = options.qs || {};
-
-    //iteration
-    this._list = options.list || [];
-    this._iterator = options.iterator || -1; //first thing we do is increment, so set to -1
-
-    //paging
-    this._previous = options.previous || [];
-    this._next = options.next || null;
-    this._cursor = options.cursor || null;
-
-    //restore entities if available
-    if (options.list) {
-      var count = options.list.length;
-      for(var i=0;i<count;i++){
-        //make new entity with
-        var entity = this._client.restoreEntity(options.list[i]);
-        this._list[i] = entity;
-      }
+    if (options) {
+        this._client = options.client;
+        this._type = options.type;
+        this.qs = options.qs || {};
+        //iteration
+        this._list = options.list || [];
+        this._iterator = options.iterator || -1;
+        //first thing we do is increment, so set to -1
+        //paging
+        this._previous = options.previous || [];
+        this._next = options.next || null;
+        this._cursor = options.cursor || null;
+        //restore entities if available
+        if (options.list) {
+            var count = options.list.length;
+            for (var i = 0; i < count; i++) {
+                //make new entity with
+                var entity = this._client.restoreEntity(options.list[i]);
+                this._list[i] = entity;
+            }
+        }
+    }
+    if (callback) {
+        //populate the collection
+        this.fetch(callback);
     }
-  }
-  if (callback) {
-    //populate the collection
-    this.fetch(callback);
-  }
-
 };
 
-
 /*
  *  gets the data from the collection object for serialization
  *
  *  @method serialize
  *  @return {object} data
  */
-Usergrid.Collection.prototype.serialize = function () {
-
-  //pull out the state from this object and return it
-  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;
-      callback(err, collection);
-    }
-  });
+Usergrid.Collection.prototype.serialize = function() {
+    //pull out the state from this object and return it
+    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;
+            callback(err, collection);
+        }
+    });
 };
 
 /*
@@ -1643,58 +1595,59 @@ Usergrid.Collection.prototype.addCollection = function (collectionName, options,
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Collection.prototype.fetch = function (callback) {
-  var self = this;
-  var qs = this.qs;
-
-  //add in the cursor if one is available
-  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, data) {
-    if(err && self._client.logging) {
-      console.log('error getting collection');
+Usergrid.Collection.prototype.fetch = function(callback) {
+    var self = this;
+    var qs = this.qs;
+    //add in the cursor if one is available
+    if (this._cursor) {
+        qs.cursor = this._cursor;
     } else {
-      //save the cursor if there is one
-      var cursor = data.cursor || null;
-      self.saveCursor(cursor);
-      if (data.entities) {
-        self.resetEntityPointer();
-        var count = data.entities.length;
-        //save entities locally
-        self._list = []; //clear the local list first
-        for (var i=0;i<count;i++) {
-          var uuid = data.entities[i].uuid;
-          if (uuid) {
-            var entityData = data.entities[i] || {};
-            self._baseType = data.entities[i].type; //store the base type in the collection
-            entityData.type = self._type;//make sure entities are same type (have same path) as parent collection.
-            var entityOptions = {
-              type:self._type,
-              client:self._client,
-              uuid:uuid,
-              data:entityData
-            };
-
-            var ent = new Usergrid.Entity(entityOptions);
-            ent._json = JSON.stringify(entityData, null, 2);
-            var ct = self._list.length;
-            self._list[ct] = ent;
-          }
-        }
-      }
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+        delete qs.cursor;
     }
-  });
+    var options = {
+        method: "GET",
+        endpoint: this._type,
+        qs: this.qs
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("error getting collection");
+        } else {
+            //save the cursor if there is one
+            var cursor = data.cursor || null;
+            self.saveCursor(cursor);
+            if (data.entities) {
+                self.resetEntityPointer();
+                var count = data.entities.length;
+                //save entities locally
+                self._list = [];
+                //clear the local list first
+                for (var i = 0; i < count; i++) {
+                    var uuid = data.entities[i].uuid;
+                    if (uuid) {
+                        var entityData = data.entities[i] || {};
+                        self._baseType = data.entities[i].type;
+                        //store the base type in the collection
+                        entityData.type = self._type;
+                        //make sure entities are same type (have same path) as parent collection.
+                        var entityOptions = {
+                            type: self._type,
+                            client: self._client,
+                            uuid: uuid,
+                            data: entityData
+                        };
+                        var ent = new Usergrid.Entity(entityOptions);
+                        ent._json = JSON.stringify(entityData, null, 2);
+                        var ct = self._list.length;
+                        self._list[ct] = ent;
+                    }
+                }
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1705,27 +1658,26 @@ Usergrid.Collection.prototype.fetch = function (callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data, entity)
  */
-Usergrid.Collection.prototype.addEntity = function (options, callback) {
-  var self = this;
-  options.type = this._type;
-
-  //create the new entity
-  this._client.createEntity(options, function (err, entity) {
-    if (!err) {
-      //then add the entity to the list
-      var count = self._list.length;
-      self._list[count] = entity;
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, entity);
-    }
-  });
+Usergrid.Collection.prototype.addEntity = function(options, callback) {
+    var self = this;
+    options.type = this._type;
+    //create the new entity
+    this._client.createEntity(options, function(err, entity) {
+        if (!err) {
+            //then add the entity to the list
+            var count = self._list.length;
+            self._list[count] = entity;
+        }
+        if (typeof callback === "function") {
+            callback(err, entity);
+        }
+    });
 };
 
-Usergrid.Collection.prototype.addExistingEntity = function (entity) {
-  //entity should already exist in the db, so just add it to the list
-  var count = this._list.length;
-  this._list[count] = entity;
+Usergrid.Collection.prototype.addExistingEntity = function(entity) {
+    //entity should already exist in the db, so just add it to the list
+    var count = this._list.length;
+    this._list[count] = entity;
 };
 
 /*
@@ -1736,35 +1688,34 @@ Usergrid.Collection.prototype.addExistingEntity = function (entity) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Collection.prototype.destroyEntity = function (entity, callback) {
-  var self = this;
-  entity.destroy(function(err, data) {
-    if (err) {
-      if (self._client.logging) {
-        console.log('could not destroy entity');
-      }
-      if (typeof(callback) === 'function') {
-        callback(err, data);
-      }
-    } else {
-      //destroy was good, so repopulate the collection
-      self.fetch(callback);
-    }
-  });
-  //remove entity from the local store
-  this.removeEntity(entity);
+Usergrid.Collection.prototype.destroyEntity = function(entity, callback) {
+    var self = this;
+    entity.destroy(function(err, data) {
+        if (err) {
+            if (self._client.logging) {
+                console.log("could not destroy entity");
+            }
+            if (typeof callback === "function") {
+                callback(err, data);
+            }
+        } else {
+            //destroy was good, so repopulate the collection
+            self.fetch(callback);
+        }
+    });
+    //remove entity from the local store
+    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);
+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 false;
+    return false;
 };
 
 /*
@@ -1775,25 +1726,23 @@ Usergrid.Collection.prototype.removeEntity = function (entity) {
  *  @param {function} callback
  *  @return {callback} callback(err, data, entity)
  */
-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;
+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;
+        }
     }
-  }
-
-  //get the entity from the database
-  var options = {
-    data: {
-      type: this._type,
-      uuid:uuid
-    },
-    client: this._client
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(callback);
+    //get the entity from the database
+    var options = {
+        data: {
+            type: this._type,
+            uuid: uuid
+        },
+        client: this._client
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(callback);
 };
 
 /*
@@ -1802,12 +1751,12 @@ Usergrid.Collection.prototype.getEntityByUUID = function (uuid, callback) {
  *  @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;
+Usergrid.Collection.prototype.getFirstEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[0];
+    }
+    return null;
 };
 
 /*
@@ -1816,12 +1765,12 @@ Usergrid.Collection.prototype.getFirstEntity = function () {
  *  @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;
+Usergrid.Collection.prototype.getLastEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[count - 1];
+    }
+    return null;
 };
 
 /*
@@ -1833,13 +1782,13 @@ Usergrid.Collection.prototype.getLastEntity = function () {
  *  @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.l

<TRUNCATED>

[04/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/mocha.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/mocha.css b/sdks/html5-javascript/tests/resources/css/mocha.css
new file mode 100644
index 0000000..42b9798
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/mocha.css
@@ -0,0 +1,270 @@
+@charset "utf-8";
+
+body {
+  margin:0;
+}
+
+#mocha {
+  font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
+  margin: 60px 50px;
+}
+
+#mocha ul,
+#mocha li {
+  margin: 0;
+  padding: 0;
+}
+
+#mocha ul {
+  list-style: none;
+}
+
+#mocha h1,
+#mocha h2 {
+  margin: 0;
+}
+
+#mocha h1 {
+  margin-top: 15px;
+  font-size: 1em;
+  font-weight: 200;
+}
+
+#mocha h1 a {
+  text-decoration: none;
+  color: inherit;
+}
+
+#mocha h1 a:hover {
+  text-decoration: underline;
+}
+
+#mocha .suite .suite h1 {
+  margin-top: 0;
+  font-size: .8em;
+}
+
+#mocha .hidden {
+  display: none;
+}
+
+#mocha h2 {
+  font-size: 12px;
+  font-weight: normal;
+  cursor: pointer;
+}
+
+#mocha .suite {
+  margin-left: 15px;
+}
+
+#mocha .test {
+  margin-left: 15px;
+  overflow: hidden;
+}
+
+#mocha .test.pending:hover h2::after {
+  content: '(pending)';
+  font-family: arial, sans-serif;
+}
+
+#mocha .test.pass.medium .duration {
+  background: #c09853;
+}
+
+#mocha .test.pass.slow .duration {
+  background: #b94a48;
+}
+
+#mocha .test.pass::before {
+  content: '✓';
+  font-size: 12px;
+  display: block;
+  float: left;
+  margin-right: 5px;
+  color: #00d6b2;
+}
+
+#mocha .test.pass .duration {
+  font-size: 9px;
+  margin-left: 5px;
+  padding: 2px 5px;
+  color: #fff;
+  -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
+  -webkit-border-radius: 5px;
+  -moz-border-radius: 5px;
+  -ms-border-radius: 5px;
+  -o-border-radius: 5px;
+  border-radius: 5px;
+}
+
+#mocha .test.pass.fast .duration {
+  display: none;
+}
+
+#mocha .test.pending {
+  color: #0b97c4;
+}
+
+#mocha .test.pending::before {
+  content: 'â—¦';
+  color: #0b97c4;
+}
+
+#mocha .test.fail {
+  color: #c00;
+}
+
+#mocha .test.fail pre {
+  color: black;
+}
+
+#mocha .test.fail::before {
+  content: '✖';
+  font-size: 12px;
+  display: block;
+  float: left;
+  margin-right: 5px;
+  color: #c00;
+}
+
+#mocha .test pre.error {
+  color: #c00;
+  max-height: 300px;
+  overflow: auto;
+}
+
+/**
+ * (1): approximate for browsers not supporting calc
+ * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
+ *      ^^ seriously
+ */
+#mocha .test pre {
+  display: block;
+  float: left;
+  clear: left;
+  font: 12px/1.5 monaco, monospace;
+  margin: 5px;
+  padding: 15px;
+  border: 1px solid #eee;
+  max-width: 85%; /*(1)*/
+  max-width: calc(100% - 42px); /*(2)*/
+  word-wrap: break-word;
+  border-bottom-color: #ddd;
+  -webkit-border-radius: 3px;
+  -webkit-box-shadow: 0 1px 3px #eee;
+  -moz-border-radius: 3px;
+  -moz-box-shadow: 0 1px 3px #eee;
+  border-radius: 3px;
+}
+
+#mocha .test h2 {
+  position: relative;
+}
+
+#mocha .test a.replay {
+  position: absolute;
+  top: 3px;
+  right: 0;
+  text-decoration: none;
+  vertical-align: middle;
+  display: block;
+  width: 15px;
+  height: 15px;
+  line-height: 15px;
+  text-align: center;
+  background: #eee;
+  font-size: 15px;
+  -moz-border-radius: 15px;
+  border-radius: 15px;
+  -webkit-transition: opacity 200ms;
+  -moz-transition: opacity 200ms;
+  transition: opacity 200ms;
+  opacity: 0.3;
+  color: #888;
+}
+
+#mocha .test:hover a.replay {
+  opacity: 1;
+}
+
+#mocha-report.pass .test.fail {
+  display: none;
+}
+
+#mocha-report.fail .test.pass {
+  display: none;
+}
+
+#mocha-report.pending .test.pass,
+#mocha-report.pending .test.fail {
+  display: none;
+}
+#mocha-report.pending .test.pass.pending {
+  display: block;
+}
+
+#mocha-error {
+  color: #c00;
+  font-size: 1.5em;
+  font-weight: 100;
+  letter-spacing: 1px;
+}
+
+#mocha-stats {
+  position: fixed;
+  top: 15px;
+  right: 10px;
+  font-size: 12px;
+  margin: 0;
+  color: #888;
+  z-index: 1;
+}
+
+#mocha-stats .progress {
+  float: right;
+  padding-top: 0;
+}
+
+#mocha-stats em {
+  color: black;
+}
+
+#mocha-stats a {
+  text-decoration: none;
+  color: inherit;
+}
+
+#mocha-stats a:hover {
+  border-bottom: 1px solid #eee;
+}
+
+#mocha-stats li {
+  display: inline-block;
+  margin: 0 5px;
+  list-style: none;
+  padding-top: 11px;
+}
+
+#mocha-stats canvas {
+  width: 40px;
+  height: 40px;
+}
+
+#mocha code .comment { color: #ddd; }
+#mocha code .init { color: #2f6fad; }
+#mocha code .string { color: #5890ad; }
+#mocha code .keyword { color: #8a6343; }
+#mocha code .number { color: #2f6fad; }
+
+@media screen and (max-device-width: 480px) {
+  #mocha {
+    margin: 60px 0px;
+  }
+
+  #mocha #stats {
+    position: absolute;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/styles.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/styles.css b/sdks/html5-javascript/tests/resources/css/styles.css
new file mode 100755
index 0000000..7492f93
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/styles.css
@@ -0,0 +1,91 @@
+/**
+*  All Calls is a Node.js sample app that is powered by Usergrid
+*  This app shows how to make the 4 REST calls (GET, POST,
+*  PUT, DELETE) against the usergrid API.
+*
+*  Learn more at http://Usergrid.com/docs
+*
+*   Copyright 2012 Apigee 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.
+*/
+
+/**
+*  @file styles.css
+*  @author Rod Simpson (rod@apigee.com)
+*
+*/
+
+body {
+  background-color: #fff;
+  min-height: 800px;
+}
+
+/* buttons ================================================================= */
+.btn-primary{border-color:#1455ab #1455ab #0c3367;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);background-color:#146cab;background-image:-moz-linear-gradient(top, #147bab, #1455ab);background-image:-ms-linear-gradient(top, #147bab, #1455ab);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#147bab), to(#1455ab));background-image:-webkit-linear-gradient(top, #147bab, #1455ab);background-image:-o-linear-gradient(top, #147bab, #1455ab);background-image:linear-gradient(top, #147bab, #1455ab);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#147bab', endColorstr='#1455ab', GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#1455ab;}
+
+.header{
+   padding: 10px;
+   width: 100%;
+   height: 40px;
+   background-color: #ff4200;
+   color: #fff;
+   text-align: left;
+   font-size: 16px;
+   font-weight: 800;
+}
+.breadcrumb{
+  font-size: 16px;
+}
+.info{
+  padding: 0px 30px 30px 30px;
+  font-size: 16px;
+}
+h3{
+ padding-bottom: 20px;
+}
+.main{
+   display: block;
+   padding: 0 30px 30px 30px ;
+   background-color: #fff;
+}
+.form-block{
+  display: block;
+  display: none;
+  padding: 10px 0;
+  min-height: 210px;
+  background-color: #fff;
+}
+.section-header{
+  font-size: 20px;
+  font-weight: 200;
+  padding-bottom: 20px;
+}
+.note {
+   padding-bottom: 20px;
+}
+.response-box{
+   margin: 0 auto;
+   padding: 10px;
+   width: 640px;
+   border: 1px solid silver;
+   background-color: #ddd;
+   font-weight: bold;
+}
+pre{
+   border: none;
+   padding: 0;
+}
+.left{
+   float: left;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/images/apigee.png
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/images/apigee.png b/sdks/html5-javascript/tests/resources/images/apigee.png
new file mode 100755
index 0000000..c0d0f84
Binary files /dev/null and b/sdks/html5-javascript/tests/resources/images/apigee.png differ

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js b/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
new file mode 100644
index 0000000..74368f0
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/blanket_mocha.min.js
@@ -0,0 +1 @@
+(function(e){(function(t,n){"use strict";typeof e=="function"&&e.amd?e(["exports"],n):typeof exports!="undefined"?n(exports):n(t.esprima={})})(this,function(e){"use strict";function m(e,t){if(!e)throw new Error("ASSERT: "+t)}function g(e,t){return u.slice(e,t)}function y(e){return"0123456789".indexOf(e)>=0}function b(e){return"0123456789abcdefABCDEF".indexOf(e)>=0}function w(e){return"01234567".indexOf(e)>=0}function E(e){return e===" "||e===" "||e===""||e==="\f"||e==="\u00a0"||e.charCodeAt(0)>=5760&&"\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\ufeff".indexOf(e)>=0}function S(e){return e==="\n"||e==="\r"||e==="\u2028"||e==="\u2029"}function x(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierStart.test(e)}function T(e){return e==="$"||e==="_"||e==="\\"||e>="a"&&e<="z"||e>="A"&&e<="Z"||e>="0"&&e<="9"||e.charCodeAt(0)>=128&&o.NonAsciiIdentifierPart.test(e)}function N(e){
 switch(e){case"class":case"enum":case"export":case"extends":case"import":case"super":return!0}return!1}function C(e){switch(e){case"implements":case"interface":case"package":case"private":case"protected":case"public":case"static":case"yield":case"let":return!0}return!1}function k(e){return e==="eval"||e==="arguments"}function L(e){var t=!1;switch(e.length){case 2:t=e==="if"||e==="in"||e==="do";break;case 3:t=e==="var"||e==="for"||e==="new"||e==="try";break;case 4:t=e==="this"||e==="else"||e==="case"||e==="void"||e==="with";break;case 5:t=e==="while"||e==="break"||e==="catch"||e==="throw";break;case 6:t=e==="return"||e==="typeof"||e==="delete"||e==="switch";break;case 7:t=e==="default"||e==="finally";break;case 8:t=e==="function"||e==="continue"||e==="debugger";break;case 10:t=e==="instanceof"}if(t)return!0;switch(e){case"const":return!0;case"yield":case"let":return!0}return a&&C(e)?!0:N(e)}function A(){var e,t,n;t=!1,n=!1;while(f<h){e=u[f];if(n)e=u[f++],S(e)&&(n=!1,e==="\r"&&u[f]===
 "\n"&&++f,++l,c=f);else if(t)S(e)?(e==="\r"&&u[f+1]==="\n"&&++f,++l,++f,c=f,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")):(e=u[f++],f>=h&&R({},s.UnexpectedToken,"ILLEGAL"),e==="*"&&(e=u[f],e==="/"&&(++f,t=!1)));else if(e==="/"){e=u[f+1];if(e==="/")f+=2,n=!0;else{if(e!=="*")break;f+=2,t=!0,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")}}else if(E(e))++f;else{if(!S(e))break;++f,e==="\r"&&u[f]==="\n"&&++f,++l,c=f}}}function O(e){var t,n,r,i=0;n=e==="u"?4:2;for(t=0;t<n;++t){if(!(f<h&&b(u[f])))return"";r=u[f++],i=i*16+"0123456789abcdef".indexOf(r.toLowerCase())}return String.fromCharCode(i)}function M(){var e,n,r,i;e=u[f];if(!x(e))return;n=f;if(e==="\\"){++f;if(u[f]!=="u")return;++f,i=f,e=O("u");if(e){if(e==="\\"||!x(e))return;r=e}else f=i,r="u"}else r=u[f++];while(f<h){e=u[f];if(!T(e))break;if(e==="\\"){++f;if(u[f]!=="u")return;++f,i=f,e=O("u");if(e){if(e==="\\"||!T(e))return;r+=e}else f=i,r+="u"}else r+=u[f++]}return r.length===1?{type:t.Identifier,value:r,lineNumber:l,lineStart:c,range:[n,f]}:L(r
 )?{type:t.Keyword,value:r,lineNumber:l,lineStart:c,range:[n,f]}:r==="null"?{type:t.NullLiteral,value:r,lineNumber:l,lineStart:c,range:[n,f]}:r==="true"||r==="false"?{type:t.BooleanLiteral,value:r,lineNumber:l,lineStart:c,range:[n,f]}:{type:t.Identifier,value:r,lineNumber:l,lineStart:c,range:[n,f]}}function _(){var e=f,n=u[f],r,i,s;if(n===";"||n==="{"||n==="}")return++f,{type:t.Punctuator,value:n,lineNumber:l,lineStart:c,range:[e,f]};if(n===","||n==="("||n===")")return++f,{type:t.Punctuator,value:n,lineNumber:l,lineStart:c,range:[e,f]};r=u[f+1];if(n==="."&&!y(r))return{type:t.Punctuator,value:u[f++],lineNumber:l,lineStart:c,range:[e,f]};i=u[f+2],s=u[f+3];if(n===">"&&r===">"&&i===">"&&s==="=")return f+=4,{type:t.Punctuator,value:">>>=",lineNumber:l,lineStart:c,range:[e,f]};if(n==="="&&r==="="&&i==="=")return f+=3,{type:t.Punctuator,value:"===",lineNumber:l,lineStart:c,range:[e,f]};if(n==="!"&&r==="="&&i==="=")return f+=3,{type:t.Punctuator,value:"!==",lineNumber:l,lineStart:c,range:[e
 ,f]};if(n===">"&&r===">"&&i===">")return f+=3,{type:t.Punctuator,value:">>>",lineNumber:l,lineStart:c,range:[e,f]};if(n==="<"&&r==="<"&&i==="=")return f+=3,{type:t.Punctuator,value:"<<=",lineNumber:l,lineStart:c,range:[e,f]};if(n===">"&&r===">"&&i==="=")return f+=3,{type:t.Punctuator,value:">>=",lineNumber:l,lineStart:c,range:[e,f]};if(r==="="&&"<>=!+-*%&|^/".indexOf(n)>=0)return f+=2,{type:t.Punctuator,value:n+r,lineNumber:l,lineStart:c,range:[e,f]};if(n===r&&"+-<>&|".indexOf(n)>=0&&"+-<>&|".indexOf(r)>=0)return f+=2,{type:t.Punctuator,value:n+r,lineNumber:l,lineStart:c,range:[e,f]};if("[]<>+-*%&|^!~?:=/".indexOf(n)>=0)return{type:t.Punctuator,value:u[f++],lineNumber:l,lineStart:c,range:[e,f]}}function D(){var e,n,r;r=u[f],m(y(r)||r===".","Numeric literal must start with a decimal digit or a decimal point"),n=f,e="";if(r!=="."){e=u[f++],r=u[f];if(e==="0"){if(r==="x"||r==="X"){e+=u[f++];while(f<h){r=u[f];if(!b(r))break;e+=u[f++]}return e.length<=2&&R({},s.UnexpectedToken,"ILLEGAL"),
 f<h&&(r=u[f],x(r)&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseInt(e,16),lineNumber:l,lineStart:c,range:[n,f]}}if(w(r)){e+=u[f++];while(f<h){r=u[f];if(!w(r))break;e+=u[f++]}return f<h&&(r=u[f],(x(r)||y(r))&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseInt(e,8),octal:!0,lineNumber:l,lineStart:c,range:[n,f]}}y(r)&&R({},s.UnexpectedToken,"ILLEGAL")}while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}if(r==="."){e+=u[f++];while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}if(r==="e"||r==="E"){e+=u[f++],r=u[f];if(r==="+"||r==="-")e+=u[f++];r=u[f];if(y(r)){e+=u[f++];while(f<h){r=u[f];if(!y(r))break;e+=u[f++]}}else r="character "+r,f>=h&&(r="<end>"),R({},s.UnexpectedToken,"ILLEGAL")}return f<h&&(r=u[f],x(r)&&R({},s.UnexpectedToken,"ILLEGAL")),{type:t.NumericLiteral,value:parseFloat(e),lineNumber:l,lineStart:c,range:[n,f]}}function P(){var e="",n,r,i,o,a,p,d=!1;n=u[f],m(n==="'"||n==='"',"String literal must starts with a quote"),r=f,++f;while(f<h){i=u[f++];
 if(i===n){n="";break}if(i==="\\"){i=u[f++];if(!S(i))switch(i){case"n":e+="\n";break;case"r":e+="\r";break;case"t":e+="  ";break;case"u":case"x":p=f,a=O(i),a?e+=a:(f=p,e+=i);break;case"b":e+="\b";break;case"f":e+="\f";break;case"v":e+="";break;default:w(i)?(o="01234567".indexOf(i),o!==0&&(d=!0),f<h&&w(u[f])&&(d=!0,o=o*8+"01234567".indexOf(u[f++]),"0123".indexOf(i)>=0&&f<h&&w(u[f])&&(o=o*8+"01234567".indexOf(u[f++]))),e+=String.fromCharCode(o)):e+=i}else++l,i==="\r"&&u[f]==="\n"&&++f}else{if(S(i))break;e+=i}}return n!==""&&R({},s.UnexpectedToken,"ILLEGAL"),{type:t.StringLiteral,value:e,octal:d,lineNumber:l,lineStart:c,range:[r,f]}}function H(){var e,t,n,r,i,o,a=!1,l,c=!1;p=null,A(),n=f,t=u[f],m(t==="/","Regular expression literal must start with a slash"),e=u[f++];while(f<h){t=u[f++],e+=t;if(t==="\\")t=u[f++],S(t)&&R({},s.UnterminatedRegExp),e+=t;else if(a)t==="]"&&(a=!1);else{if(t==="/"){c=!0;break}t==="["?a=!0:S(t)&&R({},s.UnterminatedRegExp)}}c||R({},s.UnterminatedRegExp),r=e.subs
 tr(1,e.length-2),i="";while(f<h){t=u[f];if(!T(t))break;++f;if(t==="\\"&&f<h){t=u[f];if(t==="u"){++f,l=f,t=O("u");if(t){i+=t,e+="\\u";for(;l<f;++l)e+=u[l]}else f=l,i+="u",e+="\\u"}else e+="\\"}else i+=t,e+=t}try{o=new RegExp(r,i)}catch(d){R({},s.InvalidRegExp)}return{literal:e,value:o,range:[n,f]}}function B(e){return e.type===t.Identifier||e.type===t.Keyword||e.type===t.BooleanLiteral||e.type===t.NullLiteral}function j(){var e,n;A();if(f>=h)return{type:t.EOF,lineNumber:l,lineStart:c,range:[f,f]};n=_();if(typeof n!="undefined")return n;e=u[f];if(e==="'"||e==='"')return P();if(e==="."||y(e))return D();n=M();if(typeof n!="undefined")return n;R({},s.UnexpectedToken,"ILLEGAL")}function F(){var e;return p?(f=p.range[1],l=p.lineNumber,c=p.lineStart,e=p,p=null,e):(p=null,j())}function I(){var e,t,n;return p!==null?p:(e=f,t=l,n=c,p=j(),f=e,l=t,c=n,p)}function q(){var e,t,n,r;return e=f,t=l,n=c,A(),r=l!==t,f=e,l=t,c=n,r}function R(e,t){var n,r=Array.prototype.slice.call(arguments,2),i=t.repla
 ce(/%(\d)/g,function(e,t){return r[t]||""});throw typeof e.lineNumber=="number"?(n=new Error("Line "+e.lineNumber+": "+i),n.index=e.range[0],n.lineNumber=e.lineNumber,n.column=e.range[0]-c+1):(n=new Error("Line "+l+": "+i),n.index=f,n.lineNumber=l,n.column=f-c+1),n}function U(){try{R.apply(null,arguments)}catch(e){if(!v.errors)throw e;v.errors.push(e)}}function z(e){e.type===t.EOF&&R(e,s.UnexpectedEOS),e.type===t.NumericLiteral&&R(e,s.UnexpectedNumber),e.type===t.StringLiteral&&R(e,s.UnexpectedString),e.type===t.Identifier&&R(e,s.UnexpectedIdentifier);if(e.type===t.Keyword){if(N(e.value))R(e,s.UnexpectedReserved);else if(a&&C(e.value)){U(e,s.StrictReservedWord);return}R(e,s.UnexpectedToken,e.value)}R(e,s.UnexpectedToken,e.value)}function W(e){var n=F();(n.type!==t.Punctuator||n.value!==e)&&z(n)}function X(e){var n=F();(n.type!==t.Keyword||n.value!==e)&&z(n)}function V(e){var n=I();return n.type===t.Punctuator&&n.value===e}function $(e){var n=I();return n.type===t.Keyword&&n.value===
 e}function J(){var e=I(),n=e.value;return e.type!==t.Punctuator?!1:n==="="||n==="*="||n==="/="||n==="%="||n==="+="||n==="-="||n==="<<="||n===">>="||n===">>>="||n==="&="||n==="^="||n==="|="}function K(){var e,n;if(u[f]===";"){F();return}n=l,A();if(l!==n)return;if(V(";")){F();return}e=I(),e.type!==t.EOF&&!V("}")&&z(e)}function Q(e){return e.type===r.Identifier||e.type===r.MemberExpression}function G(){var e=[];W("[");while(!V("]"))V(",")?(F(),e.push(null)):(e.push(Tt()),V("]")||W(","));return W("]"),{type:r.ArrayExpression,elements:e}}function Y(e,t){var n,i;return n=a,i=Gt(),t&&a&&k(e[0].name)&&U(t,s.StrictParamName),a=n,{type:r.FunctionExpression,id:null,params:e,defaults:[],body:i,rest:null,generator:!1,expression:!1}}function Z(){var e=F();return e.type===t.StringLiteral||e.type===t.NumericLiteral?(a&&e.octal&&U(e,s.StrictOctalLiteral),ln(e)):{type:r.Identifier,name:e.value}}function et(){var e,n,i,o;e=I();if(e.type===t.Identifier)return i=Z(),e.value==="get"&&!V(":")?(n=Z(),W("("
 ),W(")"),{type:r.Property,key:n,value:Y([]),kind:"get"}):e.value==="set"&&!V(":")?(n=Z(),W("("),e=I(),e.type!==t.Identifier?(W(")"),U(e,s.UnexpectedToken,e.value),{type:r.Property,key:n,value:Y([]),kind:"set"}):(o=[Lt()],W(")"),{type:r.Property,key:n,value:Y(o,e),kind:"set"})):(W(":"),{type:r.Property,key:i,value:Tt(),kind:"init"});if(e.type!==t.EOF&&e.type!==t.Punctuator)return n=Z(),W(":"),{type:r.Property,key:n,value:Tt(),kind:"init"};z(e)}function tt(){var e=[],t,n,o,u={},f=String;W("{");while(!V("}"))t=et(),t.key.type===r.Identifier?n=t.key.name:n=f(t.key.value),o=t.kind==="init"?i.Data:t.kind==="get"?i.Get:i.Set,Object.prototype.hasOwnProperty.call(u,n)?(u[n]===i.Data?a&&o===i.Data?U({},s.StrictDuplicateProperty):o!==i.Data&&U({},s.AccessorDataProperty):o===i.Data?U({},s.AccessorDataProperty):u[n]&o&&U({},s.AccessorGetSet),u[n]|=o):u[n]=o,e.push(t),V("}")||W(",");return W("}"),{type:r.ObjectExpression,properties:e}}function nt(){var e;return W("("),e=Nt(),W(")"),e}function rt(
 ){var e=I(),n=e.type;if(n===t.Identifier)return{type:r.Identifier,name:F().value};if(n===t.StringLiteral||n===t.NumericLiteral)return a&&e.octal&&U(e,s.StrictOctalLiteral),ln(F());if(n===t.Keyword){if($("this"))return F(),{type:r.ThisExpression};if($("function"))return Zt()}return n===t.BooleanLiteral?(F(),e.value=e.value==="true",ln(e)):n===t.NullLiteral?(F(),e.value=null,ln(e)):V("[")?G():V("{")?tt():V("(")?nt():V("/")||V("/=")?ln(H()):z(F())}function it(){var e=[];W("(");if(!V(")"))while(f<h){e.push(Tt());if(V(")"))break;W(",")}return W(")"),e}function st(){var e=F();return B(e)||z(e),{type:r.Identifier,name:e.value}}function ot(){return W("."),st()}function ut(){var e;return W("["),e=Nt(),W("]"),e}function at(){var e;return X("new"),e={type:r.NewExpression,callee:lt(),arguments:[]},V("(")&&(e.arguments=it()),e}function ft(){var e;e=$("new")?at():rt();while(V(".")||V("[")||V("("))V("(")?e={type:r.CallExpression,callee:e,arguments:it()}:V("[")?e={type:r.MemberExpression,computed:!
 0,object:e,property:ut()}:e={type:r.MemberExpression,computed:!1,object:e,property:ot()};return e}function lt(){var e;e=$("new")?at():rt();while(V(".")||V("["))V("[")?e={type:r.MemberExpression,computed:!0,object:e,property:ut()}:e={type:r.MemberExpression,computed:!1,object:e,property:ot()};return e}function ct(){var e=ft(),n;return n=I(),n.type!==t.Punctuator?e:((V("++")||V("--"))&&!q()&&(a&&e.type===r.Identifier&&k(e.name)&&U({},s.StrictLHSPostfix),Q(e)||U({},s.InvalidLHSInAssignment),e={type:r.UpdateExpression,operator:F().value,argument:e,prefix:!1}),e)}function ht(){var e,n;return e=I(),e.type!==t.Punctuator&&e.type!==t.Keyword?ct():V("++")||V("--")?(e=F(),n=ht(),a&&n.type===r.Identifier&&k(n.name)&&U({},s.StrictLHSPrefix),Q(n)||U({},s.InvalidLHSInAssignment),n={type:r.UpdateExpression,operator:e.value,argument:n,prefix:!0},n):V("+")||V("-")||V("~")||V("!")?(n={type:r.UnaryExpression,operator:F().value,argument:ht(),prefix:!0},n):$("delete")||$("void")||$("typeof")?(n={type:r.
 UnaryExpression,operator:F().value,argument:ht(),prefix:!0},a&&n.operator==="delete"&&n.argument.type===r.Identifier&&U({},s.StrictDelete),n):ct()}function pt(){var e=ht();while(V("*")||V("/")||V("%"))e={type:r.BinaryExpression,operator:F().value,left:e,right:ht()};return e}function dt(){var e=pt();while(V("+")||V("-"))e={type:r.BinaryExpression,operator:F().value,left:e,right:pt()};return e}function vt(){var e=dt();while(V("<<")||V(">>")||V(">>>"))e={type:r.BinaryExpression,operator:F().value,left:e,right:dt()};return e}function mt(){var e,t;t=d.allowIn,d.allowIn=!0,e=vt();while(V("<")||V(">")||V("<=")||V(">=")||t&&$("in")||$("instanceof"))e={type:r.BinaryExpression,operator:F().value,left:e,right:vt()};return d.allowIn=t,e}function gt(){var e=mt();while(V("==")||V("!=")||V("===")||V("!=="))e={type:r.BinaryExpression,operator:F().value,left:e,right:mt()};return e}function yt(){var e=gt();while(V("&"))F(),e={type:r.BinaryExpression,operator:"&",left:e,right:gt()};return e}function b
 t(){var e=yt();while(V("^"))F(),e={type:r.BinaryExpression,operator:"^",left:e,right:yt()};return e}function wt(){var e=bt();while(V("|"))F(),e={type:r.BinaryExpression,operator:"|",left:e,right:bt()};return e}function Et(){var e=wt();while(V("&&"))F(),e={type:r.LogicalExpression,operator:"&&",left:e,right:wt()};return e}function St(){var e=Et();while(V("||"))F(),e={type:r.LogicalExpression,operator:"||",left:e,right:Et()};return e}function xt(){var e,t,n;return e=St(),V("?")&&(F(),t=d.allowIn,d.allowIn=!0,n=Tt(),d.allowIn=t,W(":"),e={type:r.ConditionalExpression,test:e,consequent:n,alternate:Tt()}),e}function Tt(){var e,t;return e=I(),t=xt(),J()&&(Q(t)||U({},s.InvalidLHSInAssignment),a&&t.type===r.Identifier&&k(t.name)&&U(e,s.StrictLHSAssignment),t={type:r.AssignmentExpression,operator:F().value,left:t,right:Tt()}),t}function Nt(){var e=Tt();if(V(",")){e={type:r.SequenceExpression,expressions:[e]};while(f<h){if(!V(","))break;F(),e.expressions.push(Tt())}}return e}function Ct(){var 
 e=[],t;while(f<h){if(V("}"))break;t=en();if(typeof t=="undefined")break;e.push(t)}return e}function kt(){var e;return W("{"),e=Ct(),W("}"),{type:r.BlockStatement,body:e}}function Lt(){var e=F();return e.type!==t.Identifier&&z(e),{type:r.Identifier,name:e.value}}function At(e){var t=Lt(),n=null;return a&&k(t.name)&&U({},s.StrictVarName),e==="const"?(W("="),n=Tt()):V("=")&&(F(),n=Tt()),{type:r.VariableDeclarator,id:t,init:n}}function Ot(e){var t=[];do{t.push(At(e));if(!V(","))break;F()}while(f<h);return t}function Mt(){var e;return X("var"),e=Ot(),K(),{type:r.VariableDeclaration,declarations:e,kind:"var"}}function _t(e){var t;return X(e),t=Ot(e),K(),{type:r.VariableDeclaration,declarations:t,kind:e}}function Dt(){return W(";"),{type:r.EmptyStatement}}function Pt(){var e=Nt();return K(),{type:r.ExpressionStatement,expression:e}}function Ht(){var e,t,n;return X("if"),W("("),e=Nt(),W(")"),t=Qt(),$("else")?(F(),n=Qt()):n=null,{type:r.IfStatement,test:e,consequent:t,alternate:n}}function B
 t(){var e,t,n;return X("do"),n=d.inIteration,d.inIteration=!0,e=Qt(),d.inIteration=n,X("while"),W("("),t=Nt(),W(")"),V(";")&&F(),{type:r.DoWhileStatement,body:e,test:t}}function jt(){var e,t,n;return X("while"),W("("),e=Nt(),W(")"),n=d.inIteration,d.inIteration=!0,t=Qt(),d.inIteration=n,{type:r.WhileStatement,test:e,body:t}}function Ft(){var e=F();return{type:r.VariableDeclaration,declarations:Ot(),kind:e.value}}function It(){var e,t,n,i,o,u,a;return e=t=n=null,X("for"),W("("),V(";")?F():($("var")||$("let")?(d.allowIn=!1,e=Ft(),d.allowIn=!0,e.declarations.length===1&&$("in")&&(F(),i=e,o=Nt(),e=null)):(d.allowIn=!1,e=Nt(),d.allowIn=!0,$("in")&&(Q(e)||U({},s.InvalidLHSInForIn),F(),i=e,o=Nt(),e=null)),typeof i=="undefined"&&W(";")),typeof i=="undefined"&&(V(";")||(t=Nt()),W(";"),V(")")||(n=Nt())),W(")"),a=d.inIteration,d.inIteration=!0,u=Qt(),d.inIteration=a,typeof i=="undefined"?{type:r.ForStatement,init:e,test:t,update:n,body:u}:{type:r.ForInStatement,left:i,right:o,body:u,each:!1}}f
 unction qt(){var e,n=null;return X("continue"),u[f]===";"?(F(),d.inIteration||R({},s.IllegalContinue),{type:r.ContinueStatement,label:null}):q()?(d.inIteration||R({},s.IllegalContinue),{type:r.ContinueStatement,label:null}):(e=I(),e.type===t.Identifier&&(n=Lt(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)||R({},s.UnknownLabel,n.name)),K(),n===null&&!d.inIteration&&R({},s.IllegalContinue),{type:r.ContinueStatement,label:n})}function Rt(){var e,n=null;return X("break"),u[f]===";"?(F(),!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:null}):q()?(!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:null}):(e=I(),e.type===t.Identifier&&(n=Lt(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)||R({},s.UnknownLabel,n.name)),K(),n===null&&!d.inIteration&&!d.inSwitch&&R({},s.IllegalBreak),{type:r.BreakStatement,label:n})}function Ut(){var e,n=null;return X("return"),d.inFunctionBody||U({},s.IllegalReturn),u[f]===" "&&x(
 u[f+1])?(n=Nt(),K(),{type:r.ReturnStatement,argument:n}):q()?{type:r.ReturnStatement,argument:null}:(V(";")||(e=I(),!V("}")&&e.type!==t.EOF&&(n=Nt())),K(),{type:r.ReturnStatement,argument:n})}function zt(){var e,t;return a&&U({},s.StrictModeWith),X("with"),W("("),e=Nt(),W(")"),t=Qt(),{type:r.WithStatement,object:e,body:t}}function Wt(){var e,t=[],n;$("default")?(F(),e=null):(X("case"),e=Nt()),W(":");while(f<h){if(V("}")||$("default")||$("case"))break;n=Qt();if(typeof n=="undefined")break;t.push(n)}return{type:r.SwitchCase,test:e,consequent:t}}function Xt(){var e,t,n,i,o;X("switch"),W("("),e=Nt(),W(")"),W("{"),t=[];if(V("}"))return F(),{type:r.SwitchStatement,discriminant:e,cases:t};i=d.inSwitch,d.inSwitch=!0,o=!1;while(f<h){if(V("}"))break;n=Wt(),n.test===null&&(o&&R({},s.MultipleDefaultsInSwitch),o=!0),t.push(n)}return d.inSwitch=i,W("}"),{type:r.SwitchStatement,discriminant:e,cases:t}}function Vt(){var e;return X("throw"),q()&&R({},s.NewlineAfterThrow),e=Nt(),K(),{type:r.ThrowStat
 ement,argument:e}}function $t(){var e;return X("catch"),W("("),V(")")&&z(I()),e=Lt(),a&&k(e.name)&&U({},s.StrictCatchVariable),W(")"),{type:r.CatchClause,param:e,body:kt()}}function Jt(){var e,t=[],n=null;return X("try"),e=kt(),$("catch")&&t.push($t()),$("finally")&&(F(),n=kt()),t.length===0&&!n&&R({},s.NoCatchOrFinally),{type:r.TryStatement,block:e,guardedHandlers:[],handlers:t,finalizer:n}}function Kt(){return X("debugger"),K(),{type:r.DebuggerStatement}}function Qt(){var e=I(),n,i;e.type===t.EOF&&z(e);if(e.type===t.Punctuator)switch(e.value){case";":return Dt();case"{":return kt();case"(":return Pt();default:}if(e.type===t.Keyword)switch(e.value){case"break":return Rt();case"continue":return qt();case"debugger":return Kt();case"do":return Bt();case"for":return It();case"function":return Yt();case"if":return Ht();case"return":return Ut();case"switch":return Xt();case"throw":return Vt();case"try":return Jt();case"var":return Mt();case"while":return jt();case"with":return zt();defau
 lt:}return n=Nt(),n.type===r.Identifier&&V(":")?(F(),Object.prototype.hasOwnProperty.call(d.labelSet,n.name)&&R({},s.Redeclaration,"Label",n.name),d.labelSet[n.name]=!0,i=Qt(),delete d.labelSet[n.name],{type:r.LabeledStatement,label:n,body:i}):(K(),{type:r.ExpressionStatement,expression:n})}function Gt(){var e,n=[],i,o,u,l,c,p,v;W("{");while(f<h){i=I();if(i.type!==t.StringLiteral)break;e=en(),n.push(e);if(e.expression.type!==r.Literal)break;o=g(i.range[0]+1,i.range[1]-1),o==="use strict"?(a=!0,u&&U(u,s.StrictOctalLiteral)):!u&&i.octal&&(u=i)}l=d.labelSet,c=d.inIteration,p=d.inSwitch,v=d.inFunctionBody,d.labelSet={},d.inIteration=!1,d.inSwitch=!1,d.inFunctionBody=!0;while(f<h){if(V("}"))break;e=en();if(typeof e=="undefined")break;n.push(e)}return W("}"),d.labelSet=l,d.inIteration=c,d.inSwitch=p,d.inFunctionBody=v,{type:r.BlockStatement,body:n}}function Yt(){var e,t,n=[],i,o,u,l,c,p,d;X("function"),o=I(),e=Lt(),a?k(o.value)&&U(o,s.StrictFunctionName):k(o.value)?(l=o,c=s.StrictFunction
 Name):C(o.value)&&(l=o,c=s.StrictReservedWord),W("(");if(!V(")")){d={};while(f<h){o=I(),t=Lt(),a?(k(o.value)&&(u=o,c=s.StrictParamName),Object.prototype.hasOwnProperty.call(d,o.value)&&(u=o,c=s.StrictParamDupe)):l||(k(o.value)?(l=o,c=s.StrictParamName):C(o.value)?(l=o,c=s.StrictReservedWord):Object.prototype.hasOwnProperty.call(d,o.value)&&(l=o,c=s.StrictParamDupe)),n.push(t),d[t.name]=!0;if(V(")"))break;W(",")}}return W(")"),p=a,i=Gt(),a&&l&&R(l,c),a&&u&&U(u,c),a=p,{type:r.FunctionDeclaration,id:e,params:n,defaults:[],body:i,rest:null,generator:!1,expression:!1}}function Zt(){var e,t=null,n,i,o,u,l=[],c,p,d;X("function"),V("(")||(e=I(),t=Lt(),a?k(e.value)&&U(e,s.StrictFunctionName):k(e.value)?(i=e,o=s.StrictFunctionName):C(e.value)&&(i=e,o=s.StrictReservedWord)),W("(");if(!V(")")){d={};while(f<h){e=I(),u=Lt(),a?(k(e.value)&&(n=e,o=s.StrictParamName),Object.prototype.hasOwnProperty.call(d,e.value)&&(n=e,o=s.StrictParamDupe)):i||(k(e.value)?(i=e,o=s.StrictParamName):C(e.value)?(i=e,o
 =s.StrictReservedWord):Object.prototype.hasOwnProperty.call(d,e.value)&&(i=e,o=s.StrictParamDupe)),l.push(u),d[u.name]=!0;if(V(")"))break;W(",")}}return W(")"),p=a,c=Gt(),a&&i&&R(i,o),a&&n&&U(n,o),a=p,{type:r.FunctionExpression,id:t,params:l,defaults:[],body:c,rest:null,generator:!1,expression:!1}}function en(){var e=I();if(e.type===t.Keyword)switch(e.value){case"const":case"let":return _t(e.value);case"function":return Yt();default:return Qt()}if(e.type!==t.EOF)return Qt()}function tn(){var e,n=[],i,o,u;while(f<h){i=I();if(i.type!==t.StringLiteral)break;e=en(),n.push(e);if(e.expression.type!==r.Literal)break;o=g(i.range[0]+1,i.range[1]-1),o==="use strict"?(a=!0,u&&U(u,s.StrictOctalLiteral)):!u&&i.octal&&(u=i)}while(f<h){e=en();if(typeof e=="undefined")break;n.push(e)}return n}function nn(){var e;return a=!1,e={type:r.Program,body:tn()},e}function rn(e,t,n,r,i){m(typeof n=="number","Comment must have valid position");if(v.comments.length>0&&v.comments[v.comments.length-1].range[1]>n
 )return;v.comments.push({type:e,value:t,range:[n,r],loc:i})}function sn(){var e,t,n,r,i,o;e="",i=!1,o=!1;while(f<h){t=u[f];if(o)t=u[f++],S(t)?(n.end={line:l,column:f-c-1},o=!1,rn("Line",e,r,f-1,n),t==="\r"&&u[f]==="\n"&&++f,++l,c=f,e=""):f>=h?(o=!1,e+=t,n.end={line:l,column:h-c},rn("Line",e,r,h,n)):e+=t;else if(i)S(t)?(t==="\r"&&u[f+1]==="\n"?(++f,e+="\r\n"):e+=t,++l,++f,c=f,f>=h&&R({},s.UnexpectedToken,"ILLEGAL")):(t=u[f++],f>=h&&R({},s.UnexpectedToken,"ILLEGAL"),e+=t,t==="*"&&(t=u[f],t==="/"&&(e=e.substr(0,e.length-1),i=!1,++f,n.end={line:l,column:f-c},rn("Block",e,r,f,n),e="")));else if(t==="/"){t=u[f+1];if(t==="/")n={start:{line:l,column:f-c}},r=f,f+=2,o=!0,f>=h&&(n.end={line:l,column:f-c},o=!1,rn("Line",e,r,f,n));else{if(t!=="*")break;r=f,f+=2,i=!0,n={start:{line:l,column:f-c-2}},f>=h&&R({},s.UnexpectedToken,"ILLEGAL")}}else if(E(t))++f;else{if(!S(t))break;++f,t==="\r"&&u[f]==="\n"&&++f,++l,c=f}}}function on(){var e,t,n,r=[];for(e=0;e<v.comments.length;++e)t=v.comments[e],n={ty
 pe:t.type,value:t.value},v.range&&(n.range=t.range),v.loc&&(n.loc=t.loc),r.push(n);v.comments=r}function un(){var e,r,i,s,o;return A(),e=f,r={start:{line:l,column:f-c}},i=v.advance(),r.end={line:l,column:f-c},i.type!==t.EOF&&(s=[i.range[0],i.range[1]],o=g(i.range[0],i.range[1]),v.tokens.push({type:n[i.type],value:o,range:s,loc:r})),i}function an(){var e,t,n,r;return A(),e=f,t={start:{line:l,column:f-c}},n=v.scanRegExp(),t.end={line:l,column:f-c},v.tokens.length>0&&(r=v.tokens[v.tokens.length-1],r.range[0]===e&&r.type==="Punctuator"&&(r.value==="/"||r.value==="/=")&&v.tokens.pop()),v.tokens.push({type:"RegularExpression",value:n.literal,range:[e,f],loc:t}),n}function fn(){var e,t,n,r=[];for(e=0;e<v.tokens.length;++e)t=v.tokens[e],n={type:t.type,value:t.value},v.range&&(n.range=t.range),v.loc&&(n.loc=t.loc),r.push(n);v.tokens=r}function ln(e){return{type:r.Literal,value:e.value}}function cn(e){return{type:r.Literal,value:e.value,raw:g(e.range[0],e.range[1])}}function hn(){var e={};ret
 urn e.range=[f,f],e.loc={start:{line:l,column:f-c},end:{line:l,column:f-c}},e.end=function(){this.range[1]=f,this.loc.end.line=l,this.loc.end.column=f-c},e.applyGroup=function(e){v.range&&(e.groupRange=[this.range[0],this.range[1]]),v.loc&&(e.groupLoc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e.apply=function(e){v.range&&(e.range=[this.range[0],this.range[1]]),v.loc&&(e.loc={start:{line:this.loc.start.line,column:this.loc.start.column},end:{line:this.loc.end.line,column:this.loc.end.column}})},e}function pn(){var e,t;return A(),e=hn(),W("("),t=Nt(),W(")"),e.end(),e.applyGroup(t),t}function dn(){var e,t;A(),e=hn(),t=$("new")?at():rt();while(V(".")||V("["))V("[")?(t={type:r.MemberExpression,computed:!0,object:t,property:ut()},e.end(),e.apply(t)):(t={type:r.MemberExpression,computed:!1,object:t,property:ot()},e.end(),e.apply(t));return t}function vn(){var e,t;A(),e=hn(),t=$("new")?at():rt();while(V(".")||V(
 "[")||V("("))V("(")?(t={type:r.CallExpression,callee:t,arguments:it()},e.end(),e.apply(t)):V("[")?(t={type:r.MemberExpression,computed:!0,object:t,property:ut()},e.end(),e.apply(t)):(t={type:r.MemberExpression,computed:!1,object:t,property:ot()},e.end(),e.apply(t));return t}function mn(e){var t,n,r;t=Object.prototype.toString.apply(e)==="[object Array]"?[]:{};for(n in e)e.hasOwnProperty(n)&&n!=="groupRange"&&n!=="groupLoc"&&(r=e[n],r===null||typeof r!="object"||r instanceof RegExp?t[n]=r:t[n]=mn(r));return t}function gn(e,t){return function(n){function i(e){return e.type===r.LogicalExpression||e.type===r.BinaryExpression}function s(n){var r,o;i(n.left)&&s(n.left),i(n.right)&&s(n.right),e&&(n.left.groupRange||n.right.groupRange?(r=n.left.groupRange?n.left.groupRange[0]:n.left.range[0],o=n.right.groupRange?n.right.groupRange[1]:n.right.range[1],n.range=[r,o]):typeof n.range=="undefined"&&(r=n.left.range[0],o=n.right.range[1],n.range=[r,o])),t&&(n.left.groupLoc||n.right.groupLoc?(r=n.l
 eft.groupLoc?n.left.groupLoc.start:n.left.loc.start,o=n.right.groupLoc?n.right.groupLoc.end:n.right.loc.end,n.loc={start:r,end:o}):typeof n.loc=="undefined"&&(n.loc={start:n.left.loc.start,end:n.right.loc.end}))}return function(){var r,o;return A(),r=hn(),o=n.apply(null,arguments),r.end(),e&&typeof o.range=="undefined"&&r.apply(o),t&&typeof o.loc=="undefined"&&r.apply(o),i(o)&&s(o),o}}}function yn(){var e;v.comments&&(v.skipComment=A,A=sn),v.raw&&(v.createLiteral=ln,ln=cn);if(v.range||v.loc)v.parseGroupExpression=nt,v.parseLeftHandSideExpression=lt,v.parseLeftHandSideExpressionAllowCall=ft,nt=pn,lt=dn,ft=vn,e=gn(v.range,v.loc),v.parseAdditiveExpression=dt,v.parseAssignmentExpression=Tt,v.parseBitwiseANDExpression=yt,v.parseBitwiseORExpression=wt,v.parseBitwiseXORExpression=bt,v.parseBlock=kt,v.parseFunctionSourceElements=Gt,v.parseCatchClause=$t,v.parseComputedMember=ut,v.parseConditionalExpression=xt,v.parseConstLetDeclaration=_t,v.parseEqualityExpression=gt,v.parseExpression=Nt,v.
 parseForVariableDeclaration=Ft,v.parseFunctionDeclaration=Yt,v.parseFunctionExpression=Zt,v.parseLogicalANDExpression=Et,v.parseLogicalORExpression=St,v.parseMultiplicativeExpression=pt,v.parseNewExpression=at,v.parseNonComputedProperty=st,v.parseObjectProperty=et,v.parseObjectPropertyKey=Z,v.parsePostfixExpression=ct,v.parsePrimaryExpression=rt,v.parseProgram=nn,v.parsePropertyFunction=Y,v.parseRelationalExpression=mt,v.parseStatement=Qt,v.parseShiftExpression=vt,v.parseSwitchCase=Wt,v.parseUnaryExpression=ht,v.parseVariableDeclaration=At,v.parseVariableIdentifier=Lt,dt=e(v.parseAdditiveExpression),Tt=e(v.parseAssignmentExpression),yt=e(v.parseBitwiseANDExpression),wt=e(v.parseBitwiseORExpression),bt=e(v.parseBitwiseXORExpression),kt=e(v.parseBlock),Gt=e(v.parseFunctionSourceElements),$t=e(v.parseCatchClause),ut=e(v.parseComputedMember),xt=e(v.parseConditionalExpression),_t=e(v.parseConstLetDeclaration),gt=e(v.parseEqualityExpression),Nt=e(v.parseExpression),Ft=e(v.parseForVariable
 Declaration),Yt=e(v.parseFunctionDeclaration),Zt=e(v.parseFunctionExpression),lt=e(lt),Et=e(v.parseLogicalANDExpression),St=e(v.parseLogicalORExpression),pt=e(v.parseMultiplicativeExpression),at=e(v.parseNewExpression),st=e(v.parseNonComputedProperty),et=e(v.parseObjectProperty),Z=e(v.parseObjectPropertyKey),ct=e(v.parsePostfixExpression),rt=e(v.parsePrimaryExpression),nn=e(v.parseProgram),Y=e(v.parsePropertyFunction),mt=e(v.parseRelationalExpression),Qt=e(v.parseStatement),vt=e(v.parseShiftExpression),Wt=e(v.parseSwitchCase),ht=e(v.parseUnaryExpression),At=e(v.parseVariableDeclaration),Lt=e(v.parseVariableIdentifier);typeof v.tokens!="undefined"&&(v.advance=j,v.scanRegExp=H,j=un,H=an)}function bn(){typeof v.skipComment=="function"&&(A=v.skipComment),v.raw&&(ln=v.createLiteral);if(v.range||v.loc)dt=v.parseAdditiveExpression,Tt=v.parseAssignmentExpression,yt=v.parseBitwiseANDExpression,wt=v.parseBitwiseORExpression,bt=v.parseBitwiseXORExpression,kt=v.parseBlock,Gt=v.parseFunctionSour
 ceElements,$t=v.parseCatchClause,ut=v.parseComputedMember,xt=v.parseConditionalExpression,_t=v.parseConstLetDeclaration,gt=v.parseEqualityExpression,Nt=v.parseExpression,Ft=v.parseForVariableDeclaration,Yt=v.parseFunctionDeclaration,Zt=v.parseFunctionExpression,nt=v.parseGroupExpression,lt=v.parseLeftHandSideExpression,ft=v.parseLeftHandSideExpressionAllowCall,Et=v.parseLogicalANDExpression,St=v.parseLogicalORExpression,pt=v.parseMultiplicativeExpression,at=v.parseNewExpression,st=v.parseNonComputedProperty,et=v.parseObjectProperty,Z=v.parseObjectPropertyKey,rt=v.parsePrimaryExpression,ct=v.parsePostfixExpression,nn=v.parseProgram,Y=v.parsePropertyFunction,mt=v.parseRelationalExpression,Qt=v.parseStatement,vt=v.parseShiftExpression,Wt=v.parseSwitchCase,ht=v.parseUnaryExpression,At=v.parseVariableDeclaration,Lt=v.parseVariableIdentifier;typeof v.scanRegExp=="function"&&(j=v.advance,H=v.scanRegExp)}function wn(e){var t=e.length,n=[],r;for(r=0;r<t;++r)n[r]=e.charAt(r);return n}function
  En(e,t){var n,r;r=String,typeof e!="string"&&!(e instanceof String)&&(e=r(e)),u=e,f=0,l=u.length>0?1:0,c=0,h=u.length,p=null,d={allowIn:!0,labelSet:{},inFunctionBody:!1,inIteration:!1,inSwitch:!1},v={},typeof t!="undefined"&&(v.range=typeof t.range=="boolean"&&t.range,v.loc=typeof t.loc=="boolean"&&t.loc,v.raw=typeof t.raw=="boolean"&&t.raw,typeof t.tokens=="boolean"&&t.tokens&&(v.tokens=[]),typeof t.comment=="boolean"&&t.comment&&(v.comments=[]),typeof t.tolerant=="boolean"&&t.tolerant&&(v.errors=[])),h>0&&typeof u[0]=="undefined"&&(e instanceof String&&(u=e.valueOf()),typeof u[0]=="undefined"&&(u=wn(e))),yn();try{n=nn(),typeof v.comments!="undefined"&&(on(),n.comments=v.comments),typeof v.tokens!="undefined"&&(fn(),n.tokens=v.tokens),typeof v.errors!="undefined"&&(n.errors=v.errors);if(v.range||v.loc)n.body=mn(n.body)}catch(i){throw i}finally{bn(),v={}}return n}var t,n,r,i,s,o,u,a,f,l,c,h,p,d,v;t={BooleanLiteral:1,EOF:2,Identifier:3,Keyword:4,NullLiteral:5,NumericLiteral:6,Punctu
 ator:7,StringLiteral:8},n={},n[t.BooleanLiteral]="Boolean",n[t.EOF]="<end>",n[t.Identifier]="Identifier",n[t.Keyword]="Keyword",n[t.NullLiteral]="Null",n[t.NumericLiteral]="Numeric",n[t.Punctuator]="Punctuator",n[t.StringLiteral]="String",r={AssignmentExpression:"AssignmentExpression",ArrayExpression:"ArrayExpression",BlockStatement:"BlockStatement",BinaryExpression:"BinaryExpression",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ConditionalExpression:"ConditionalExpression",ContinueStatement:"ContinueStatement",DoWhileStatement:"DoWhileStatement",DebuggerStatement:"DebuggerStatement",EmptyStatement:"EmptyStatement",ExpressionStatement:"ExpressionStatement",ForStatement:"ForStatement",ForInStatement:"ForInStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",Literal:"Literal",LabeledStatement:"LabeledStatement",LogicalExpression:"LogicalExpression",Mem
 berExpression:"MemberExpression",NewExpression:"NewExpression",ObjectExpression:"ObjectExpression",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SequenceExpression:"SequenceExpression",SwitchStatement:"SwitchStatement",SwitchCase:"SwitchCase",ThisExpression:"ThisExpression",ThrowStatement:"ThrowStatement",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement",WithStatement:"WithStatement"},i={Data:1,Get:2,Set:4},s={UnexpectedToken:"Unexpected token %0",UnexpectedNumber:"Unexpected number",UnexpectedString:"Unexpected string",UnexpectedIdentifier:"Unexpected identifier",UnexpectedReserved:"Unexpected reserved word",UnexpectedEOS:"Unexpected end of input",NewlineAfterThrow:"Illegal newline after throw",InvalidRegExp:"Invalid regular expression",UnterminatedRegExp:"Invalid regular expression: missing /",In
 validLHSInAssignment:"Invalid left-hand side in assignment",InvalidLHSInForIn:"Invalid left-hand side in for-in",MultipleDefaultsInSwitch:"More than one default clause in switch statement",NoCatchOrFinally:"Missing catch or finally after try",UnknownLabel:"Undefined label '%0'",Redeclaration:"%0 '%1' has already been declared",IllegalContinue:"Illegal continue statement",IllegalBreak:"Illegal break statement",IllegalReturn:"Illegal return statement",StrictModeWith:"Strict mode code may not include a with statement",StrictCatchVariable:"Catch variable may not be eval or arguments in strict mode",StrictVarName:"Variable name may not be eval or arguments in strict mode",StrictParamName:"Parameter name eval or arguments is not allowed in strict mode",StrictParamDupe:"Strict mode function may not have duplicate parameter names",StrictFunctionName:"Function name may not be eval or arguments in strict mode",StrictOctalLiteral:"Octal literals are not allowed in strict mode.",StrictDelete:"D
 elete of an unqualified identifier in strict mode.",StrictDuplicateProperty:"Duplicate data property in object literal not allowed in strict mode",AccessorDataProperty:"Object literal may not have data and accessor property with the same name",AccessorGetSet:"Object literal may not have multiple get/set accessors with the same name",StrictLHSAssignment:"Assignment to eval or arguments is not allowed in strict mode",StrictLHSPostfix:"Postfix increment/decrement may not have eval or arguments operand in strict mode",StrictLHSPrefix:"Prefix increment/decrement may not have eval or arguments operand in strict mode",StrictReservedWord:"Use of future reserved word in strict mode"},o={NonAsciiIdentifierStart:new RegExp("[\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u062
 0-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\
 u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18
 f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0
 -\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]"),NonAsciiIdentifierPart:new RegExp("[\u00aa\u0
 0b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0300-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u0483-\u0487\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u05d0-\u05ea\u05f0-\u05f2\u0610-\u061a\u0620-\u0669\u066e-\u06d3\u06d5-\u06dc\u06df-\u06e8\u06ea-\u06fc\u06ff\u0710-\u074a\u074d-\u07b1\u07c0-\u07f5\u07fa\u0800-\u082d\u0840-\u085b\u08a0\u08a2-\u08ac\u08e4-\u08fe\u0900-\u0963\u0966-\u096f\u0971-\u0977\u0979-\u097f\u0981-\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bc-\u09c4\u09c7\u09c8\u09cb-\u09ce\u09d7\u09dc\u09dd\u09df-\u09e3\u09e6-\u09f1\u0a01-\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a59-\u0a5c\u0a5e\u0a66-\u0a75\u0a81-\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9
 \u0abc-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ad0\u0ae0-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3c-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5c\u0b5d\u0b5f-\u0b63\u0b66-\u0b6f\u0b71\u0b82\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd0\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c58\u0c59\u0c60-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbc-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0cde\u0ce0-\u0ce3\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d44\u0d46-\u0d48\u0d4a-\u0d4e\u0d57\u0d60-\u0d63\u0d66-\u0d6f\u0d7a-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dca\u0dcf-\u0
 dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e01-\u0e3a\u0e40-\u0e4e\u0e50-\u0e59\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb9\u0ebb-\u0ebd\u0ec0-\u0ec4\u0ec6\u0ec8-\u0ecd\u0ed0-\u0ed9\u0edc-\u0edf\u0f00\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e-\u0f47\u0f49-\u0f6c\u0f71-\u0f84\u0f86-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1049\u1050-\u109d\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u135d-\u135f\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1714\u1720-\u1734\u1740-\u1753\u1760-\u176c\u176e-\u1770\u1772\u1773\u1780-\u17d3\u17d7\u17dc\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1820-\u1877\u1880-\u18aa\u18b0-\u18f5\u1900-\u191c\u1920-\u192b\u1930-\u193b\u1946-\u196d\u
 1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19d9\u1a00-\u1a1b\u1a20-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1aa7\u1b00-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1bf3\u1c00-\u1c37\u1c40-\u1c49\u1c4d-\u1c7d\u1cd0-\u1cd2\u1cd4-\u1cf6\u1d00-\u1de6\u1dfc-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200c\u200d\u203f\u2040\u2054\u2071\u207f\u2090-\u209c\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d7f-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2de0-\u2dff\u2e2f\u3005-\u3007\u3021-\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u3099\u30
 9a\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua62b\ua640-\ua66f\ua674-\ua67d\ua67f-\ua697\ua69f-\ua6f1\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua827\ua840-\ua873\ua880-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f7\ua8fb\ua900-\ua92d\ua930-\ua953\ua960-\ua97c\ua980-\ua9c0\ua9cf-\ua9d9\uaa00-\uaa36\uaa40-\uaa4d\uaa50-\uaa59\uaa60-\uaa76\uaa7a\uaa7b\uaa80-\uaac2\uaadb-\uaadd\uaae0-\uaaef\uaaf2-\uaaf6\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabea\uabec\uabed\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\ufe70-\ufe74\ufe76-\ufefc\uff10-\uff19\uff21-\uff3a\uff3f\uff41-\uff5a\uff66-
 \uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]")},typeof "esprima"[0]=="undefined"&&(g=function(t,n){return u.slice(t,n).join("")}),e.version="1.0.4",e.parse=En,e.Syntax=function(){var e,t={};typeof Object.create=="function"&&(t=Object.create(null));for(e in r)r.hasOwnProperty(e)&&(t[e]=r[e]);return typeof Object.freeze=="function"&&Object.freeze(t),t}()})})(null),function(e,t){function o(e,t,n){function o(t){n[e.range[0]]=t;for(var r=e.range[0]+1;r<e.range[1];r++)n[r]=""}if(!e.range)return;e.parent=t,e.source=function(){return n.slice(e.range[0],e.range[1]).join("")};if(e.update&&typeof e.update=="object"){var s=e.update;i(r(s),function(e){o[e]=s[e]}),e.update=o}else e.update=o}var n=e("esprima").parse,r=Object.keys||function(e){var t=[];for(var n in e)t.push(n);return t},i=function(e,t){if(e.forEach)return e.forEach(t);for(var n=0;n<e.length;n++)t.call(e,e[n],n,e)},s=Array.isArray||function(e){return Object.prototype.toString.call(e)==="[object Array]"};t.exports=func
 tion(e,t,u){typeof t=="function"&&(u=t,t={}),typeof e=="object"&&(t=e,e=t.source,delete t.source),e=e===undefined?t.source:e,t.range=!0,typeof e!="string"&&(e=String(e));var a=n(e,t),f={chunks:e.split(""),toString:function(){return f.chunks.join("")},inspect:function(){return f.toString()}},l=0;return function c(e,t){o(e,t,f.chunks),i(r(e),function(t){if(t==="parent")return;var n=e[t];s(n)?i(n,function(t){t&&typeof t.type=="string"&&c(t,e)}):n&&typeof n.type=="string"&&(o(n,e,f.chunks),c(n,e))}),u(e)}(a,undefined),f},window.falafel=t.exports}(function(){return{parse:esprima.parse}},{exports:{}});var inBrowser=typeof window!="undefined"&&this===window,parseAndModify=inBrowser?window.falafel:require("falafel");(inBrowser?window:exports).blanket=function(){var e=["ExpressionStatement","BreakStatement","ContinueStatement","VariableDeclaration","ReturnStatement","ThrowStatement","TryStatement","FunctionDeclaration","IfStatement","WhileStatement","DoWhileStatement","ForStatement","ForInSt
 atement","SwitchStatement","WithStatement"],t=["IfStatement","WhileStatement","DoWhileStatement","ForStatement","ForInStatement","WithStatement"],n,r=Math.floor(Math.random()*1e3),i={},s={reporter:null,adapter:null,filter:null,customVariable:null,loader:null,ignoreScriptError:!1,existingRequireJS:!1,autoStart:!1,timeout:180,ignoreCors:!1,branchTracking:!1,sourceURL:!1,debug:!1,engineOnly:!1,testReadyCallback:null,commonJS:!1,instrumentCache:!1,modulePattern:null};return inBrowser&&typeof window.blanket!="undefined"&&(n=window.blanket.noConflict()),_blanket={noConflict:function(){return n?n:_blanket},_getCopyNumber:function(){return r},extend:function(e){_blanket._extend(_blanket,e)},_extend:function(e,t){if(t)for(var n in t)e[n]instanceof Object&&typeof e[n]!="function"?_blanket._extend(e[n],t[n]):e[n]=t[n]},getCovVar:function(){var e=_blanket.options("customVariable");return e?(_blanket.options("debug")&&console.log("BLANKET-Using custom tracking variable:",e),inBrowser?"window."+e
 :e):inBrowser?"window._$blanket":"_$jscoverage"},options:function(e,t){if(typeof e!="string")_blanket._extend(s,e);else{if(typeof t=="undefined")return s[e];s[e]=t}},instrument:function(e,t){var n=e.inputFile,r=e.inputFileName;if(_blanket.options("instrumentCache")&&sessionStorage&&sessionStorage.getItem("blanket_instrument_store-"+r))_blanket.options("debug")&&console.log("BLANKET-Reading instrumentation from cache: ",r),t(sessionStorage.getItem("blanket_instrument_store-"+r));else{var i=_blanket._prepareSource(n);_blanket._trackingArraySetup=[];var s=parseAndModify(n,{loc:!0,comment:!0},_blanket._addTracking(r));s=_blanket._trackingSetup(r,i)+s,_blanket.options("sourceURL")&&(s+="\n//@ sourceURL="+r.replace("http://","")),_blanket.options("debug")&&console.log("BLANKET-Instrumented file: ",r),_blanket.options("instrumentCache")&&sessionStorage&&(_blanket.options("debug")&&console.log("BLANKET-Saving instrumentation to cache: ",r),sessionStorage.setItem("blanket_instrument_store-"+
 r,s)),t(s)}},_trackingArraySetup:[],_branchingArraySetup:[],_prepareSource:function(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/(\r\n|\n|\r)/gm,"\n").split("\n")},_trackingSetup:function(e,t){var n=_blanket.options("branchTracking"),r=t.join("',\n'"),i="",s=_blanket.getCovVar();return i+="if (typeof "+s+" === 'undefined') "+s+" = {};\n",n&&(i+="var _$branchFcn=function(f,l,c,r){ ",i+="if (!!r) { ",i+=s+"[f].branchData[l][c][0] = "+s+"[f].branchData[l][c][0] || [];",i+=s+"[f].branchData[l][c][0].push(r); }",i+="else { ",i+=s+"[f].branchData[l][c][1] = "+s+"[f].branchData[l][c][1] || [];",i+=s+"[f].branchData[l][c][1].push(r); }",i+="return r;};\n"),i+="if (typeof "+s+"['"+e+"'] === 'undefined'){",i+=s+"['"+e+"']=[];\n",n&&(i+=s+"['"+e+"'].branchData=[];\n"),i+=s+"['"+e+"'].source=['"+r+"'];\n",_blanket._trackingArraySetup.sort(function(e,t){return parseInt(e,10)>parseInt(t,10)}).forEach(function(t){i+=s+"['"+e+"']["+t+"]=0;\n"}),n&&_blanket._branchingArraySetup.sor
 t(function(e,t){return e.line>t.line}).sort(function(e,t){return e.column>t.column}).forEach(function(t){t.file===e&&(i+="if (typeof "+s+"['"+e+"'].branchData["+t.line+"] === 'undefined'){\n",i+=s+"['"+e+"'].branchData["+t.line+"]=[];\n",i+="}",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"] = [];\n",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"].consequent = "+JSON.stringify(t.consequent)+";\n",i+=s+"['"+e+"'].branchData["+t.line+"]["+t.column+"].alternate = "+JSON.stringify(t.alternate)+";\n")}),i+="}",i},_blockifyIf:function(e){if(t.indexOf(e.type)>-1){var n=e.consequent||e.body,r=e.alternate;r&&r.type!=="BlockStatement"&&r.update("{\n"+r.source()+"}\n"),n&&n.type!=="BlockStatement"&&n.update("{\n"+n.source()+"}\n")}},_trackBranch:function(e,t){var n=e.loc.start.line,r=e.loc.start.column;_blanket._branchingArraySetup.push({line:n,column:r,file:t,consequent:e.consequent.loc,alternate:e.alternate.loc});var i="_$branchFcn('"+t+"',"+n+","+r+","+e.test.source()+")?"+e.conse
 quent.source()+":"+e.alternate.source();e.update(i)},_addTracking:function(t){var n=_blanket.getCovVar();return function(r){_blanket._blockifyIf(r);if(e.indexOf(r.type)>-1&&r.parent.type!=="LabeledStatement"){_blanket._checkDefs(r,t);if(r.type==="VariableDeclaration"&&(r.parent.type==="ForStatement"||r.parent.type==="ForInStatement"))return;if(!r.loc||!r.loc.start)throw new Error("The instrumenter encountered a node with no location: "+Object.keys(r));r.update(n+"['"+t+"']["+r.loc.start.line+"]++;\n"+r.source()),_blanket._trackingArraySetup.push(r.loc.start.line)}else _blanket.options("branchTracking")&&r.type==="ConditionalExpression"&&_blanket._trackBranch(r,t)}},_checkDefs:function(e,t){if(inBrowser){e.type==="VariableDeclaration"&&e.declarations&&e.declarations.forEach(function(n){if(n.id.name==="window")throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  "+t+":"+e.loc.start.line)}),e.type==="FunctionDeclaration"&&e.params&&e.params.forEach(func
 tion(n){if(n.name==="window")throw new Error("Instrumentation error, you cannot redefine the 'window' variable in  "+t+":"+e.loc.start.line)});if(e.type==="ExpressionStatement"&&e.expression&&e.expression.left&&e.expression.left.object&&e.expression.left.property&&e.expression.left.object.name+"."+e.expression.left.property.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in  "+t+":"+e.loc.start.line)}else if(e.type==="ExpressionStatement"&&e.expression&&e.expression.left&&!e.expression.left.object&&!e.expression.left.property&&e.expression.left.name===_blanket.getCovVar())throw new Error("Instrumentation error, you cannot redefine the coverage variable in  "+t+":"+e.loc.start.line)},setupCoverage:function(){i.instrumentation="blanket",i.stats={suites:0,tests:0,passes:0,pending:0,failures:0,start:new Date}},_checkIfSetup:function(){if(!i.stats)throw new Error("You must call blanket.setupCoverage() first.")},onTestStart:fun
 ction(){_blanket.options("debug")&&console.log("BLANKET-Test event started"),this._checkIfSetup(),i.stats.tests++,i.stats.pending++},onTestDone:function(e,t){this._checkIfSetup(),t===e?i.stats.passes++:i.stats.failures++,i.stats.pending--},onModuleStart:function(){this._checkIfSetup(),i.stats.suites++},onTestsDone:function(){_blanket.options("debug")&&console.log("BLANKET-Test event done"),this._checkIfSetup(),i.stats.end=new Date,inBrowser?this.report(i):(_blanket.options("branchTracking")||delete (inBrowser?window:global)[_blanket.getCovVar()].branchFcn,this.options("reporter").call(this,i))}},_blanket}(),function(e){var t=e.options;e.extend({outstandingRequireFiles:[],options:function(n,r){var i={};if(typeof n!="string")t(n),i=n;else{if(typeof r=="undefined")return t(n);t(n,r),i[n]=r}i.adapter&&e._loadFile(i.adapter),i.loader&&e._loadFile(i.loader)},requiringFile:function(t,n){typeof t=="undefined"?e.outstandingRequireFiles=[]:typeof n=="undefined"?e.outstandingRequireFiles.push(
 t):e.outstandingRequireFiles.splice(e.outstandingRequireFiles.indexOf(t),1)},requireFilesLoaded:function(){return e.outstandingRequireFiles.length===0},showManualLoader:function(){if(document.getElementById("blanketLoaderDialog"))return;var e="<div class='blanketDialogOverlay'>";e+="&nbsp;</div>",e+="<div class='blanketDialogVerticalOffset'>",e+="<div class='blanketDialogBox'>",e+="<b>Error:</b> Blanket.js encountered a cross origin request error while instrumenting the source files.  ",e+="<br><br>This is likely caused by the source files being referenced locally (using the file:// protocol). ",e+="<br><br>Some solutions include <a href='http://askubuntu.com/questions/160245/making-google-chrome-option-allow-file-access-from-files-permanent' target='_blank'>starting Chrome with special flags</a>, <a target='_blank' href='https://github.com/remy/servedir'>running a server locally</a>, or using a browser without these CORS restrictions (Safari).",e+="<br>",typeof FileReader!="undefin
 ed"&&(e+="<br>Or, try the experimental loader.  When prompted, simply click on the directory containing all the source files you want covered.",e+="<a href='javascript:document.getElementById(\"fileInput\").click();'>Start Loader</a>",e+="<input type='file' type='application/x-javascript' accept='application/x-javascript' webkitdirectory id='fileInput' multiple onchange='window.blanket.manualFileLoader(this.files)' style='visibility:hidden;position:absolute;top:-50;left:-50'/>"),e+="<br><span style='float:right;cursor:pointer;'  onclick=document.getElementById('blanketLoaderDialog').style.display='none';>Close</span>",e+="<div style='clear:both'></div>",e+="</div></div>";var t=".blanketDialogWrapper {";t+="display:block;",t+="position:fixed;",t+="z-index:40001; }",t+=".blanketDialogOverlay {",t+="position:fixed;",t+="width:100%;",t+="height:100%;",t+="background-color:black;",t+="opacity:.5; ",t+="-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=50)'; ",t+="filter:alpha(o
 pacity=50); ",t+="z-index:40001; }",t+=".blanketDialogVerticalOffset { ",t+="position:fixed;",t+="top:30%;",t+="width:100%;",t+="z-index:40002; }",t+=".blanketDialogBox { ",t+="width:405px; ",t+="position:relative;",t+="margin:0 auto;",t+="background-color:white;",t+="padding:10px;",t+="border:1px solid black; }";var n=document.createElement("style");n.innerHTML=t,document.head.appendChild(n);var r=document.createElement("div");r.id="blanketLoaderDialog",r.className="blanketDialogWrapper",r.innerHTML=e,document.body.insertBefore(r,document.body.firstChild)},manualFileLoader:function(e){function o(e){var t=new FileReader;t.onload=s,t.readAsText(e)}var t=Array.prototype.slice;e=t.call(e).filter(function(e){return e.type!==""});var n=e.length-1,r=0,i={};sessionStorage.blanketSessionLoader&&(i=JSON.parse(sessionStorage.blanketSessionLoader));var s=function(t){var s=t.currentTarget.result,u=e[r],a=u.webkitRelativePath&&u.webkitRelativePath!==""?u.webkitRelativePath:u.name;i[a]=s,r++,r===
 n?(sessionStorage.setItem("blanketSessionLoader",JSON.stringify(i)),document.location.reload()):o(e[r])};o(e[r])},_loadFile:function(t){if(typeof t!="undefined"){var n=new XMLHttpRequest;n.open("GET",t,!1),n.send(),e._addScript(n.responseText)}},_addScript:function(e){var t=document.createElement("script");t.type="text/javascript",t.text=e,(document.body||document.getElementsByTagName("head")[0]).appendChild(t)},hasAdapter:function(t){return e.options("adapter")!==null},report:function(t){document.getElementById("blanketLoaderDialog")||(e.blanketSession=null),t.files=window._$blanket;var n=blanket.options("commonJS")?blanket._commonjs.require:window.require;if(!t.files||!Object.keys(t.files).length){e.options("debug")&&console.log("BLANKET-Reporting No files were instrumented.");return}typeof t.files.branchFcn!="undefined"&&delete t.files.branchFcn;if(typeof e.options("reporter")=="string")e._loadFile(e.options("reporter")),e.customReporter(t,e.options("reporter_options"));else if(t
 ypeof e.options("reporter")=="function")e.options("reporter")(t,e.options("reporter_options"));else{if(typeof e.defaultReporter!="function")throw new Error("no reporter defined.");e.defaultReporter(t,e.options("reporter_options"))}},_bindStartTestRunner:function(e,t){e?e(t):window.addEventListener("load",t,!1)},_loadSourceFiles:function(t){function r(e){var t=Object.create(Object.getPrototypeOf(e)),n=Object.getOwnPropertyNames(e);return n.forEach(function(n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r)}),t}var n=blanket.options("commonJS")?blanket._commonjs.require:window.require;e.options("debug")&&console.log("BLANKET-Collecting page scripts");var i=e.utils.collectPageScripts();if(i.length===0)t();else{sessionStorage.blanketSessionLoader&&(e.blanketSession=JSON.parse(sessionStorage.blanketSessionLoader)),i.forEach(function(t,n){e.utils.cache[t]={loaded:!1}});var s=-1;e.utils.loadAll(function(e){return e?typeof i[s+1]!="undefined":(s++,s>=i.length?null:i[
 s])},t)}},beforeStartTestRunner:function(t){t=t||{},t.checkRequirejs=typeof t.checkRequirejs=="undefined"?!0:t.checkRequirejs,t.callback=t.callback||function(){},t.coverage=typeof t.coverage=="undefined"?!0:t.coverage,t.coverage?e._bindStartTestRunner(t.bindEvent,function(){e._loadSourceFiles(function(){var n=function(){return t.condition?t.condition():e.requireFilesLoaded()},r=function(){if(n()){e.options("debug")&&console.log("BLANKET-All files loaded, init start test runner callback.");var i=e.options("testReadyCallback");i?typeof i=="function"?i(t.callback):typeof i=="string"&&(e._addScript(i),t.callback()):t.callback()}else setTimeout(r,13)};r()})}):t.callback()},utils:{qualifyURL:function(e){var t=document.createElement("a");return t.href=e,t.href}}})}(blanket),blanket.defaultReporter=function(e){function l(e){var t=document.getElementById(e);t.style.display==="block"?t.style.display="none":t.style.display="block"}function d(e){return e.replace(/\&/g,"&amp;").replace(/</g,"&lt
 ;").replace(/\>/g,"&gt;").replace(/\"/g,"&quot;").replace(/\'/g,"&apos;")}function v(e,t){var n=t?0:1;return typeof e=="undefined"||typeof e===null||typeof e[n]=="undefined"?!1:e[n].length>0}function g(e,t,n,r,i){var s="",o="";if(m.length>0){s+="<span class='"+(v(m[0][1],m[0][1].consequent===m[0][0])?"branchOkay":"branchWarning")+"'>";if(m[0][0].end.line===i){s+=d(t.slice(0,m[0][0].end.column))+"</span>",t=t.slice(m[0][0].end.column),m.shift();if(m.length>0){s+="<span class='"+(v(m[0][1],!1)?"branchOkay":"branchWarning")+"'>";if(m[0][0].end.line===i){s+=d(t.slice(0,m[0][0].end.column))+"</span>",t=t.slice(m[0][0].end.column),m.shift();if(!n)return{src:s+d(t),cols:n}}else{if(!n)return{src:s+d(t)+"</span>",cols:n};o="</span>"}}else if(!n)return{src:s+d(t),cols:n}}else{if(!n)return{src:s+d(t)+"</span>",cols:n};o="</span>"}}var u=n[e],a=u.consequent;if(a.start.line>i)m.unshift([u.alternate,u]),m.unshift([a,u]),t=d(t);else{var f="<span class='"+(v(u,!0)?"branchOkay":"branchWarning")+"'>"
 ;s+=d(t.slice(0,a.start.column-r))+f;if(n.length>e+1&&n[e+1].consequent.start.line===i&&n[e+1].consequent.start.column-r<n[e].consequent.end.column-r){var l=g(e+1,t.slice(a.start.column-r,a.end.column-r),n,a.start.column-r,i);s+=l.src,n=l.cols,n[e+1]=n[e+2],n.length--}else s+=d(t.slice(a.start.column-r,a.end.column-r));s+="</span>";var c=u.alternate;if(c.start.line>i)s+=d(t.slice(a.end.column-r)),m.unshift([c,u]);else{s+=d(t.slice(a.end.column-r,c.start.column-r)),f="<span class='"+(v(u,!1)?"branchOkay":"branchWarning")+"'>",s+=f;if(n.length>e+1&&n[e+1].consequent.start.line===i&&n[e+1].consequent.start.column-r<n[e].alternate.end.column-r){var h=g(e+1,t.slice(c.start.column-r,c.end.column-r),n,c.start.column-r,i);s+=h.src,n=h.cols,n[e+1]=n[e+2],n.length--}else s+=d(t.slice(c.start.column-r,c.end.column-r));s+="</span>",s+=d(t.slice(c.end.column-r)),t=s}}return{src:t+o,cols:n}}var t="#blanket-main {margin:2px;background:#EEE;color:#333;clear:both;font-family:'Helvetica Neue Light', 
 'HelveticaNeue-Light', 'Helvetica Neue', Calibri, Helvetica, Arial, sans-serif; font-size:17px;} #blanket-main a {color:#333;text-decoration:none;}  #blanket-main a:hover {text-decoration:underline;} .blanket {margin:0;padding:5px;clear:both;border-bottom: 1px solid #FFFFFF;} .bl-error {color:red;}.bl-success {color:#5E7D00;} .bl-file{width:auto;} .bl-cl{float:left;} .blanket div.rs {margin-left:50px; width:150px; float:right} .bl-nb {padding-right:10px;} #blanket-main a.bl-logo {color: #EB1764;cursor: pointer;font-weight: bold;text-decoration: none} .bl-source{ overflow-x:scroll; background-color: #FFFFFF; border: 1px solid #CBCBCB; color: #363636; margin: 25px 20px; width: 80%;} .bl-source div{white-space: pre;font-family: monospace;} .bl-source > div > span:first-child{background-color: #EAEAEA;color: #949494;display: inline-block;padding: 0 10px;text-align: center;width: 30px;} .bl-source .miss{background-color:#e6c3c7} .bl-source span.branchWarning{color:#000;background-color:y
 ellow;} .bl-source span.branchOkay{color:#000;background-color:transparent;}",n=60,r=document.head,i=0,s=document.body,o,u=Object.keys(e.files).some(function(t){return typeof e.files[t].branchData!="undefined"}),a="<div id='blanket-main'><div class='blanket bl-title'><div class='bl-cl bl-file'><a href='http://alex-seville.github.com/blanket/' target='_blank' class='bl-logo'>Blanket.js</a> results</div><div class='bl-cl rs'>Coverage (%)</div><div class='bl-cl rs'>Covered/Total Smts.</div>"+(u?"<div class='bl-cl rs'>Covered/Total Branches</div>":"")+"<div style='clear:both;'></div></div>",f="<div class='blanket {{statusclass}}'><div class='bl-cl bl-file'><span class='bl-nb'>{{fileNumber}}.</span><a href='javascript:blanket_toggleSource(\"file-{{fileNumber}}\")'>{{file}}</a></div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+(u?"<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>":"")+"<div id='file-{{fileNumber}}'
  class='bl-source' style='display:none;'>{{source}}</div><div style='clear:both;'></div></div>";grandTotalTemplate="<div class='blanket grand-total {{statusclass}}'><div class='bl-cl'>{{rowTitle}}</div><div class='bl-cl rs'>{{percentage}} %</div><div class='bl-cl rs'>{{numberCovered}}/{{totalSmts}}</div>"+(u?"<div class='bl-cl rs'>{{passedBranches}}/{{totalBranches}}</div>":"")+"<div style='clear:both;'></div></div>";var c=document.createElement("script");c.type="text/javascript",c.text=l.toString().replace("function "+l.name,"function blanket_toggleSource"),s.appendChild(c);var h=function(e,t){return Math.round(e/t*100*100)/100},p=function(e,t,n){var r=document.createElement(e);r.innerHTML=n,t.appendChild(r)},m=[],y=function(e){return typeof e!="undefined"},b=e.files,w={totalSmts:0,numberOfFilesCovered:0,passedBranches:0,totalBranches:0,moduleTotalStatements:{},moduleTotalCoveredStatements:{},moduleTotalBranches:{},moduleTotalCoveredBranches:{}},E=_blanket.options("modulePattern"),
 S=E?new RegExp(E):null;for(var x in b){i++;var T=b[x],N=0,C=0,k=[],L,A=[];for(L=0;L<T.source.length;L+=1){var O=T.source[L];if(m.length>0||typeof T.branchData!="undefined")if(typeof T.branchData[L+1]!="undefined"){var M=T.branchData[L+1].filter(y),_=0;O=g(_,O,M,0,L+1).src}else m.length?O=g(0,O,null,0,L+1).src:O=d(O);else O=d(O);var D="";T[L+1]?(C+=1,N+=1,D="hit"):T[L+1]===0&&(N++,D="miss"),k[L+1]="<div class='"+D+"'><span class=''>"+(L+1)+"</span>"+O+"</div>"}w.totalSmts+=N,w.numberOfFilesCovered+=C;var P=0,H=0;if(typeof T.branchData!="undefined")for(var B=0;B<T.branchData.length;B++)if(typeof T.branchData[B]!="undefined")for(var j=0;j<T.branchData[B].length;j++)typeof T.branchData[B][j]!="undefined"&&(P++,typeof T.branchData[B][j][0]!="undefined"&&T.branchData[B][j][0].length>0&&typeof T.branchData[B][j][1]!="undefined"&&T.branchData[B][j][1].length>0&&H++);w.passedBranches+=H,w.totalBranches+=P;if(S){var F=x.match(S)[1];w.moduleTotalStatements.hasOwnProperty(F)||(w.moduleTotalStat
 ements[F]=0,w.moduleTotalCoveredStatements[F]=0),w.moduleTotalStatements[F]+=N,w.moduleTotalCoveredStatements[F]+=C,w.moduleTotalBranches.hasOwnProperty(F)||(w.moduleTotalBranches[F]=0,w.moduleTotalCoveredBranches[F]=0),w.moduleTotalBranches[F]+=P,w.moduleTotalCoveredBranches[F]+=H}var I=h(C,N),q=f.replace("{{file}}",x).replace("{{percentage}}",I).replace("{{numberCovered}}",C).replace(/\{\{fileNumber\}\}/g,i).replace("{{totalSmts}}",N).replace("{{totalBranches}}",P).replace("{{passedBranches}}",H).replace("{{source}}",k.join(" "));I<n?q=q.replace("{{statusclass}}","bl-error"):q=q.replace("{{statusclass}}","bl-success"),a+=q}var R=function(e,t,r,i,s){var o=h(t,e),u=o<n?"bl-error":"bl-success",f=s?"Total for module: "+s:"Global total",l=grandTotalTemplate.replace("{{rowTitle}}",f).replace("{{percentage}}",o).replace("{{numberCovered}}",t).replace("{{totalSmts}}",e).replace("{{passedBranches}}",i).replace("{{totalBranches}}",r).replace("{{statusclass}}",u);a+=l};if(S)for(var U in w.mo
 duleTotalStatements)if(w.moduleTotalStatements.hasOwnProperty(U)){var z=w.moduleTotalStatements[U],W=w.moduleTotalCoveredStatements[U],X=w.moduleTotalBranches[U],V=w.moduleTotalCoveredBranches[U];R(z,W,X,V,U)}R(w.totalSmts,w.numberOfFilesCovered,w.totalBranches,w.passedBranches,null),a+="</div>",p("style",r,t),document.getElementById("blanket-main")?document.getElementById("blanket-main").innerHTML=a.slice(23,-6):p("div",s,a)},function(){var e={},t=Array.prototype.slice,n=t.call(document.scripts);t.call(n[n.length-1].attributes).forEach(function(t){t.nodeName==="data-cover-only"&&(e.filter=t.nodeValue),t.nodeName==="data-cover-never"&&(e.antifilter=t.nodeValue),t.nodeName==="data-cover-reporter"&&(e.reporter=t.nodeValue),t.nodeName==="data-cover-adapter"&&(e.adapter=t.nodeValue),t.nodeName==="data-cover-loader"&&(e.loader=t.nodeValue),t.nodeName==="data-cover-timeout"&&(e.timeout=t.nodeValue),t.nodeName==="data-cover-modulepattern"&&(e.modulePattern=t.nodeValue);if(t.nodeName==="dat
 a-cover-reporter-options")try{e.reporter_options=JSON.parse(t.nodeValue)}catch(n){if(blanket.options("debug"))throw new Error("Invalid reporter options.  Must be a valid stringified JSON object.")}t.nodeName==="data-cover-testReadyCallback"&&(e.testReadyCallback=t.nodeValue),t.nodeName==="data-cover-customVariable"&&(e.customVariable=t.nodeValue);if(t.nodeName==="data-cover-flags"){var r=" "+t.nodeValue+" ";r.indexOf(" ignoreError ")>-1&&(e.ignoreScriptError=!0),r.indexOf(" autoStart ")>-1&&(e.autoStart=!0),r.indexOf(" ignoreCors ")>-1&&(e.ignoreCors=!0),r.indexOf(" branchTracking ")>-1&&(e.branchTracking=!0),r.indexOf(" sourceURL ")>-1&&(e.sourceURL=!0),r.indexOf(" debug ")>-1&&(e.debug=!0),r.indexOf(" engineOnly ")>-1&&(e.engineOnly=!0),r.indexOf(" commonJS ")>-1&&(e.commonJS=!0),r.indexOf(" instrumentCache ")>-1&&(e.instrumentCache=!0)}}),blanket.options(e),typeof requirejs!="undefined"&&blanket.options("existingRequireJS",!0),blanket.options("commonJS")&&(blanket._commonjs={})}(
 ),function(e){e.extend({utils:{normalizeBackslashes:function(e){return e.replace(/\\/g,"/")},matchPatternAttribute:function(t,n){if(typeof n=="string"){if(n.indexOf("[")===0){var r=n.slice(1,n.length-1).split(",");return r.some(function(n){return e.utils.matchPatternAttribute(t,e.utils.normalizeBackslashes(n.slice(1,-1)))})}if(n.indexOf("//")===0){var i=n.slice(2,n.lastIndexOf("/")),s=n.slice(n.lastIndexOf("/")+1),o=new RegExp(i,s);return o.test(t)}return n.indexOf("#")===0?window[n.slice(1)].call(window,t):t.indexOf(e.utils.normalizeBackslashes(n))>-1}if(n instanceof Array)return n.some(function(n){return e.utils.matchPatternAttribute(t,n)});if(n instanceof RegExp)return n.test(t);if(typeof n=="function")return n.call(window,t)},blanketEval:function(t){e._addScript(t)},collectPageScripts:function(){var t=Array.prototype.slice,n=t.call(document.scripts),r=[],i=[],s=e.options("filter");if(s!=null){var o=e.options("antifilter");r=t.call(document.scripts).filter(function(n){return t.ca
 ll(n.attributes).filter(function(t){return t.nodeName==="src"&&e.utils.matchPatternAttribute(t.nodeValue,s)&&(typeof o=="undefined"||!e.utils.matchPatternAttribute(t.nodeValue,o))}).length===1})}else r=t.call(document.querySelectorAll("script[data-cover]"));return i=r.map(function(n){return e.utils.qualifyURL(t.call(n.attributes).filter(function(e){return e.nodeName==="src"})[0].nodeValue)}),s||e.options("filter","['"+i.join("','")+"']"),i},loadAll:function(t,n,r){var i=t(),s=e.utils.scriptIsLoaded(i,e.utils.ifOrdered,t,n);if(!e.utils.cache[i]||!e.utils.cache[i].loaded){var o=function(){e.options("debug")&&console.log("BLANKET-Mark script:"+i+", as loaded and move to next script."),s()},u=function(t){e.options("debug")&&console.log("BLANKET-File loading finished"),typeof t!="undefined"&&(e.options("debug")&&console.log("BLANKET-Add file to DOM."),e._addScript(t)),o()};e.utils.attachScript({url:i},function(t){e.utils.processFile(t,i,u,u)})}else s()},attachScript:function(t,n){var r=e
 .options("timeout")||3e3;setTimeout(function(){if(!e.utils.cache[t.url].loaded)throw new Error("error loading source script")},r),e.utils.getFile(t.url,n,function(){throw new Error("error loading source script")})},ifOrdered:function(t,n){var r=t(!0);r?e.utils.loadAll(t,n):n(new Error("Error in loading chain."))},scriptIsLoaded:function(t,n,r,i){return e.options("debug")&&console.log("BLANKET-Returning function"),function(){e.options("debug")&&console.log("BLANKET-Marking file as loaded: "+t),e.utils.cache[t].loaded=!0,e.utils.allLoaded()?(e.options("debug")&&console.log("BLANKET-All files loaded"),i()):n&&(e.options("debug")&&console.log("BLANKET-Load next file."),n(r,i))}},cache:{},allLoaded:function(){var t=Object.keys(e.utils.cache);for(var n=0;n<t.length;n++)if(!e.utils.cache[t[n]].loaded)return!1;return!0},processFile:function(t,n,r,i){var s=e.options("filter"),o=e.options("antifilter");typeof o!="undefined"&&e.utils.matchPatternAttribute(n,o)?(i(t),e.options("debug")&&console
 .log("BLANKET-File will never be instrumented:"+n),e.requiringFile(n,!0)):e.utils.matchPatternAttribute(n,s)?(e.options("debug")&&console.log("BLANKET-Attempting instrument of:"+n),e.instrument({inputFile:t,inputFileName:n},function(i){try{e.options("debug")&&console.log("BLANKET-instrument of:"+n+" was successfull."),e.utils.blanketEval(i),r(),e.requiringFile(n,!0)}catch(s){if(!e.options("ignoreScriptError"))throw new Error("Error parsing instrumented code: "+s);e.options("debug")&&console.log("BLANKET-There was an error loading the file:"+n),r(t),e.requiringFile(n,!0)}})):(e.options("debug")&&console.log("BLANKET-Loading (without instrumenting) the file:"+n),i(t),e.requiringFile(n,!0))},cacheXhrConstructor:function(){var e,t,n,r;if(typeof XMLHttpRequest!="undefined")e=XMLHttpRequest,this.createXhr=function(){return new e};else if(typeof ActiveXObject!="undefined"){e=ActiveXObject;for(n=0;n<3;n+=1){r=progIds[n];try{new ActiveXObject(r);break}catch(i){}}this.createXhr=function(){ret
 urn new e(r)}}},craeteXhr:function(){throw new Error("cacheXhrConstructor is supposed to overwrite this function.")},getFile:function(t,n,r,i){var s=!1;if(e.blanketSession){var o=Object.keys(e.blanketSession);for(var u=0;u<o.length;u++){var a=o[u];if(t.indexOf(a)>-1){n(e.blanketSession[a]),s=!0;return}}}if(!s){var f=e.utils.createXhr();f.open("GET",t,!0),i&&i(f,t),f.onreadystatechange=function(e){var i,s;f.readyState===4&&(i=f.status,i>399&&i<600?(s=new Error(t+" HTTP status: "+i),s.xhr=f,r(s)):n(f.responseText))};try{f.send(null)}catch(l){if(!l.code||l.code!==101&&l.code!==1012||e.options("ignoreCors")!==!1)throw l;e.showManualLoader()}}}}}),function(){var t=blanket.options("commonJS")?blanket._commonjs.require:window.require,n=blanket.options("commonJS")?blanket._commonjs.requirejs:window.requirejs;!e.options("engineOnly")&&e.options("existingRequireJS")&&(e.utils.oldloader=n.load,n.load=function(t,n,r){e.requiringFile(r),e.utils.getFile(r,function(i){e.utils.processFile(i,r,funct
 ion(){t.completeLoad(n)},function(){e.utils.oldloader(t,n,r)})},function(t){throw e.requiringFile(),t})}),e.utils.cacheXhrConstructor()}()}(blanket),function(){if(!mocha)throw new Exception("mocha library does not exist in global namespace!");var e=mocha._reporter,t=function(t){t.on("start",function(){blanket.setupCoverage()}),t.on("end",function(){blanket.onTestsDone()}),t.on("suite",function(){blanket.onModuleStart()}),t.on("test",function(){blanket.onTestStart()}),t.on("test end",function(e){blanket.onTestDone(e.parent.tests.length,e.state==="passed")}),e.apply(this,arguments)};mocha.reporter(t);var n=mocha.run,r=null;mocha.run=function(e){r=e,console.log("waiting for blanket...")},blanket.beforeStartTestRunner({callback:function(){blanket.options("existingRequireJS")||n(r),mocha.run=n}})}();


[08/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/js/mocha.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/js/mocha.js b/sdks/html5-javascript/tests/resources/js/mocha.js
new file mode 100644
index 0000000..00dcda1
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/js/mocha.js
@@ -0,0 +1,5341 @@
+;(function(){
+
+
+// CommonJS require()
+
+function require(p){
+    var path = require.resolve(p)
+      , mod = require.modules[path];
+    if (!mod) throw new Error('failed to require "' + p + '"');
+    if (!mod.exports) {
+      mod.exports = {};
+      mod.call(mod.exports, mod, mod.exports, require.relative(path));
+    }
+    return mod.exports;
+  }
+
+require.modules = {};
+
+require.resolve = function (path){
+    var orig = path
+      , reg = path + '.js'
+      , index = path + '/index.js';
+    return require.modules[reg] && reg
+      || require.modules[index] && index
+      || orig;
+  };
+
+require.register = function (path, fn){
+    require.modules[path] = fn;
+  };
+
+require.relative = function (parent) {
+    return function(p){
+      if ('.' != p.charAt(0)) return require(p);
+      
+      var path = parent.split('/')
+        , segs = p.split('/');
+      path.pop();
+      
+      for (var i = 0; i < segs.length; i++) {
+        var seg = segs[i];
+        if ('..' == seg) path.pop();
+        else if ('.' != seg) path.push(seg);
+      }
+
+      return require(path.join('/'));
+    };
+  };
+
+
+require.register("browser/debug.js", function(module, exports, require){
+
+module.exports = function(type){
+  return function(){
+    
+  }
+};
+}); // module: browser/debug.js
+
+require.register("browser/diff.js", function(module, exports, require){
+/* See license.txt for terms of usage */
+
+/*
+ * Text diff implementation.
+ * 
+ * This library supports the following APIS:
+ * JsDiff.diffChars: Character by character diff
+ * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
+ * JsDiff.diffLines: Line based diff
+ * 
+ * JsDiff.diffCss: Diff targeted at CSS content
+ * 
+ * These methods are based on the implementation proposed in
+ * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
+ * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
+ */
+var JsDiff = (function() {
+  function clonePath(path) {
+    return { newPos: path.newPos, components: path.components.slice(0) };
+  }
+  function removeEmpty(array) {
+    var ret = [];
+    for (var i = 0; i < array.length; i++) {
+      if (array[i]) {
+        ret.push(array[i]);
+      }
+    }
+    return ret;
+  }
+  function escapeHTML(s) {
+    var n = s;
+    n = n.replace(/&/g, "&amp;");
+    n = n.replace(/</g, "&lt;");
+    n = n.replace(/>/g, "&gt;");
+    n = n.replace(/"/g, "&quot;");
+
+    return n;
+  }
+
+
+  var fbDiff = function(ignoreWhitespace) {
+    this.ignoreWhitespace = ignoreWhitespace;
+  };
+  fbDiff.prototype = {
+      diff: function(oldString, newString) {
+        // Handle the identity case (this is due to unrolling editLength == 0
+        if (newString == oldString) {
+          return [{ value: newString }];
+        }
+        if (!newString) {
+          return [{ value: oldString, removed: true }];
+        }
+        if (!oldString) {
+          return [{ value: newString, added: true }];
+        }
+
+        newString = this.tokenize(newString);
+        oldString = this.tokenize(oldString);
+
+        var newLen = newString.length, oldLen = oldString.length;
+        var maxEditLength = newLen + oldLen;
+        var bestPath = [{ newPos: -1, components: [] }];
+
+        // Seed editLength = 0
+        var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
+        if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
+          return bestPath[0].components;
+        }
+
+        for (var editLength = 1; editLength <= maxEditLength; editLength++) {
+          for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
+            var basePath;
+            var addPath = bestPath[diagonalPath-1],
+                removePath = bestPath[diagonalPath+1];
+            oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
+            if (addPath) {
+              // No one else is going to attempt to use this value, clear it
+              bestPath[diagonalPath-1] = undefined;
+            }
+
+            var canAdd = addPath && addPath.newPos+1 < newLen;
+            var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
+            if (!canAdd && !canRemove) {
+              bestPath[diagonalPath] = undefined;
+              continue;
+            }
+
+            // Select the diagonal that we want to branch from. We select the prior
+            // path whose position in the new string is the farthest from the origin
+            // and does not pass the bounds of the diff graph
+            if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
+              basePath = clonePath(removePath);
+              this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
+            } else {
+              basePath = clonePath(addPath);
+              basePath.newPos++;
+              this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
+            }
+
+            var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
+
+            if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
+              return basePath.components;
+            } else {
+              bestPath[diagonalPath] = basePath;
+            }
+          }
+        }
+      },
+
+      pushComponent: function(components, value, added, removed) {
+        var last = components[components.length-1];
+        if (last && last.added === added && last.removed === removed) {
+          // We need to clone here as the component clone operation is just
+          // as shallow array clone
+          components[components.length-1] =
+            {value: this.join(last.value, value), added: added, removed: removed };
+        } else {
+          components.push({value: value, added: added, removed: removed });
+        }
+      },
+      extractCommon: function(basePath, newString, oldString, diagonalPath) {
+        var newLen = newString.length,
+            oldLen = oldString.length,
+            newPos = basePath.newPos,
+            oldPos = newPos - diagonalPath;
+        while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
+          newPos++;
+          oldPos++;
+          
+          this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
+        }
+        basePath.newPos = newPos;
+        return oldPos;
+      },
+
+      equals: function(left, right) {
+        var reWhitespace = /\S/;
+        if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
+          return true;
+        } else {
+          return left == right;
+        }
+      },
+      join: function(left, right) {
+        return left + right;
+      },
+      tokenize: function(value) {
+        return value;
+      }
+  };
+  
+  var CharDiff = new fbDiff();
+  
+  var WordDiff = new fbDiff(true);
+  WordDiff.tokenize = function(value) {
+    return removeEmpty(value.split(/(\s+|\b)/));
+  };
+  
+  var CssDiff = new fbDiff(true);
+  CssDiff.tokenize = function(value) {
+    return removeEmpty(value.split(/([{}:;,]|\s+)/));
+  };
+  
+  var LineDiff = new fbDiff();
+  LineDiff.tokenize = function(value) {
+    return value.split(/^/m);
+  };
+  
+  return {
+    diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
+    diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
+    diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
+
+    diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
+
+    createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
+      var ret = [];
+
+      ret.push("Index: " + fileName);
+      ret.push("===================================================================");
+      ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
+      ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
+
+      var diff = LineDiff.diff(oldStr, newStr);
+      if (!diff[diff.length-1].value) {
+        diff.pop();   // Remove trailing newline add
+      }
+      diff.push({value: "", lines: []});   // Append an empty value to make cleanup easier
+
+      function contextLines(lines) {
+        return lines.map(function(entry) { return ' ' + entry; });
+      }
+      function eofNL(curRange, i, current) {
+        var last = diff[diff.length-2],
+            isLast = i === diff.length-2,
+            isLastOfType = i === diff.length-3 && (current.added === !last.added || current.removed === !last.removed);
+
+        // Figure out if this is the last line for the given file and missing NL
+        if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
+          curRange.push('\\ No newline at end of file');
+        }
+      }
+
+      var oldRangeStart = 0, newRangeStart = 0, curRange = [],
+          oldLine = 1, newLine = 1;
+      for (var i = 0; i < diff.length; i++) {
+        var current = diff[i],
+            lines = current.lines || current.value.replace(/\n$/, "").split("\n");
+        current.lines = lines;
+
+        if (current.added || current.removed) {
+          if (!oldRangeStart) {
+            var prev = diff[i-1];
+            oldRangeStart = oldLine;
+            newRangeStart = newLine;
+            
+            if (prev) {
+              curRange = contextLines(prev.lines.slice(-4));
+              oldRangeStart -= curRange.length;
+              newRangeStart -= curRange.length;
+            }
+          }
+          curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
+          eofNL(curRange, i, current);
+
+          if (current.added) {
+            newLine += lines.length;
+          } else {
+            oldLine += lines.length;
+          }
+        } else {
+          if (oldRangeStart) {
+            // Close out any changes that have been output (or join overlapping)
+            if (lines.length <= 8 && i < diff.length-2) {
+              // Overlapping
+              curRange.push.apply(curRange, contextLines(lines));
+            } else {
+              // end the range and output
+              var contextSize = Math.min(lines.length, 4);
+              ret.push(
+                  "@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
+                  + " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
+                  + " @@");
+              ret.push.apply(ret, curRange);
+              ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
+              if (lines.length <= 4) {
+                eofNL(ret, i, current);
+              }
+
+              oldRangeStart = 0;  newRangeStart = 0; curRange = [];
+            }
+          }
+          oldLine += lines.length;
+          newLine += lines.length;
+        }
+      }
+
+      return ret.join('\n') + '\n';
+    },
+
+    convertChangesToXML: function(changes){
+      var ret = [];
+      for ( var i = 0; i < changes.length; i++) {
+        var change = changes[i];
+        if (change.added) {
+          ret.push("<ins>");
+        } else if (change.removed) {
+          ret.push("<del>");
+        }
+
+        ret.push(escapeHTML(change.value));
+
+        if (change.added) {
+          ret.push("</ins>");
+        } else if (change.removed) {
+          ret.push("</del>");
+        }
+      }
+      return ret.join("");
+    }
+  };
+})();
+
+if (typeof module !== "undefined") {
+    module.exports = JsDiff;
+}
+
+}); // module: browser/diff.js
+
+require.register("browser/events.js", function(module, exports, require){
+
+/**
+ * Module exports.
+ */
+
+exports.EventEmitter = EventEmitter;
+
+/**
+ * Check if `obj` is an array.
+ */
+
+function isArray(obj) {
+  return '[object Array]' == {}.toString.call(obj);
+}
+
+/**
+ * Event emitter constructor.
+ *
+ * @api public
+ */
+
+function EventEmitter(){};
+
+/**
+ * Adds a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.on = function (name, fn) {
+  if (!this.$events) {
+    this.$events = {};
+  }
+
+  if (!this.$events[name]) {
+    this.$events[name] = fn;
+  } else if (isArray(this.$events[name])) {
+    this.$events[name].push(fn);
+  } else {
+    this.$events[name] = [this.$events[name], fn];
+  }
+
+  return this;
+};
+
+EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+/**
+ * Adds a volatile listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.once = function (name, fn) {
+  var self = this;
+
+  function on () {
+    self.removeListener(name, on);
+    fn.apply(this, arguments);
+  };
+
+  on.listener = fn;
+  this.on(name, on);
+
+  return this;
+};
+
+/**
+ * Removes a listener.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeListener = function (name, fn) {
+  if (this.$events && this.$events[name]) {
+    var list = this.$events[name];
+
+    if (isArray(list)) {
+      var pos = -1;
+
+      for (var i = 0, l = list.length; i < l; i++) {
+        if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
+          pos = i;
+          break;
+        }
+      }
+
+      if (pos < 0) {
+        return this;
+      }
+
+      list.splice(pos, 1);
+
+      if (!list.length) {
+        delete this.$events[name];
+      }
+    } else if (list === fn || (list.listener && list.listener === fn)) {
+      delete this.$events[name];
+    }
+  }
+
+  return this;
+};
+
+/**
+ * Removes all listeners for an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.removeAllListeners = function (name) {
+  if (name === undefined) {
+    this.$events = {};
+    return this;
+  }
+
+  if (this.$events && this.$events[name]) {
+    this.$events[name] = null;
+  }
+
+  return this;
+};
+
+/**
+ * Gets all listeners for a certain event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.listeners = function (name) {
+  if (!this.$events) {
+    this.$events = {};
+  }
+
+  if (!this.$events[name]) {
+    this.$events[name] = [];
+  }
+
+  if (!isArray(this.$events[name])) {
+    this.$events[name] = [this.$events[name]];
+  }
+
+  return this.$events[name];
+};
+
+/**
+ * Emits an event.
+ *
+ * @api public
+ */
+
+EventEmitter.prototype.emit = function (name) {
+  if (!this.$events) {
+    return false;
+  }
+
+  var handler = this.$events[name];
+
+  if (!handler) {
+    return false;
+  }
+
+  var args = [].slice.call(arguments, 1);
+
+  if ('function' == typeof handler) {
+    handler.apply(this, args);
+  } else if (isArray(handler)) {
+    var listeners = handler.slice();
+
+    for (var i = 0, l = listeners.length; i < l; i++) {
+      listeners[i].apply(this, args);
+    }
+  } else {
+    return false;
+  }
+
+  return true;
+};
+}); // module: browser/events.js
+
+require.register("browser/fs.js", function(module, exports, require){
+
+}); // module: browser/fs.js
+
+require.register("browser/path.js", function(module, exports, require){
+
+}); // module: browser/path.js
+
+require.register("browser/progress.js", function(module, exports, require){
+
+/**
+ * Expose `Progress`.
+ */
+
+module.exports = Progress;
+
+/**
+ * Initialize a new `Progress` indicator.
+ */
+
+function Progress() {
+  this.percent = 0;
+  this.size(0);
+  this.fontSize(11);
+  this.font('helvetica, arial, sans-serif');
+}
+
+/**
+ * Set progress size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.size = function(n){
+  this._size = n;
+  return this;
+};
+
+/**
+ * Set text to `str`.
+ *
+ * @param {String} str
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.text = function(str){
+  this._text = str;
+  return this;
+};
+
+/**
+ * Set font size to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ * @api public
+ */
+
+Progress.prototype.fontSize = function(n){
+  this._fontSize = n;
+  return this;
+};
+
+/**
+ * Set font `family`.
+ *
+ * @param {String} family
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.font = function(family){
+  this._font = family;
+  return this;
+};
+
+/**
+ * Update percentage to `n`.
+ *
+ * @param {Number} n
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.update = function(n){
+  this.percent = n;
+  return this;
+};
+
+/**
+ * Draw on `ctx`.
+ *
+ * @param {CanvasRenderingContext2d} ctx
+ * @return {Progress} for chaining
+ */
+
+Progress.prototype.draw = function(ctx){
+  var percent = Math.min(this.percent, 100)
+    , size = this._size
+    , half = size / 2
+    , x = half
+    , y = half
+    , rad = half - 1
+    , fontSize = this._fontSize;
+
+  ctx.font = fontSize + 'px ' + this._font;
+
+  var angle = Math.PI * 2 * (percent / 100);
+  ctx.clearRect(0, 0, size, size);
+
+  // outer circle
+  ctx.strokeStyle = '#9f9f9f';
+  ctx.beginPath();
+  ctx.arc(x, y, rad, 0, angle, false);
+  ctx.stroke();
+
+  // inner circle
+  ctx.strokeStyle = '#eee';
+  ctx.beginPath();
+  ctx.arc(x, y, rad - 1, 0, angle, true);
+  ctx.stroke();
+
+  // text
+  var text = this._text || (percent | 0) + '%'
+    , w = ctx.measureText(text).width;
+
+  ctx.fillText(
+      text
+    , x - w / 2 + 1
+    , y + fontSize / 2 - 1);
+
+  return this;
+};
+
+}); // module: browser/progress.js
+
+require.register("browser/tty.js", function(module, exports, require){
+
+exports.isatty = function(){
+  return true;
+};
+
+exports.getWindowSize = function(){
+  return [window.innerHeight, window.innerWidth];
+};
+}); // module: browser/tty.js
+
+require.register("context.js", function(module, exports, require){
+
+/**
+ * Expose `Context`.
+ */
+
+module.exports = Context;
+
+/**
+ * Initialize a new `Context`.
+ *
+ * @api private
+ */
+
+function Context(){}
+
+/**
+ * Set or get the context `Runnable` to `runnable`.
+ *
+ * @param {Runnable} runnable
+ * @return {Context}
+ * @api private
+ */
+
+Context.prototype.runnable = function(runnable){
+  if (0 == arguments.length) return this._runnable;
+  this.test = this._runnable = runnable;
+  return this;
+};
+
+/**
+ * Set test timeout `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.timeout = function(ms){
+  this.runnable().timeout(ms);
+  return this;
+};
+
+/**
+ * Set test slowness threshold `ms`.
+ *
+ * @param {Number} ms
+ * @return {Context} self
+ * @api private
+ */
+
+Context.prototype.slow = function(ms){
+  this.runnable().slow(ms);
+  return this;
+};
+
+/**
+ * Inspect the context void of `._runnable`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Context.prototype.inspect = function(){
+  return JSON.stringify(this, function(key, val){
+    if ('_runnable' == key) return;
+    if ('test' == key) return;
+    return val;
+  }, 2);
+};
+
+}); // module: context.js
+
+require.register("hook.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+
+/**
+ * Expose `Hook`.
+ */
+
+module.exports = Hook;
+
+/**
+ * Initialize a new `Hook` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Hook(title, fn) {
+  Runnable.call(this, title, fn);
+  this.type = 'hook';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+
+function F(){};
+F.prototype = Runnable.prototype;
+Hook.prototype = new F;
+Hook.prototype.constructor = Hook;
+
+
+/**
+ * Get or set the test `err`.
+ *
+ * @param {Error} err
+ * @return {Error}
+ * @api public
+ */
+
+Hook.prototype.error = function(err){
+  if (0 == arguments.length) {
+    var err = this._error;
+    this._error = null;
+    return err;
+  }
+
+  this._error = err;
+};
+
+
+}); // module: hook.js
+
+require.register("interfaces/bdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * BDD-style interface:
+ * 
+ *      describe('Array', function(){
+ *        describe('#indexOf()', function(){
+ *          it('should return -1 when not present', function(){
+ *
+ *          });
+ *
+ *          it('should return the index when present', function(){
+ *
+ *          });
+ *        });
+ *      });
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context, file, mocha){
+
+    /**
+     * Execute before running tests.
+     */
+
+    context.before = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after running tests.
+     */
+
+    context.after = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.beforeEach = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.afterEach = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`
+     * and callback `fn` containing nested suites
+     * and/or tests.
+     */
+  
+    context.describe = context.context = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+      return suite;
+    };
+
+    /**
+     * Pending describe.
+     */
+
+    context.xdescribe =
+    context.xcontext =
+    context.describe.skip = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suite.pending = true;
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+    };
+
+    /**
+     * Exclusive suite.
+     */
+
+    context.describe.only = function(title, fn){
+      var suite = context.describe(title, fn);
+      mocha.grep(suite.fullTitle());
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.it = context.specify = function(title, fn){
+      var suite = suites[0];
+      if (suite.pending) var fn = null;
+      var test = new Test(title, fn);
+      suite.addTest(test);
+      return test;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.it.only = function(title, fn){
+      var test = context.it(title, fn);
+      mocha.grep(test.fullTitle());
+    };
+
+    /**
+     * Pending test case.
+     */
+
+    context.xit =
+    context.xspecify =
+    context.it.skip = function(title){
+      context.it(title);
+    };
+  });
+};
+
+}); // module: interfaces/bdd.js
+
+require.register("interfaces/exports.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ * 
+ *     exports.Array = {
+ *       '#indexOf()': {
+ *         'should return -1 when the value is not present': function(){
+ *           
+ *         },
+ *
+ *         'should return the correct index when the value is present': function(){
+ *           
+ *         }
+ *       }
+ *     };
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('require', visit);
+
+  function visit(obj) {
+    var suite;
+    for (var key in obj) {
+      if ('function' == typeof obj[key]) {
+        var fn = obj[key];
+        switch (key) {
+          case 'before':
+            suites[0].beforeAll(fn);
+            break;
+          case 'after':
+            suites[0].afterAll(fn);
+            break;
+          case 'beforeEach':
+            suites[0].beforeEach(fn);
+            break;
+          case 'afterEach':
+            suites[0].afterEach(fn);
+            break;
+          default:
+            suites[0].addTest(new Test(key, fn));
+        }
+      } else {
+        var suite = Suite.create(suites[0], key);
+        suites.unshift(suite);
+        visit(obj[key]);
+        suites.shift();
+      }
+    }
+  }
+};
+}); // module: interfaces/exports.js
+
+require.register("interfaces/index.js", function(module, exports, require){
+
+exports.bdd = require('./bdd');
+exports.tdd = require('./tdd');
+exports.qunit = require('./qunit');
+exports.exports = require('./exports');
+
+}); // module: interfaces/index.js
+
+require.register("interfaces/qunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * QUnit-style interface:
+ * 
+ *     suite('Array');
+ *     
+ *     test('#length', function(){
+ *       var arr = [1,2,3];
+ *       ok(arr.length == 3);
+ *     });
+ *     
+ *     test('#indexOf()', function(){
+ *       var arr = [1,2,3];
+ *       ok(arr.indexOf(1) == 0);
+ *       ok(arr.indexOf(2) == 1);
+ *       ok(arr.indexOf(3) == 2);
+ *     });
+ *     
+ *     suite('String');
+ *     
+ *     test('#length', function(){
+ *       ok('foo'.length == 3);
+ *     });
+ * 
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context){
+
+    /**
+     * Execute before running tests.
+     */
+
+    context.before = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after running tests.
+     */
+
+    context.after = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.beforeEach = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.afterEach = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`.
+     */
+  
+    context.suite = function(title){
+      if (suites.length > 1) suites.shift();
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.test = function(title, fn){
+      suites[0].addTest(new Test(title, fn));
+    };
+  });
+};
+
+}); // module: interfaces/qunit.js
+
+require.register("interfaces/tdd.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite')
+  , Test = require('../test');
+
+/**
+ * TDD-style interface:
+ *
+ *      suite('Array', function(){
+ *        suite('#indexOf()', function(){
+ *          suiteSetup(function(){
+ *
+ *          });
+ *          
+ *          test('should return -1 when not present', function(){
+ *
+ *          });
+ *
+ *          test('should return the index when present', function(){
+ *
+ *          });
+ *
+ *          suiteTeardown(function(){
+ *
+ *          });
+ *        });
+ *      });
+ *
+ */
+
+module.exports = function(suite){
+  var suites = [suite];
+
+  suite.on('pre-require', function(context, file, mocha){
+
+    /**
+     * Execute before each test case.
+     */
+
+    context.setup = function(fn){
+      suites[0].beforeEach(fn);
+    };
+
+    /**
+     * Execute after each test case.
+     */
+
+    context.teardown = function(fn){
+      suites[0].afterEach(fn);
+    };
+
+    /**
+     * Execute before the suite.
+     */
+
+    context.suiteSetup = function(fn){
+      suites[0].beforeAll(fn);
+    };
+
+    /**
+     * Execute after the suite.
+     */
+
+    context.suiteTeardown = function(fn){
+      suites[0].afterAll(fn);
+    };
+
+    /**
+     * Describe a "suite" with the given `title`
+     * and callback `fn` containing nested suites
+     * and/or tests.
+     */
+
+    context.suite = function(title, fn){
+      var suite = Suite.create(suites[0], title);
+      suites.unshift(suite);
+      fn.call(suite);
+      suites.shift();
+      return suite;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.suite.only = function(title, fn){
+      var suite = context.suite(title, fn);
+      mocha.grep(suite.fullTitle());
+    };
+
+    /**
+     * Describe a specification or test-case
+     * with the given `title` and callback `fn`
+     * acting as a thunk.
+     */
+
+    context.test = function(title, fn){
+      var test = new Test(title, fn);
+      suites[0].addTest(test);
+      return test;
+    };
+
+    /**
+     * Exclusive test-case.
+     */
+
+    context.test.only = function(title, fn){
+      var test = context.test(title, fn);
+      mocha.grep(test.fullTitle());
+    };
+
+    /**
+     * Pending test case.
+     */
+
+    context.test.skip = function(title){
+      context.test(title);
+    };
+  });
+};
+
+}); // module: interfaces/tdd.js
+
+require.register("mocha.js", function(module, exports, require){
+/*!
+ * mocha
+ * Copyright(c) 2011 TJ Holowaychuk <tj...@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var path = require('browser/path')
+  , utils = require('./utils');
+
+/**
+ * Expose `Mocha`.
+ */
+
+exports = module.exports = Mocha;
+
+/**
+ * Expose internals.
+ */
+
+exports.utils = utils;
+exports.interfaces = require('./interfaces');
+exports.reporters = require('./reporters');
+exports.Runnable = require('./runnable');
+exports.Context = require('./context');
+exports.Runner = require('./runner');
+exports.Suite = require('./suite');
+exports.Hook = require('./hook');
+exports.Test = require('./test');
+
+/**
+ * Return image `name` path.
+ *
+ * @param {String} name
+ * @return {String}
+ * @api private
+ */
+
+function image(name) {
+  return __dirname + '/../images/' + name + '.png';
+}
+
+/**
+ * Setup mocha with `options`.
+ *
+ * Options:
+ *
+ *   - `ui` name "bdd", "tdd", "exports" etc
+ *   - `reporter` reporter instance, defaults to `mocha.reporters.Dot`
+ *   - `globals` array of accepted globals
+ *   - `timeout` timeout in milliseconds
+ *   - `bail` bail on the first test failure
+ *   - `slow` milliseconds to wait before considering a test slow
+ *   - `ignoreLeaks` ignore global leaks
+ *   - `grep` string or regexp to filter tests with
+ *
+ * @param {Object} options
+ * @api public
+ */
+
+function Mocha(options) {
+  options = options || {};
+  this.files = [];
+  this.options = options;
+  this.grep(options.grep);
+  this.suite = new exports.Suite('', new exports.Context);
+  this.ui(options.ui);
+  this.bail(options.bail);
+  this.reporter(options.reporter);
+  if (options.timeout) this.timeout(options.timeout);
+  if (options.slow) this.slow(options.slow);
+}
+
+/**
+ * Enable or disable bailing on the first failure.
+ *
+ * @param {Boolean} [bail]
+ * @api public
+ */
+
+Mocha.prototype.bail = function(bail){
+  if (0 == arguments.length) bail = true;
+  this.suite.bail(bail);
+  return this;
+};
+
+/**
+ * Add test `file`.
+ *
+ * @param {String} file
+ * @api public
+ */
+
+Mocha.prototype.addFile = function(file){
+  this.files.push(file);
+  return this;
+};
+
+/**
+ * Set reporter to `reporter`, defaults to "dot".
+ *
+ * @param {String|Function} reporter name or constructor
+ * @api public
+ */
+
+Mocha.prototype.reporter = function(reporter){
+  if ('function' == typeof reporter) {
+    this._reporter = reporter;
+  } else {
+    reporter = reporter || 'dot';
+    try {
+      this._reporter = require('./reporters/' + reporter);
+    } catch (err) {
+      this._reporter = require(reporter);
+    }
+    if (!this._reporter) throw new Error('invalid reporter "' + reporter + '"');
+  }
+  return this;
+};
+
+/**
+ * Set test UI `name`, defaults to "bdd".
+ *
+ * @param {String} bdd
+ * @api public
+ */
+
+Mocha.prototype.ui = function(name){
+  name = name || 'bdd';
+  this._ui = exports.interfaces[name];
+  if (!this._ui) throw new Error('invalid interface "' + name + '"');
+  this._ui = this._ui(this.suite);
+  return this;
+};
+
+/**
+ * Load registered files.
+ *
+ * @api private
+ */
+
+Mocha.prototype.loadFiles = function(fn){
+  var self = this;
+  var suite = this.suite;
+  var pending = this.files.length;
+  this.files.forEach(function(file){
+    file = path.resolve(file);
+    suite.emit('pre-require', global, file, self);
+    suite.emit('require', require(file), file, self);
+    suite.emit('post-require', global, file, self);
+    --pending || (fn && fn());
+  });
+};
+
+/**
+ * Enable growl support.
+ *
+ * @api private
+ */
+
+Mocha.prototype._growl = function(runner, reporter) {
+  var notify = require('growl');
+
+  runner.on('end', function(){
+    var stats = reporter.stats;
+    if (stats.failures) {
+      var msg = stats.failures + ' of ' + runner.total + ' tests failed';
+      notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
+    } else {
+      notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
+          name: 'mocha'
+        , title: 'Passed'
+        , image: image('ok')
+      });
+    }
+  });
+};
+
+/**
+ * Add regexp to grep, if `re` is a string it is escaped.
+ *
+ * @param {RegExp|String} re
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.grep = function(re){
+  this.options.grep = 'string' == typeof re
+    ? new RegExp(utils.escapeRegexp(re))
+    : re;
+  return this;
+};
+
+/**
+ * Invert `.grep()` matches.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.invert = function(){
+  this.options.invert = true;
+  return this;
+};
+
+/**
+ * Ignore global leaks.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.ignoreLeaks = function(){
+  this.options.ignoreLeaks = true;
+  return this;
+};
+
+/**
+ * Enable global leak checking.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.checkLeaks = function(){
+  this.options.ignoreLeaks = false;
+  return this;
+};
+
+/**
+ * Enable growl support.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.growl = function(){
+  this.options.growl = true;
+  return this;
+};
+
+/**
+ * Ignore `globals` array or string.
+ *
+ * @param {Array|String} globals
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.globals = function(globals){
+  this.options.globals = (this.options.globals || []).concat(globals);
+  return this;
+};
+
+/**
+ * Set the timeout in milliseconds.
+ *
+ * @param {Number} timeout
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.timeout = function(timeout){
+  this.suite.timeout(timeout);
+  return this;
+};
+
+/**
+ * Set slowness threshold in milliseconds.
+ *
+ * @param {Number} slow
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.slow = function(slow){
+  this.suite.slow(slow);
+  return this;
+};
+
+/**
+ * Makes all tests async (accepting a callback)
+ *
+ * @return {Mocha}
+ * @api public
+ */
+
+Mocha.prototype.asyncOnly = function(){
+  this.options.asyncOnly = true;
+  return this;
+};
+
+/**
+ * Run tests and invoke `fn()` when complete.
+ *
+ * @param {Function} fn
+ * @return {Runner}
+ * @api public
+ */
+
+Mocha.prototype.run = function(fn){
+  if (this.files.length) this.loadFiles();
+  var suite = this.suite;
+  var options = this.options;
+  var runner = new exports.Runner(suite);
+  var reporter = new this._reporter(runner);
+  runner.ignoreLeaks = options.ignoreLeaks;
+  runner.asyncOnly = options.asyncOnly;
+  if (options.grep) runner.grep(options.grep, options.invert);
+  if (options.globals) runner.globals(options.globals);
+  if (options.growl) this._growl(runner, reporter);
+  return runner.run(fn);
+};
+
+}); // module: blanket_mocha.js
+
+require.register("ms.js", function(module, exports, require){
+
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * @param {String|Number} val
+ * @return {String|Number}
+ * @api public
+ */
+
+module.exports = function(val){
+  if ('string' == typeof val) return parse(val);
+  return format(val);
+}
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @param {String} str
+ * @return {Number}
+ * @api private
+ */
+
+function parse(str) {
+  var m = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
+  if (!m) return;
+  var n = parseFloat(m[1]);
+  var type = (m[2] || 'ms').toLowerCase();
+  switch (type) {
+    case 'years':
+    case 'year':
+    case 'y':
+      return n * 31557600000;
+    case 'days':
+    case 'day':
+    case 'd':
+      return n * 86400000;
+    case 'hours':
+    case 'hour':
+    case 'h':
+      return n * 3600000;
+    case 'minutes':
+    case 'minute':
+    case 'm':
+      return n * 60000;
+    case 'seconds':
+    case 'second':
+    case 's':
+      return n * 1000;
+    case 'ms':
+      return n;
+  }
+}
+
+/**
+ * Format the given `ms`.
+ *
+ * @param {Number} ms
+ * @return {String}
+ * @api public
+ */
+
+function format(ms) {
+  if (ms == d) return Math.round(ms / d) + ' day';
+  if (ms > d) return Math.round(ms / d) + ' days';
+  if (ms == h) return Math.round(ms / h) + ' hour';
+  if (ms > h) return Math.round(ms / h) + ' hours';
+  if (ms == m) return Math.round(ms / m) + ' minute';
+  if (ms > m) return Math.round(ms / m) + ' minutes';
+  if (ms == s) return Math.round(ms / s) + ' second';
+  if (ms > s) return Math.round(ms / s) + ' seconds';
+  return ms + ' ms';
+}
+}); // module: ms.js
+
+require.register("reporters/base.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var tty = require('browser/tty')
+  , diff = require('browser/diff')
+  , ms = require('../ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Check if both stdio streams are associated with a tty.
+ */
+
+var isatty = tty.isatty(1) && tty.isatty(2);
+
+/**
+ * Expose `Base`.
+ */
+
+exports = module.exports = Base;
+
+/**
+ * Enable coloring by default.
+ */
+
+exports.useColors = isatty;
+
+/**
+ * Default color map.
+ */
+
+exports.colors = {
+    'pass': 90
+  , 'fail': 31
+  , 'bright pass': 92
+  , 'bright fail': 91
+  , 'bright yellow': 93
+  , 'pending': 36
+  , 'suite': 0
+  , 'error title': 0
+  , 'error message': 31
+  , 'error stack': 90
+  , 'checkmark': 32
+  , 'fast': 90
+  , 'medium': 33
+  , 'slow': 31
+  , 'green': 32
+  , 'light': 90
+  , 'diff gutter': 90
+  , 'diff added': 42
+  , 'diff removed': 41
+};
+
+/**
+ * Default symbol map.
+ */
+ 
+exports.symbols = {
+  ok: '✓',
+  err: '✖',
+  dot: '․'
+};
+
+// With node.js on Windows: use symbols available in terminal default fonts
+if ('win32' == process.platform) {
+  exports.symbols.ok = '\u221A';
+  exports.symbols.err = '\u00D7';
+  exports.symbols.dot = '.';
+}
+
+/**
+ * Color `str` with the given `type`,
+ * allowing colors to be disabled,
+ * as well as user-defined color
+ * schemes.
+ *
+ * @param {String} type
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+var color = exports.color = function(type, str) {
+  if (!exports.useColors) return str;
+  return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Expose term window size, with some
+ * defaults for when stderr is not a tty.
+ */
+
+exports.window = {
+  width: isatty
+    ? process.stdout.getWindowSize
+      ? process.stdout.getWindowSize(1)[0]
+      : tty.getWindowSize()[1]
+    : 75
+};
+
+/**
+ * Expose some basic cursor interactions
+ * that are common among reporters.
+ */
+
+exports.cursor = {
+  hide: function(){
+    process.stdout.write('\u001b[?25l');
+  },
+
+  show: function(){
+    process.stdout.write('\u001b[?25h');
+  },
+
+  deleteLine: function(){
+    process.stdout.write('\u001b[2K');
+  },
+
+  beginningOfLine: function(){
+    process.stdout.write('\u001b[0G');
+  },
+
+  CR: function(){
+    exports.cursor.deleteLine();
+    exports.cursor.beginningOfLine();
+  }
+};
+
+/**
+ * Outut the given `failures` as a list.
+ *
+ * @param {Array} failures
+ * @api public
+ */
+
+exports.list = function(failures){
+  console.error();
+  failures.forEach(function(test, i){
+    // format
+    var fmt = color('error title', '  %s) %s:\n')
+      + color('error message', '     %s')
+      + color('error stack', '\n%s\n');
+
+    // msg
+    var err = test.err
+      , message = err.message || ''
+      , stack = err.stack || message
+      , index = stack.indexOf(message) + message.length
+      , msg = stack.slice(0, index)
+      , actual = err.actual
+      , expected = err.expected
+      , escape = true;
+
+    // explicitly show diff
+    if (err.showDiff) {
+      escape = false;
+      err.actual = actual = JSON.stringify(actual, null, 2);
+      err.expected = expected = JSON.stringify(expected, null, 2);
+    }
+
+    // actual / expected diff
+    if ('string' == typeof actual && 'string' == typeof expected) {
+      var len = Math.max(actual.length, expected.length);
+
+      if (len < 20) msg = errorDiff(err, 'Chars', escape);
+      else msg = errorDiff(err, 'Words', escape);
+
+      // linenos
+      var lines = msg.split('\n');
+      if (lines.length > 4) {
+        var width = String(lines.length).length;
+        msg = lines.map(function(str, i){
+          return pad(++i, width) + ' |' + ' ' + str;
+        }).join('\n');
+      }
+
+      // legend
+      msg = '\n'
+        + color('diff removed', 'actual')
+        + ' '
+        + color('diff added', 'expected')
+        + '\n\n'
+        + msg
+        + '\n';
+
+      // indent
+      msg = msg.replace(/^/gm, '      ');
+
+      fmt = color('error title', '  %s) %s:\n%s')
+        + color('error stack', '\n%s\n');
+    }
+
+    // indent stack trace without msg
+    stack = stack.slice(index ? index + 1 : index)
+      .replace(/^/gm, '  ');
+
+    console.error(fmt, (i + 1), test.fullTitle(), msg, stack);
+  });
+};
+
+/**
+ * Initialize a new `Base` reporter.
+ *
+ * All other reporters generally
+ * inherit from this reporter, providing
+ * stats such as test duration, number
+ * of tests passed / failed etc.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Base(runner) {
+  var self = this
+    , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }
+    , failures = this.failures = [];
+
+  if (!runner) return;
+  this.runner = runner;
+
+  runner.stats = stats;
+
+  runner.on('start', function(){
+    stats.start = new Date;
+  });
+
+  runner.on('suite', function(suite){
+    stats.suites = stats.suites || 0;
+    suite.root || stats.suites++;
+  });
+
+  runner.on('test end', function(test){
+    stats.tests = stats.tests || 0;
+    stats.tests++;
+  });
+
+  runner.on('pass', function(test){
+    stats.passes = stats.passes || 0;
+
+    var medium = test.slow() / 2;
+    test.speed = test.duration > test.slow()
+      ? 'slow'
+      : test.duration > medium
+        ? 'medium'
+        : 'fast';
+
+    stats.passes++;
+  });
+
+  runner.on('fail', function(test, err){
+    stats.failures = stats.failures || 0;
+    stats.failures++;
+    test.err = err;
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    stats.end = new Date;
+    stats.duration = new Date - stats.start;
+  });
+
+  runner.on('pending', function(){
+    stats.pending++;
+  });
+}
+
+/**
+ * Output common epilogue used by many of
+ * the bundled reporters.
+ *
+ * @api public
+ */
+
+Base.prototype.epilogue = function(){
+  var stats = this.stats
+    , fmt
+    , tests;
+
+  console.log();
+
+  function pluralize(n) {
+    return 1 == n ? 'test' : 'tests';
+  }
+
+  // failure
+  if (stats.failures) {
+    fmt = color('bright fail', '  ' + exports.symbols.err)
+      + color('fail', ' %d of %d %s failed')
+      + color('light', ':')
+
+    console.error(fmt,
+      stats.failures,
+      this.runner.total,
+      pluralize(this.runner.total));
+
+    Base.list(this.failures);
+    console.error();
+    return;
+  }
+
+  // pass
+  fmt = color('bright pass', ' ')
+    + color('green', ' %d %s complete')
+    + color('light', ' (%s)');
+
+  console.log(fmt,
+    stats.tests || 0,
+    pluralize(stats.tests),
+    ms(stats.duration));
+
+  // pending
+  if (stats.pending) {
+    fmt = color('pending', ' ')
+      + color('pending', ' %d %s pending');
+
+    console.log(fmt, stats.pending, pluralize(stats.pending));
+  }
+
+  console.log();
+};
+
+/**
+ * Pad the given `str` to `len`.
+ *
+ * @param {String} str
+ * @param {String} len
+ * @return {String}
+ * @api private
+ */
+
+function pad(str, len) {
+  str = String(str);
+  return Array(len - str.length + 1).join(' ') + str;
+}
+
+/**
+ * Return a character diff for `err`.
+ *
+ * @param {Error} err
+ * @return {String}
+ * @api private
+ */
+
+function errorDiff(err, type, escape) {
+  return diff['diff' + type](err.actual, err.expected).map(function(str){
+    if (escape) {
+      str.value = str.value
+        .replace(/\t/g, '<tab>')
+        .replace(/\r/g, '<CR>')
+        .replace(/\n/g, '<LF>\n');
+    }
+    if (str.added) return colorLines('diff added', str.value);
+    if (str.removed) return colorLines('diff removed', str.value);
+    return str.value;
+  }).join('');
+}
+
+/**
+ * Color lines for `str`, using the color `name`.
+ *
+ * @param {String} name
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+function colorLines(name, str) {
+  return str.split('\n').map(function(str){
+    return color(name, str);
+  }).join('\n');
+}
+
+}); // module: reporters/base.js
+
+require.register("reporters/doc.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils');
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = Doc;
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Doc(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total
+    , indents = 2;
+
+  function indent() {
+    return Array(indents).join('  ');
+  }
+
+  runner.on('suite', function(suite){
+    if (suite.root) return;
+    ++indents;
+    console.log('%s<section class="suite">', indent());
+    ++indents;
+    console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
+    console.log('%s<dl>', indent());
+  });
+
+  runner.on('suite end', function(suite){
+    if (suite.root) return;
+    console.log('%s</dl>', indent());
+    --indents;
+    console.log('%s</section>', indent());
+    --indents;
+  });
+
+  runner.on('pass', function(test){
+    console.log('%s  <dt>%s</dt>', indent(), utils.escape(test.title));
+    var code = utils.escape(utils.clean(test.fn.toString()));
+    console.log('%s  <dd><pre><code>%s</code></pre></dd>', indent(), code);
+  });
+}
+
+}); // module: reporters/doc.js
+
+require.register("reporters/dot.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = Dot;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Dot(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , n = 0;
+
+  runner.on('start', function(){
+    process.stdout.write('\n  ');
+  });
+
+  runner.on('pending', function(test){
+    process.stdout.write(color('pending', Base.symbols.dot));
+  });
+
+  runner.on('pass', function(test){
+    if (++n % width == 0) process.stdout.write('\n  ');
+    if ('slow' == test.speed) {
+      process.stdout.write(color('bright yellow', Base.symbols.dot));
+    } else {
+      process.stdout.write(color(test.speed, Base.symbols.dot));
+    }
+  });
+
+  runner.on('fail', function(test, err){
+    if (++n % width == 0) process.stdout.write('\n  ');
+    process.stdout.write(color('fail', Base.symbols.dot));
+  });
+
+  runner.on('end', function(){
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Dot.prototype = new F;
+Dot.prototype.constructor = Dot;
+
+}); // module: reporters/dot.js
+
+require.register("reporters/html-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var JSONCov = require('./json-cov')
+  , fs = require('browser/fs');
+
+/**
+ * Expose `HTMLCov`.
+ */
+
+exports = module.exports = HTMLCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTMLCov(runner) {
+  var jade = require('jade')
+    , file = __dirname + '/templates/coverage.jade'
+    , str = fs.readFileSync(file, 'utf8')
+    , fn = jade.compile(str, { filename: file })
+    , self = this;
+
+  JSONCov.call(this, runner, false);
+
+  runner.on('end', function(){
+    process.stdout.write(fn({
+        cov: self.cov
+      , coverageClass: coverageClass
+    }));
+  });
+}
+
+/**
+ * Return coverage class for `n`.
+ *
+ * @return {String}
+ * @api private
+ */
+
+function coverageClass(n) {
+  if (n >= 75) return 'high';
+  if (n >= 50) return 'medium';
+  if (n >= 25) return 'low';
+  return 'terrible';
+}
+}); // module: reporters/html-cov.js
+
+require.register("reporters/html.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils')
+  , Progress = require('../browser/progress')
+  , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = HTML;
+
+/**
+ * Stats template.
+ */
+
+var statsTemplate = '<ul id="mocha-stats">'
+  + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
+  + '<li class="passes"><a href="#">passes:</a> <em>0</em></li>'
+  + '<li class="failures"><a href="#">failures:</a> <em>0</em></li>'
+  + '<li class="duration">duration: <em>0</em>s</li>'
+  + '</ul>';
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function HTML(runner, root) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total
+    , stat = fragment(statsTemplate)
+    , items = stat.getElementsByTagName('li')
+    , passes = items[1].getElementsByTagName('em')[0]
+    , passesLink = items[1].getElementsByTagName('a')[0]
+    , failures = items[2].getElementsByTagName('em')[0]
+    , failuresLink = items[2].getElementsByTagName('a')[0]
+    , duration = items[3].getElementsByTagName('em')[0]
+    , canvas = stat.getElementsByTagName('canvas')[0]
+    , report = fragment('<ul id="mocha-report"></ul>')
+    , stack = [report]
+    , progress
+    , ctx
+
+  root = root || document.getElementById('mocha');
+
+  if (canvas.getContext) {
+    var ratio = window.devicePixelRatio || 1;
+    canvas.style.width = canvas.width;
+    canvas.style.height = canvas.height;
+    canvas.width *= ratio;
+    canvas.height *= ratio;
+    ctx = canvas.getContext('2d');
+    ctx.scale(ratio, ratio);
+    progress = new Progress;
+  }
+
+  if (!root) return error('#mocha div missing, add it to your document');
+
+  // pass toggle
+  on(passesLink, 'click', function(){
+    unhide();
+    var name = /pass/.test(report.className) ? '' : ' pass';
+    report.className = report.className.replace(/fail|pass/g, '') + name;
+    if (report.className.trim()) hideSuitesWithout('test pass');
+  });
+
+  // failure toggle
+  on(failuresLink, 'click', function(){
+    unhide();
+    var name = /fail/.test(report.className) ? '' : ' fail';
+    report.className = report.className.replace(/fail|pass/g, '') + name;
+    if (report.className.trim()) hideSuitesWithout('test fail');
+  });
+
+  root.appendChild(stat);
+  root.appendChild(report);
+
+  if (progress) progress.size(40);
+
+  runner.on('suite', function(suite){
+    if (suite.root) return;
+
+    // suite
+    var url = '?grep=' + encodeURIComponent(suite.fullTitle());
+    var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
+
+    // container
+    stack[0].appendChild(el);
+    stack.unshift(document.createElement('ul'));
+    el.appendChild(stack[0]);
+  });
+
+  runner.on('suite end', function(suite){
+    if (suite.root) return;
+    stack.shift();
+  });
+
+  runner.on('fail', function(test, err){
+    if ('hook' == test.type) runner.emit('test end', test);
+  });
+
+  runner.on('test end', function(test){
+    window.scrollTo(0, document.body.scrollHeight);
+
+    // TODO: add to stats
+    var percent = stats.tests / this.total * 100 | 0;
+    if (progress) progress.update(percent).draw(ctx);
+
+    // update stats
+    var ms = new Date - stats.start;
+    text(passes, stats.passes);
+    text(failures, stats.failures);
+    text(duration, (ms / 1000).toFixed(2));
+
+    // test
+    if ('passed' == test.state) {
+      var el = fragment('<li class="test pass %e"><h2>%e<span class="duration">%ems</span> <a href="?grep=%e" class="replay">‣</a></h2></li>', test.speed, test.title, test.duration, encodeURIComponent(test.fullTitle()));
+    } else if (test.pending) {
+      var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
+    } else {
+      var el = fragment('<li class="test fail"><h2>%e <a href="?grep=%e" class="replay">‣</a></h2></li>', test.title, encodeURIComponent(test.fullTitle()));
+      var str = test.err.stack || test.err.toString();
+
+      // FF / Opera do not add the message
+      if (!~str.indexOf(test.err.message)) {
+        str = test.err.message + '\n' + str;
+      }
+
+      // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
+      // check for the result of the stringifying.
+      if ('[object Error]' == str) str = test.err.message;
+
+      // Safari doesn't give you a stack. Let's at least provide a source line.
+      if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) {
+        str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")";
+      }
+
+      el.appendChild(fragment('<pre class="error">%e</pre>', str));
+    }
+
+    // toggle code
+    // TODO: defer
+    if (!test.pending) {
+      var h2 = el.getElementsByTagName('h2')[0];
+
+      on(h2, 'click', function(){
+        pre.style.display = 'none' == pre.style.display
+          ? 'block'
+          : 'none';
+      });
+
+      var pre = fragment('<pre><code>%e</code></pre>', utils.clean(test.fn.toString()));
+      el.appendChild(pre);
+      pre.style.display = 'none';
+    }
+
+    // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
+    if (stack[0]) stack[0].appendChild(el);
+  });
+}
+
+/**
+ * Display error `msg`.
+ */
+
+function error(msg) {
+  document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
+}
+
+/**
+ * Return a DOM fragment from `html`.
+ */
+
+function fragment(html) {
+  var args = arguments
+    , div = document.createElement('div')
+    , i = 1;
+
+  div.innerHTML = html.replace(/%([se])/g, function(_, type){
+    switch (type) {
+      case 's': return String(args[i++]);
+      case 'e': return escape(args[i++]);
+    }
+  });
+
+  return div.firstChild;
+}
+
+/**
+ * Check for suites that do not have elements
+ * with `classname`, and hide them.
+ */
+
+function hideSuitesWithout(classname) {
+  var suites = document.getElementsByClassName('suite');
+  for (var i = 0; i < suites.length; i++) {
+    var els = suites[i].getElementsByClassName(classname);
+    if (0 == els.length) suites[i].className += ' hidden';
+  }
+}
+
+/**
+ * Unhide .hidden suites.
+ */
+
+function unhide() {
+  var els = document.getElementsByClassName('suite hidden');
+  for (var i = 0; i < els.length; ++i) {
+    els[i].className = els[i].className.replace('suite hidden', 'suite');
+  }
+}
+
+/**
+ * Set `el` text to `str`.
+ */
+
+function text(el, str) {
+  if (el.textContent) {
+    el.textContent = str;
+  } else {
+    el.innerText = str;
+  }
+}
+
+/**
+ * Listen on `event` with callback `fn`.
+ */
+
+function on(el, event, fn) {
+  if (el.addEventListener) {
+    el.addEventListener(event, fn, false);
+  } else {
+    el.attachEvent('on' + event, fn);
+  }
+}
+
+}); // module: reporters/html.js
+
+require.register("reporters/index.js", function(module, exports, require){
+
+exports.Base = require('./base');
+exports.Dot = require('./dot');
+exports.Doc = require('./doc');
+exports.TAP = require('./tap');
+exports.JSON = require('./json');
+exports.HTML = require('./html');
+exports.List = require('./list');
+exports.Min = require('./min');
+exports.Spec = require('./spec');
+exports.Nyan = require('./nyan');
+exports.XUnit = require('./xunit');
+exports.Markdown = require('./markdown');
+exports.Progress = require('./progress');
+exports.Landing = require('./landing');
+exports.JSONCov = require('./json-cov');
+exports.HTMLCov = require('./html-cov');
+exports.JSONStream = require('./json-stream');
+exports.Teamcity = require('./teamcity');
+
+}); // module: reporters/index.js
+
+require.register("reporters/json-cov.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `JSONCov`.
+ */
+
+exports = module.exports = JSONCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @param {Runner} runner
+ * @param {Boolean} output
+ * @api public
+ */
+
+function JSONCov(runner, output) {
+  var self = this
+    , output = 1 == arguments.length ? true : output;
+
+  Base.call(this, runner);
+
+  var tests = []
+    , failures = []
+    , passes = [];
+
+  runner.on('test end', function(test){
+    tests.push(test);
+  });
+
+  runner.on('pass', function(test){
+    passes.push(test);
+  });
+
+  runner.on('fail', function(test){
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    var cov = global._$jscoverage || {};
+    var result = self.cov = map(cov);
+    result.stats = self.stats;
+    result.tests = tests.map(clean);
+    result.failures = failures.map(clean);
+    result.passes = passes.map(clean);
+    if (!output) return;
+    process.stdout.write(JSON.stringify(result, null, 2 ));
+  });
+}
+
+/**
+ * Map jscoverage data to a JSON structure
+ * suitable for reporting.
+ *
+ * @param {Object} cov
+ * @return {Object}
+ * @api private
+ */
+
+function map(cov) {
+  var ret = {
+      instrumentation: 'node-jscoverage'
+    , sloc: 0
+    , hits: 0
+    , misses: 0
+    , coverage: 0
+    , files: []
+  };
+
+  for (var filename in cov) {
+    var data = coverage(filename, cov[filename]);
+    ret.files.push(data);
+    ret.hits += data.hits;
+    ret.misses += data.misses;
+    ret.sloc += data.sloc;
+  }
+
+  ret.files.sort(function(a, b) {
+    return a.filename.localeCompare(b.filename);
+  });
+
+  if (ret.sloc > 0) {
+    ret.coverage = (ret.hits / ret.sloc) * 100;
+  }
+
+  return ret;
+};
+
+/**
+ * Map jscoverage data for a single source file
+ * to a JSON structure suitable for reporting.
+ *
+ * @param {String} filename name of the source file
+ * @param {Object} data jscoverage coverage data
+ * @return {Object}
+ * @api private
+ */
+
+function coverage(filename, data) {
+  var ret = {
+    filename: filename,
+    coverage: 0,
+    hits: 0,
+    misses: 0,
+    sloc: 0,
+    source: {}
+  };
+
+  data.source.forEach(function(line, num){
+    num++;
+
+    if (data[num] === 0) {
+      ret.misses++;
+      ret.sloc++;
+    } else if (data[num] !== undefined) {
+      ret.hits++;
+      ret.sloc++;
+    }
+
+    ret.source[num] = {
+        source: line
+      , coverage: data[num] === undefined
+        ? ''
+        : data[num]
+    };
+  });
+
+  ret.coverage = ret.hits / ret.sloc * 100;
+
+  return ret;
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+
+}); // module: reporters/json-cov.js
+
+require.register("reporters/json-stream.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , total = runner.total;
+
+  runner.on('start', function(){
+    console.log(JSON.stringify(['start', { total: total }]));
+  });
+
+  runner.on('pass', function(test){
+    console.log(JSON.stringify(['pass', clean(test)]));
+  });
+
+  runner.on('fail', function(test, err){
+    console.log(JSON.stringify(['fail', clean(test)]));
+  });
+
+  runner.on('end', function(){
+    process.stdout.write(JSON.stringify(['end', self.stats]));
+  });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+}); // module: reporters/json-stream.js
+
+require.register("reporters/json.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `JSON`.
+ */
+
+exports = module.exports = JSONReporter;
+
+/**
+ * Initialize a new `JSON` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function JSONReporter(runner) {
+  var self = this;
+  Base.call(this, runner);
+
+  var tests = []
+    , failures = []
+    , passes = [];
+
+  runner.on('test end', function(test){
+    tests.push(test);
+  });
+
+  runner.on('pass', function(test){
+    passes.push(test);
+  });
+
+  runner.on('fail', function(test){
+    failures.push(test);
+  });
+
+  runner.on('end', function(){
+    var obj = {
+        stats: self.stats
+      , tests: tests.map(clean)
+      , failures: failures.map(clean)
+      , passes: passes.map(clean)
+    };
+
+    process.stdout.write(JSON.stringify(obj, null, 2));
+  });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @param {Object} test
+ * @return {Object}
+ * @api private
+ */
+
+function clean(test) {
+  return {
+      title: test.title
+    , fullTitle: test.fullTitle()
+    , duration: test.duration
+  }
+}
+}); // module: reporters/json.js
+
+require.register("reporters/landing.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Landing`.
+ */
+
+exports = module.exports = Landing;
+
+/**
+ * Airplane color.
+ */
+
+Base.colors.plane = 0;
+
+/**
+ * Airplane crash color.
+ */
+
+Base.colors['plane crash'] = 31;
+
+/**
+ * Runway color.
+ */
+
+Base.colors.runway = 90;
+
+/**
+ * Initialize a new `Landing` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Landing(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , total = runner.total
+    , stream = process.stdout
+    , plane = color('plane', '✈')
+    , crashed = -1
+    , n = 0;
+
+  function runway() {
+    var buf = Array(width).join('-');
+    return '  ' + color('runway', buf);
+  }
+
+  runner.on('start', function(){
+    stream.write('\n  ');
+    cursor.hide();
+  });
+
+  runner.on('test end', function(test){
+    // check if the plane crashed
+    var col = -1 == crashed
+      ? width * ++n / total | 0
+      : crashed;
+
+    // show the crash
+    if ('failed' == test.state) {
+      plane = color('plane crash', '✈');
+      crashed = col;
+    }
+
+    // render landing strip
+    stream.write('\u001b[4F\n\n');
+    stream.write(runway());
+    stream.write('\n  ');
+    stream.write(color('runway', Array(col).join('â‹…')));
+    stream.write(plane)
+    stream.write(color('runway', Array(width - col).join('â‹…') + '\n'));
+    stream.write(runway());
+    stream.write('\u001b[0m');
+  });
+
+  runner.on('end', function(){
+    cursor.show();
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Landing.prototype = new F;
+Landing.prototype.constructor = Landing;
+
+}); // module: reporters/landing.js
+
+require.register("reporters/list.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function List(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , n = 0;
+
+  runner.on('start', function(){
+    console.log();
+  });
+
+  runner.on('test', function(test){
+    process.stdout.write(color('pass', '    ' + test.fullTitle() + ': '));
+  });
+
+  runner.on('pending', function(test){
+    var fmt = color('checkmark', '  -')
+      + color('pending', ' %s');
+    console.log(fmt, test.fullTitle());
+  });
+
+  runner.on('pass', function(test){
+    var fmt = color('checkmark', '  '+Base.symbols.dot)
+      + color('pass', ' %s: ')
+      + color(test.speed, '%dms');
+    cursor.CR();
+    console.log(fmt, test.fullTitle(), test.duration);
+  });
+
+  runner.on('fail', function(test, err){
+    cursor.CR();
+    console.log(color('fail', '  %d) %s'), ++n, test.fullTitle());
+  });
+
+  runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+List.prototype = new F;
+List.prototype.constructor = List;
+
+
+}); // module: reporters/list.js
+
+require.register("reporters/markdown.js", function(module, exports, require){
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils');
+
+/**
+ * Expose `Markdown`.
+ */
+
+exports = module.exports = Markdown;
+
+/**
+ * Initialize a new `Markdown` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Markdown(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , level = 0
+    , buf = '';
+
+  function title(str) {
+    return Array(level).join('#') + ' ' + str;
+  }
+
+  function indent() {
+    return Array(level).join('  ');
+  }
+
+  function mapTOC(suite, obj) {
+    var ret = obj;
+    obj = obj[suite.title] = obj[suite.title] || { suite: suite };
+    suite.suites.forEach(function(suite){
+      mapTOC(suite, obj);
+    });
+    return ret;
+  }
+
+  function stringifyTOC(obj, level) {
+    ++level;
+    var buf = '';
+    var link;
+    for (var key in obj) {
+      if ('suite' == key) continue;
+      if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+      if (key) buf += Array(level).join('  ') + link;
+      buf += stringifyTOC(obj[key], level);
+    }
+    --level;
+    return buf;
+  }
+
+  function generateTOC(suite) {
+    var obj = mapTOC(suite, {});
+    return stringifyTOC(obj, 0);
+  }
+
+  generateTOC(runner.suite);
+
+  runner.on('suite', function(suite){
+    ++level;
+    var slug = utils.slug(suite.fullTitle());
+    buf += '<a name="' + slug + '"></a>' + '\n';
+    buf += title(suite.title) + '\n';
+  });
+
+  runner.on('suite end', function(suite){
+    --level;
+  });
+
+  runner.on('pass', function(test){
+    var code = utils.clean(test.fn.toString());
+    buf += test.title + '.\n';
+    buf += '\n```js\n';
+    buf += code + '\n';
+    buf += '```\n\n';
+  });
+
+  runner.on('end', function(){
+    process.stdout.write('# TOC\n');
+    process.stdout.write(generateTOC(runner.suite));
+    process.stdout.write(buf);
+  });
+}
+}); // module: reporters/markdown.js
+
+require.register("reporters/min.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Min`.
+ */
+
+exports = module.exports = Min;
+
+/**
+ * Initialize a new `Min` minimal test reporter (best used with --watch).
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Min(runner) {
+  Base.call(this, runner);
+  
+  runner.on('start', function(){
+    // clear screen
+    process.stdout.write('\u001b[2J');
+    // set cursor position
+    process.stdout.write('\u001b[1;3H');
+  });
+
+  runner.on('end', this.epilogue.bind(this));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Min.prototype = new F;
+Min.prototype.constructor = Min;
+
+}); // module: reporters/min.js
+
+require.register("reporters/nyan.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = NyanCat;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function NyanCat(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , width = Base.window.width * .75 | 0
+    , rainbowColors = this.rainbowColors = self.generateColors()
+    , colorIndex = this.colorIndex = 0
+    , numerOfLines = this.numberOfLines = 4
+    , trajectories = this.trajectories = [[], [], [], []]
+    , nyanCatWidth = this.nyanCatWidth = 11
+    , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth)
+    , scoreboardWidth = this.scoreboardWidth = 5
+    , tick = this.tick = 0
+    , n = 0;
+
+  runner.on('start', function(){
+    Base.cursor.hide();
+    self.draw('start');
+  });
+
+  runner.on('pending', function(test){
+    self.draw('pending');
+  });
+
+  runner.on('pass', function(test){
+    self.draw('pass');
+  });
+
+  runner.on('fail', function(test, err){
+    self.draw('fail');
+  });
+
+  runner.on('end', function(){
+    Base.cursor.show();
+    for (var i = 0; i < self.numberOfLines; i++) write('\n');
+    self.epilogue();
+  });
+}
+
+/**
+ * Draw the nyan cat with runner `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.draw = function(status){
+  this.appendRainbow();
+  this.drawScoreboard();
+  this.drawRainbow();
+  this.drawNyanCat(status);
+  this.tick = !this.tick;
+};
+
+/**
+ * Draw the "scoreboard" showing the number
+ * of passes, failures and pending tests.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawScoreboard = function(){
+  var stats = this.stats;
+  var colors = Base.colors;
+
+  function draw(color, n) {
+    write(' ');
+    write('\u001b[' + color + 'm' + n + '\u001b[0m');
+    write('\n');
+  }
+
+  draw(colors.green, stats.passes);
+  draw(colors.fail, stats.failures);
+  draw(colors.pending, stats.pending);
+  write('\n');
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Append the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.appendRainbow = function(){
+  var segment = this.tick ? '_' : '-';
+  var rainbowified = this.rainbowify(segment);
+
+  for (var index = 0; index < this.numberOfLines; index++) {
+    var trajectory = this.trajectories[index];
+    if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift();
+    trajectory.push(rainbowified);
+  }
+};
+
+/**
+ * Draw the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawRainbow = function(){
+  var self = this;
+
+  this.trajectories.forEach(function(line, index) {
+    write('\u001b[' + self.scoreboardWidth + 'C');
+    write(line.join(''));
+    write('\n');
+  });
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw the nyan cat with `status`.
+ *
+ * @param {String} status
+ * @api private
+ */
+
+NyanCat.prototype.drawNyanCat = function(status) {
+  var self = this;
+  var startWidth = this.scoreboardWidth + this.trajectories[0].length;
+
+  [0, 1, 2, 3].forEach(function(index) {
+    write('\u001b[' + startWidth + 'C');
+
+    switch (index) {
+      case 0:
+        write('_,------,');
+        write('\n');
+        break;
+      case 1:
+        var padding = self.tick ? '  ' : '   ';
+        write('_|' + padding + '/\\_/\\ ');
+        write('\n');
+        break;
+      case 2:
+        var padding = self.tick ? '_' : '__';
+        var tail = self.tick ? '~' : '^';
+        var face;
+        switch (status) {
+          case 'pass':
+            face = '( ^ .^)';
+            break;
+          case 'fail':
+            face = '( o .o)';
+            break;
+          default:
+            face = '( - .-)';
+        }
+        write(tail + '|' + padding + face + ' ');
+        write('\n');
+        break;
+      case 3:
+        var padding = self.tick ? ' ' : '  ';
+        write(padding + '""  "" ');
+        write('\n');
+        break;
+    }
+  });
+
+  this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Move cursor up `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorUp = function(n) {
+  write('\u001b[' + n + 'A');
+};
+
+/**
+ * Move cursor down `n`.
+ *
+ * @param {Number} n
+ * @api private
+ */
+
+NyanCat.prototype.cursorDown = function(n) {
+  write('\u001b[' + n + 'B');
+};
+
+/**
+ * Generate rainbow colors.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+NyanCat.prototype.generateColors = function(){
+  var colors = [];
+
+  for (var i = 0; i < (6 * 7); i++) {
+    var pi3 = Math.floor(Math.PI / 3);
+    var n = (i * (1.0 / 6));
+    var r = Math.floor(3 * Math.sin(n) + 3);
+    var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
+    var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
+    colors.push(36 * r + 6 * g + b + 16);
+  }
+
+  return colors;
+};
+
+/**
+ * Apply rainbow to the given `str`.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api private
+ */
+
+NyanCat.prototype.rainbowify = function(str){
+  var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
+  this.colorIndex += 1;
+  return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Stdout helper.
+ */
+
+function write(string) {
+  process.stdout.write(string);
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+NyanCat.prototype = new F;
+NyanCat.prototype.constructor = NyanCat;
+
+
+}); // module: reporters/nyan.js
+
+require.register("reporters/progress.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Progress`.
+ */
+
+exports = module.exports = Progress;
+
+/**
+ * General progress bar color.
+ */
+
+Base.colors.progress = 90;
+
+/**
+ * Initialize a new `Progress` bar test reporter.
+ *
+ * @param {Runner} runner
+ * @param {Object} options
+ * @api public
+ */
+
+function Progress(runner, options) {
+  Base.call(this, runner);
+
+  var self = this
+    , options = options || {}
+    , stats = this.stats
+    , width = Base.window.width * .50 | 0
+    , total = runner.total
+    , complete = 0
+    , max = Math.max;
+
+  // default chars
+  options.open = options.open || '[';
+  options.complete = options.complete || 'â–¬';
+  options.incomplete = options.incomplete || Base.symbols.dot;
+  options.close = options.close || ']';
+  options.verbose = false;
+
+  // tests started
+  runner.on('start', function(){
+    console.log();
+    cursor.hide();
+  });
+
+  // tests complete
+  runner.on('test end', function(){
+    complete++;
+    var incomplete = total - complete
+      , percent = complete / total
+      , n = width * percent | 0
+      , i = width - n;
+
+    cursor.CR();
+    process.stdout.write('\u001b[J');
+    process.stdout.write(color('progress', '  ' + options.open));
+    process.stdout.write(Array(n).join(options.complete));
+    process.stdout.write(Array(i).join(options.incomplete));
+    process.stdout.write(color('progress', options.close));
+    if (options.verbose) {
+      process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
+    }
+  });
+
+  // tests are complete, output some stats
+  // and the failures if any
+  runner.on('end', function(){
+    cursor.show();
+    console.log();
+    self.epilogue();
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Progress.prototype = new F;
+Progress.prototype.constructor = Progress;
+
+
+}); // module: reporters/progress.js
+
+require.register("reporters/spec.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `Spec`.
+ */
+
+exports = module.exports = Spec;
+
+/**
+ * Initialize a new `Spec` test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Spec(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , indents = 0
+    , n = 0;
+
+  function indent() {
+    return Array(indents).join('  ')
+  }
+
+  runner.on('start', function(){
+    console.log();
+  });
+
+  runner.on('suite', function(suite){
+    ++indents;
+    console.log(color('suite', '%s%s'), indent(), suite.title);
+  });
+
+  runner.on('suite end', function(suite){
+    --indents;
+    if (1 == indents) console.log();
+  });
+
+  runner.on('test', function(test){
+    process.stdout.write(indent() + color('pass', '  â—¦ ' + test.title + ': '));
+  });
+
+  runner.on('pending', function(test){
+    var fmt = indent() + color('pending', '  - %s');
+    console.log(fmt, test.title);
+  });
+
+  runner.on('pass', function(test){
+    if ('fast' == test.speed) {
+      var fmt = indent()
+        + color('checkmark', '  ' + Base.symbols.ok)
+        + color('pass', ' %s ');
+      cursor.CR();
+      console.log(fmt, test.title);
+    } else {
+      var fmt = indent()
+        + color('checkmark', '  ' + Base.symbols.ok)
+        + color('pass', ' %s ')
+        + color(test.speed, '(%dms)');
+      cursor.CR();
+      console.log(fmt, test.title, test.duration);
+    }
+  });
+
+  runner.on('fail', function(test, err){
+    cursor.CR();
+    console.log(indent() + color('fail', '  %d) %s'), ++n, test.title);
+  });
+
+  runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+Spec.prototype = new F;
+Spec.prototype.constructor = Spec;
+
+
+}); // module: reporters/spec.js
+
+require.register("reporters/tap.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , cursor = Base.cursor
+  , color = Base.color;
+
+/**
+ * Expose `TAP`.
+ */
+
+exports = module.exports = TAP;
+
+/**
+ * Initialize a new `TAP` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function TAP(runner) {
+  Base.call(this, runner);
+
+  var self = this
+    , stats = this.stats
+    , n = 1
+    , passes = 0
+    , failures = 0;
+
+  runner.on('start', function(){
+    var total = runner.grepTotal(runner.suite);
+    console.log('%d..%d', 1, total);
+  });
+
+  runner.on('test end', function(){
+    ++n;
+  });
+
+  runner.on('pending', function(test){
+    console.log('ok %d %s # SKIP -', n, title(test));
+  });
+
+  runner.on('pass', function(test){
+    passes++;
+    console.log('ok %d %s', n, title(test));
+  });
+
+  runner.on('fail', function(test, err){
+    failures++;
+    console.log('not ok %d %s', n, title(test));
+    if (err.stack) console.log(err.stack.replace(/^/gm, '  '));
+  });
+
+  runner.on('end', function(){
+    console.log('# tests ' + (passes + failures));
+    console.log('# pass ' + passes);
+    console.log('# fail ' + failures);
+  });
+}
+
+/**
+ * Return a TAP-safe title of `test`
+ *
+ * @param {Object} test
+ * @return {String}
+ * @api private
+ */
+
+function title(test) {
+  return test.fullTitle().replace(/#/g, '');
+}
+
+}); // module: reporters/tap.js
+
+require.register("reporters/teamcity.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `Teamcity`.
+ */
+
+exports = module.exports = Teamcity;
+
+/**
+ * Initialize a new `Teamcity` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Teamcity(runner) {
+  Base.call(this, runner);
+  var stats = this.stats;
+
+  runner.on('start', function() {
+    console.log("##teamcity[testSuiteStarted name='mocha.suite']");
+  });
+
+  runner.on('test', function(test) {
+    console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']");
+  });
+
+  runner.on('fail', function(test, err) {
+    console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']");
+  });
+
+  runner.on('pending', function(test) {
+    console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']");
+  });
+
+  runner.on('test end', function(test) {
+    console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']");
+  });
+
+  runner.on('end', function() {
+    console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']");
+  });
+}
+
+/**
+ * Escape the given `str`.
+ */
+
+function escape(str) {
+  return str
+    .replace(/\|/g, "||")
+    .replace(/\n/g, "|n")
+    .replace(/\r/g, "|r")
+    .replace(/\[/g, "|[")
+    .replace(/\]/g, "|]")
+    .replace(/\u0085/g, "|x")
+    .replace(/\u2028/g, "|l")
+    .replace(/\u2029/g, "|p")
+    .replace(/'/g, "|'");
+}
+
+}); // module: reporters/teamcity.js
+
+require.register("reporters/xunit.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base')
+  , utils = require('../utils')
+  , escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Expose `XUnit`.
+ */
+
+exports = module.exports = XUnit;
+
+/**
+ * Initialize a new `XUnit` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function XUnit(runner) {
+  Base.call(this, runner);
+  var stats = this.stats
+    , tests = []
+    , self = this;
+
+  runner.on('pass', function(test){
+    tests.push(test);
+  });
+  
+  runner.on('fail', function(test){
+    tests.push(test);
+  });
+
+  runner.on('end', function(){
+    console.log(tag('testsuite', {
+        name: 'Mocha Tests'
+      , tests: stats.tests
+      , failures: stats.failures
+      , errors: stats.failures
+      , skip: stats.tests - stats.failures - stats.passes
+      , timestamp: (new Date).toUTCString()
+      , time: stats.duration / 1000
+    }, false));
+
+    tests.forEach(test);
+    console.log('</testsuite>');    
+  });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+
+function F(){};
+F.prototype = Base.prototype;
+XUnit.prototype = new F;
+XUnit.prototype.constructor = XUnit;
+
+
+/**
+ * Output tag for the given `test.`
+ */
+
+function test(test) {
+  var attrs = {
+      classname: test.parent.fullTitle()
+    , name: test.title
+    , time: test.duration / 1000
+  };
+
+  if ('failed' == test.state) {
+    var err = test.err;
+    attrs.message = escape(err.message);
+    console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack))));
+  } else if (test.pending) {
+    console.log(tag('testcase', attrs, false, tag('skipped', {}, true)));
+  } else {
+    console.log(tag('testcase', attrs, true) );
+  }
+}
+
+/**
+ * HTML tag helper.
+ */
+
+function tag(name, attrs, close, content) {
+  var end = close ? '/>' : '>'
+    , pairs = []
+    , tag;
+
+  for (var key in attrs) {
+    pairs.push(key + '="' + escape(attrs[key]) + '"');
+  }
+
+  tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
+  if (content) tag += content + '</' + name + end;
+  return tag;
+}
+
+/**
+ * Return cdata escaped CDATA `str`.
+ */
+
+function cdata(str) {
+  return '<![CDATA[' + escape(str) + ']]>';
+}
+
+}); // module: reporters/xunit.js
+
+require.register("runnable.js", function(module, exports, require){
+
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('browser/events').EventEmitter
+  , debug = require('browser/debug')('mocha:runnable')
+  , milliseconds = require('./ms');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+var Date = global.Date
+  , setTimeout = global.setTimeout
+  , setInterval = global.setInterval
+  , clearTimeout = global.clearTimeout
+  , clearInterval = global.clearInterval;
+
+/**
+ * Object#toString().
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Expose `Runnable`.
+ */
+
+module.exports = Runnable;
+
+/**
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+
+function Runnable(title, fn) {
+  this.title = title;
+  this.fn = fn;
+  this.async = fn && fn.length;
+  this.sync = ! this.async;
+  this._timeout = 2000;
+  this._slow = 75;
+  this.timedOut = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+
+function F(){};
+F.prototype = EventEmitter.prototype;
+Runnable.prototype = new F;
+Runnable.prototype.constructor = Runnable;
+
+
+/**
+ * Set & get timeout `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.timeout = function(ms){
+  if (0 == arguments.length) return this._timeout;
+  if ('string' == typeof ms) ms = milliseconds(ms);
+  debug('timeout %d', ms);
+  this._timeout = ms;
+  if (this.timer) this.resetTimeout();
+  return this;
+};
+
+/**
+ * Set & get slow `ms`.
+ *
+ * @param {Number|String} ms
+ * @return {Runnable|Number} ms or self
+ * @api private
+ */
+
+Runnable.prototype.slow = function(ms){
+  if (0 === arguments.length) return this._slow;
+  if ('string' == typeof ms) ms = milliseconds(ms);
+  debug('timeout %d', ms);
+  this._slow = ms;
+  return this;
+};
+
+/**
+ * Return the full title generated by recursively
+ * concatenating the parent's full title.
+ *
+ * @return {String}
+ * @api public
+ */
+
+Runnable.prototype.fullTitle = function(){
+  return this.parent.fullTitle() + ' ' + this.title;
+};
+
+/**
+ * Clear the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.clearTimeout = function(){
+  clearTimeout(this.timer);
+};
+
+/**
+ * Inspect the runnable void of private properties.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Runnable.prototype.inspect = function(){
+  return JSON.stringify(this, function(key, val){
+    if ('_' == key[0]) return;
+    if ('parent' == key) return '#<Suite>';
+    if ('ctx' == key) return '#<Context>';
+    return val;
+  }, 2);
+};
+
+/**
+ * Reset the timeout.
+ *
+ * @api private
+ */
+
+Runnable.prototype.resetTimeout = function(){
+  var self = this
+    , ms = this.timeout();
+
+  this.clearTimeout();
+  if (ms) {
+    this.timer = setTimeout(function(){
+      self.callback(new Error('timeout of ' + ms + 'ms exceeded'));
+      self.timedOut = true;
+    }, ms);
+  }
+};
+
+/**
+ * Run the test and invoke `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+
+Runnable.prototype.run = function(fn){
+  var self = this
+    , ms = this.timeout()
+    , start = new Date
+    , ctx = this.ctx
+    , finished
+    , emitted;
+
+  if (ctx) ctx.runnable(this);
+
+  // timeout
+  if (this.async) {
+    if (ms) {
+      this.timer = setTimeout(function(){
+        done(new Error('timeout of ' + ms + 'ms exceeded'));
+        self.timedOut = true;
+      }, ms);
+    }
+  }
+
+  // called multiple times
+  function multiple(err) {
+    if (emitted) return;
+    emitted = true;
+    self.emit('error', err || new Error('done() called multiple times'));
+  }
+
+  // finished
+  function done(err) {
+    if (self.timedOut) return;
+    if (finished) return multiple(err);
+    self.clearTimeout();
+    self.duration = new Date - start;
+    finished = true;
+    fn(err);
+  }
+
+  // for .resetTimeout()
+  this.callback = done;
+
+  // async
+  if (this.async) {
+    try {
+      this

<TRUNCATED>

[13/27] built with the new Events module included

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8367ea49/sdks/html5-javascript/usergrid.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.min.js b/sdks/html5-javascript/usergrid.min.js
index edcdb4a..c701528 100644
--- a/sdks/html5-javascript/usergrid.min.js
+++ b/sdks/html5-javascript/usergrid.min.js
@@ -1 +1,2 @@
-window.console=window.console||{};window.console.log=window.console.log||function(){};window.Usergrid=window.Usergrid||{};Usergrid=Usergrid||{};Usergrid.SDK_VERSION="0.10.07";Usergrid.Client=function(a){this.URI=a.URI||"https://api.usergrid.com";if(a.orgName){this.set("orgName",a.orgName)}if(a.appName){this.set("appName",a.appName)}this.buildCurl=a.buildCurl||false;this.logging=a.logging||false;this._callTimeout=a.callTimeout||30000;this._callTimeoutCallback=a.callTimeoutCallback||null;this.logoutCallback=a.logoutCallback||null};Usergrid.Client.prototype.request=function(p,j){var o=this;var a=p.method||"GET";var n=p.endpoint;var c=p.body||{};var f=p.qs||{};var k=p.mQuery||false;var e=this.get("orgName");var d=this.get("appName");if(!k&&!e&&!d){if(typeof(this.logoutCallback)==="function"){return this.logoutCallback(true,"no_org_or_app_name_specified")}}if(k){var b=this.URI+"/"+n}else{var b=this.URI+"/"+e+"/"+d+"/"+n}if(o.getToken()){f.access_token=o.getToken()}var m=encodeParams(f);i
 f(m){b+="?"+m}c=JSON.stringify(c);var l=new XMLHttpRequest();l.open(a,b,true);if(c){l.setRequestHeader("Content-Type","application/json");l.setRequestHeader("Accept","application/json")}l.onerror=function(q){o._end=new Date().getTime();if(o.logging){console.log("success (time: "+o.calcTimeDiff()+"): "+a+" "+b)}if(o.logging){console.log("Error: API call failed at the network level.")}clearTimeout(h);var r=true;if(typeof(j)==="function"){j(r,q)}};l.onload=function(q){o._end=new Date().getTime();if(o.logging){console.log("success (time: "+o.calcTimeDiff()+"): "+a+" "+b)}clearTimeout(h);q=JSON.parse(l.responseText);if(l.status!=200){var r=q.error;var s=q.error_description;if(o.logging){console.log("Error ("+l.status+")("+r+"): "+s)}if((r=="auth_expired_session_token")||(r=="auth_missing_credentials")||(r=="auth_unverified_oath")||(r=="expired_token")||(r=="unauthorized")||(r=="auth_invalid")){if(typeof(o.logoutCallback)==="function"){return o.logoutCallback(true,q)}}if(typeof(j)==="func
 tion"){j(true,q)}}else{if(typeof(j)==="function"){j(false,q)}}};var h=setTimeout(function(){l.abort();if(o._callTimeoutCallback==="function"){o._callTimeoutCallback("API CALL TIMEOUT")}else{o.callback("API CALL TIMEOUT")}},o._callTimeout);if(this.logging){console.log("calling: "+a+" "+b)}if(this.buildCurl){var g={uri:b,body:c,method:a};this.buildCurlCall(g)}this._start=new Date().getTime();l.send(c)};Usergrid.Client.prototype.createGroup=function(a,d){var c=a.getOnExist||false;var a={path:a.path,client:this,data:a};var b=new Usergrid.Group(a);b.fetch(function(f,g){var e=(f&&"service_resource_not_found"===g.error||"no_name_specified"===g.error||"null_pointer"===g.error)||(!f&&c);if(e){b.save(function(h,j){if(typeof(d)==="function"){d(h,b)}})}else{if(typeof(d)==="function"){d(f,b)}}})};Usergrid.Client.prototype.createEntity=function(b,d){var c=b.getOnExist||false;var b={client:this,data:b};var a=new Usergrid.Entity(b);a.fetch(function(f,g){var e=(f&&"service_resource_not_found"===g.er
 ror||"no_name_specified"===g.error||"null_pointer"===g.error)||(!f&&c);if(e){a.set(b.data);a.save(function(h,j){if(typeof(d)==="function"){d(h,a,j)}})}else{if(typeof(d)==="function"){d(f,a,g)}}})};Usergrid.Client.prototype.getEntity=function(b,c){var b={client:this,data:b};var a=new Usergrid.Entity(b);a.fetch(function(d,e){if(typeof(c)==="function"){c(d,a,e)}})};Usergrid.Client.prototype.restoreEntity=function(c){var d=JSON.parse(c);var b={client:this,data:d};var a=new Usergrid.Entity(b);return a};Usergrid.Client.prototype.createCollection=function(a,c){a.client=this;var b=new Usergrid.Collection(a,function(d,e){if(typeof(c)==="function"){c(d,b,e)}})};Usergrid.Client.prototype.restoreCollection=function(a){var b=JSON.parse(a);b.client=this;var c=new Usergrid.Collection(b);return c};Usergrid.Client.prototype.getFeedForUser=function(c,b){var a={method:"GET",endpoint:"users/"+c+"/feed"};this.request(a,function(d,e){if(typeof(b)==="function"){if(d){b(d)}else{b(d,e,e.entities)}}})};Userg
 rid.Client.prototype.createUserActivity=function(b,c,d){c.type="users/"+b+"/activities";var c={client:this,data:c};var a=new Usergrid.Entity(c);a.save(function(e,f){if(typeof(d)==="function"){d(e,a)}})};Usergrid.Client.prototype.createUserActivityWithEntity=function(a,c,e){var d=a.get("username");var b={actor:{displayName:d,uuid:a.get("uuid"),username:d,email:a.get("email"),picture:a.get("picture"),image:{duration:0,height:80,url:a.get("picture"),width:80},},verb:"post",content:c};this.createUserActivity(d,b,e)};Usergrid.Client.prototype.calcTimeDiff=function(){var c=0;var b=this._end-this._start;try{c=((b/10)/60).toFixed(2)}catch(a){return 0}return c};Usergrid.Client.prototype.setToken=function(a){this.set("token",a)};Usergrid.Client.prototype.getToken=function(){return this.get("token")};Usergrid.Client.prototype.setObject=function(a,b){if(b){b=JSON.stringify(b)}this.set(a,b)};Usergrid.Client.prototype.set=function(b,c){var a="apigee_"+b;this[b]=c;if(typeof(Storage)!=="undefined")
 {if(c){localStorage.setItem(a,c)}else{localStorage.removeItem(a)}}};Usergrid.Client.prototype.getObject=function(a){return JSON.parse(this.get(a))};Usergrid.Client.prototype.get=function(b){var a="apigee_"+b;if(this[b]){return this[b]}else{if(typeof(Storage)!=="undefined"){return localStorage.getItem(a)}}return null};Usergrid.Client.prototype.signup=function(g,e,d,c,f){var a=this;var b={type:"users",username:g,password:e,email:d,name:c};this.createEntity(b,f)};Usergrid.Client.prototype.login=function(e,c,d){var a=this;var b={method:"POST",endpoint:"token",body:{username:e,password:c,grant_type:"password"}};this.request(b,function(h,j){var f={};if(h&&a.logging){console.log("error trying to log user in")}else{var g={client:a,data:j.user};f=new Usergrid.Entity(g);a.setToken(j.access_token)}if(typeof(d)==="function"){d(h,j,f)}})};Usergrid.Client.prototype.reAuthenticateLite=function(c){var a=this;var b={method:"GET",endpoint:"management/me",mQuery:true};this.request(b,function(e,d){if(e
 &&a.logging){console.log("error trying to re-authenticate user")}else{a.setToken(d.access_token)}if(typeof(c)==="function"){c(e)}})};Usergrid.Client.prototype.reAuthenticate=function(c,d){var a=this;var b={method:"GET",endpoint:"management/users/"+c,mQuery:true};this.request(b,function(k,l){var f={};var j={};var m={};if(k&&a.logging){console.log("error trying to full authenticate user")}else{var n=l.data;a.setToken(n.token);a.set("email",n.email);localStorage.setItem("accessToken",n.token);localStorage.setItem("userUUID",n.uuid);localStorage.setItem("userEmail",n.email);var g={username:n.username,email:n.email,name:n.name,uuid:n.uuid};var q={client:a,data:g};m=new Usergrid.Entity(q);f=n.organizations;var p="";try{var h=a.get("orgName");p=(f[h])?f[h]:f[Object.keys(f)[0]];a.set("orgName",p.name)}catch(o){k=true;if(a.logging){console.log("error selecting org")}}j=a.parseApplicationsArray(p);a.selectFirstApp(j);a.setObject("organizations",f);a.setObject("applications",j)}if(typeof(d)===
 "function"){d(k,n,m,f,j)}})};Usergrid.Client.prototype.loginFacebook=function(a,d){var b=this;var c={method:"GET",endpoint:"auth/facebook",qs:{fb_access_token:a}};this.request(c,function(g,h){var e={};if(g&&b.logging){console.log("error trying to log user in")}else{var f={client:b,data:h.user};e=new Usergrid.Entity(f);b.setToken(h.access_token)}if(typeof(d)==="function"){d(g,h,e)}})};Usergrid.Client.prototype.getLoggedInUser=function(c){if(!this.getToken()){c(true,null,null)}else{var a=this;var b={method:"GET",endpoint:"users/me"};this.request(b,function(f,g){if(f){if(a.logging){console.log("error trying to log user in")}if(typeof(c)==="function"){c(f,g,null)}}else{var e={client:a,data:g.entities[0]};var d=new Usergrid.Entity(e);if(typeof(c)==="function"){c(f,g,d)}}})}};Usergrid.Client.prototype.isLoggedIn=function(){if(this.getToken()){return true}return false};Usergrid.Client.prototype.logout=function(){this.setToken(null)};Usergrid.Client.prototype.buildCurlCall=function(c){var b
 ="curl";var e=(c.method||"GET").toUpperCase();var a=c.body||{};var d=c.uri;if(e==="POST"){b+=" -X POST"}else{if(e==="PUT"){b+=" -X PUT"}else{if(e==="DELETE"){b+=" -X DELETE"}else{b+=" -X GET"}}}b+=" "+d;if(a!=='"{}"'&&e!=="GET"&&e!=="DELETE"){b+=" -d '"+a+"'"}console.log(b);return b};Usergrid.Client.prototype.getDisplayImage=function(a,c,b){try{if(c){return c}var b=b||50;if(a.length){return"https://secure.gravatar.com/avatar/"+MD5(a)+"?s="+b+encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png")}else{return"https://apigee.com/usergrid/images/user_profile.png"}}catch(d){return"https://apigee.com/usergrid/images/user_profile.png"}};Usergrid.Entity=function(a){if(a){this._data=a.data||{};this._client=a.client||{}}};Usergrid.Entity.prototype.serialize=function(){return JSON.stringify(this._data)};Usergrid.Entity.prototype.get=function(a){if(a){return this._data[a]}else{return this._data}};Usergrid.Entity.prototype.set=function(a,b){if(typeof a==="object"){for(var c in a){th
 is._data[c]=a[c]}}else{if(typeof a==="string"){if(b===null){delete this._data[a]}else{this._data[a]=b}}else{this._data={}}}};Usergrid.Entity.prototype.save=function(h){var c=this.get("type");var g="POST";if(isUUID(this.get("uuid"))){g="PUT";c+="/"+this.get("uuid")}var a=this;var e={};var f=this.get();for(var d in f){if(d==="metadata"||d==="created"||d==="modified"||d==="type"||d==="activated"||d==="uuid"){continue}e[d]=f[d]}var b={method:g,endpoint:c,body:e};this._client.request(b,function(n,k){if(n&&a._client.logging){console.log("could not save entity");if(typeof(h)==="function"){return h(n,k,a)}}else{if(k.entities){if(k.entities.length){var j=k.entities[0];a.set(j);var p=k.path;while(p.substring(0,1)==="/"){p=p.substring(1)}a.set("type",p)}}var o=((a.get("type")==="user"||a.get("type")==="users")&&f.oldpassword&&f.newpassword);if(o){var m={};m.oldpassword=f.oldpassword;m.newpassword=f.newpassword;var l={method:"PUT",endpoint:c+"/password",body:m};a._client.request(l,function(q,r)
 {if(q&&a._client.logging){console.log("could not update user")}a.set("oldpassword",null);a.set("newpassword",null);if(typeof(h)==="function"){h(q,r,a)}})}else{if(typeof(h)==="function"){h(n,k,a)}}}})};Usergrid.Entity.prototype.fetch=function(e){var d=this.get("type");var a=this;if(this.get("uuid")){d+="/"+this.get("uuid")}else{if(d==="users"){if(this.get("username")){d+="/"+this.get("username")}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}else{if(d==="a path"){if(this.get("path")){d+="/"+encodeURIComponent(this.get("name"))}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}else{if(this.get("name")){d+="/"+encodeURIComponent(this.get("name"))}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}}}var b={method:"GET",endpoint:d};this._client.request(b,function(g,h)
 {if(g&&a._client.logging){console.log("could not get entity")}else{if(h.user){a.set(h.user);a._json=JSON.stringify(h.user,null,2)}else{if(h.entities){if(h.entities.length){var f=h.entities[0];a.set(f)}}}}if(typeof(e)==="function"){e(g,h,a)}})};Usergrid.Entity.prototype.destroy=function(e){var d=this.get("type");if(isUUID(this.get("uuid"))){d+="/"+this.get("uuid")}else{if(typeof(e)==="function"){var c="Error trying to delete object - no uuid specified.";if(a._client.logging){console.log(c)}e(true,c)}}var a=this;var b={method:"DELETE",endpoint:d};this._client.request(b,function(f,g){if(f&&a._client.logging){console.log("entity could not be deleted")}else{a.set(null)}if(typeof(e)==="function"){e(f,g)}})};Usergrid.Entity.prototype.connect=function(a,d,h){var k=this;var f=d.get("type");var c=this.getEntityId(d);if(!c){if(typeof(h)==="function"){var g="Error trying to delete object - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var e=this.get("type");var b=thi
 s.getEntityId(this);if(!b){if(typeof(h)==="function"){var g="Error in connect - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var j=e+"/"+b+"/"+a+"/"+f+"/"+c;var l={method:"POST",endpoint:j};this._client.request(l,function(m,n){if(m&&k._client.logging){console.log("entity could not be connected")}if(typeof(h)==="function"){h(m,n)}})};Usergrid.Entity.prototype.getEntityId=function(a){var b=false;if(isUUID(a.get("uuid"))){b=a.get("uuid")}else{if(type==="users"){b=a.get("username")}else{if(a.get("name")){b=a.get("name")}}}return b};Usergrid.Entity.prototype.getConnections=function(d,h){var c=this;var b=this.get("type");var a=this.getEntityId(this);if(!a){if(typeof(h)==="function"){var f="Error in getConnections - no uuid specified.";if(c._client.logging){console.log(f)}h(true,f)}return}var g=b+"/"+a+"/"+d+"/";var e={method:"GET",endpoint:g};this._client.request(e,function(l,m){if(l&&c._client.logging){console.log("entity could not be connected")}c[d]={};var 
 k=m.entities.length;for(var j=0;j<k;j++){if(m.entities[j].type==="user"){c[d][m.entities[j].username]=m.entities[j]}else{c[d][m.entities[j].name]=m.entities[j]}}if(typeof(h)==="function"){h(l,m,m.entities)}})};Usergrid.Entity.prototype.getGroups=function(d){var a=this;var c="users/"+this.get("uuid")+"/groups";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("entity could not be connected")}a.groups=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getActivities=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/activities";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("entity could not be connected")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString()}a.activities=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getFollow
 ing=function(d){var a=this;var c="users/"+this.get("uuid")+"/following";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user following")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString();var g=a._client.getDisplayImage(f.entities[entity].email,f.entities[entity].picture);f.entities[entity]._portal_image_icon=g}a.following=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getFollowers=function(d){var a=this;var c="users/"+this.get("uuid")+"/followers";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user followers")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString();var g=a._client.getDisplayImage(f.entities[entity].email,f.entities[entity].picture);f.entities[entity]._portal_image_icon=g}
 a.followers=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getRoles=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/roles";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user roles")}a.roles=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getPermissions=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/permissions";var b={method:"GET",endpoint:c};this._client.request(b,function(g,m){if(g&&a._client.logging){console.log("could not get user permissions")}var p=[];if(m.data){var r=m.data;var o=0;for(var n in r){o++;var h=r[n];var l=h.split(":");var s="";var q=l[0];if(l.length>1){s=l[0];q=l[1]}s.replace("*","get,post,put,delete");var e=s.split(",");var f={};f.get="no";f.post="no";f.put="no";f["delete"]="no";for(var k in e){f[e[k]]="yes"}p.push({operations:f,path:q,perm:h})}}a.permissions=p;if(typeof
 (d)==="function"){d(g,m,m.entities)}})};Usergrid.Entity.prototype.disconnect=function(a,d,h){var k=this;var f=d.get("type");var c=this.getEntityId(d);if(!c){if(typeof(h)==="function"){var g="Error trying to delete object - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var e=this.get("type");var b=this.getEntityId(this);if(!b){if(typeof(h)==="function"){var g="Error in connect - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var j=e+"/"+b+"/"+a+"/"+f+"/"+c;var l={method:"DELETE",endpoint:j};this._client.request(l,function(m,n){if(m&&k._client.logging){console.log("entity could not be disconnected")}if(typeof(h)==="function"){h(m,n)}})};Usergrid.Collection=function(b,e){if(b){this._client=b.client;this._type=b.type;this.qs=b.qs||{};this._list=b.list||[];this._iterator=b.iterator||-1;this._previous=b.previous||[];this._next=b.next||null;this._cursor=b.cursor||null;if(b.list){var d=b.list.length;for(var c=0;c<d;c++){var a=this._clie
 nt.restoreEntity(b.list[c]);this._list[c]=a}}}if(e){this.fetch(e)}};Usergrid.Collection.prototype.serialize=function(){var c={};c.type=this._type;c.qs=this.qs;c.iterator=this._iterator;c.previous=this._previous;c.next=this._next;c.cursor=this._cursor;this.resetEntityPointer();var b=0;c.list=[];while(this.hasNextEntity()){var a=this.getNextEntity();c.list[b]=a.serialize();b++}c=JSON.stringify(c);return c};Usergrid.Collection.prototype.addCollection=function(b,a,d){self=this;a.client=this._client;var c=new Usergrid.Collection(a,function(g,h){if(typeof(d)==="function"){c.resetEntityPointer();while(c.hasNextEntity()){var e=c.getNextEntity();var f=e.get("email");var j=self._client.getDisplayImage(e.get("email"),e.get("picture"));e._portal_image_icon=j}self[b]=c;d(g,c)}})};Usergrid.Collection.prototype.fetch=function(d){var b=this;var a=this.qs;if(this._cursor){a.cursor=this._cursor}else{delete a.cursor}var c={method:"GET",endpoint:this._type,qs:this.qs};this._client.request(c,function(g,
 h){if(g&&b._client.logging){console.log("error getting collection")}else{var o=h.cursor||null;b.saveCursor(o);if(h.entities){b.resetEntityPointer();var l=h.entities.length;b._list=[];for(var j=0;j<l;j++){var e=h.entities[j].uuid;if(e){var f=h.entities[j]||{};b._baseType=h.entities[j].type;f.type=b._type;var n={type:b._type,client:b._client,uuid:e,data:f};var m=new Usergrid.Entity(n);m._json=JSON.stringify(f,null,2);var k=b._list.length;b._list[k]=m}}}}if(typeof(d)==="function"){d(g,h)}})};Usergrid.Collection.prototype.addEntity=function(b,c){var a=this;b.type=this._type;this._client.createEntity(b,function(f,d){if(!f){var e=a._list.length;a._list[e]=d}if(typeof(c)==="function"){c(f,d)}})};Usergrid.Collection.prototype.addExistingEntity=function(a){var b=this._list.length;this._list[b]=a};Usergrid.Collection.prototype.destroyEntity=function(b,c){var a=this;b.destroy(function(d,e){if(d){if(a._client.logging){console.log("could not destroy entity")}if(typeof(c)==="function"){c(d,e)}}el
 se{a.fetch(c)}});this.removeEntity(b)};Usergrid.Collection.prototype.removeEntity=function(a){var b=a.get("uuid");for(key in this._list){var c=this._list[key];if(c.get("uuid")===b){return this._list.splice(key,1)}}return false};Usergrid.Collection.prototype.getEntityByUUID=function(c,e){for(key in this._list){var d=this._list[key];if(d.get("uuid")===c){return d}}var b={data:{type:this._type,uuid:c},client:this._client};var a=new Usergrid.Entity(b);a.fetch(e)};Usergrid.Collection.prototype.getFirstEntity=function(){var a=this._list.length;if(a>0){return this._list[0]}return null};Usergrid.Collection.prototype.getLastEntity=function(){var a=this._list.length;if(a>0){return this._list[a-1]}return null};Usergrid.Collection.prototype.hasNextEntity=function(){var a=this._iterator+1;var b=(a>=0&&a<this._list.length);if(b){return true}return false};Usergrid.Collection.prototype.getNextEntity=function(){this._iterator++;var a=(this._iterator>=0&&this._iterator<=this._list.length);if(a){retur
 n this._list[this._iterator]}return false};Usergrid.Collection.prototype.hasPrevEntity=function(){var b=this._iterator-1;var a=(b>=0&&b<this._list.length);if(a){return true}return false};Usergrid.Collection.prototype.getPrevEntity=function(){this._iterator--;var a=(this._iterator>=0&&this._iterator<=this._list.length);if(a){return this.list[this._iterator]}return false};Usergrid.Collection.prototype.resetEntityPointer=function(){this._iterator=-1};Usergrid.Collection.prototype.saveCursor=function(a){if(this._next!==a){this._next=a}};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(a){if(this.hasNextPage()){this._previous.push(this._cursor);this._cursor=this._next;this._list=[];this.fetch(a)}};Usergrid.Collection.prototype.hasPreviousPage=function(){return(this._previous.length>0)};Usergrid.Collection.prot
 otype.getPreviousPage=function(a){if(this.hasPreviousPage()){this._next=null;this._cursor=this._previous.pop();this._list=[];this.fetch(a)}};Usergrid.Group=function(a,b){this._path=a.path;this._list=[];this._client=a.client;this._data=a.data||{};this._data.type="groups"};Usergrid.Group.prototype=new Usergrid.Entity();Usergrid.Group.prototype.fetch=function(f){var a=this;var e="groups/"+this._path;var d="groups/"+this._path+"/users";var b={method:"GET",endpoint:e};var c={method:"GET",endpoint:d};this._client.request(b,function(h,j){if(h){if(a._client.logging){console.log("error getting group")}if(typeof(f)==="function"){f(h,j)}}else{if(j.entities){var g=j.entities[0];a._data=g||{};a._client.request(c,function(p,q){if(p&&a._client.logging){console.log("error getting group users")}else{if(q.entities){var o=q.entities.length;a._list=[];for(var l=0;l<o;l++){var n=q.entities[l].uuid;if(n){var r=q.entities[l]||{};var m={type:r.type,client:a._client,uuid:n,data:r};var k=new Usergrid.Entity(
 m);a._list.push(k)}}}}if(typeof(f)==="function"){f(p,q,a._list)}})}}})};Usergrid.Group.prototype.members=function(a){if(typeof(a)==="function"){a(null,this._list)}};Usergrid.Group.prototype.add=function(b,c){var a=this;var b={method:"POST",endpoint:"groups/"+this._path+"/users/"+b.user.get("username")};this._client.request(b,function(d,e){if(d){if(typeof(c)==="function"){c(d,e,e.entities)}}else{a.fetch(c)}})};Usergrid.Group.prototype.remove=function(b,c){var a=this;var b={method:"DELETE",endpoint:"groups/"+this._path+"/users/"+b.user.get("username")};this._client.request(b,function(d,e){if(d){if(typeof(c)==="function"){c(d,e)}}else{a.fetch(c)}})};Usergrid.Group.prototype.feed=function(d){var a=this;var c="groups/"+this._path+"/feed";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a.logging){console.log("error trying to log user in")}if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Group.prototype.createGroupActivity=function(c,d){var b=c.user;var 
 c={actor:{displayName:b.get("username"),uuid:b.get("uuid"),username:b.get("username"),email:b.get("email"),picture:b.get("picture"),image:{duration:0,height:80,url:b.get("picture"),width:80},},verb:"post",content:c.content};c.type="groups/"+this._path+"/activities";var c={client:this._client,data:c};var a=new Usergrid.Entity(c);a.save(function(e,f){if(typeof(d)==="function"){d(e,a)}})};function isUUID(a){var b=/^[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}$/;if(!a){return false}return b.test(a)}function encodeParams(d){tail=[];var b=[];if(d instanceof Array){for(i in d){b=d[i];if((b instanceof Array)&&(b.length>1)){tail.push(b[0]+"="+encodeURIComponent(b[1]))}}}else{for(var a in d){if(d.hasOwnProperty(a)){var c=d[a];if(c instanceof Array){for(i in c){b=c[i];tail.push(a+"="+encodeURIComponent(b))}}else{tail.push(a+"="+encodeURIComponent(c))}}}}return tail.join("&")};
\ No newline at end of file
+/*! usergrid@0.0.0 2014-01-16 */
+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 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")),xh
 r.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_invalid"
 ==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;options
 ={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 options
 ={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.entit
 ies))})},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.Clie
 nt.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",dat
 a.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,data){v
 ar 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").toUpperCase()
 ,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.Entit
 y.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 callback)
 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("uuid");
 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={method:"
 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("entit
 y 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){va
 r 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)})},User
 grid.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(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,"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=data.da
 ta,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 callba
 ck&&(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,data.i
 terator=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(options,
 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=function(en
 tity){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.Collecti
 on.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!==curs
 or&&(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",groupOpti
 ons={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(opt
 ions,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: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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})};var COUNTER_RESOLUTIONS={ALL:"all",MINUTE:"minute",FIVE_MINUTES:"five_minutes",HALF_HOUR:"half_hour",HOUR:"hour",SIX_DAY:"six_day",DAY:"day",WEEK:"week",MONTH:"month"};COUNTER_RESOLUTIONS.valueOf=function(str){return Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){return COUNTER_RESOLUTIONS[res]===str?COUNTER_RESOLUTIONS[res]:void 0}),COUNTER_RESOLUTIONS.ALL},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._dat
 a.type="events",this._data.counters=options.counters||{},"function"==typeof callback&&callback.call(self,!1,self)},Usergrid.Event.prototype=new Usergrid.Entity,Usergrid.Event.prototype.fetch=function(callback){this.getData(null,null,null,null,callback)},Usergrid.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),self.save(callback))},Usergrid.Event.prototype.decrement=function(name,value,callback){this.increment(name,-value,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=COUNTER_RESOLUTIONS.valueOf(resolution);if(start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(sta
 rt)?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


[23/27] git commit: renaming 'Event' to 'Counter'

Posted by sn...@apache.org.
renaming 'Event' to 'Counter'


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

Branch: refs/pull/34/head
Commit: 2c77ebf6ea06b293a7e219da3a7e654eb6334545
Parents: dc31ba5
Author: ryan bridges <rb...@apigee.com>
Authored: Mon Jan 27 16:22:54 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Mon Jan 27 16:22:54 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/lib/Event.js | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2c77ebf6/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
index c39ec94..74d019c 100644
--- a/sdks/html5-javascript/lib/Event.js
+++ b/sdks/html5-javascript/lib/Event.js
@@ -5,7 +5,7 @@
  *  @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 || {};
@@ -27,9 +27,9 @@ var COUNTER_RESOLUTIONS=[
  *  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){
+Usergrid.Counter.prototype.fetch=function(callback){
   this.getData(null, null, null, null, callback);
 }
 /*
@@ -43,7 +43,7 @@ Usergrid.Event.prototype.fetch=function(callback){
  * @param {function} callback
  * @returns {callback} callback(err, event)
  */
-Usergrid.Event.prototype.increment=function(name, value, callback){
+Usergrid.Counter.prototype.increment=function(name, value, callback){
   var self=this;
   if(isNaN(value)){
     if(typeof(callback) === 'function') {
@@ -65,7 +65,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
  * @returns {callback} callback(err, event)
  */
 
-Usergrid.Event.prototype.decrement=function(name, value, callback){
+Usergrid.Counter.prototype.decrement=function(name, value, callback){
   this.increment(name, -((parseInt(value))||1), callback);
 };
 /*
@@ -80,11 +80,11 @@ Usergrid.Event.prototype.decrement=function(name, value, callback){
  * @returns {callback} callback(err, event)
  */
 
-Usergrid.Event.prototype.reset=function(name, callback){
+Usergrid.Counter.prototype.reset=function(name, callback){
   this.increment(name, 0, callback);
 };
 
-Usergrid.Event.prototype.getData=function(start, end, resolution, counters, callback){
+Usergrid.Counter.prototype.getData=function(start, end, resolution, counters, callback){
   var start_time, 
       end_time,
       res=(resolution||'all').toLowerCase();


[16/27] built with the new Events module included

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8367ea49/sdks/html5-javascript/usergrid.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.min.js b/sdks/html5-javascript/usergrid.min.js
index edcdb4a..c701528 100644
--- a/sdks/html5-javascript/usergrid.min.js
+++ b/sdks/html5-javascript/usergrid.min.js
@@ -1 +1,2 @@
-window.console=window.console||{};window.console.log=window.console.log||function(){};window.Usergrid=window.Usergrid||{};Usergrid=Usergrid||{};Usergrid.SDK_VERSION="0.10.07";Usergrid.Client=function(a){this.URI=a.URI||"https://api.usergrid.com";if(a.orgName){this.set("orgName",a.orgName)}if(a.appName){this.set("appName",a.appName)}this.buildCurl=a.buildCurl||false;this.logging=a.logging||false;this._callTimeout=a.callTimeout||30000;this._callTimeoutCallback=a.callTimeoutCallback||null;this.logoutCallback=a.logoutCallback||null};Usergrid.Client.prototype.request=function(p,j){var o=this;var a=p.method||"GET";var n=p.endpoint;var c=p.body||{};var f=p.qs||{};var k=p.mQuery||false;var e=this.get("orgName");var d=this.get("appName");if(!k&&!e&&!d){if(typeof(this.logoutCallback)==="function"){return this.logoutCallback(true,"no_org_or_app_name_specified")}}if(k){var b=this.URI+"/"+n}else{var b=this.URI+"/"+e+"/"+d+"/"+n}if(o.getToken()){f.access_token=o.getToken()}var m=encodeParams(f);i
 f(m){b+="?"+m}c=JSON.stringify(c);var l=new XMLHttpRequest();l.open(a,b,true);if(c){l.setRequestHeader("Content-Type","application/json");l.setRequestHeader("Accept","application/json")}l.onerror=function(q){o._end=new Date().getTime();if(o.logging){console.log("success (time: "+o.calcTimeDiff()+"): "+a+" "+b)}if(o.logging){console.log("Error: API call failed at the network level.")}clearTimeout(h);var r=true;if(typeof(j)==="function"){j(r,q)}};l.onload=function(q){o._end=new Date().getTime();if(o.logging){console.log("success (time: "+o.calcTimeDiff()+"): "+a+" "+b)}clearTimeout(h);q=JSON.parse(l.responseText);if(l.status!=200){var r=q.error;var s=q.error_description;if(o.logging){console.log("Error ("+l.status+")("+r+"): "+s)}if((r=="auth_expired_session_token")||(r=="auth_missing_credentials")||(r=="auth_unverified_oath")||(r=="expired_token")||(r=="unauthorized")||(r=="auth_invalid")){if(typeof(o.logoutCallback)==="function"){return o.logoutCallback(true,q)}}if(typeof(j)==="func
 tion"){j(true,q)}}else{if(typeof(j)==="function"){j(false,q)}}};var h=setTimeout(function(){l.abort();if(o._callTimeoutCallback==="function"){o._callTimeoutCallback("API CALL TIMEOUT")}else{o.callback("API CALL TIMEOUT")}},o._callTimeout);if(this.logging){console.log("calling: "+a+" "+b)}if(this.buildCurl){var g={uri:b,body:c,method:a};this.buildCurlCall(g)}this._start=new Date().getTime();l.send(c)};Usergrid.Client.prototype.createGroup=function(a,d){var c=a.getOnExist||false;var a={path:a.path,client:this,data:a};var b=new Usergrid.Group(a);b.fetch(function(f,g){var e=(f&&"service_resource_not_found"===g.error||"no_name_specified"===g.error||"null_pointer"===g.error)||(!f&&c);if(e){b.save(function(h,j){if(typeof(d)==="function"){d(h,b)}})}else{if(typeof(d)==="function"){d(f,b)}}})};Usergrid.Client.prototype.createEntity=function(b,d){var c=b.getOnExist||false;var b={client:this,data:b};var a=new Usergrid.Entity(b);a.fetch(function(f,g){var e=(f&&"service_resource_not_found"===g.er
 ror||"no_name_specified"===g.error||"null_pointer"===g.error)||(!f&&c);if(e){a.set(b.data);a.save(function(h,j){if(typeof(d)==="function"){d(h,a,j)}})}else{if(typeof(d)==="function"){d(f,a,g)}}})};Usergrid.Client.prototype.getEntity=function(b,c){var b={client:this,data:b};var a=new Usergrid.Entity(b);a.fetch(function(d,e){if(typeof(c)==="function"){c(d,a,e)}})};Usergrid.Client.prototype.restoreEntity=function(c){var d=JSON.parse(c);var b={client:this,data:d};var a=new Usergrid.Entity(b);return a};Usergrid.Client.prototype.createCollection=function(a,c){a.client=this;var b=new Usergrid.Collection(a,function(d,e){if(typeof(c)==="function"){c(d,b,e)}})};Usergrid.Client.prototype.restoreCollection=function(a){var b=JSON.parse(a);b.client=this;var c=new Usergrid.Collection(b);return c};Usergrid.Client.prototype.getFeedForUser=function(c,b){var a={method:"GET",endpoint:"users/"+c+"/feed"};this.request(a,function(d,e){if(typeof(b)==="function"){if(d){b(d)}else{b(d,e,e.entities)}}})};Userg
 rid.Client.prototype.createUserActivity=function(b,c,d){c.type="users/"+b+"/activities";var c={client:this,data:c};var a=new Usergrid.Entity(c);a.save(function(e,f){if(typeof(d)==="function"){d(e,a)}})};Usergrid.Client.prototype.createUserActivityWithEntity=function(a,c,e){var d=a.get("username");var b={actor:{displayName:d,uuid:a.get("uuid"),username:d,email:a.get("email"),picture:a.get("picture"),image:{duration:0,height:80,url:a.get("picture"),width:80},},verb:"post",content:c};this.createUserActivity(d,b,e)};Usergrid.Client.prototype.calcTimeDiff=function(){var c=0;var b=this._end-this._start;try{c=((b/10)/60).toFixed(2)}catch(a){return 0}return c};Usergrid.Client.prototype.setToken=function(a){this.set("token",a)};Usergrid.Client.prototype.getToken=function(){return this.get("token")};Usergrid.Client.prototype.setObject=function(a,b){if(b){b=JSON.stringify(b)}this.set(a,b)};Usergrid.Client.prototype.set=function(b,c){var a="apigee_"+b;this[b]=c;if(typeof(Storage)!=="undefined")
 {if(c){localStorage.setItem(a,c)}else{localStorage.removeItem(a)}}};Usergrid.Client.prototype.getObject=function(a){return JSON.parse(this.get(a))};Usergrid.Client.prototype.get=function(b){var a="apigee_"+b;if(this[b]){return this[b]}else{if(typeof(Storage)!=="undefined"){return localStorage.getItem(a)}}return null};Usergrid.Client.prototype.signup=function(g,e,d,c,f){var a=this;var b={type:"users",username:g,password:e,email:d,name:c};this.createEntity(b,f)};Usergrid.Client.prototype.login=function(e,c,d){var a=this;var b={method:"POST",endpoint:"token",body:{username:e,password:c,grant_type:"password"}};this.request(b,function(h,j){var f={};if(h&&a.logging){console.log("error trying to log user in")}else{var g={client:a,data:j.user};f=new Usergrid.Entity(g);a.setToken(j.access_token)}if(typeof(d)==="function"){d(h,j,f)}})};Usergrid.Client.prototype.reAuthenticateLite=function(c){var a=this;var b={method:"GET",endpoint:"management/me",mQuery:true};this.request(b,function(e,d){if(e
 &&a.logging){console.log("error trying to re-authenticate user")}else{a.setToken(d.access_token)}if(typeof(c)==="function"){c(e)}})};Usergrid.Client.prototype.reAuthenticate=function(c,d){var a=this;var b={method:"GET",endpoint:"management/users/"+c,mQuery:true};this.request(b,function(k,l){var f={};var j={};var m={};if(k&&a.logging){console.log("error trying to full authenticate user")}else{var n=l.data;a.setToken(n.token);a.set("email",n.email);localStorage.setItem("accessToken",n.token);localStorage.setItem("userUUID",n.uuid);localStorage.setItem("userEmail",n.email);var g={username:n.username,email:n.email,name:n.name,uuid:n.uuid};var q={client:a,data:g};m=new Usergrid.Entity(q);f=n.organizations;var p="";try{var h=a.get("orgName");p=(f[h])?f[h]:f[Object.keys(f)[0]];a.set("orgName",p.name)}catch(o){k=true;if(a.logging){console.log("error selecting org")}}j=a.parseApplicationsArray(p);a.selectFirstApp(j);a.setObject("organizations",f);a.setObject("applications",j)}if(typeof(d)===
 "function"){d(k,n,m,f,j)}})};Usergrid.Client.prototype.loginFacebook=function(a,d){var b=this;var c={method:"GET",endpoint:"auth/facebook",qs:{fb_access_token:a}};this.request(c,function(g,h){var e={};if(g&&b.logging){console.log("error trying to log user in")}else{var f={client:b,data:h.user};e=new Usergrid.Entity(f);b.setToken(h.access_token)}if(typeof(d)==="function"){d(g,h,e)}})};Usergrid.Client.prototype.getLoggedInUser=function(c){if(!this.getToken()){c(true,null,null)}else{var a=this;var b={method:"GET",endpoint:"users/me"};this.request(b,function(f,g){if(f){if(a.logging){console.log("error trying to log user in")}if(typeof(c)==="function"){c(f,g,null)}}else{var e={client:a,data:g.entities[0]};var d=new Usergrid.Entity(e);if(typeof(c)==="function"){c(f,g,d)}}})}};Usergrid.Client.prototype.isLoggedIn=function(){if(this.getToken()){return true}return false};Usergrid.Client.prototype.logout=function(){this.setToken(null)};Usergrid.Client.prototype.buildCurlCall=function(c){var b
 ="curl";var e=(c.method||"GET").toUpperCase();var a=c.body||{};var d=c.uri;if(e==="POST"){b+=" -X POST"}else{if(e==="PUT"){b+=" -X PUT"}else{if(e==="DELETE"){b+=" -X DELETE"}else{b+=" -X GET"}}}b+=" "+d;if(a!=='"{}"'&&e!=="GET"&&e!=="DELETE"){b+=" -d '"+a+"'"}console.log(b);return b};Usergrid.Client.prototype.getDisplayImage=function(a,c,b){try{if(c){return c}var b=b||50;if(a.length){return"https://secure.gravatar.com/avatar/"+MD5(a)+"?s="+b+encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png")}else{return"https://apigee.com/usergrid/images/user_profile.png"}}catch(d){return"https://apigee.com/usergrid/images/user_profile.png"}};Usergrid.Entity=function(a){if(a){this._data=a.data||{};this._client=a.client||{}}};Usergrid.Entity.prototype.serialize=function(){return JSON.stringify(this._data)};Usergrid.Entity.prototype.get=function(a){if(a){return this._data[a]}else{return this._data}};Usergrid.Entity.prototype.set=function(a,b){if(typeof a==="object"){for(var c in a){th
 is._data[c]=a[c]}}else{if(typeof a==="string"){if(b===null){delete this._data[a]}else{this._data[a]=b}}else{this._data={}}}};Usergrid.Entity.prototype.save=function(h){var c=this.get("type");var g="POST";if(isUUID(this.get("uuid"))){g="PUT";c+="/"+this.get("uuid")}var a=this;var e={};var f=this.get();for(var d in f){if(d==="metadata"||d==="created"||d==="modified"||d==="type"||d==="activated"||d==="uuid"){continue}e[d]=f[d]}var b={method:g,endpoint:c,body:e};this._client.request(b,function(n,k){if(n&&a._client.logging){console.log("could not save entity");if(typeof(h)==="function"){return h(n,k,a)}}else{if(k.entities){if(k.entities.length){var j=k.entities[0];a.set(j);var p=k.path;while(p.substring(0,1)==="/"){p=p.substring(1)}a.set("type",p)}}var o=((a.get("type")==="user"||a.get("type")==="users")&&f.oldpassword&&f.newpassword);if(o){var m={};m.oldpassword=f.oldpassword;m.newpassword=f.newpassword;var l={method:"PUT",endpoint:c+"/password",body:m};a._client.request(l,function(q,r)
 {if(q&&a._client.logging){console.log("could not update user")}a.set("oldpassword",null);a.set("newpassword",null);if(typeof(h)==="function"){h(q,r,a)}})}else{if(typeof(h)==="function"){h(n,k,a)}}}})};Usergrid.Entity.prototype.fetch=function(e){var d=this.get("type");var a=this;if(this.get("uuid")){d+="/"+this.get("uuid")}else{if(d==="users"){if(this.get("username")){d+="/"+this.get("username")}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}else{if(d==="a path"){if(this.get("path")){d+="/"+encodeURIComponent(this.get("name"))}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}else{if(this.get("name")){d+="/"+encodeURIComponent(this.get("name"))}else{if(typeof(e)==="function"){var c="no_name_specified";if(a._client.logging){console.log(c)}return e(true,{error:c},a)}}}}}var b={method:"GET",endpoint:d};this._client.request(b,function(g,h)
 {if(g&&a._client.logging){console.log("could not get entity")}else{if(h.user){a.set(h.user);a._json=JSON.stringify(h.user,null,2)}else{if(h.entities){if(h.entities.length){var f=h.entities[0];a.set(f)}}}}if(typeof(e)==="function"){e(g,h,a)}})};Usergrid.Entity.prototype.destroy=function(e){var d=this.get("type");if(isUUID(this.get("uuid"))){d+="/"+this.get("uuid")}else{if(typeof(e)==="function"){var c="Error trying to delete object - no uuid specified.";if(a._client.logging){console.log(c)}e(true,c)}}var a=this;var b={method:"DELETE",endpoint:d};this._client.request(b,function(f,g){if(f&&a._client.logging){console.log("entity could not be deleted")}else{a.set(null)}if(typeof(e)==="function"){e(f,g)}})};Usergrid.Entity.prototype.connect=function(a,d,h){var k=this;var f=d.get("type");var c=this.getEntityId(d);if(!c){if(typeof(h)==="function"){var g="Error trying to delete object - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var e=this.get("type");var b=thi
 s.getEntityId(this);if(!b){if(typeof(h)==="function"){var g="Error in connect - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var j=e+"/"+b+"/"+a+"/"+f+"/"+c;var l={method:"POST",endpoint:j};this._client.request(l,function(m,n){if(m&&k._client.logging){console.log("entity could not be connected")}if(typeof(h)==="function"){h(m,n)}})};Usergrid.Entity.prototype.getEntityId=function(a){var b=false;if(isUUID(a.get("uuid"))){b=a.get("uuid")}else{if(type==="users"){b=a.get("username")}else{if(a.get("name")){b=a.get("name")}}}return b};Usergrid.Entity.prototype.getConnections=function(d,h){var c=this;var b=this.get("type");var a=this.getEntityId(this);if(!a){if(typeof(h)==="function"){var f="Error in getConnections - no uuid specified.";if(c._client.logging){console.log(f)}h(true,f)}return}var g=b+"/"+a+"/"+d+"/";var e={method:"GET",endpoint:g};this._client.request(e,function(l,m){if(l&&c._client.logging){console.log("entity could not be connected")}c[d]={};var 
 k=m.entities.length;for(var j=0;j<k;j++){if(m.entities[j].type==="user"){c[d][m.entities[j].username]=m.entities[j]}else{c[d][m.entities[j].name]=m.entities[j]}}if(typeof(h)==="function"){h(l,m,m.entities)}})};Usergrid.Entity.prototype.getGroups=function(d){var a=this;var c="users/"+this.get("uuid")+"/groups";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("entity could not be connected")}a.groups=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getActivities=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/activities";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("entity could not be connected")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString()}a.activities=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getFollow
 ing=function(d){var a=this;var c="users/"+this.get("uuid")+"/following";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user following")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString();var g=a._client.getDisplayImage(f.entities[entity].email,f.entities[entity].picture);f.entities[entity]._portal_image_icon=g}a.following=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getFollowers=function(d){var a=this;var c="users/"+this.get("uuid")+"/followers";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user followers")}for(entity in f.entities){f.entities[entity].createdDate=(new Date(f.entities[entity].created)).toUTCString();var g=a._client.getDisplayImage(f.entities[entity].email,f.entities[entity].picture);f.entities[entity]._portal_image_icon=g}
 a.followers=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getRoles=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/roles";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a._client.logging){console.log("could not get user roles")}a.roles=f.entities;if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Entity.prototype.getPermissions=function(d){var a=this;var c=this.get("type")+"/"+this.get("uuid")+"/permissions";var b={method:"GET",endpoint:c};this._client.request(b,function(g,m){if(g&&a._client.logging){console.log("could not get user permissions")}var p=[];if(m.data){var r=m.data;var o=0;for(var n in r){o++;var h=r[n];var l=h.split(":");var s="";var q=l[0];if(l.length>1){s=l[0];q=l[1]}s.replace("*","get,post,put,delete");var e=s.split(",");var f={};f.get="no";f.post="no";f.put="no";f["delete"]="no";for(var k in e){f[e[k]]="yes"}p.push({operations:f,path:q,perm:h})}}a.permissions=p;if(typeof
 (d)==="function"){d(g,m,m.entities)}})};Usergrid.Entity.prototype.disconnect=function(a,d,h){var k=this;var f=d.get("type");var c=this.getEntityId(d);if(!c){if(typeof(h)==="function"){var g="Error trying to delete object - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var e=this.get("type");var b=this.getEntityId(this);if(!b){if(typeof(h)==="function"){var g="Error in connect - no uuid specified.";if(k._client.logging){console.log(g)}h(true,g)}return}var j=e+"/"+b+"/"+a+"/"+f+"/"+c;var l={method:"DELETE",endpoint:j};this._client.request(l,function(m,n){if(m&&k._client.logging){console.log("entity could not be disconnected")}if(typeof(h)==="function"){h(m,n)}})};Usergrid.Collection=function(b,e){if(b){this._client=b.client;this._type=b.type;this.qs=b.qs||{};this._list=b.list||[];this._iterator=b.iterator||-1;this._previous=b.previous||[];this._next=b.next||null;this._cursor=b.cursor||null;if(b.list){var d=b.list.length;for(var c=0;c<d;c++){var a=this._clie
 nt.restoreEntity(b.list[c]);this._list[c]=a}}}if(e){this.fetch(e)}};Usergrid.Collection.prototype.serialize=function(){var c={};c.type=this._type;c.qs=this.qs;c.iterator=this._iterator;c.previous=this._previous;c.next=this._next;c.cursor=this._cursor;this.resetEntityPointer();var b=0;c.list=[];while(this.hasNextEntity()){var a=this.getNextEntity();c.list[b]=a.serialize();b++}c=JSON.stringify(c);return c};Usergrid.Collection.prototype.addCollection=function(b,a,d){self=this;a.client=this._client;var c=new Usergrid.Collection(a,function(g,h){if(typeof(d)==="function"){c.resetEntityPointer();while(c.hasNextEntity()){var e=c.getNextEntity();var f=e.get("email");var j=self._client.getDisplayImage(e.get("email"),e.get("picture"));e._portal_image_icon=j}self[b]=c;d(g,c)}})};Usergrid.Collection.prototype.fetch=function(d){var b=this;var a=this.qs;if(this._cursor){a.cursor=this._cursor}else{delete a.cursor}var c={method:"GET",endpoint:this._type,qs:this.qs};this._client.request(c,function(g,
 h){if(g&&b._client.logging){console.log("error getting collection")}else{var o=h.cursor||null;b.saveCursor(o);if(h.entities){b.resetEntityPointer();var l=h.entities.length;b._list=[];for(var j=0;j<l;j++){var e=h.entities[j].uuid;if(e){var f=h.entities[j]||{};b._baseType=h.entities[j].type;f.type=b._type;var n={type:b._type,client:b._client,uuid:e,data:f};var m=new Usergrid.Entity(n);m._json=JSON.stringify(f,null,2);var k=b._list.length;b._list[k]=m}}}}if(typeof(d)==="function"){d(g,h)}})};Usergrid.Collection.prototype.addEntity=function(b,c){var a=this;b.type=this._type;this._client.createEntity(b,function(f,d){if(!f){var e=a._list.length;a._list[e]=d}if(typeof(c)==="function"){c(f,d)}})};Usergrid.Collection.prototype.addExistingEntity=function(a){var b=this._list.length;this._list[b]=a};Usergrid.Collection.prototype.destroyEntity=function(b,c){var a=this;b.destroy(function(d,e){if(d){if(a._client.logging){console.log("could not destroy entity")}if(typeof(c)==="function"){c(d,e)}}el
 se{a.fetch(c)}});this.removeEntity(b)};Usergrid.Collection.prototype.removeEntity=function(a){var b=a.get("uuid");for(key in this._list){var c=this._list[key];if(c.get("uuid")===b){return this._list.splice(key,1)}}return false};Usergrid.Collection.prototype.getEntityByUUID=function(c,e){for(key in this._list){var d=this._list[key];if(d.get("uuid")===c){return d}}var b={data:{type:this._type,uuid:c},client:this._client};var a=new Usergrid.Entity(b);a.fetch(e)};Usergrid.Collection.prototype.getFirstEntity=function(){var a=this._list.length;if(a>0){return this._list[0]}return null};Usergrid.Collection.prototype.getLastEntity=function(){var a=this._list.length;if(a>0){return this._list[a-1]}return null};Usergrid.Collection.prototype.hasNextEntity=function(){var a=this._iterator+1;var b=(a>=0&&a<this._list.length);if(b){return true}return false};Usergrid.Collection.prototype.getNextEntity=function(){this._iterator++;var a=(this._iterator>=0&&this._iterator<=this._list.length);if(a){retur
 n this._list[this._iterator]}return false};Usergrid.Collection.prototype.hasPrevEntity=function(){var b=this._iterator-1;var a=(b>=0&&b<this._list.length);if(a){return true}return false};Usergrid.Collection.prototype.getPrevEntity=function(){this._iterator--;var a=(this._iterator>=0&&this._iterator<=this._list.length);if(a){return this.list[this._iterator]}return false};Usergrid.Collection.prototype.resetEntityPointer=function(){this._iterator=-1};Usergrid.Collection.prototype.saveCursor=function(a){if(this._next!==a){this._next=a}};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(a){if(this.hasNextPage()){this._previous.push(this._cursor);this._cursor=this._next;this._list=[];this.fetch(a)}};Usergrid.Collection.prototype.hasPreviousPage=function(){return(this._previous.length>0)};Usergrid.Collection.prot
 otype.getPreviousPage=function(a){if(this.hasPreviousPage()){this._next=null;this._cursor=this._previous.pop();this._list=[];this.fetch(a)}};Usergrid.Group=function(a,b){this._path=a.path;this._list=[];this._client=a.client;this._data=a.data||{};this._data.type="groups"};Usergrid.Group.prototype=new Usergrid.Entity();Usergrid.Group.prototype.fetch=function(f){var a=this;var e="groups/"+this._path;var d="groups/"+this._path+"/users";var b={method:"GET",endpoint:e};var c={method:"GET",endpoint:d};this._client.request(b,function(h,j){if(h){if(a._client.logging){console.log("error getting group")}if(typeof(f)==="function"){f(h,j)}}else{if(j.entities){var g=j.entities[0];a._data=g||{};a._client.request(c,function(p,q){if(p&&a._client.logging){console.log("error getting group users")}else{if(q.entities){var o=q.entities.length;a._list=[];for(var l=0;l<o;l++){var n=q.entities[l].uuid;if(n){var r=q.entities[l]||{};var m={type:r.type,client:a._client,uuid:n,data:r};var k=new Usergrid.Entity(
 m);a._list.push(k)}}}}if(typeof(f)==="function"){f(p,q,a._list)}})}}})};Usergrid.Group.prototype.members=function(a){if(typeof(a)==="function"){a(null,this._list)}};Usergrid.Group.prototype.add=function(b,c){var a=this;var b={method:"POST",endpoint:"groups/"+this._path+"/users/"+b.user.get("username")};this._client.request(b,function(d,e){if(d){if(typeof(c)==="function"){c(d,e,e.entities)}}else{a.fetch(c)}})};Usergrid.Group.prototype.remove=function(b,c){var a=this;var b={method:"DELETE",endpoint:"groups/"+this._path+"/users/"+b.user.get("username")};this._client.request(b,function(d,e){if(d){if(typeof(c)==="function"){c(d,e)}}else{a.fetch(c)}})};Usergrid.Group.prototype.feed=function(d){var a=this;var c="groups/"+this._path+"/feed";var b={method:"GET",endpoint:c};this._client.request(b,function(e,f){if(e&&a.logging){console.log("error trying to log user in")}if(typeof(d)==="function"){d(e,f,f.entities)}})};Usergrid.Group.prototype.createGroupActivity=function(c,d){var b=c.user;var 
 c={actor:{displayName:b.get("username"),uuid:b.get("uuid"),username:b.get("username"),email:b.get("email"),picture:b.get("picture"),image:{duration:0,height:80,url:b.get("picture"),width:80},},verb:"post",content:c.content};c.type="groups/"+this._path+"/activities";var c={client:this._client,data:c};var a=new Usergrid.Entity(c);a.save(function(e,f){if(typeof(d)==="function"){d(e,a)}})};function isUUID(a){var b=/^[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}$/;if(!a){return false}return b.test(a)}function encodeParams(d){tail=[];var b=[];if(d instanceof Array){for(i in d){b=d[i];if((b instanceof Array)&&(b.length>1)){tail.push(b[0]+"="+encodeURIComponent(b[1]))}}}else{for(var a in d){if(d.hasOwnProperty(a)){var c=d[a];if(c instanceof Array){for(i in c){b=c[i];tail.push(a+"="+encodeURIComponent(b))}}else{tail.push(a+"="+encodeURIComponent(c))}}}}return tail.join("&")};
\ No newline at end of file
+/*! usergrid@0.0.0 2014-01-16 */
+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 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")),xh
 r.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_invalid"
 ==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;options
 ={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 options
 ={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.entit
 ies))})},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.Clie
 nt.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",dat
 a.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,data){v
 ar 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").toUpperCase()
 ,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.Entit
 y.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 callback)
 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("uuid");
 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={method:"
 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("entit
 y 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){va
 r 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)})},User
 grid.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(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,"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=data.da
 ta,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 callba
 ck&&(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,data.i
 terator=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(options,
 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=function(en
 tity){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.Collecti
 on.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!==curs
 or&&(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",groupOpti
 ons={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(opt
 ions,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: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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})};var COUNTER_RESOLUTIONS={ALL:"all",MINUTE:"minute",FIVE_MINUTES:"five_minutes",HALF_HOUR:"half_hour",HOUR:"hour",SIX_DAY:"six_day",DAY:"day",WEEK:"week",MONTH:"month"};COUNTER_RESOLUTIONS.valueOf=function(str){return Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){return COUNTER_RESOLUTIONS[res]===str?COUNTER_RESOLUTIONS[res]:void 0}),COUNTER_RESOLUTIONS.ALL},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._dat
 a.type="events",this._data.counters=options.counters||{},"function"==typeof callback&&callback.call(self,!1,self)},Usergrid.Event.prototype=new Usergrid.Entity,Usergrid.Event.prototype.fetch=function(callback){this.getData(null,null,null,null,callback)},Usergrid.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),self.save(callback))},Usergrid.Event.prototype.decrement=function(name,value,callback){this.increment(name,-value,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=COUNTER_RESOLUTIONS.valueOf(resolution);if(start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(sta
 rt)?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


[05/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css b/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
new file mode 100755
index 0000000..e87551e
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
@@ -0,0 +1,18 @@
+/*!
+ * Bootstrap v2.0.4
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box
 -sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bott
 om .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.127659574%;*margin-left:2.0744680846382977%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.
 row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%}.row-fluid .span11{width:91.489361693%;*width:91.4361702036383%}.row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%}.row-fluid .span9{width:74.468085099%;*width:74.4148936096383%}.row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%}.row-fluid .span7{width:57.446808505%;*width:57.3936170156383%}.row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%}.row-fluid .span5{width:40.425531911%;*width:40.3723404216383%}.row-fluid .span4{width:31.914893614%;*width:31.8617021246383%}.row-fluid .span3{width:23.404255317%;*width:23.3510638276383%}.row-fluid .span2{width:14.89361702%;*width:14.8404255306383%}.row-fluid .span1{width:6.382978723%;*width:6.329787233638298%}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-f
 luid:before,.container-fluid:after{display:table;content:""}.container-fluid:after{clear:both}p{margin:0 0 9px}p small{font-size:11px;color:#999}.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px}h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{font-size:18px;line-height:27px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eee}.page-header h1{line-height:1}ul,ol{padding:0;margin:0 0 9px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}ul{list-style:disc}ol{list-style:decimal}li{line-height:18px}ul.unstyled,ol.unstyled
 {margin-left:0;list-style:none}dl{margin-bottom:18px}dt,dd{line-height:18px}dt{font-weight:bold;line-height:17px}dd{margin-left:9px}.dl-horizontal dt{float:left;width:120px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:18px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}strong{font-weight:bold}em{font-style:italic}.muted{color:#999}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px}blockquote small{display:block;line-height:18px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}q:before,q:af
 ter,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:18px;font-style:normal;line-height:18px}small{font-size:100%}cite{font-style:normal}code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:18px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 18px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;
 margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:13.5px;color:#999}label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555}input,textarea{width:210px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],inpu
 t[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-ms-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,i
 nput[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer}input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}.uneditable-textarea{width:auto;height:auto}select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px}select{width:220px;border:1px solid #bbb}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2
 px}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-f
 luid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:930px}input.span11,textarea.span11,.uneditable-input.span11{width:850px}input.span10,textarea.span10,.uneditable-input.span10{width:770px}input.span9,textarea.span9,.uneditable-input.span9{width:690px}input.span8,textarea.span8,.uneditable-input.span8{width:610px}input.span7,textarea.span7,.uneditable-input.span7{width:530px}input.span6,textarea.span6,.uneditable-input.span6{width:450px}input.span5,textarea.span5,.uneditable-input.span5{width:370px}input.span4,textarea.span4,.uneditable-input.span4{width:290px}input.span3,textarea.span3,.uneditable-input.span3{width:210px}input.span2,textarea.span2,.uneditable-input.span2{width:130px}input.span1,textarea.span1,.uneditable-input.span1{width:50px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],tex
 tarea[readonly]{cursor:not-allowed;background-color:#eee;border-color:#ddd}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group
 .error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border
 -color:#468847}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display
 :table;content:""}.form-actions:after{clear:both}.uneditable-input{overflow:hidden;white-space:nowrap;cursor:not-allowed;background-color:#fff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}:-moz-placeholder{color:#999}:-ms-input-placeholder{color:#999}::-webkit-input-placeholder{color:#999}.help-block,.help-inline{color:#555}.help-block{display:block;margin-bottom:9px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-prepend,.input-append{margin-bottom:5px}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:middle;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend input:focus,.input-append input:focu
 s,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{z-index:2}.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc}.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;height:18px;min-width:16px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #fff;vertical-align:middle;background-color:#eee;border:1px solid #ccc}.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-a
 ppend select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .uneditable-input{border-right-color:#ccc;border-left-color:#eee}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.search-query{padding-right:14px;padding-right:4px 
 \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.fo
 rm-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:9px}legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:18px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:160px}.form-horizontal .help-block{margin-top:9px;margin-bottom:0}.form-horizontal .for
 m-actions{padding-left:160px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:18px}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered captio
 n+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-bor
 der-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;marg
 in-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-posi
 tion:14px 14px;background-repeat:no-repeat}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0}.icon-white{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-positio
 n:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{backgr
 ound-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust
 {background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign
 {background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-7
 2px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72p
 x -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;heig
 ht:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";opacity:.3;filter:alpha(opacity=30)}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown:hover .caret,.open .caret{opacity:1;filter:alpha(opacity=100)}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:4px 0;margin:1px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background
 -color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0,0,0,0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1p
 x 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-ms-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-ms-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40
 )}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 10px 4px;margin-bottom:0;*margin-left:.3em;font-size:13px;line-height:18px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border
 -radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#e6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-ms-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outlin
 e:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:1px}.btn-small{padding:5px 9px;font-size:11px;line-height:16px}.btn-small [class^="icon-"]{margin-top:-1px}.btn-mini{padding:2px 6px;font-size:11px;line-height:14px}.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:h
 over,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#ccc;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.btn-primary{background-color:#0074cc;*background-color:#05c;background-image:-ms-linear-gradient(top,#08c,#05c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#05c));background-image:-webkit-linear-gradient(top,#08c,#05c);background-image:-o-linear-gradient(top,#08c,#05c);background-image:-moz-linear-gradient(top,#08c,#05c);background-image:linear-gradient(top,#08c,#05c);background-repeat:repeat-x;border-color:#05c #05c #003580;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc',endCo
 lorstr='#0055cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#05c;*background-color:#004ab3}.btn-primary:active,.btn-primary.active{background-color:#004099 \9}.btn-warning{background-color:#faa732;*background-color:#f89406;background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0);filter:p
 rogid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{background-color:#da4f49;*background-color:#bd362f;background-image:-ms-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#bd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradie
 nt(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{background-color:#5bb75b;*background-color:#51a351;background-image:-ms-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-suc
 cess:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{background-color:#49afcd;*background-color:#2f96b4;background-image:-ms-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled
 ,.btn-info[disabled]{background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{background-color:#414141;*background-color:#222;background-image:-ms-linear-gradient(top,#555,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#555),to(#222));background-image:-webkit-linear-gradient(top,#555,#222);background-image:-o-linear-gradient(top,#555,#222);background-image:-moz-linear-gradient(top,#555,#222);background-image:linear-gradient(top,#555,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#555555',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222;*background-color:#151515}.btn-inverse:active,.bt
 n-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-group{position:relative;*margin-left:.3em;*zoom:1}.btn-group:before,.btn-group:after{display:table;content:""}.btn-group:after{clear:both}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:9px;margin-bottom:9px}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-group>.btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn:first-child{margin-left:0;-webkit-bord
 er-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.bt
 n-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.dropdown-toggle{*padding-top:4px;padding-right:8px;*padding-bottom:4px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini.dropdown-toggle{padding-right:5px;padding-left:5px}.btn-group>.btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px}.btn-group>.btn-large.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rg
 ba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#05c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:7px;margin-left:0}.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100)}.btn-mini .caret{margin-top:5px}.btn-small .caret{margin-top:6px}.btn-large .caret{margin-top:6px;border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success 
 .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:.75;filter:alpha(opacity=75)}.alert{padding:8px 35px 8px 14px;margin-bottom:18px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert-heading{color:inherit}.alert .close{position:relative;top:-2px;right:-21px;line-height:18px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:18px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav .nav-header{display:block;pa
 dding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14
 px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px
  0 0;border-radius:4px 4px 0 0}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px}.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333;border-bottom-color:#333}.nav>.dropdown.active>a:hover{color:#000;cursor:pointer}.nav-tabs .
 open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-c
 olor:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-ta
 bs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.navbar{*position:relative;*z-index:2;margin-bottom:18px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top,#333,#222);background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(
 0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar{color:#999}.navbar .brand:hover{text-decoration:none}.navbar .brand{display:block;float:left;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#999}.navbar .navbar-text{margin-bottom:0;line-height:40px}.navbar .navbar-link{color:#999}.navbar .navbar-link:hover{color:#fff}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6
 px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#fff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}.navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;
 color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{display:block;float:left}.navbar .nav>li>a{float:none;padding:9px 10px 11px;line-height:19px;color:#999;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar .btn{display:inline-block;padding:4px 10px 4px;margin:5px 5px 6px;line-height:18px}.navbar .btn-group{padding:5
 px 5px 6px;margin:0}.navbar .nav>li>a:hover{color:#fff;text-decoration:none;background-color:transparent}.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#fff;text-decoration:none;background-color:#222}.navbar .divider-vertical{width:1px;height:40px;margin:0 9px;overflow:hidden;background-color:#222;border-right:1px solid #333}.navbar .nav.pull-right{margin-right:0;margin-left:10px}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;background-color:#2c2c2c;*background-color:#222;background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-image:-moz-linear-gradient(top,#333,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:pro
 gid:dximagetransform.microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{background-color:#222;*background-color:#151515}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#080808 \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{
 margin-top:3px}.navbar .dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown .dropdown-toggle .caret,.navbar .nav li.dropdown.open .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .nav li.dropdown.active .caret{opacity:1;filter:alpha(opacity=100)}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navba
 r .nav li.dropdown.open.active>.dropdown-toggle{background-color:transparent}.navbar .nav li.dropdown.active>.dropdown-toggle:hover{color:#fff}.navbar .pull-right .dropdown-menu,.navbar .dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right .dropdown-menu:before,.navbar .dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right .dropdown-menu:after,.navbar .dropdown-menu.pull-right:after{right:13px;left:auto}.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top,#fff,#f5f5f5);background-image:-ms-linear-gradient(top,#fff,#f5f5f5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#fff,#f5f5f5);background-image:-o-linear-gradient(top,#fff,#f5f5f5);background-image:linear-gradient(top,#fff,#f5f5f5);background-repeat:repeat-x;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;filter:p
 rogid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#f5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#999}.breadcrumb .active a{color:#333}.pagination{height:36px;margin:18px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination li{display:inline}.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0}.pagination a:hover,.pagination .active a{background-color:#f5f5f5}.pagination .active a{color:#999;cursor:default}.pagination .disabled span,.pagination 
 .disabled a,.pagination .disabled a:hover{color:#999;cursor:default;background-color:transparent}.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin-bottom:18px;margin-left:0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover{color:#999;cursor:default;background-color:#fff}.modal-open
  .dropdown-menu{z-index:2050}.modal-open .dropdown.open{*z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2070}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-ms-transition:opacity .3s linear,top
  .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1020;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity
 :.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-2px}.tooltip.right{margin-left:2px}.tooltip.bottom{margin-top:2px}.tooltip.left{margin-left:-2px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:ab
 solute;width:0;height:0}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px}.popover.top{margin-top:-5px}.popover.right{margin-left:5px}.popover.bottom{margin-top:5px}.popover.left{margin-left:-5px}.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.popover .arrow{position:absolute;width:0;height:0}.popover-inner{width:280px;padding:3px;overflow:hidden;background:#000;background:rgba(0,0,0,0.8);-webkit-border-radius:
 6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3)}.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.popover-content{padding:14px;background-color:#fff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:18px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webk
 it-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:0 1px 1px rgba(0,0,0,0.075);box-shadow:0 1px 1px rgba(0,0,0,0.075)}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px}.label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important
 [href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-pos
 ition:0 0}}.progress{height:18px;margin-bottom:18px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-ms-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(top,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5',endColorstr='#f9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{width:0;height:18px;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#14
 9bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(top,#149bdf,#0480be);background-image:-ms-linear-gradient(top,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf',endColorstr='#0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-ms-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .bar{background-color:#149bdf;background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,tra
 nsparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:linear-gradient(-45deg,rgba(255,255,255,0.15
 ) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-ms-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(top,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximage
 transform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35',GradientType=0)}.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);ba
 ckground-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-ms-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(top,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#57a957',GradientType=0)}.progress-success.progress-striped .bar{background-color:#62c462;background-
 image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 
 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-ms-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(top,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#339bb9',GradientType=0)}.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255
 ,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,tr
 ansparent 75%,transparent)}.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0)}.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 2
 5%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:18px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;
 border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:18px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-ms-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;wi
 dth:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:10px 15px 5px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{color:#fff}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}
+/*!
+ * Bootstrap Responsive v2.0.4
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}@media(max-width:767px){.visible-phone{display:inherit!important}.hidden-phone{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(min-width:768px) and (max-width:979px){.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-h
 eader h1 small{display:block;line-height:18px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{position:absolute;top:10px;right:10px;left:10px;width:auto;margin:0}.modal.fade.in{top:auto}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.input-large,.input-xlarg
 e,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin
 -left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.762430939%;*margin-left:2.709239449638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:99.999999993%;*width:99.9468085036383%}.row-fluid .span11{width:91.436464082%;*width:91.38327259263829%}.row-fluid .span10{width:82.87292817100001%;*width:82.8197366816383%}.row-fluid .span9{width:74.30939226%;*width:74.25620077063829%}.row-fluid .span8{width:65.74585634900001%;*width:65.6926648596383%}.row-fluid .span7{width:57.18
 2320438000005%;*width:57.129128948638304%}.row-fluid .span6{width:48.618784527%;*width:48.5655930376383%}.row-fluid .span5{width:40.055248616%;*width:40.0020571266383%}.row-fluid .span4{width:31.491712705%;*width:31.4385212156383%}.row-fluid .span3{width:22.928176794%;*width:22.874985304638297%}.row-fluid .span2{width:14.364640883%;*width:14.311449393638298%}.row-fluid .span1{width:5.801104972%;*width:5.747913482638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:714px}input.span11,textarea.span11,.uneditable-input.span11{width:652px}input.span10,textarea.span10,.uneditable-input.span10{width:590px}input.span9,textarea.span9,.uneditable-input.span9{width:528px}input.span8,textarea.span8,.uneditable-input.span8{width:466px}input.span7,textarea.span7,.uneditable-input.span7{width:404px}input.span6,textarea.span6,.uneditable-input.span6{width:342px}input.span5,textarea.span5,.uneditable-input.span5{width:280px}input.span4,t
 extarea.span4,.uneditable-input.span4{width:218px}input.span3,textarea.span3,.uneditable-input.span3{width:156px}input.span2,textarea.span2,.uneditable-input.span2{width:94px}input.span1,textarea.span1,.uneditable-input.span1{width:32px}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.off

<TRUNCATED>

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

Posted by sn...@apache.org.
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


[21/27] git commit: Prettying up the tests

Posted by sn...@apache.org.
Prettying up the 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/dc31ba57
Tree: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/tree/dc31ba57
Diff: http://git-wip-us.apache.org/repos/asf/incubator-usergrid/diff/dc31ba57

Branch: refs/pull/34/head
Commit: dc31ba575ab6811ba9816d9afaef23c8f649b9af
Parents: 2953c67
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 13:26:12 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 13:26:12 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/tests/mocha/test.js | 37 +++++++-------------------
 1 file changed, 9 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/dc31ba57/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 24d6530..8034f06 100644
--- a/sdks/html5-javascript/tests/mocha/test.js
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -218,7 +218,7 @@ describe('Usergrid', function(){
 				});
 			})
 		});
-		it('should create a new dogs collection', function(done){
+		it('should CREATE a new dogs collection', function(done){
 			var options = {
 				type:'dogs',
 				qs:{ql:'order by index'}
@@ -230,33 +230,23 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should retrieve dogs from the collection', function(done){
+		it('should RETRIEVE dogs from the collection', function(done){
 			loop(done);
 		});
-		it('should retrieve the next page of dogs from the collection', function(done){
+		it('should RETRIEVE the next page of dogs from the collection', function(done){
 			if(dogs.hasNextPage()){
 				dogs.getNextPage(function(err){loop(done);});
 			}else{
 				done();
 			}
 		});
-		it('should retrieve the previous page of dogs from the collection', function(done){
+		it('should RETRIEVE the previous page of dogs from the collection', function(done){
 			if(dogs.hasPreviousPage()){
 				dogs.getPreviousPage(function(err){loop(done);});
 			}else{
 				done();
 			}
 		});
-		/*it('should retrieve the dog', function(done){
-			if(!dog){
-				assert(false, "dog not created");
-				done();
-			}
-			dog.fetch(function(err){
-				assert(!err, "dog not fetched");
-				done();
-			});
-		});*/
 	});
 	describe('Usergrid Events', function(){
 		var ev;
@@ -264,7 +254,7 @@ describe('Usergrid', function(){
 		var HOUR=MINUTE*60;
 		var time=Date.now()-HOUR;
 
-		it('should create an event', function(done){
+		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){
 				assert(!err, data.error_description);
 				console.log(data);
@@ -278,7 +268,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		/*it('should reset a counter', function(done){
+		it('should reset a counter', function(done){
 			time+=MINUTE*10
 			ev.set("timestamp", time);
 			ev.reset('test', function(err, data){
@@ -286,7 +276,7 @@ describe('Usergrid', function(){
 				console.log(data);
 				done();
 			});
-		});*/
+		});
 		it("should increment 'test' counter", function(done){
 			time+=MINUTE*10
 			ev.set("timestamp", time);
@@ -322,23 +312,14 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		/*it('should fetch counter data', function(done){
+		it('should fetch counter data', function(done){
 			ev.getData('all', null, null, ['test', 'test_counter'], function(err, data){
 				assert(!err, data.error_description);
 				console.log(data);
 				console.log(time, Date.now());
 				done();
 			});
-		});*/
-	});
-	/*describe('Usergrid Counters', function(){
-		it('should create a counter', function(done){
-			var counter = new Apigee.Event({client:client, data:{category:"mocha_test", timestamp:28, name:'test'}}, function(err, data){
-				assert(!err, data.error_description);
-				console.log(data);
-				done();
-			});
 		});
-	});*/
+	});
 });
 


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

Posted by sn...@apache.org.
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/head
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


[27/27] git commit: Merge 31d481a9fbfd1e4bb9ecae621731c7cf4dbea616 into 832017bf7b1c2e8b809b8254f2fd70eebab58d0f

Posted by sn...@apache.org.
Merge 31d481a9fbfd1e4bb9ecae621731c7cf4dbea616 into 832017bf7b1c2e8b809b8254f2fd70eebab58d0f


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

Branch: refs/pull/34/merge
Commit: cc175edb0b928b28e32a5564e113e0b70c451c72
Parents: 832017b 31d481a
Author: ryan bridges <rb...@apigee.com>
Authored: Mon Jan 27 14:13:37 2014 -0800
Committer: ryan bridges <rb...@apigee.com>
Committed: Mon Jan 27 14:13:37 2014 -0800

----------------------------------------------------------------------
 sdks/html5-javascript/Gruntfile.js              |   83 +
 sdks/html5-javascript/lib/Client.js             |  865 +++
 sdks/html5-javascript/lib/Collection.js         |  446 ++
 sdks/html5-javascript/lib/Counter.js            |  186 +
 sdks/html5-javascript/lib/Entity.js             |  646 +++
 sdks/html5-javascript/lib/Group.js              |  233 +
 sdks/html5-javascript/lib/Usergrid.js           |   87 +
 sdks/html5-javascript/package.json              |   22 +
 sdks/html5-javascript/tests/mocha/index.html    |   49 +
 sdks/html5-javascript/tests/mocha/test.js       |  325 ++
 .../tests/qunit/apigee_test.html                |   14 +
 sdks/html5-javascript/tests/qunit/tests.js      |    3 +
 .../resources/css/bootstrap-combined.min.css    |   18 +
 .../tests/resources/css/mocha.css               |  270 +
 .../tests/resources/css/styles.css              |   91 +
 .../tests/resources/images/apigee.png           |  Bin 0 -> 6010 bytes
 .../tests/resources/js/blanket_mocha.min.js     |    1 +
 .../tests/resources/js/json2.js                 |  486 ++
 .../tests/resources/js/mocha.js                 | 5341 ++++++++++++++++++
 sdks/html5-javascript/tests/test.html           |   37 +
 sdks/html5-javascript/tests/test.js             |  910 +++
 sdks/html5-javascript/usergrid.js               | 3078 +++++-----
 sdks/html5-javascript/usergrid.min.js           |    3 +-
 23 files changed, 11691 insertions(+), 1503 deletions(-)
----------------------------------------------------------------------



[20/27] git commit: fixed issue with counter resolutions. Fixed global scope leak in client.

Posted by sn...@apache.org.
fixed issue with counter resolutions. Fixed global scope leak in client.


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

Branch: refs/pull/34/merge
Commit: 2953c67dd5f40adf1568c543fa40cc6406dc11ea
Parents: 8367ea4
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 13:21:39 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 13:21:39 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/lib/Client.js       |  1 +
 sdks/html5-javascript/lib/Event.js        | 34 ++++++++-----------------
 sdks/html5-javascript/tests/mocha/test.js | 24 ++++++++----------
 sdks/html5-javascript/usergrid.js         | 35 ++++++++------------------
 sdks/html5-javascript/usergrid.min.js     |  4 +--
 5 files changed, 33 insertions(+), 65 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/lib/Client.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Client.js b/sdks/html5-javascript/lib/Client.js
index 3fc4338..c6fb550 100644
--- a/sdks/html5-javascript/lib/Client.js
+++ b/sdks/html5-javascript/lib/Client.js
@@ -46,6 +46,7 @@ Usergrid.Client.prototype.request = function (options, callback) {
   var mQuery = options.mQuery || false; //is this a query to the management endpoint?
   var orgName = this.get('orgName');
   var appName = this.get('appName');
+  var uri;
   if(!mQuery && !orgName && !appName){
     if (typeof(this.logoutCallback) === 'function') {
       return this.logoutCallback(true, 'no_org_or_app_name_specified');

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/lib/Event.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/lib/Event.js b/sdks/html5-javascript/lib/Event.js
index 789240f..c39ec94 100644
--- a/sdks/html5-javascript/lib/Event.js
+++ b/sdks/html5-javascript/lib/Event.js
@@ -1,23 +1,3 @@
-var COUNTER_RESOLUTIONS = {
-  'ALL': 'all',
-  'MINUTE': 'minute',
-  'FIVE_MINUTES': 'five_minutes',
-  'HALF_HOUR': 'half_hour',
-  'HOUR': 'hour',
-  'SIX_DAY': 'six_day',
-  'DAY': 'day',
-  'WEEK': 'week',
-  'MONTH': 'month'
-};
-COUNTER_RESOLUTIONS.valueOf=function(str){
-  Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){
-    if(COUNTER_RESOLUTIONS[res]===str){
-      return COUNTER_RESOLUTIONS[res];
-    }
-  });
-  return COUNTER_RESOLUTIONS.ALL;
-};
-
 /*
  *  A class to model a Usergrid event.
  *
@@ -38,7 +18,10 @@ Usergrid.Event = function(options, callback) {
   }
   //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.
@@ -67,7 +50,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
       return callback.call(self, true, "'value' for increment, decrement must be a number");
     }
   }
-  self._data.counters[name]=parseInt(value);
+  self._data.counters[name]=(parseInt(value))||1;
   return self.save(callback);
 };
 /*
@@ -83,7 +66,7 @@ Usergrid.Event.prototype.increment=function(name, value, callback){
  */
 
 Usergrid.Event.prototype.decrement=function(name, value, callback){
-  this.increment(name, -(value), callback);
+  this.increment(name, -((parseInt(value))||1), callback);
 };
 /*
  * resets the counter for a specific event
@@ -104,7 +87,10 @@ Usergrid.Event.prototype.reset=function(name, callback){
 Usergrid.Event.prototype.getData=function(start, end, resolution, counters, callback){
   var start_time, 
       end_time,
-      res=COUNTER_RESOLUTIONS.valueOf(resolution);
+      res=(resolution||'all').toLowerCase();
+  if(COUNTER_RESOLUTIONS.indexOf(res)===-1){
+    res='all';
+  }
   if(start){
     switch(typeof start){
       case "undefined":

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/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 d74541c..24d6530 100644
--- a/sdks/html5-javascript/tests/mocha/test.js
+++ b/sdks/html5-javascript/tests/mocha/test.js
@@ -44,28 +44,28 @@ describe('Usergrid', function(){
 			method:'GET',
 			endpoint:'users'
 		};
-		it('should Create a new user', function(done){
+		it('should CREATE a new user', function(done){
 			client.request({method:'POST',endpoint:'users', body:{ username:'fred', password:'secret' }}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Retrieve an existing user', function(done){
+		it('should RETRIEVE an existing user', function(done){
 			client.request({method:'GET',endpoint:'users/fred', body:{}}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Update an existing user', function(done){
+		it('should UPDATE an existing user', function(done){
 			client.request({method:'PUT',endpoint:'users/fred', body:{ newkey:'newvalue' }}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
 				]);
 		    });
 		});
-		it('should Delete the user from the database', function(done){
+		it('should DELETE the user from the database', function(done){
 			client.request({method:'DELETE',endpoint:'users/fred'}, function (err, data) {
 				usergridTestHarness(err, data, done, [
 					function(err, data){assert(true)}
@@ -98,7 +98,7 @@ describe('Usergrid', function(){
 	    		done();
 		    });
 	  	});
-		it('should create a new dog', function(done){
+		it('should CREATE a new dog', function(done){
 			var options = {
 				type:'dogs',
 				name:'Rocky'
@@ -110,7 +110,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should retrieve the dog', function(done){
+		it('should RETRIEVE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -122,7 +122,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should update the dog', function(done){
+		it('should UPDATE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -145,7 +145,7 @@ describe('Usergrid', function(){
 				done();
 			});
 		});
-		it('should remove the dog', function(done){
+		it('should DELETE the dog', function(done){
 			if(!dog){
 				assert(false, "dog not created");
 				done();
@@ -263,6 +263,7 @@ describe('Usergrid', function(){
 		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){
 				assert(!err, data.error_description);
@@ -312,7 +313,7 @@ describe('Usergrid', function(){
 				console.log(JSON.stringify(data,null,4));
 				done();
 			});
-		});
+		});	
 		it('should fetch event', function(done){
 			ev.fetch(function(err, data){
 				assert(!err, data.error_description);
@@ -339,10 +340,5 @@ describe('Usergrid', function(){
 			});
 		});
 	});*/
-	describe('Usergrid extra', function(){
-		it('should not be phonegap', function(done){
-			
-		});
-	});
 });
 

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
index 96dbbe8..9fc9482 100644
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,4 +1,4 @@
-/*! usergrid@0.0.0 2014-01-16 */
+/*! usergrid@0.0.0 2014-01-21 */
 /*
  *  This module is a collection of classes designed to make working with
  *  the Appigee App Services API as easy as possible.
@@ -133,6 +133,7 @@ Usergrid.Client.prototype.request = function(options, callback) {
     //is this a query to the management endpoint?
     var orgName = this.get("orgName");
     var appName = this.get("appName");
+    var uri;
     if (!mQuery && !orgName && !appName) {
         if (typeof this.logoutCallback === "function") {
             return this.logoutCallback(true, "no_org_or_app_name_specified");
@@ -2161,27 +2162,6 @@ Usergrid.Group.prototype.createGroupActivity = function(options, callback) {
     });
 };
 
-var COUNTER_RESOLUTIONS = {
-    ALL: "all",
-    MINUTE: "minute",
-    FIVE_MINUTES: "five_minutes",
-    HALF_HOUR: "half_hour",
-    HOUR: "hour",
-    SIX_DAY: "six_day",
-    DAY: "day",
-    WEEK: "week",
-    MONTH: "month"
-};
-
-COUNTER_RESOLUTIONS.valueOf = function(str) {
-    Object.keys(COUNTER_RESOLUTIONS).forEach(function(res) {
-        if (COUNTER_RESOLUTIONS[res] === str) {
-            return COUNTER_RESOLUTIONS[res];
-        }
-    });
-    return COUNTER_RESOLUTIONS.ALL;
-};
-
 /*
  *  A class to model a Usergrid event.
  *
@@ -2202,6 +2182,8 @@ Usergrid.Event = function(options, 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.
@@ -2231,7 +2213,7 @@ Usergrid.Event.prototype.increment = function(name, value, callback) {
             return callback.call(self, true, "'value' for increment, decrement must be a number");
         }
     }
-    self._data.counters[name] = parseInt(value);
+    self._data.counters[name] = parseInt(value) || 1;
     return self.save(callback);
 };
 
@@ -2247,7 +2229,7 @@ Usergrid.Event.prototype.increment = function(name, value, callback) {
  * @returns {callback} callback(err, event)
  */
 Usergrid.Event.prototype.decrement = function(name, value, callback) {
-    this.increment(name, -value, callback);
+    this.increment(name, -(parseInt(value) || 1), callback);
 };
 
 /*
@@ -2266,7 +2248,10 @@ Usergrid.Event.prototype.reset = function(name, callback) {
 };
 
 Usergrid.Event.prototype.getData = function(start, end, resolution, counters, callback) {
-    var start_time, end_time, res = COUNTER_RESOLUTIONS.valueOf(resolution);
+    var start_time, end_time, res = (resolution || "all").toLowerCase();
+    if (COUNTER_RESOLUTIONS.indexOf(res) === -1) {
+        res = "all";
+    }
     if (start) {
         switch (typeof start) {
           case "undefined":

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/2953c67d/sdks/html5-javascript/usergrid.min.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.min.js b/sdks/html5-javascript/usergrid.min.js
index c701528..4d37d2d 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-16 */
-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 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")),xh
 r.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_invalid"
 ==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;options
 ={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 options
 ={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.entit
 ies))})},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.Clie
 nt.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",dat
 a.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,data){v
 ar 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").toUpperCase()
 ,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.Entit
 y.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 callback)
 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("uuid");
 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={method:"
 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("entit
 y 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){va
 r 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)})},User
 grid.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(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,"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=data.da
 ta,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 callba
 ck&&(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,data.i
 terator=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(options,
 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=function(en
 tity){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.Collecti
 on.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!==curs
 or&&(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",groupOpti
 ons={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(opt
 ions,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: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"}};var entity=new Usergrid.Entity(options);entity.save(function(err){"function"==typeof callback&&callback(err,entity)})};var COUNTER_RESOLUTIONS={ALL:"all",MINUTE:"minute",FIVE_MINUTES:"five_minutes",HALF_HOUR:"half_hour",HOUR:"hour",SIX_DAY:"six_day",DAY:"day",WEEK:"week",MONTH:"month"};COUNTER_RESOLUTIONS.valueOf=function(str){return Object.keys(COUNTER_RESOLUTIONS).forEach(function(res){return COUNTER_RESOLUTIONS[res]===str?COUNTER_RESOLUTIONS[res]:void 0}),COUNTER_RESOLUTIONS.ALL},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._dat
 a.type="events",this._data.counters=options.counters||{},"function"==typeof callback&&callback.call(self,!1,self)},Usergrid.Event.prototype=new Usergrid.Entity,Usergrid.Event.prototype.fetch=function(callback){this.getData(null,null,null,null,callback)},Usergrid.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),self.save(callback))},Usergrid.Event.prototype.decrement=function(name,value,callback){this.increment(name,-value,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=COUNTER_RESOLUTIONS.valueOf(resolution);if(start)switch(typeof start){case"undefined":start_time=0;break;case"number":start_time=start;break;case"string":start_time=isNaN(sta
 rt)?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-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


[11/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css b/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
new file mode 100755
index 0000000..e87551e
--- /dev/null
+++ b/sdks/html5-javascript/tests/resources/css/bootstrap-combined.min.css
@@ -0,0 +1,18 @@
+/*!
+ * Bootstrap v2.0.4
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box
 -sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover{color:#005580;text-decoration:underline}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bott
 om .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.127659574%;*margin-left:2.0744680846382977%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.
 row-fluid .span12{width:99.99999998999999%;*width:99.94680850063828%}.row-fluid .span11{width:91.489361693%;*width:91.4361702036383%}.row-fluid .span10{width:82.97872339599999%;*width:82.92553190663828%}.row-fluid .span9{width:74.468085099%;*width:74.4148936096383%}.row-fluid .span8{width:65.95744680199999%;*width:65.90425531263828%}.row-fluid .span7{width:57.446808505%;*width:57.3936170156383%}.row-fluid .span6{width:48.93617020799999%;*width:48.88297871863829%}.row-fluid .span5{width:40.425531911%;*width:40.3723404216383%}.row-fluid .span4{width:31.914893614%;*width:31.8617021246383%}.row-fluid .span3{width:23.404255317%;*width:23.3510638276383%}.row-fluid .span2{width:14.89361702%;*width:14.8404255306383%}.row-fluid .span1{width:6.382978723%;*width:6.329787233638298%}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-f
 luid:before,.container-fluid:after{display:table;content:""}.container-fluid:after{clear:both}p{margin:0 0 9px}p small{font-size:11px;color:#999}.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px}h1,h2,h3,h4,h5,h6{margin:0;font-family:inherit;font-weight:bold;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999}h1{font-size:30px;line-height:36px}h1 small{font-size:18px}h2{font-size:24px;line-height:36px}h2 small{font-size:18px}h3{font-size:18px;line-height:27px}h3 small{font-size:14px}h4,h5,h6{line-height:18px}h4{font-size:14px}h4 small{font-size:12px}h5{font-size:12px}h6{font-size:11px;color:#999;text-transform:uppercase}.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eee}.page-header h1{line-height:1}ul,ol{padding:0;margin:0 0 9px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}ul{list-style:disc}ol{list-style:decimal}li{line-height:18px}ul.unstyled,ol.unstyled
 {margin-left:0;list-style:none}dl{margin-bottom:18px}dt,dd{line-height:18px}dt{font-weight:bold;line-height:17px}dd{margin-left:9px}.dl-horizontal dt{float:left;width:120px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:130px}hr{margin:18px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}strong{font-weight:bold}em{font-style:italic}.muted{color:#999}abbr[title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px}blockquote small{display:block;line-height:18px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}q:before,q:af
 ter,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:18px;font-style:normal;line-height:18px}small{font-size:100%}cite{font-style:normal}code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12.025px;line-height:18px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:18px}pre code{padding:0;color:inherit;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 18px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;
 margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:13.5px;color:#999}label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555}input,textarea{width:210px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],inpu
 t[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-ms-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,i
 nput[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer}input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}.uneditable-textarea{width:auto;height:auto}select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px}select{width:220px;border:1px solid #bbb}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2
 px}.radio,.checkbox{min-height:18px;padding-left:18px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-f
 luid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:930px}input.span11,textarea.span11,.uneditable-input.span11{width:850px}input.span10,textarea.span10,.uneditable-input.span10{width:770px}input.span9,textarea.span9,.uneditable-input.span9{width:690px}input.span8,textarea.span8,.uneditable-input.span8{width:610px}input.span7,textarea.span7,.uneditable-input.span7{width:530px}input.span6,textarea.span6,.uneditable-input.span6{width:450px}input.span5,textarea.span5,.uneditable-input.span5{width:370px}input.span4,textarea.span4,.uneditable-input.span4{width:290px}input.span3,textarea.span3,.uneditable-input.span3{width:210px}input.span2,textarea.span2,.uneditable-input.span2{width:130px}input.span1,textarea.span1,.uneditable-input.span1{width:50px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],tex
 tarea[readonly]{cursor:not-allowed;background-color:#eee;border-color:#ddd}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853}.control-group.warning .checkbox:focus,.control-group.warning .radio:focus,.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group
 .error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48}.control-group.error .checkbox:focus,.control-group.error .radio:focus,.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border
 -color:#468847}.control-group.success .checkbox:focus,.control-group.success .radio:focus,.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display
 :table;content:""}.form-actions:after{clear:both}.uneditable-input{overflow:hidden;white-space:nowrap;cursor:not-allowed;background-color:#fff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}:-moz-placeholder{color:#999}:-ms-input-placeholder{color:#999}::-webkit-input-placeholder{color:#999}.help-block,.help-inline{color:#555}.help-block{display:block;margin-bottom:9px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-prepend,.input-append{margin-bottom:5px}.input-prepend input,.input-append input,.input-prepend select,.input-append select,.input-prepend .uneditable-input,.input-append .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:middle;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend input:focus,.input-append input:focu
 s,.input-prepend select:focus,.input-append select:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{z-index:2}.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc}.input-prepend .add-on,.input-append .add-on{display:inline-block;width:auto;height:18px;min-width:16px;padding:4px 5px;font-weight:normal;line-height:18px;text-align:center;text-shadow:0 1px 0 #fff;vertical-align:middle;background-color:#eee;border:1px solid #ccc}.input-prepend .add-on,.input-append .add-on,.input-prepend .btn,.input-append .btn{margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append input,.input-a
 ppend select,.input-append .uneditable-input{-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-append .uneditable-input{border-right-color:#ccc;border-left-color:#eee}.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.search-query{padding-right:14px;padding-right:4px 
 \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.fo
 rm-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:9px}legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:18px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:160px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:160px}.form-horizontal .help-block{margin-top:9px;margin-bottom:0}.form-horizontal .for
 m-actions{padding-left:160px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:18px}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered captio
 n+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-bor
 der-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9}.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5}table .span1{float:none;width:44px;margin-left:0}table .span2{float:none;width:124px;margin-left:0}table .span3{float:none;width:204px;margin-left:0}table .span4{float:none;width:284px;margin-left:0}table .span5{float:none;width:364px;margin-left:0}table .span6{float:none;width:444px;margin-left:0}table .span7{float:none;width:524px;margin-left:0}table .span8{float:none;width:604px;margin-left:0}table .span9{float:none;width:684px;marg
 in-left:0}table .span10{float:none;width:764px;margin-left:0}table .span11{float:none;width:844px;margin-left:0}table .span12{float:none;width:924px;margin-left:0}table .span13{float:none;width:1004px;margin-left:0}table .span14{float:none;width:1084px;margin-left:0}table .span15{float:none;width:1164px;margin-left:0}table .span16{float:none;width:1244px;margin-left:0}table .span17{float:none;width:1324px;margin-left:0}table .span18{float:none;width:1404px;margin-left:0}table .span19{float:none;width:1484px;margin-left:0}table .span20{float:none;width:1564px;margin-left:0}table .span21{float:none;width:1644px;margin-left:0}table .span22{float:none;width:1724px;margin-left:0}table .span23{float:none;width:1804px;margin-left:0}table .span24{float:none;width:1884px;margin-left:0}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-posi
 tion:14px 14px;background-repeat:no-repeat}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0}.icon-white{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-positio
 n:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{backgr
 ound-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust
 {background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign
 {background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-7
 2px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{background-position:-384px -120px}.icon-folder-open{background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72p
 x -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;heig
 ht:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";opacity:.3;filter:alpha(opacity=30)}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown:hover .caret,.open .caret{opacity:1;filter:alpha(opacity=100)}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:4px 0;margin:1px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background
 -color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#333;white-space:nowrap}.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#fff;text-decoration:none;background-color:#08c}.open{*z-index:1000}.open>.dropdown-menu{display:block}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:"\2191"}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0,0,0,0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1p
 x 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-ms-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-ms-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40
 )}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 10px 4px;margin-bottom:0;*margin-left:.3em;font-size:13px;line-height:18px;*line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-ms-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(top,#fff,#e6e6e6);background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border
 -radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#e6e6e6',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover{color:#333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-ms-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outlin
 e:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.btn-large [class^="icon-"]{margin-top:1px}.btn-small{padding:5px 9px;font-size:11px;line-height:16px}.btn-small [class^="icon-"]{margin-top:-1px}.btn-mini{padding:2px 6px;font-size:11px;line-height:14px}.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:h
 over,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn{border-color:#ccc;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25)}.btn-primary{background-color:#0074cc;*background-color:#05c;background-image:-ms-linear-gradient(top,#08c,#05c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#05c));background-image:-webkit-linear-gradient(top,#08c,#05c);background-image:-o-linear-gradient(top,#08c,#05c);background-image:-moz-linear-gradient(top,#08c,#05c);background-image:linear-gradient(top,#08c,#05c);background-repeat:repeat-x;border-color:#05c #05c #003580;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#0088cc',endCo
 lorstr='#0055cc',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#05c;*background-color:#004ab3}.btn-primary:active,.btn-primary.active{background-color:#004099 \9}.btn-warning{background-color:#faa732;*background-color:#f89406;background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0);filter:p
 rogid:dximagetransform.microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{background-color:#da4f49;*background-color:#bd362f;background-image:-ms-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(top,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#bd362f',GradientType=0);filter:progid:dximagetransform.microsoft.gradie
 nt(enabled=false)}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{background-color:#5bb75b;*background-color:#51a351;background-image:-ms-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(top,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#51a351',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-success:hover,.btn-suc
 cess:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{background-color:#49afcd;*background-color:#2f96b4;background-image:-ms-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(top,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#2f96b4',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled
 ,.btn-info[disabled]{background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{background-color:#414141;*background-color:#222;background-image:-ms-linear-gradient(top,#555,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#555),to(#222));background-image:-webkit-linear-gradient(top,#555,#222);background-image:-o-linear-gradient(top,#555,#222);background-image:-moz-linear-gradient(top,#555,#222);background-image:linear-gradient(top,#555,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:dximagetransform.microsoft.gradient(startColorstr='#555555',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#222;*background-color:#151515}.btn-inverse:active,.bt
 n-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-group{position:relative;*margin-left:.3em;*zoom:1}.btn-group:before,.btn-group:after{display:table;content:""}.btn-group:after{clear:both}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:9px;margin-bottom:9px}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1}.btn-group>.btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn:first-child{margin-left:0;-webkit-bord
 er-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.bt
 n-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.dropdown-toggle{*padding-top:4px;padding-right:8px;*padding-bottom:4px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini.dropdown-toggle{padding-right:5px;padding-left:5px}.btn-group>.btn-small.dropdown-toggle{*padding-top:4px;*padding-bottom:4px}.btn-group>.btn-large.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rg
 ba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#05c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:7px;margin-left:0}.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100)}.btn-mini .caret{margin-top:5px}.btn-small .caret{margin-top:6px}.btn-large .caret{margin-top:6px;border-top-width:5px;border-right-width:5px;border-left-width:5px}.dropup .btn-large .caret{border-top:0;border-bottom:5px solid #000}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success 
 .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:.75;filter:alpha(opacity=75)}.alert{padding:8px 35px 8px 14px;margin-bottom:18px;color:#c09853;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert-heading{color:inherit}.alert .close{position:relative;top:-2px;right:-21px;line-height:18px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:18px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover{text-decoration:none;background-color:#eee}.nav>.pull-right{float:right}.nav .nav-header{display:block;pa
 dding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:8px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14
 px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:18px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px
  0 0;border-radius:4px 4px 0 0}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.nav-tabs.nav-stacked>li>a:hover{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px}.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333;border-bottom-color:#333}.nav>.dropdown.active>a:hover{color:#000;cursor:pointer}.nav-tabs .
 open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover{border-top-color:#ddd;border-bottom-c
 olor:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-ta
 bs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.navbar{*position:relative;*z-index:2;margin-bottom:18px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top,#333,#222);background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(
 0,0,0,0.25),inset 0 -1px 0 rgba(0,0,0,0.1)}.navbar .container{width:auto}.nav-collapse.collapse{height:auto}.navbar{color:#999}.navbar .brand:hover{text-decoration:none}.navbar .brand{display:block;float:left;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#999}.navbar .navbar-text{margin-bottom:0;line-height:40px}.navbar .navbar-link{color:#999}.navbar .navbar-link:hover{color:#fff}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn{margin:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6
 px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#fff;background-color:#626262;border:1px solid #151515;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none}.navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;
 color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-bottom{bottom:0}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right}.navbar .nav>li{display:block;float:left}.navbar .nav>li>a{float:none;padding:9px 10px 11px;line-height:19px;color:#999;text-decoration:none;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar .btn{display:inline-block;padding:4px 10px 4px;margin:5px 5px 6px;line-height:18px}.navbar .btn-group{padding:5
 px 5px 6px;margin:0}.navbar .nav>li>a:hover{color:#fff;text-decoration:none;background-color:transparent}.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#fff;text-decoration:none;background-color:#222}.navbar .divider-vertical{width:1px;height:40px;margin:0 9px;overflow:hidden;background-color:#222;border-right:1px solid #333}.navbar .nav.pull-right{margin-right:0;margin-left:10px}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;background-color:#2c2c2c;*background-color:#222;background-image:-ms-linear-gradient(top,#333,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#333),to(#222));background-image:-webkit-linear-gradient(top,#333,#222);background-image:-o-linear-gradient(top,#333,#222);background-image:linear-gradient(top,#333,#222);background-image:-moz-linear-gradient(top,#333,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:pro
 gid:dximagetransform.microsoft.gradient(startColorstr='#333333',endColorstr='#222222',GradientType=0);filter:progid:dximagetransform.microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{background-color:#222;*background-color:#151515}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#080808 \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{
 margin-top:3px}.navbar .dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown .dropdown-toggle .caret,.navbar .nav li.dropdown.open .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar .nav li.dropdown.active .caret{opacity:1;filter:alpha(opacity=100)}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navba
 r .nav li.dropdown.open.active>.dropdown-toggle{background-color:transparent}.navbar .nav li.dropdown.active>.dropdown-toggle:hover{color:#fff}.navbar .pull-right .dropdown-menu,.navbar .dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right .dropdown-menu:before,.navbar .dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right .dropdown-menu:after,.navbar .dropdown-menu.pull-right:after{right:13px;left:auto}.breadcrumb{padding:7px 14px;margin:0 0 18px;list-style:none;background-color:#fbfbfb;background-image:-moz-linear-gradient(top,#fff,#f5f5f5);background-image:-ms-linear-gradient(top,#fff,#f5f5f5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f5f5f5));background-image:-webkit-linear-gradient(top,#fff,#f5f5f5);background-image:-o-linear-gradient(top,#fff,#f5f5f5);background-image:linear-gradient(top,#fff,#f5f5f5);background-repeat:repeat-x;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;filter:p
 rogid:dximagetransform.microsoft.gradient(startColorstr='#ffffff',endColorstr='#f5f5f5',GradientType=0);-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.breadcrumb li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb .divider{padding:0 5px;color:#999}.breadcrumb .active a{color:#333}.pagination{height:36px;margin:18px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination li{display:inline}.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0}.pagination a:hover,.pagination .active a{background-color:#f5f5f5}.pagination .active a{color:#999;cursor:default}.pagination .disabled span,.pagination 
 .disabled a,.pagination .disabled a:hover{color:#999;cursor:default;background-color:transparent}.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px}.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pager{margin-bottom:18px;margin-left:0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;content:""}.pager:after{clear:both}.pager li{display:inline}.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager a:hover{text-decoration:none;background-color:#f5f5f5}.pager .next a{float:right}.pager .previous a{float:left}.pager .disabled a,.pager .disabled a:hover{color:#999;cursor:default;background-color:#fff}.modal-open
  .dropdown-menu{z-index:2050}.modal-open .dropdown.open{*z-index:2050}.modal-open .popover{z-index:2060}.modal-open .tooltip{z-index:2070}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;overflow:auto;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-ms-transition:opacity .3s linear,top
  .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:50%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-body{max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.tooltip{position:absolute;z-index:1020;display:block;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity
 :.8;filter:alpha(opacity=80)}.tooltip.top{margin-top:-2px}.tooltip.right{margin-left:2px}.tooltip.bottom{margin-top:2px}.tooltip.left{margin-left:-2px}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:ab
 solute;width:0;height:0}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px}.popover.top{margin-top:-5px}.popover.right{margin-left:5px}.popover.bottom{margin-top:5px}.popover.left{margin-left:-5px}.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-top:5px solid #000;border-right:5px solid transparent;border-left:5px solid transparent}.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-right:5px solid #000;border-bottom:5px solid transparent}.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-right:5px solid transparent;border-bottom:5px solid #000;border-left:5px solid transparent}.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000}.popover .arrow{position:absolute;width:0;height:0}.popover-inner{width:280px;padding:3px;overflow:hidden;background:#000;background:rgba(0,0,0,0.8);-webkit-border-radius:
 6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3)}.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0}.popover-content{padding:14px;background-color:#fff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:18px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webk
 it-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:0 1px 1px rgba(0,0,0,0.075);box-shadow:0 1px 1px rgba(0,0,0,0.075)}a.thumbnail:hover{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px}.label,.badge{font-size:10.998px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{padding:1px 4px 2px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding:1px 9px 2px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}a.label:hover,a.badge:hover{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important
 [href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-pos
 ition:0 0}}.progress{height:18px;margin-bottom:18px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-ms-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(top,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#f5f5f5',endColorstr='#f9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{width:0;height:18px;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#14
 9bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(top,#149bdf,#0480be);background-image:-ms-linear-gradient(top,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#149bdf',endColorstr='#0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-ms-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress-striped .bar{background-color:#149bdf;background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,tra
 nsparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:linear-gradient(-45deg,rgba(255,255,255,0.15
 ) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-ms-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(top,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:dximage
 transform.microsoft.gradient(startColorstr='#ee5f5b',endColorstr='#c43c35',GradientType=0)}.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);ba
 ckground-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-ms-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(top,#62c462,#57a957);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#62c462',endColorstr='#57a957',GradientType=0)}.progress-success.progress-striped .bar{background-color:#62c462;background-
 image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 
 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-ms-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(top,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#5bc0de',endColorstr='#339bb9',GradientType=0)}.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255
 ,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,tr
 ansparent 75%,transparent)}.progress-warning .bar{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-ms-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(top,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:dximagetransform.microsoft.gradient(startColorstr='#fbb450',endColorstr='#f89406',GradientType=0)}.progress-warning.progress-striped .bar{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 2
 5%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:18px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;
 border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:18px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel .item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-ms-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel .item>img{display:block;line-height:1}.carousel .active,.carousel .next,.carousel .prev{display:block}.carousel .active{left:0}.carousel .next,.carousel .prev{position:absolute;top:0;width:100%}.carousel .next{left:100%}.carousel .prev{left:-100%}.carousel .next.left,.carousel .prev.right{left:0}.carousel .active.left{left:-100%}.carousel .active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;wi
 dth:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:10px 15px 5px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{color:#fff}.hero-unit{padding:60px;margin-bottom:30px;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit p{font-size:18px;font-weight:200;line-height:27px;color:inherit}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}
+/*!
+ * Bootstrap Responsive v2.0.4
+ *
+ * Copyright 2012 Twitter, Inc
+ * Licensed under the Apache License v2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Designed and built with all the love in the world @twitter by @mdo and @fat.
+ */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}@media(max-width:767px){.visible-phone{display:inherit!important}.hidden-phone{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(min-width:768px) and (max-width:979px){.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-h
 eader h1 small{display:block;line-height:18px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.modal{position:absolute;top:10px;right:10px;left:10px;width:auto;margin:0}.modal.fade.in{top:auto}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:auto;margin-left:0}.input-large,.input-xlarg
 e,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:20px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin
 -left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:28px;margin-left:2.762430939%;*margin-left:2.709239449638298%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .span12{width:99.999999993%;*width:99.9468085036383%}.row-fluid .span11{width:91.436464082%;*width:91.38327259263829%}.row-fluid .span10{width:82.87292817100001%;*width:82.8197366816383%}.row-fluid .span9{width:74.30939226%;*width:74.25620077063829%}.row-fluid .span8{width:65.74585634900001%;*width:65.6926648596383%}.row-fluid .span7{width:57.18
 2320438000005%;*width:57.129128948638304%}.row-fluid .span6{width:48.618784527%;*width:48.5655930376383%}.row-fluid .span5{width:40.055248616%;*width:40.0020571266383%}.row-fluid .span4{width:31.491712705%;*width:31.4385212156383%}.row-fluid .span3{width:22.928176794%;*width:22.874985304638297%}.row-fluid .span2{width:14.364640883%;*width:14.311449393638298%}.row-fluid .span1{width:5.801104972%;*width:5.747913482638298%}input,textarea,.uneditable-input{margin-left:0}input.span12,textarea.span12,.uneditable-input.span12{width:714px}input.span11,textarea.span11,.uneditable-input.span11{width:652px}input.span10,textarea.span10,.uneditable-input.span10{width:590px}input.span9,textarea.span9,.uneditable-input.span9{width:528px}input.span8,textarea.span8,.uneditable-input.span8{width:466px}input.span7,textarea.span7,.uneditable-input.span7{width:404px}input.span6,textarea.span6,.uneditable-input.span6{width:342px}input.span5,textarea.span5,.uneditable-input.span5{width:280px}input.span4,t
 extarea.span4,.uneditable-input.span4{width:218px}input.span3,textarea.span3,.uneditable-input.span3{width:156px}input.span2,textarea.span2,.uneditable-input.span2{width:94px}input.span1,textarea.span1,.uneditable-input.span1{width:32px}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;content:""}.row:after{clear:both}[class*="span"]{float:left;margin-left:30px}.container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.off

<TRUNCATED>

[17/27] built with the new Events module included

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/8367ea49/sdks/html5-javascript/usergrid.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/usergrid.js b/sdks/html5-javascript/usergrid.js
old mode 100755
new mode 100644
index 948238b..96dbbe8
--- a/sdks/html5-javascript/usergrid.js
+++ b/sdks/html5-javascript/usergrid.js
@@ -1,3 +1,4 @@
+/*! usergrid@0.0.0 2014-01-16 */
 /*
  *  This module is a collection of classes designed to make working with
  *  the Appigee App Services API as easy as possible.
@@ -21,37 +22,89 @@
  *  @author matt dobson (matt@apigee.com)
  *  @author ryan bridges (rbridges@apigee.com)
  */
-
-
 //Hack around IE console.log
 window.console = window.console || {};
+
 window.console.log = window.console.log || function() {};
 
 //Usergrid namespace encapsulates this SDK
 window.Usergrid = window.Usergrid || {};
+
 Usergrid = Usergrid || {};
-Usergrid.USERGRID_SDK_VERSION = '0.10.07';
 
-Usergrid.Client = function(options) {
-  //usergrid enpoint
-  this.URI = options.URI || 'https://api.usergrid.com';
+Usergrid.USERGRID_SDK_VERSION = "0.10.07";
 
-  //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
-  if (options.orgName) {
-    this.set('orgName', options.orgName);
-  }
-  if (options.appName) {
-    this.set('appName', options.appName);
-  }
+/*
+ * Tests if the string is a uuid
+ *
+ * @public
+ * @method isUUID
+ * @param {string} uuid The string to test
+ * @returns {Boolean} true if string is uuid
+ */
+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}$/;
+    if (!uuid) {
+        return false;
+    }
+    return uuidValueRegex.test(uuid);
+}
 
-  //other options
-  this.buildCurl = options.buildCurl || false;
-  this.logging = options.logging || false;
+/*
+ *  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 tail = [];
+    var item = [];
+    var i;
+    if (params instanceof Array) {
+        for (i in params) {
+            item = params[i];
+            if (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("&");
+}
 
-  //timeout and callbacks
-  this._callTimeout =  options.callTimeout || 30000; //default to 30 seconds
-  this._callTimeoutCallback =  options.callTimeoutCallback || null;
-  this.logoutCallback =  options.logoutCallback || null;
+Usergrid.Client = function(options) {
+    //usergrid enpoint
+    this.URI = options.URI || "https://api.usergrid.com";
+    //Find your Orgname and Appname in the Admin portal (http://apigee.com/usergrid)
+    if (options.orgName) {
+        this.set("orgName", options.orgName);
+    }
+    if (options.appName) {
+        this.set("appName", options.appName);
+    }
+    //other options
+    this.buildCurl = options.buildCurl || false;
+    this.logging = options.logging || false;
+    //timeout and callbacks
+    this._callTimeout = options.callTimeout || 3e4;
+    //default to 30 seconds
+    this._callTimeoutCallback = options.callTimeoutCallback || null;
+    this.logoutCallback = options.logoutCallback || null;
 };
 
 /*
@@ -70,139 +123,125 @@ Usergrid.Client = function(options) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.request = function (options, callback) {
-  var self = this;
-  var method = options.method || 'GET';
-  var endpoint = options.endpoint;
-  var body = options.body || {};
-  var qs = options.qs || {};
-  var mQuery = options.mQuery || false; //is this a query to the management endpoint?
-  var orgName = this.get('orgName');
-  var appName = this.get('appName');
-  if(!mQuery && !orgName && !appName){
-    if (typeof(this.logoutCallback) === 'function') {
-      return this.logoutCallback(true, 'no_org_or_app_name_specified');
-    }
-  }
-  if (mQuery) {
-    uri = this.URI + '/' + endpoint;
-  } else {
-    uri = this.URI + '/' + orgName + '/' + appName + '/' + endpoint;
-  }
-
-  if (self.getToken()) {
-    qs.access_token = self.getToken();
-    /* //could also use headers for the token
-     xhr.setRequestHeader("Authorization", "Bearer " + self.getToken());
-     xhr.withCredentials = true;
-     */
-  }
-
-  //append params to the path
-  var encoded_params = encodeParams(qs);
-  if (encoded_params) {
-    uri += "?" + encoded_params;
-  }
-
-  //stringify the body object
-  body = JSON.stringify(body);
-
-  //so far so good, so run the query
-  var xhr = new XMLHttpRequest();
-  xhr.open(method, uri, true);
-  //add content type = json if there is a json payload
-  if (body) {
-    xhr.setRequestHeader("Content-Type", "application/json");
-    xhr.setRequestHeader("Accept", "application/json");
-  }
-
-  // Handle response.
-  xhr.onerror = function(response) {
-    self._end = new Date().getTime();
-    if (self.logging) {
-      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
-    }
-    if (self.logging) {
-      console.log('Error: API call failed at the network level.');
-    }
-    //network error
-    clearTimeout(timeout);
-    var err = true;
-    if (typeof(callback) === 'function') {
-      callback(err, response);
-    }
-  };
-
-  xhr.onload = function(response) {
-    //call timing, get time, then log the call
-    self._end = new Date().getTime();
-    if (self.logging) {
-      console.log('success (time: ' + self.calcTimeDiff() + '): ' + method + ' ' + uri);
-    }
-    //call completed
-    clearTimeout(timeout);
-    //decode the response
-    try{
-      response = JSON.parse(xhr.responseText);
-    }catch (e){
-      response = {error:'unhandled_error',error_description:xhr.responseText};
-      xhr.status = xhr.status === 200 ? 400 : xhr.status;
-      console.error(e);
+Usergrid.Client.prototype.request = function(options, callback) {
+    var self = this;
+    var method = options.method || "GET";
+    var endpoint = options.endpoint;
+    var body = options.body || {};
+    var qs = options.qs || {};
+    var mQuery = options.mQuery || false;
+    //is this a query to the management endpoint?
+    var orgName = this.get("orgName");
+    var appName = this.get("appName");
+    if (!mQuery && !orgName && !appName) {
+        if (typeof this.logoutCallback === "function") {
+            return this.logoutCallback(true, "no_org_or_app_name_specified");
+        }
     }
-    if (xhr.status != 200)   {
-      //there was an api error
-      var error = response.error;
-      var error_description = response.error_description;
-      if (self.logging) {
-        console.log('Error (' + xhr.status + ')(' + error + '): ' + error_description);
-      }
-      if ( (error == "auth_expired_session_token") ||
-        (error == "auth_missing_credentials")   ||
-        (error == "auth_unverified_oath")       ||
-        (error == "expired_token")              ||
-        (error == "unauthorized")               ||
-        (error == "auth_invalid")) {
-        //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
-        //if the user has specified a logout callback:
-        if (typeof(self.logoutCallback) === 'function') {
-          return self.logoutCallback(true, response);
-        }
-      }
-      if (typeof(callback) === 'function') {
-        callback(true, response);
-      }
+    if (mQuery) {
+        uri = this.URI + "/" + endpoint;
     } else {
-      if (typeof(callback) === 'function') {
-        callback(false, response);
-      }
-    }
-  };
-
-  var timeout = setTimeout(
-    function() {
-      xhr.abort();
-      if (self._callTimeoutCallback === 'function') {
-        self._callTimeoutCallback('API CALL TIMEOUT');
-      } else {
-        self.callback('API CALL TIMEOUT');
-      }
-    },
-    self._callTimeout); //set for 30 seconds
-
-  if (this.logging) {
-    console.log('calling: ' + method + ' ' + uri);
-  }
-  if (this.buildCurl) {
-    var curlOptions = {
-      uri:uri,
-      body:body,
-      method:method
+        uri = this.URI + "/" + orgName + "/" + appName + "/" + endpoint;
+    }
+    if (self.getToken()) {
+        qs.access_token = self.getToken();
+    }
+    //append params to the path
+    var encoded_params = encodeParams(qs);
+    if (encoded_params) {
+        uri += "?" + encoded_params;
+    }
+    //stringify the body object
+    body = JSON.stringify(body);
+    //so far so good, so run the query
+    var xhr = new XMLHttpRequest();
+    xhr.open(method, uri, true);
+    //add content type = json if there is a json payload
+    if (body) {
+        xhr.setRequestHeader("Content-Type", "application/json");
+        xhr.setRequestHeader("Accept", "application/json");
+    }
+    // Handle response.
+    xhr.onerror = function(response) {
+        self._end = new Date().getTime();
+        if (self.logging) {
+            console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
+        }
+        if (self.logging) {
+            console.log("Error: API call failed at the network level.");
+        }
+        //network error
+        clearTimeout(timeout);
+        var err = true;
+        if (typeof callback === "function") {
+            callback(err, response);
+        }
+    };
+    xhr.onload = function(response) {
+        //call timing, get time, then log the call
+        self._end = new Date().getTime();
+        if (self.logging) {
+            console.log("success (time: " + self.calcTimeDiff() + "): " + method + " " + uri);
+        }
+        //call completed
+        clearTimeout(timeout);
+        //decode the response
+        try {
+            response = JSON.parse(xhr.responseText);
+        } catch (e) {
+            response = {
+                error: "unhandled_error",
+                error_description: xhr.responseText
+            };
+            xhr.status = xhr.status === 200 ? 400 : xhr.status;
+            console.error(e);
+        }
+        if (xhr.status != 200) {
+            //there was an api error
+            var error = response.error;
+            var error_description = response.error_description;
+            if (self.logging) {
+                console.log("Error (" + xhr.status + ")(" + error + "): " + error_description);
+            }
+            if (error == "auth_expired_session_token" || error == "auth_missing_credentials" || error == "auth_unverified_oath" || error == "expired_token" || error == "unauthorized" || error == "auth_invalid") {
+                //these errors mean the user is not authorized for whatever reason. If a logout function is defined, call it
+                //if the user has specified a logout callback:
+                if (typeof self.logoutCallback === "function") {
+                    return self.logoutCallback(true, response);
+                }
+            }
+            if (typeof callback === "function") {
+                callback(true, response);
+            }
+        } else {
+            if (typeof callback === "function") {
+                callback(false, response);
+            }
+        }
+    };
+    var timeout = setTimeout(function() {
+        xhr.abort();
+        if (self._callTimeoutCallback === "function") {
+            self._callTimeoutCallback("API CALL TIMEOUT");
+        } else {
+            self.callback("API CALL TIMEOUT");
+        }
+    }, self._callTimeout);
+    //set for 30 seconds
+    if (this.logging) {
+        console.log("calling: " + method + " " + uri);
+    }
+    if (this.buildCurl) {
+        var curlOptions = {
+            uri: uri,
+            body: body,
+            method: method
+        };
+        this.buildCurlCall(curlOptions);
     }
-    this.buildCurlCall(curlOptions);
-  }
-  this._start = new Date().getTime();
-  xhr.send(body);
-}
+    this._start = new Date().getTime();
+    xhr.send(body);
+};
 
 /*
  *  function for building asset urls
@@ -213,21 +252,18 @@ Usergrid.Client.prototype.request = function (options, callback) {
  *  @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();
-  }
-
-  //append params to the path
-  var encoded_params = encodeParams(qs);
-  if (encoded_params) {
-    assetURL += "?" + encoded_params;
-  }
-
-  return assetURL;
+    var self = this;
+    var qs = {};
+    var assetURL = this.URI + "/" + this.orgName + "/" + this.appName + "/assets/" + uuid + "/data";
+    if (self.getToken()) {
+        qs.access_token = self.getToken();
+    }
+    //append params to the path
+    var encoded_params = encodeParams(qs);
+    if (encoded_params) {
+        assetURL += "?" + encoded_params;
+    }
+    return assetURL;
 };
 
 /*
@@ -240,29 +276,27 @@ Usergrid.Client.prototype.buildAssetURL = function(uuid) {
  *  @return {callback} callback(err, data)
  */
 Usergrid.Client.prototype.createGroup = function(options, callback) {
-  var getOnExist = options.getOnExist || false;
-
-  options = {
-    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);
-    if (okToSave) {
-      group.save(function(err, data){
-        if (typeof(callback) === 'function') {
-          callback(err, group);
-        }
-      });
-    } else {
-      if(typeof(callback) === 'function') {
-        callback(err, group);
-      }
-    }
-  });
+    var getOnExist = options.getOnExist || false;
+    options = {
+        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;
+        if (okToSave) {
+            group.save(function(err, data) {
+                if (typeof callback === "function") {
+                    callback(err, group);
+                }
+            });
+        } else {
+            if (typeof callback === "function") {
+                callback(err, group);
+            }
+        }
+    });
 };
 
 /*
@@ -276,10 +310,10 @@ Usergrid.Client.prototype.createGroup = function(options, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createEntity = function (options, callback) {
-  // todo: replace the check for new / save on not found code with simple save
-  // when users PUT on no user fix is in place.
-  /*
+Usergrid.Client.prototype.createEntity = function(options, callback) {
+    // todo: replace the check for new / save on not found code with simple save
+    // when users PUT on no user fix is in place.
+    /*
    var options = {
    client:this,
    data:options
@@ -291,29 +325,30 @@ Usergrid.Client.prototype.createEntity = function (options, callback) {
    }
    });
    */
-  var getOnExist = options.getOnExist || false; //if true, will return entity if one already exists
-  var options = {
-    client:this,
-    data:options
-  };
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(function(err, data) {
-    //if the fetch doesn't find what we are looking for, or there is no error, do a save
-    var okToSave = (err && 'service_resource_not_found' === data.error || 'no_name_specified' === data.error || 'null_pointer' === data.error) || (!err && getOnExist);
-    if(okToSave) {
-      entity.set(options.data); //add the data again just in case
-      entity.save(function(err, data) {
-        if (typeof(callback) === 'function') {
-          callback(err, entity, data);
-        }
-      });
-    } else {
-      if (typeof(callback) === 'function') {
-        callback(err, entity, data);
-      }
-    }
-  });
-
+    var getOnExist = options.getOnExist || false;
+    //if true, will return entity if one already exists
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(function(err, data) {
+        //if the fetch doesn't find what we are looking for, or there is no error, do a save
+        var okToSave = err && "service_resource_not_found" === data.error || "no_name_specified" === data.error || "null_pointer" === data.error || !err && getOnExist;
+        if (okToSave) {
+            entity.set(options.data);
+            //add the data again just in case
+            entity.save(function(err, data) {
+                if (typeof callback === "function") {
+                    callback(err, entity, data);
+                }
+            });
+        } else {
+            if (typeof callback === "function") {
+                callback(err, entity, data);
+            }
+        }
+    });
 };
 
 /*
@@ -330,17 +365,17 @@ Usergrid.Client.prototype.createEntity = function (options, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.getEntity = function (options, callback) {
-  var options = {
-    client:this,
-    data:options
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, entity, data);
-    }
-  });
+Usergrid.Client.prototype.getEntity = function(options, callback) {
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, entity, data);
+        }
+    });
 };
 
 /*
@@ -353,14 +388,14 @@ Usergrid.Client.prototype.getEntity = function (options, callback) {
  *  @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;
+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;
 };
 
 /*
@@ -374,13 +409,13 @@ Usergrid.Client.prototype.restoreEntity = function (serializedObject) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createCollection = function (options, callback) {
-  options.client = this;
-  var collection = new Usergrid.Collection(options, function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, collection, data);
-    }
-  });
+Usergrid.Client.prototype.createCollection = function(options, callback) {
+    options.client = this;
+    var collection = new Usergrid.Collection(options, function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, collection, data);
+        }
+    });
 };
 
 /*
@@ -393,11 +428,11 @@ Usergrid.Client.prototype.createCollection = function (options, callback) {
  *  @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;
+Usergrid.Client.prototype.restoreCollection = function(serializedObject) {
+    var data = JSON.parse(serializedObject);
+    data.client = this;
+    var collection = new Usergrid.Collection(data);
+    return collection;
 };
 
 /*
@@ -410,20 +445,19 @@ Usergrid.Client.prototype.restoreCollection = function (serializedObject) {
  *  @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(typeof(callback) === "function") {
-      if(err) {
-        callback(err);
-      } else {
-        callback(err, data, data.entities);
-      }
-    }
-  });
+    var options = {
+        method: "GET",
+        endpoint: "users/" + username + "/feed"
+    };
+    this.request(options, function(err, data) {
+        if (typeof callback === "function") {
+            if (err) {
+                callback(err);
+            } else {
+                callback(err, data, data.entities);
+            }
+        }
+    });
 };
 
 /*
@@ -461,18 +495,18 @@ Usergrid.Client.prototype.getFeedForUser = function(username, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.createUserActivity = function (user, options, callback) {
-  options.type = 'users/'+user+'/activities';
-  var options = {
-    client:this,
-    data:options
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.save(function(err, data) {
-    if (typeof(callback) === 'function') {
-      callback(err, entity);
-    }
-  });
+Usergrid.Client.prototype.createUserActivity = function(user, options, callback) {
+    options.type = "users/" + user + "/activities";
+    var options = {
+        client: this,
+        data: options
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.save(function(err, data) {
+        if (typeof callback === "function") {
+            callback(err, entity);
+        }
+    });
 };
 
 /*
@@ -489,41 +523,39 @@ Usergrid.Client.prototype.createUserActivity = function (user, options, 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);
-
+    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;
+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;
 };
 
 /*
@@ -534,8 +566,8 @@ Usergrid.Client.prototype.calcTimeDiff = function () {
  *  @params {string} token
  *  @return none
  */
-Usergrid.Client.prototype.setToken = function (token) {
-  this.set('token', token);
+Usergrid.Client.prototype.setToken = function(token) {
+    this.set("token", token);
 };
 
 /*
@@ -545,41 +577,41 @@ Usergrid.Client.prototype.setToken = function (token) {
  *  @public
  *  @return {string} token
  */
-Usergrid.Client.prototype.getToken = function () {
-  return this.get('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);
+    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.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));
+    return JSON.parse(this.get(key));
 };
 
-Usergrid.Client.prototype.get = function (key) {
-  var keyStore = 'apigee_' + key;
-  if (this[key]) {
-    return this[key];
-  } else if(typeof(Storage)!=="undefined") {
-    return localStorage.getItem(keyStore);
-  }
-  return null;
+Usergrid.Client.prototype.get = function(key) {
+    var keyStore = "apigee_" + key;
+    if (this[key]) {
+        return this[key];
+    } else if (typeof Storage !== "undefined") {
+        return localStorage.getItem(keyStore);
+    }
+    return null;
 };
 
 /*
@@ -595,16 +627,15 @@ Usergrid.Client.prototype.get = function (key) {
  * @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);
+    var self = this;
+    var options = {
+        type: "users",
+        username: username,
+        password: password,
+        email: email,
+        name: name
+    };
+    this.createEntity(options, callback);
 };
 
 /*
@@ -618,122 +649,112 @@ Usergrid.Client.prototype.signup = function(username, password, email, name, cal
  *  @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'
-    }
-  };
-  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);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user);
-    }
-  });
+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"
+        }
+    };
+    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);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, 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 {
-
-      //save the re-authed token and current email/username
-      self.setToken(response.access_token);
-
-    }
-    if (typeof(callback) === 'function') {
-      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);
-
-      //delete next block and corresponding function when iframes are refactored
-      localStorage.setItem('accessToken', data.token);
-      localStorage.setItem('userUUID', data.uuid);
-      localStorage.setItem('userEmail', data.email);
-      //end delete block
-
-
-      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 {
-        //if we have an org stored, then use that one. Otherwise, use the first one.
-        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');
+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 {
+            //save the re-authed token and current email/username
+            self.setToken(response.access_token);
         }
-      } //should always be an org
-
-      applications = self.parseApplicationsArray(org);
-      self.selectFirstApp(applications);
-
-      self.setObject('organizations', organizations);
-      self.setObject('applications', applications);
+        if (typeof callback === "function") {
+            callback(err);
+        }
+    });
+};
 
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user, organizations, applications);
-    }
-  });
+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);
+            //delete next block and corresponding function when iframes are refactored
+            localStorage.setItem("accessToken", data.token);
+            localStorage.setItem("userUUID", data.uuid);
+            localStorage.setItem("userEmail", data.email);
+            //end delete block
+            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 {
+                //if we have an org stored, then use that one. Otherwise, use the first one.
+                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");
+                }
+            }
+            //should always be an org
+            applications = self.parseApplicationsArray(org);
+            self.selectFirstApp(applications);
+            self.setObject("organizations", organizations);
+            self.setObject("applications", applications);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, user, organizations, applications);
+        }
+    });
 };
 
 /*
@@ -746,31 +767,31 @@ Usergrid.Client.prototype.reAuthenticate = function (email, callback) {
  *  @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);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, user);
-    }
-  });
+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);
+        }
+        if (typeof callback === "function") {
+            callback(err, data, user);
+        }
+    });
 };
 
 /*
@@ -781,35 +802,35 @@ Usergrid.Client.prototype.loginFacebook = function (facebookToken, callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Client.prototype.getLoggedInUser = function (callback) {
-  if (!this.getToken()) {
-    callback(true, null, null);
-  } else {
-    var self = this;
-    var options = {
-      method:'GET',
-      endpoint:'users/me'
-    };
-    this.request(options, function(err, data) {
-      if (err) {
-        if (self.logging) {
-          console.log('error trying to log user in');
-        }
-        if (typeof(callback) === 'function') {
-          callback(err, data, null);
-        }
-      } else {
+Usergrid.Client.prototype.getLoggedInUser = function(callback) {
+    if (!this.getToken()) {
+        callback(true, null, null);
+    } else {
+        var self = this;
         var options = {
-          client:self,
-          data:data.entities[0]
+            method: "GET",
+            endpoint: "users/me"
         };
-        var user = new Usergrid.Entity(options);
-        if (typeof(callback) === 'function') {
-          callback(err, data, user);
-        }
-      }
-    });
-  }
+        this.request(options, function(err, data) {
+            if (err) {
+                if (self.logging) {
+                    console.log("error trying to log user in");
+                }
+                if (typeof callback === "function") {
+                    callback(err, data, null);
+                }
+            } else {
+                var options = {
+                    client: self,
+                    data: data.entities[0]
+                };
+                var user = new Usergrid.Entity(options);
+                if (typeof callback === "function") {
+                    callback(err, data, user);
+                }
+            }
+        });
+    }
 };
 
 /*
@@ -820,11 +841,11 @@ Usergrid.Client.prototype.getLoggedInUser = function (callback) {
  *  @public
  *  @return {boolean} Returns true the user is logged in (has token and uuid), false if not
  */
-Usergrid.Client.prototype.isLoggedIn = function () {
-  if (this.getToken() && this.getToken() != 'null') {
-    return true;
-  }
-  return false;
+Usergrid.Client.prototype.isLoggedIn = function() {
+    if (this.getToken() && this.getToken() != "null") {
+        return true;
+    }
+    return false;
 };
 
 /*
@@ -834,8 +855,8 @@ Usergrid.Client.prototype.isLoggedIn = function () {
  *  @public
  *  @return none
  */
-Usergrid.Client.prototype.logout = function () {
-  this.setToken(null);
+Usergrid.Client.prototype.logout = function() {
+    this.setToken(null);
 };
 
 /*
@@ -846,54 +867,52 @@ Usergrid.Client.prototype.logout = function () {
  *  @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 - add the method to the command (no need to add anything for GET)
-  if (method === 'POST') {
-    curl += ' -X POST';
-  } else if (method === 'PUT') {
-    curl += ' -X PUT';
-  } else if (method === 'DELETE') {
-    curl += ' -X DELETE';
-  } else {
-    curl += ' -X GET';
-  }
-
-  //curl - append the path
-  curl += ' ' + uri;
-
-  //curl - add the body
-  if("undefined"!== typeof window){body = JSON.stringify(body);}//only in node module
-  if (body !== '"{}"' && method !== 'GET' && method !== 'DELETE') {
-    //curl - add in the json obj
-    curl += " -d '" + body + "'";
-  }
-
-  //log the curl command to the console
-  console.log(curl);
-
-  return curl;
-}
-
-Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
-  try {
-    if (picture) {
-      return picture;
-    }
-    var size = size || 50;
-    if (email.length) {
-      return 'https://secure.gravatar.com/avatar/' + MD5(email) + '?s=' + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+Usergrid.Client.prototype.buildCurlCall = function(options) {
+    var curl = "curl";
+    var method = (options.method || "GET").toUpperCase();
+    var body = options.body || {};
+    var uri = options.uri;
+    //curl - add the method to the command (no need to add anything for GET)
+    if (method === "POST") {
+        curl += " -X POST";
+    } else if (method === "PUT") {
+        curl += " -X PUT";
+    } else if (method === "DELETE") {
+        curl += " -X DELETE";
     } else {
-      return 'https://apigee.com/usergrid/images/user_profile.png';
+        curl += " -X GET";
     }
-  } catch(e) {
-    return 'https://apigee.com/usergrid/images/user_profile.png';
-  }
-}
+    //curl - append the path
+    curl += " " + uri;
+    //curl - add the body
+    if ("undefined" !== typeof window) {
+        body = JSON.stringify(body);
+    }
+    //only in node module
+    if (body !== '"{}"' && method !== "GET" && method !== "DELETE") {
+        //curl - add in the json obj
+        curl += " -d '" + body + "'";
+    }
+    //log the curl command to the console
+    console.log(curl);
+    return curl;
+};
+
+Usergrid.Client.prototype.getDisplayImage = function(email, picture, size) {
+    try {
+        if (picture) {
+            return picture;
+        }
+        var size = size || 50;
+        if (email.length) {
+            return "https://secure.gravatar.com/avatar/" + MD5(email) + "?s=" + size + encodeURI("&d=https://apigee.com/usergrid/images/user_profile.png");
+        } else {
+            return "https://apigee.com/usergrid/images/user_profile.png";
+        }
+    } catch (e) {
+        return "https://apigee.com/usergrid/images/user_profile.png";
+    }
+};
 
 /*
  *  A class to Model a Usergrid Entity.
@@ -903,10 +922,10 @@ Usergrid.Client.prototype.getDisplayImage = function (email, picture, size) {
  *  @param {object} options {client:client, data:{'type':'collection_type', uuid:'uuid', 'key':'value'}}
  */
 Usergrid.Entity = function(options) {
-  if (options) {
-    this._data = options.data || {};
-    this._client = options.client || {};
-  }
+    if (options) {
+        this._data = options.data || {};
+        this._client = options.client || {};
+    }
 };
 
 /*
@@ -917,8 +936,8 @@ Usergrid.Entity = function(options) {
  *  @method serialize
  *  @return {string} data
  */
-Usergrid.Entity.prototype.serialize = function () {
-  return JSON.stringify(this._data);
+Usergrid.Entity.prototype.serialize = function() {
+    return JSON.stringify(this._data);
 };
 
 /*
@@ -929,12 +948,12 @@ Usergrid.Entity.prototype.serialize = function () {
  *  @param {string} field
  *  @return {string} || {object} data
  */
-Usergrid.Entity.prototype.get = function (field) {
-  if (field) {
-    return this._data[field];
-  } else {
-    return this._data;
-  }
+Usergrid.Entity.prototype.get = function(field) {
+    if (field) {
+        return this._data[field];
+    } else {
+        return this._data;
+    }
 };
 
 /*
@@ -947,20 +966,20 @@ Usergrid.Entity.prototype.get = function (field) {
  *  @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];
+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[key] = value;
+        this._data = {};
     }
-  } else {
-    this._data = {};
-  }
 };
 
 /*
@@ -971,88 +990,86 @@ Usergrid.Entity.prototype.set = function (key, value) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Entity.prototype.save = function (callback) {
-  var type = this.get('type');
-  var method = 'POST';
-  if (isUUID(this.get('uuid'))) {
-    method = 'PUT';
-    type += '/' + this.get('uuid');
-  }
-
-  //update the entity
-  var self = this;
-  var data = {};
-  var entityData = this.get();
-    var password = this.get('password');
-    var oldpassword = this.get('oldpassword');
-    var newpassword = this.get('newpassword');
-  //remove system specific properties
-  for (var item in entityData) {
-    if (item === 'metadata' || item === 'created' || item === 'modified' ||
-          item === 'oldpassword' || item === 'newpassword' || //old and new pw not added to data
-      item === 'type' || item === 'activated' || item === 'uuid') {
-      continue;
-    }
-    data[item] = entityData[item];
-  }
-  var options =  {
-    method:method,
-    endpoint:type,
-    body:data
-  };
-  //save the entity first
-  this._client.request(options, function (err, retdata) {
-      //clear out pw info if present
-      self.set('password', null);
-      self.set('oldpassword', null);
-      self.set('newpassword', null);
-    if (err && self._client.logging) {
-      console.log('could not save entity');
-      if (typeof(callback) === 'function') {
-        return callback(err, retdata, self);
-      }
-    } else {
-      if (retdata.entities) {
-        if (retdata.entities.length) {
-          var entity = retdata.entities[0];
-          self.set(entity);
-          var path = retdata.path;
-          //for connections, API returns type
-          while (path.substring(0, 1) === "/") {
-            path = path.substring(1);
-          }
-          self.set('type', path);
-        }
-      }
-      //if this is a user, update the password if it has been specified;
-        var needPasswordChange = ((self.get('type') === 'user' || self.get('type') === 'users') && oldpassword && newpassword);
-      if (needPasswordChange) {
-        //Note: we have a ticket in to change PUT calls to /users to accept the password change
-        //      once that is done, we will remove this call and merge it all into one
-        var pwdata = {};
-          pwdata.oldpassword = oldpassword;
-          pwdata.newpassword = newpassword;
-        var options = {
-          method:'PUT',
-          endpoint:type+'/password',
-          body:pwdata
-        }
-        self._client.request(options, function (err, data) {
-          if (err && self._client.logging) {
-            console.log('could not update user');
-          }
-          //remove old and new password fields so they don't end up as part of the entity object
-          self.set('oldpassword', null);
-          self.set('newpassword', null);
-          if (typeof(callback) === 'function') {
-            callback(err, data, self);
-          }
-        });
-      } else if (typeof(callback) === 'function') {
-        callback(err, retdata, self);
-      }
+Usergrid.Entity.prototype.save = function(callback) {
+    var type = this.get("type");
+    var method = "POST";
+    if (isUUID(this.get("uuid"))) {
+        method = "PUT";
+        type += "/" + this.get("uuid");
+    }
+    //update the entity
+    var self = this;
+    var data = {};
+    var entityData = this.get();
+    var password = this.get("password");
+    var oldpassword = this.get("oldpassword");
+    var newpassword = this.get("newpassword");
+    //remove system specific properties
+    for (var item in entityData) {
+        if (item === "metadata" || item === "created" || item === "modified" || item === "oldpassword" || item === "newpassword" || //old and new pw not added to data
+        item === "type" || item === "activated" || item === "uuid") {
+            continue;
+        }
+        data[item] = entityData[item];
     }
-  });
+    var options = {
+        method: method,
+        endpoint: type,
+        body: data
+    };
+    //save the entity first
+    this._client.request(options, function(err, retdata) {
+        //clear out pw info if present
+        self.set("password", null);
+        self.set("oldpassword", null);
+        self.set("newpassword", null);
+        if (err && self._client.logging) {
+            console.log("could not save entity");
+            if (typeof callback === "function") {
+                return callback(err, retdata, self);
+            }
+        } else {
+            if (retdata.entities) {
+                if (retdata.entities.length) {
+                    var entity = retdata.entities[0];
+                    self.set(entity);
+                    var path = retdata.path;
+                    //for connections, API returns type
+                    while (path.substring(0, 1) === "/") {
+                        path = path.substring(1);
+                    }
+                    self.set("type", path);
+                }
+            }
+            //if this is a user, update the password if it has been specified;
+            var needPasswordChange = (self.get("type") === "user" || self.get("type") === "users") && oldpassword && newpassword;
+            if (needPasswordChange) {
+                //Note: we have a ticket in to change PUT calls to /users to accept the password change
+                //      once that is done, we will remove this call and merge it all into one
+                var pwdata = {};
+                pwdata.oldpassword = oldpassword;
+                pwdata.newpassword = newpassword;
+                var options = {
+                    method: "PUT",
+                    endpoint: type + "/password",
+                    body: pwdata
+                };
+                self._client.request(options, function(err, data) {
+                    if (err && self._client.logging) {
+                        console.log("could not update user");
+                    }
+                    //remove old and new password fields so they don't end up as part of the entity object
+                    self.set("oldpassword", null);
+                    self.set("newpassword", null);
+                    if (typeof callback === "function") {
+                        callback(err, data, self);
+                    }
+                });
+            } else if (typeof callback === "function") {
+                callback(err, retdata, self);
+            }
+        }
+    });
 };
 
 /*
@@ -1063,93 +1080,92 @@ Usergrid.Entity.prototype.save = function (callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Entity.prototype.fetch = function (callback) {
-  var type = this.get('type');
-  var self = this;
-
-  //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
-  try {
-    if (type === undefined) {
-      throw 'cannot fetch entity, no entity type specified'
-    } else if (this.get('uuid')) {
-      type += '/' + this.get('uuid');
-    } else if (type === 'users' && this.get('username')) {
-      type += '/' + this.get('username');
-    } else if (this.get('name')) {
-      type += '/' + encodeURIComponent(this.get('name'));
-    } else if (typeof(callback) === 'function') {
-      throw 'no_name_specified';
-    }
-  } catch (e) {
-    if (self._client.logging) {
-      console.log(e);
-    }
-    return callback(true, {
-      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) {
-        if (data.entities.length) {
-          var entity = data.entities[0];
-          self.set(entity);
-        }
-      }
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data, self);
+Usergrid.Entity.prototype.fetch = function(callback) {
+    var type = this.get("type");
+    var self = this;
+    //Check for an entity type, then if a uuid is available, use that, otherwise, use the name
+    try {
+        if (type === undefined) {
+            throw "cannot fetch entity, no entity type specified";
+        } else if (this.get("uuid")) {
+            type += "/" + this.get("uuid");
+        } else if (type === "users" && this.get("username")) {
+            type += "/" + this.get("username");
+        } else if (this.get("name")) {
+            type += "/" + encodeURIComponent(this.get("name"));
+        } else if (typeof callback === "function") {
+            throw "no_name_specified";
+        }
+    } catch (e) {
+        if (self._client.logging) {
+            console.log(e);
+        }
+        return callback(true, {
+            error: e
+        }, self);
     }
-  });
-};
-
-/*
- *  deletes the entity from the database - will only delete
- *  if the object has a valid uuid
- *
- *  @method destroy
+    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) {
+                if (data.entities.length) {
+                    var entity = data.entities[0];
+                    self.set(entity);
+                }
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data, 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 type = this.get('type');
-  if (isUUID(this.get('uuid'))) {
-    type += '/' + this.get('uuid');
-  } else {
-    if (typeof(callback) === 'function') {
-      var error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-  }
-  var options = {
-    method:'DELETE',
-    endpoint:type
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be deleted');
+Usergrid.Entity.prototype.destroy = function(callback) {
+    var self = this;
+    var type = this.get("type");
+    if (isUUID(this.get("uuid"))) {
+        type += "/" + this.get("uuid");
     } else {
-      self.set(null);
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+        if (typeof callback === "function") {
+            var error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
     }
-  });
+    var options = {
+        method: "DELETE",
+        endpoint: type
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be deleted");
+        } else {
+            self.set(null);
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1163,52 +1179,48 @@ Usergrid.Entity.prototype.destroy = function (callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.connect = function (connection, entity, callback) {
-
-  var self = this;
-
-  var error;
-  //connectee info
-  var connecteeType = entity.get('type');
-  var connectee = this.getEntityId(entity);
-  if (!connectee) {
-    if (typeof(callback) === 'function') {
-      error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  //connector info
-  var connectorType = this.get('type');
-  var connector = this.getEntityId(this);
-  if (!connector) {
-    if (typeof(callback) === 'function') {
-      error = 'Error in connect - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
-  var options = {
-    method:'POST',
-    endpoint:endpoint
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be connected');
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+Usergrid.Entity.prototype.connect = function(connection, entity, callback) {
+    var self = this;
+    var error;
+    //connectee info
+    var connecteeType = entity.get("type");
+    var connectee = this.getEntityId(entity);
+    if (!connectee) {
+        if (typeof callback === "function") {
+            error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
+    }
+    //connector info
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        if (typeof callback === "function") {
+            error = "Error in connect - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
     }
-  });
+    var endpoint = connectorType + "/" + connector + "/" + connection + "/" + connecteeType + "/" + connectee;
+    var options = {
+        method: "POST",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be connected");
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1221,18 +1233,18 @@ Usergrid.Entity.prototype.connect = function (connection, entity, callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.getEntityId = function (entity) {
-  var id = false;
-  if (isUUID(entity.get('uuid'))) {
-    id = entity.get('uuid');
-  } else {
-    if (type === 'users') {
-      id = entity.get('username');
-    } else if (entity.get('name')) {
-      id = entity.get('name');
+Usergrid.Entity.prototype.getEntityId = function(entity) {
+    var id = false;
+    if (isUUID(entity.get("uuid"))) {
+        id = entity.get("uuid");
+    } else {
+        if (type === "users") {
+            id = entity.get("username");
+        } else if (entity.get("name")) {
+            id = entity.get("name");
+        }
     }
-  }
-  return id;
+    return id;
 };
 
 /*
@@ -1246,241 +1258,195 @@ Usergrid.Entity.prototype.getEntityId = function (entity) {
  *  @return {callback} callback(err, data, connections)
  *
  */
-Usergrid.Entity.prototype.getConnections = function (connection, callback) {
-
-  var self = this;
-
-  //connector info
-  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);
-      }
-      callback(true, error);
-    }
-    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.entities.length;
-    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]
-      }
-    }
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
+Usergrid.Entity.prototype.getConnections = function(connection, callback) {
+    var self = this;
+    //connector info
+    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);
+            }
+            callback(true, error);
+        }
+        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.entities.length;
+        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];
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
-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.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;
-
-    if (typeof(callback) === 'function') {
-      callback(err, data, data.entities);
-    }
-  });
-
+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.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;
+        if (typeof callback === "function") {
+            callback(err, data, data.entities);
+        }
+    });
 };
 
 /*
@@ -1494,52 +1460,48 @@ Usergrid.Entity.prototype.getPermissions = function (callback) {
  *  @return {callback} callback(err, data)
  *
  */
-Usergrid.Entity.prototype.disconnect = function (connection, entity, callback) {
-
-  var self = this;
-
-  var error;
-  //connectee info
-  var connecteeType = entity.get('type');
-  var connectee = this.getEntityId(entity);
-  if (!connectee) {
-    if (typeof(callback) === 'function') {
-      error = 'Error trying to delete object - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  //connector info
-  var connectorType = this.get('type');
-  var connector = this.getEntityId(this);
-  if (!connector) {
-    if (typeof(callback) === 'function') {
-      error = 'Error in connect - no uuid specified.';
-      if (self._client.logging) {
-        console.log(error);
-      }
-      callback(true, error);
-    }
-    return;
-  }
-
-  var endpoint = connectorType + '/' + connector + '/' + connection + '/' + connecteeType + '/' + connectee;
-  var options = {
-    method:'DELETE',
-    endpoint:endpoint
-  };
-  this._client.request(options, function (err, data) {
-    if (err && self._client.logging) {
-      console.log('entity could not be disconnected');
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+Usergrid.Entity.prototype.disconnect = function(connection, entity, callback) {
+    var self = this;
+    var error;
+    //connectee info
+    var connecteeType = entity.get("type");
+    var connectee = this.getEntityId(entity);
+    if (!connectee) {
+        if (typeof callback === "function") {
+            error = "Error trying to delete object - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
+    }
+    //connector info
+    var connectorType = this.get("type");
+    var connector = this.getEntityId(this);
+    if (!connector) {
+        if (typeof callback === "function") {
+            error = "Error in connect - no uuid specified.";
+            if (self._client.logging) {
+                console.log(error);
+            }
+            callback(true, error);
+        }
+        return;
     }
-  });
+    var endpoint = connectorType + "/" + connector + "/" + connection + "/" + connecteeType + "/" + connectee;
+    var options = {
+        method: "DELETE",
+        endpoint: endpoint
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("entity could not be disconnected");
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1553,87 +1515,77 @@ Usergrid.Entity.prototype.disconnect = function (connection, entity, callback) {
  *  @return {callback} callback(err, data)
  */
 Usergrid.Collection = function(options, callback) {
-
-  if (options) {
-    this._client = options.client;
-    this._type = options.type;
-    this.qs = options.qs || {};
-
-    //iteration
-    this._list = options.list || [];
-    this._iterator = options.iterator || -1; //first thing we do is increment, so set to -1
-
-    //paging
-    this._previous = options.previous || [];
-    this._next = options.next || null;
-    this._cursor = options.cursor || null;
-
-    //restore entities if available
-    if (options.list) {
-      var count = options.list.length;
-      for(var i=0;i<count;i++){
-        //make new entity with
-        var entity = this._client.restoreEntity(options.list[i]);
-        this._list[i] = entity;
-      }
+    if (options) {
+        this._client = options.client;
+        this._type = options.type;
+        this.qs = options.qs || {};
+        //iteration
+        this._list = options.list || [];
+        this._iterator = options.iterator || -1;
+        //first thing we do is increment, so set to -1
+        //paging
+        this._previous = options.previous || [];
+        this._next = options.next || null;
+        this._cursor = options.cursor || null;
+        //restore entities if available
+        if (options.list) {
+            var count = options.list.length;
+            for (var i = 0; i < count; i++) {
+                //make new entity with
+                var entity = this._client.restoreEntity(options.list[i]);
+                this._list[i] = entity;
+            }
+        }
+    }
+    if (callback) {
+        //populate the collection
+        this.fetch(callback);
     }
-  }
-  if (callback) {
-    //populate the collection
-    this.fetch(callback);
-  }
-
 };
 
-
 /*
  *  gets the data from the collection object for serialization
  *
  *  @method serialize
  *  @return {object} data
  */
-Usergrid.Collection.prototype.serialize = function () {
-
-  //pull out the state from this object and return it
-  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;
-      callback(err, collection);
-    }
-  });
+Usergrid.Collection.prototype.serialize = function() {
+    //pull out the state from this object and return it
+    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;
+            callback(err, collection);
+        }
+    });
 };
 
 /*
@@ -1643,58 +1595,59 @@ Usergrid.Collection.prototype.addCollection = function (collectionName, options,
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Collection.prototype.fetch = function (callback) {
-  var self = this;
-  var qs = this.qs;
-
-  //add in the cursor if one is available
-  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, data) {
-    if(err && self._client.logging) {
-      console.log('error getting collection');
+Usergrid.Collection.prototype.fetch = function(callback) {
+    var self = this;
+    var qs = this.qs;
+    //add in the cursor if one is available
+    if (this._cursor) {
+        qs.cursor = this._cursor;
     } else {
-      //save the cursor if there is one
-      var cursor = data.cursor || null;
-      self.saveCursor(cursor);
-      if (data.entities) {
-        self.resetEntityPointer();
-        var count = data.entities.length;
-        //save entities locally
-        self._list = []; //clear the local list first
-        for (var i=0;i<count;i++) {
-          var uuid = data.entities[i].uuid;
-          if (uuid) {
-            var entityData = data.entities[i] || {};
-            self._baseType = data.entities[i].type; //store the base type in the collection
-            entityData.type = self._type;//make sure entities are same type (have same path) as parent collection.
-            var entityOptions = {
-              type:self._type,
-              client:self._client,
-              uuid:uuid,
-              data:entityData
-            };
-
-            var ent = new Usergrid.Entity(entityOptions);
-            ent._json = JSON.stringify(entityData, null, 2);
-            var ct = self._list.length;
-            self._list[ct] = ent;
-          }
-        }
-      }
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, data);
+        delete qs.cursor;
     }
-  });
+    var options = {
+        method: "GET",
+        endpoint: this._type,
+        qs: this.qs
+    };
+    this._client.request(options, function(err, data) {
+        if (err && self._client.logging) {
+            console.log("error getting collection");
+        } else {
+            //save the cursor if there is one
+            var cursor = data.cursor || null;
+            self.saveCursor(cursor);
+            if (data.entities) {
+                self.resetEntityPointer();
+                var count = data.entities.length;
+                //save entities locally
+                self._list = [];
+                //clear the local list first
+                for (var i = 0; i < count; i++) {
+                    var uuid = data.entities[i].uuid;
+                    if (uuid) {
+                        var entityData = data.entities[i] || {};
+                        self._baseType = data.entities[i].type;
+                        //store the base type in the collection
+                        entityData.type = self._type;
+                        //make sure entities are same type (have same path) as parent collection.
+                        var entityOptions = {
+                            type: self._type,
+                            client: self._client,
+                            uuid: uuid,
+                            data: entityData
+                        };
+                        var ent = new Usergrid.Entity(entityOptions);
+                        ent._json = JSON.stringify(entityData, null, 2);
+                        var ct = self._list.length;
+                        self._list[ct] = ent;
+                    }
+                }
+            }
+        }
+        if (typeof callback === "function") {
+            callback(err, data);
+        }
+    });
 };
 
 /*
@@ -1705,27 +1658,26 @@ Usergrid.Collection.prototype.fetch = function (callback) {
  *  @param {function} callback
  *  @return {callback} callback(err, data, entity)
  */
-Usergrid.Collection.prototype.addEntity = function (options, callback) {
-  var self = this;
-  options.type = this._type;
-
-  //create the new entity
-  this._client.createEntity(options, function (err, entity) {
-    if (!err) {
-      //then add the entity to the list
-      var count = self._list.length;
-      self._list[count] = entity;
-    }
-    if (typeof(callback) === 'function') {
-      callback(err, entity);
-    }
-  });
+Usergrid.Collection.prototype.addEntity = function(options, callback) {
+    var self = this;
+    options.type = this._type;
+    //create the new entity
+    this._client.createEntity(options, function(err, entity) {
+        if (!err) {
+            //then add the entity to the list
+            var count = self._list.length;
+            self._list[count] = entity;
+        }
+        if (typeof callback === "function") {
+            callback(err, entity);
+        }
+    });
 };
 
-Usergrid.Collection.prototype.addExistingEntity = function (entity) {
-  //entity should already exist in the db, so just add it to the list
-  var count = this._list.length;
-  this._list[count] = entity;
+Usergrid.Collection.prototype.addExistingEntity = function(entity) {
+    //entity should already exist in the db, so just add it to the list
+    var count = this._list.length;
+    this._list[count] = entity;
 };
 
 /*
@@ -1736,35 +1688,34 @@ Usergrid.Collection.prototype.addExistingEntity = function (entity) {
  *  @param {function} callback
  *  @return {callback} callback(err, data)
  */
-Usergrid.Collection.prototype.destroyEntity = function (entity, callback) {
-  var self = this;
-  entity.destroy(function(err, data) {
-    if (err) {
-      if (self._client.logging) {
-        console.log('could not destroy entity');
-      }
-      if (typeof(callback) === 'function') {
-        callback(err, data);
-      }
-    } else {
-      //destroy was good, so repopulate the collection
-      self.fetch(callback);
-    }
-  });
-  //remove entity from the local store
-  this.removeEntity(entity);
+Usergrid.Collection.prototype.destroyEntity = function(entity, callback) {
+    var self = this;
+    entity.destroy(function(err, data) {
+        if (err) {
+            if (self._client.logging) {
+                console.log("could not destroy entity");
+            }
+            if (typeof callback === "function") {
+                callback(err, data);
+            }
+        } else {
+            //destroy was good, so repopulate the collection
+            self.fetch(callback);
+        }
+    });
+    //remove entity from the local store
+    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);
+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 false;
+    return false;
 };
 
 /*
@@ -1775,25 +1726,23 @@ Usergrid.Collection.prototype.removeEntity = function (entity) {
  *  @param {function} callback
  *  @return {callback} callback(err, data, entity)
  */
-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;
+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;
+        }
     }
-  }
-
-  //get the entity from the database
-  var options = {
-    data: {
-      type: this._type,
-      uuid:uuid
-    },
-    client: this._client
-  }
-  var entity = new Usergrid.Entity(options);
-  entity.fetch(callback);
+    //get the entity from the database
+    var options = {
+        data: {
+            type: this._type,
+            uuid: uuid
+        },
+        client: this._client
+    };
+    var entity = new Usergrid.Entity(options);
+    entity.fetch(callback);
 };
 
 /*
@@ -1802,12 +1751,12 @@ Usergrid.Collection.prototype.getEntityByUUID = function (uuid, callback) {
  *  @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;
+Usergrid.Collection.prototype.getFirstEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[0];
+    }
+    return null;
 };
 
 /*
@@ -1816,12 +1765,12 @@ Usergrid.Collection.prototype.getFirstEntity = function () {
  *  @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;
+Usergrid.Collection.prototype.getLastEntity = function() {
+    var count = this._list.length;
+    if (count > 0) {
+        return this._list[count - 1];
+    }
+    return null;
 };
 
 /*
@@ -1833,13 +1782,13 @@ Usergrid.Collection.prototype.getLastEntity = function () {
  *  @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.l

<TRUNCATED>

[07/27] split up SDK into separate files for logical pieces. Added Grunt build to put them together. Added mocha tests

Posted by sn...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/test.html
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/test.html b/sdks/html5-javascript/tests/test.html
new file mode 100755
index 0000000..99525e2
--- /dev/null
+++ b/sdks/html5-javascript/tests/test.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+   <head>
+      <title>Readme File Tests</title>
+      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+      <link rel="stylesheet" href="resources/css/bootstrap-combined.min.css" />
+      <link rel="stylesheet" href="resources/css/styles.css" />
+      <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript"></script>
+      <script src="../usergrid.js" type="text/javascript"></script>
+      <script src="test.js" type="text/javascript"></script>
+      <script type="text/javascript">
+
+      </script>
+   </head>
+   <body>
+      <div class="header">
+         <img src="resources/images/apigee.png"> App Services (Usergrid) Javascript SDK
+      </div>
+      <div class="info">
+      This sample application runs tests on the sample code examples in the readme file.  Tests are run against App Services (Usergrid) using the Usergrid Javascript SDK.
+      </div>
+    <div id="main" class="main">
+      <div class="section-header">README sample code tests</div>
+      <div class="well">
+        <div id="name-control" class="control-group">
+          <div class="controls">
+            <button class="btn btn-primary" id="start-button" style="width: 90px;">Start</button>
+            <span style="clear: both;">&nbsp;</span>
+          </div>
+        </div>
+      </div>
+      <div class="section-header"><b>Test Output</b></div>
+      <div class="well">
+        <pre id="test-output">// Press Start button to begin</pre>
+      </div>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-usergrid/blob/ef53b3b5/sdks/html5-javascript/tests/test.js
----------------------------------------------------------------------
diff --git a/sdks/html5-javascript/tests/test.js b/sdks/html5-javascript/tests/test.js
new file mode 100755
index 0000000..dcfd735
--- /dev/null
+++ b/sdks/html5-javascript/tests/test.js
@@ -0,0 +1,910 @@
+/**
+* Test suite for all the examples in the readme
+*
+* NOTE: No, this test suite doesn't use the traditional format for
+* a test suite.  This is because the goal is to require as little
+* alteration as possible during the copy / paste operation from this test
+* suite to the readme file.
+*
+* @author rod simpson (rod@apigee.com)
+*/
+
+$(document).ready(function () {
+
+//call the runner function to start the process
+$('#start-button').bind('click', function() {
+	$('#start-button').attr("disabled", "disabled");
+	$('#test-output').html('');
+	runner(0);
+});
+
+var logSuccess = true;
+var successCount = 0;
+var logError = true;
+var errorCount = 0;
+var logNotice = true;
+var _username = 'marty2';
+var _email = 'marty2@timetravel.com';
+var _password = 'password2';
+var _newpassword = 'password3';
+
+var client = new Usergrid.Client({
+	orgName:'yourorgname',
+	appName:'sandbox',
+	logging: true, //optional - turn on logging, off by default
+	buildCurl: true //optional - turn on curl commands, off by default
+});
+
+client.logout();
+
+function runner(step, arg, arg2){
+	step++;
+	switch(step)
+	{
+		case 1:
+			notice('-----running step '+step+': DELETE user from DB to prep test');
+			clearUser(step);
+			break;
+		case 2:
+			notice('-----running step '+step+': GET test');
+			testGET(step);
+			break;
+		case 3:
+			notice('-----running step '+step+': POST test');
+			testPOST(step);
+			break;
+		case 4:
+			notice('-----running step '+step+': PUT test');
+			testPUT(step);
+			break;
+		case 5:
+			notice('-----running step '+step+': DELETE test');
+			testDELETE(step);
+			break;
+		case 6:
+			notice('-----running step '+step+': prepare database - remove all dogs (no real dogs harmed here!!)');
+			cleanupAllDogs(step);
+			break;
+		case 7:
+			notice('-----running step '+step+': make a new dog');
+			makeNewDog(step);
+			break;
+		case 8:
+			notice('-----running step '+step+': update our dog');
+			updateDog(step, arg);
+			break;
+		case 9:
+			notice('-----running step '+step+': refresh our dog');
+			refreshDog(step, arg);
+			break;
+		case 10:
+			notice('-----running step '+step+': remove our dog from database (no real dogs harmed here!!)');
+			removeDogFromDatabase(step, arg);
+			break;
+		case 11:
+			notice('-----running step '+step+': make lots of dogs!');
+			makeSampleData(step, arg);
+			break;
+		case 12:
+			notice('-----running step '+step+': make a dogs collection and show each dog');
+			testDogsCollection(step);
+			break;
+		case 13:
+			notice('-----running step '+step+': get the next page of the dogs collection and show each dog');
+			getNextDogsPage(step, arg);
+			break;
+		case 14:
+			notice('-----running step '+step+': get the previous page of the dogs collection and show each dog');
+			getPreviousDogsPage(step, arg);
+			break;
+		case 15:
+			notice('-----running step '+step+': remove all dogs from the database (no real dogs harmed here!!)');
+			cleanupAllDogs(step);
+			break;
+		case 16:
+			notice('-----running step '+step+': prepare database (remove existing user if present)');
+			prepareDatabaseForNewUser(step);
+			break;
+		case 17:
+			notice('-----running step '+step+': create a new user');
+			createUser(step);
+			break;
+		case 18:
+			notice('-----running step '+step+': update the user');
+			updateUser(step, arg);
+			break;
+		case 19:
+			notice('-----running step '+step+': get the existing user');
+			getExistingUser(step, arg);
+			break;
+		case 20:
+			notice('-----running step '+step+': refresh the user from the database');
+			refreshUser(step, arg);
+			break;
+		case 21:
+			notice('-----running step '+step+': log user in');
+			loginUser(step, arg);
+			break;
+		case 22:
+			notice('-----running step '+step+': change users password');
+			changeUsersPassword(step, arg);
+			break;
+		case 23:
+			notice('-----running step '+step+': log user out');
+			logoutUser(step, arg);
+			break;
+		case 24:
+			notice('-----running step '+step+': relogin user');
+			reloginUser(step, arg);
+			break;
+		case 25:
+			notice('-----running step '+step+': logged in user creates dog');
+			createDog(step, arg);
+			break;
+		case 26:
+			notice('-----running step '+step+': logged in user likes dog');
+			userLikesDog(step, arg, arg2);
+			break;
+		case 27:
+			notice('-----running step '+step+': logged in user removes likes connection to dog');
+			removeUserLikesDog(step, arg, arg2);
+			break;
+		case 28:
+			notice('-----running step '+step+': user removes dog');
+			removeDog(step, arg, arg2);
+			break;
+		case 29:
+			notice('-----running step '+step+': log the user out');
+			logoutUser(step, arg);
+			break;
+		case 30:
+			notice('-----running step '+step+': remove the user from the database');
+			destroyUser(step, arg);
+			break;
+		case 31:
+			notice('-----running step '+step+': try to create existing entity');
+			createExistingEntity(step, arg);
+			break;
+		case 32:
+			notice('-----running step '+step+': try to create new entity with no name');
+			createNewEntityNoName(step, arg);
+			break;
+		default:
+			notice('-----test complete!-----');
+			notice('Success count= ' + successCount);
+			notice('Error count= ' + errorCount);
+			notice('-----thank you for playing!-----');
+			$('#start-button').removeAttr("disabled");
+	}
+}
+
+//logging functions
+function success(message){
+	successCount++;
+	if (logSuccess) {
+		console.log('SUCCESS: ' + message);
+		var html = $('#test-output').html();
+		html += ('SUCCESS: ' + message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+function error(message){
+	errorCount++
+	if (logError) {
+		console.log('ERROR: ' + message);
+		var html = $('#test-output').html();
+		html += ('ERROR: ' + message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+function notice(message){
+	if (logNotice) {
+		console.log('NOTICE: ' + message);
+		var html = $('#test-output').html();
+		html += (message + '\r\n');
+		$('#test-output').html(html);
+	}
+}
+
+//tests
+function clearUser(step) {
+  var options = {
+    method:'DELETE',
+    endpoint:'users/fred'
+  };
+  client.request(options, function (err, data) {
+    //data will contain raw results from API call
+    success('User cleared from DB');
+    runner(step);
+  });
+}
+
+function testGET(step) {
+	var options = {
+		method:'GET',
+		endpoint:'users'
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('GET failed');
+		} else {
+			//data will contain raw results from API call
+			success('GET worked');
+			runner(step);
+		}
+	});
+}
+
+function testPOST(step) {
+	var options = {
+		method:'POST',
+		endpoint:'users',
+		body:{ username:'fred', password:'secret' }
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('POST failed');
+		} else {
+			//data will contain raw results from API call
+			success('POST worked');
+			runner(step);
+		}
+	});
+}
+
+function testPUT(step) {
+	var options = {
+		method:'PUT',
+		endpoint:'users/fred',
+		body:{ newkey:'newvalue' }
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('PUT failed');
+		} else {
+			//data will contain raw results from API call
+			success('PUT worked');
+			runner(step);
+		}
+	});
+}
+
+function testDELETE(step) {
+	var options = {
+		method:'DELETE',
+		endpoint:'users/fred'
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			error('DELETE failed');
+		} else {
+			//data will contain raw results from API call
+			success('DELETE worked');
+			runner(step);
+		}
+	});
+}
+
+function makeNewDog(step) {
+
+	var options = {
+		type:'dogs',
+		name:'Rocky'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('dog not created');
+		} else {
+			success('dog is created');
+
+			//once the dog is created, you can set single properties:
+			dog.set('breed','Dinosaur');
+
+			//the set function can also take a JSON object:
+			var data = {
+				master:'Fred',
+				state:'hungry'
+			}
+			//set is additive, so previously set properties are not overwritten
+			dog.set(data);
+
+			//finally, call save on the object to save it back to the database
+			dog.save(function(err){
+				if (err){
+					error('dog not saved');
+				} else {
+					success('new dog is saved');
+					runner(step, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function updateDog(step, dog) {
+
+	//change a property in the object
+	dog.set("state", "fed");
+	//and save back to the database
+	dog.save(function(err){
+		if (err){
+			error('dog not saved');
+		} else {
+			success('dog is saved');
+			runner(step, dog);
+		}
+	});
+
+}
+
+function refreshDog(step, dog){
+
+	//call fetch to refresh the data from the server
+	dog.fetch(function(err){
+		if (err){
+			error('dog not refreshed from database');
+		} else {
+			//dog has been refreshed from the database
+			//will only work if the UUID for the entity is in the dog object
+			success('dog entity refreshed from database');
+			runner(step, dog);
+		}
+	});
+
+}
+
+function removeDogFromDatabase(step, dog){
+
+	//the destroy method will delete the entity from the database
+	dog.destroy(function(err){
+		if (err){
+			error('dog not removed from database');
+		} else {
+			success('dog removed from database'); // no real dogs were harmed!
+			dog = null; //no real dogs were harmed!
+			runner(step, 1);
+		}
+	});
+
+}
+
+function makeSampleData(step, i) {
+	notice('making dog '+i);
+
+	var options = {
+		type:'dogs',
+		name:'dog'+i,
+		index:i
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('dog ' + i + ' not created');
+		} else {
+			if (i >= 30) {
+				//data made, ready to go
+				success('all dogs made');
+				runner(step);
+			} else {
+				success('dog ' + i + ' made');
+				//keep making dogs
+				makeSampleData(step, ++i);
+			}
+		}
+	});
+}
+
+function testDogsCollection(step) {
+
+	var options = {
+		type:'dogs',
+		qs:{ql:'order by index'}
+	}
+
+	client.createCollection(options, function (err, dogs) {
+		if (err) {
+			error('could not make collection');
+		} else {
+
+			success('new Collection created');
+
+			//we got the dogs, now display the Entities:
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				dog = dogs.getNextEntity();
+				var name = dog.get('name');
+				notice('dog is called ' + name);
+			}
+
+			success('looped through dogs');
+
+			//create a new dog and add it to the collection
+			var options = {
+				name:'extra-dog',
+				fur:'shedding'
+			}
+			//just pass the options to the addEntity method
+			//to the collection and it is saved automatically
+			dogs.addEntity(options, function(err, dog, data) {
+				if (err) {
+					error('extra dog not saved or added to collection');
+				} else {
+					success('extra dog saved and added to collection');
+					runner(step, dogs);
+				}
+			});
+		}
+	});
+
+}
+
+function getNextDogsPage(step, dogs) {
+
+	if (dogs.hasNextPage()) {
+		//there is a next page, so get it from the server
+		dogs.getNextPage(function(err){
+			if (err) {
+				error('could not get next page of dogs');
+			} else {
+				success('got next page of dogs');
+				//we got the next page of data, so do something with it:
+				var i = 11;
+				while(dogs.hasNextEntity()) {
+					//get a reference to the dog
+					var dog = dogs.getNextEntity();
+					var index = dog.get('index');
+					if(i !== index) {
+						error('wrong dog loaded: wanted' + i + ', got ' + index);
+					}
+					notice('got dog ' + i);
+					i++
+				}
+				success('looped through dogs')
+				runner(step, dogs);
+			}
+		});
+	} else {
+		getPreviousDogsPage(dogs);
+	}
+
+}
+
+function getPreviousDogsPage(step, dogs) {
+
+	if (dogs.hasPreviousPage()) {
+		//there is a previous page, so get it from the server
+		dogs.getPreviousPage(function(err){
+			if(err) {
+				error('could not get previous page of dogs');
+			} else {
+				success('got next page of dogs');
+				//we got the previous page of data, so do something with it:
+				var i = 1;
+				while(dogs.hasNextEntity()) {
+					//get a reference to the dog
+					var dog = dogs.getNextEntity();
+					var index = dog.get('index');
+					if(i !== index) {
+						error('wrong dog loaded: wanted' + i + ', got ' + index);
+					}
+					notice('got dog ' + i);
+					i++
+				}
+				success('looped through dogs');
+				runner(step);
+			}
+		});
+	} else {
+		getAllDogs();
+	}
+}
+
+function cleanupAllDogs(step){
+
+	var options = {
+		type:'dogs',
+		qs:{limit:50} //limit statement set to 50
+	}
+
+	client.createCollection(options, function (err, dogs) {
+		if (err) {
+			error('could not get all dogs');
+		} else {
+			success('got at most 50 dogs');
+			//we got 50 dogs, now display the Entities:
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				var dog = dogs.getNextEntity();
+				var name = dog.get('name');
+				notice('dog is called ' + name);
+			}
+			dogs.resetEntityPointer();
+			//do doggy cleanup
+			while(dogs.hasNextEntity()) {
+				//get a reference to the dog
+				var dog = dogs.getNextEntity();
+				var dogname = dog.get('name');
+				notice('removing dog ' + dogname + ' from database');
+				dog.destroy(function(err, data) {
+					if (err) {
+						error('dog not removed');
+					} else {
+						success('dog removed');
+					}
+				});
+			}
+
+			//no need to wait around for dogs to be removed, so go on to next test
+			runner(step);
+		}
+	});
+}
+
+
+function prepareDatabaseForNewUser(step) {
+	var options = {
+		method:'DELETE',
+		endpoint:'users/'+_username
+	};
+	client.request(options, function (err, data) {
+		if (err) {
+			notice('database ready - no user to delete');
+		runner(step);
+		} else {
+			//data will contain raw results from API call
+			success('database ready - user deleted worked');
+			runner(step);
+		}
+	});
+}
+
+
+function createUser(step) {
+	client.signup(_username, _password, _email, 'Marty McFly',
+		function (err, marty) {
+			if (err){
+				error('user not created');
+				runner(step, marty);
+			} else {
+				success('user created');
+				runner(step, marty);
+			}
+		}
+	);
+}
+
+function updateUser(step, marty) {
+
+	//add properties cumulatively
+	marty.set('state', 'California');
+	marty.set("girlfriend","Jennifer");
+	marty.save(function(err){
+		if (err){
+			error('user not updated');
+		} else {
+			success('user updated');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function getExistingUser(step, marty) {
+
+	var options = {
+		type:'users',
+		username:_username
+	}
+	client.getEntity(options, function(err, existingUser){
+		if (err){
+			error('existing user not retrieved');
+		} else {
+			success('existing user was retrieved');
+
+			var username = existingUser.get('username');
+			if (username === _username){
+				success('got existing user username');
+			} else {
+				error('could not get existing user username');
+			}
+			runner(step, marty);
+		}
+	});
+
+}
+
+
+function refreshUser(step, marty) {
+
+	marty.fetch(function(err){
+		if (err){
+			error('not refreshed');
+		} else {
+			success('user refreshed');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function loginUser(step, marty) {
+	username = _username;
+	password = _password;
+	client.login(username, password,
+		function (err) {
+			if (err) {
+				error('could not log user in');
+			} else {
+				success('user has been logged in');
+
+				//the login call will return an OAuth token, which is saved
+				//in the client. Any calls made now will use the token.
+				//once a user has logged in, their user object is stored
+				//in the client and you can access it this way:
+				var token = client.token;
+
+				//Then make calls against the API.  For example, you can
+				//get the user entity this way:
+				client.getLoggedInUser(function(err, data, user) {
+					if(err) {
+						error('could not get logged in user');
+					} else {
+						success('got logged in user');
+
+						//you can then get info from the user entity object:
+						var username = user.get('username');
+						notice('logged in user was: ' + username);
+
+						runner(step, user);
+					}
+				});
+
+			}
+		}
+	);
+}
+
+function changeUsersPassword(step, marty) {
+
+	marty.set('oldpassword', _password);
+	marty.set('newpassword', _newpassword);
+	marty.save(function(err){
+		if (err){
+			error('user password not updated');
+		} else {
+			success('user password updated');
+			runner(step, marty);
+		}
+	});
+
+}
+
+function logoutUser(step, marty) {
+
+	//to log the user out, call the logout() method
+	client.logout();
+
+	//verify the logout worked
+	if (client.isLoggedIn()) {
+		error('logout failed');
+	} else {
+		success('user has been logged out');
+	}
+
+	runner(step, marty);
+}
+
+function reloginUser(step, marty) {
+
+	username = _username
+	password = _newpassword;
+	client.login(username, password,
+		function (err) {
+		if (err) {
+			error('could not relog user in');
+		} else {
+			success('user has been re-logged in');
+			runner(step, marty);
+		}
+		}
+	);
+}
+
+
+
+//TODO: currently, this code assumes permissions have been set to support user actions.  need to add code to show how to add new role and permission programatically
+//
+//first create a new permission on the default role:
+//POST "https://api.usergrid.com/yourorgname/yourappname/roles/default/permissions" -d '{"permission":"get,post,put,delete:/dogs/**"}'
+//then after user actions, delete the permission on the default role:
+//DELETE "https://api.usergrid.com/yourorgname/yourappname/roles/default/permissions?permission=get%2Cpost%2Cput%2Cdelete%3A%2Fdogs%2F**"
+
+
+function createDog(step, marty) {
+
+	var options = {
+		type:'dogs',
+		name:'einstein',
+		breed:'mutt'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('POST new dog by logged in user failed');
+		} else {
+			success('POST new dog by logged in user succeeded');
+			runner(step, marty, dog);
+		}
+	});
+
+}
+
+function userLikesDog(step, marty, dog) {
+
+	marty.connect('likes', dog, function (err, data) {
+		if (err) {
+			error('connection not created');
+			runner(step, marty);
+		} else {
+
+			//call succeeded, so pull the connections back down
+			marty.getConnections('likes', function (err, data) {
+				if (err) {
+						error('could not get connections');
+				} else {
+					//verify that connection exists
+					if (marty.likes.einstein) {
+						success('connection exists');
+					} else {
+						error('connection does not exist');
+					}
+
+					runner(step, marty, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function removeUserLikesDog(step, marty, dog) {
+
+	marty.disconnect('likes', dog, function (err, data) {
+		if (err) {
+			error('connection not deleted');
+			runner(step, marty);
+		} else {
+
+			//call succeeded, so pull the connections back down
+			marty.getConnections('likes', function (err, data) {
+				if (err) {
+					error('error getting connections');
+				} else {
+					//verify that connection exists
+					if (marty.likes.einstein) {
+						error('connection still exists');
+					} else {
+						success('connection deleted');
+					}
+
+					runner(step, marty, dog);
+				}
+			});
+		}
+	});
+
+}
+
+function removeDog(step, marty, dog) {
+
+	//now delete the dog from the database
+	dog.destroy(function(err, data) {
+		if (err) {
+			error('dog not removed');
+		} else {
+			success('dog removed');
+		}
+	});
+	runner(step, marty);
+}
+
+function destroyUser(step, marty) {
+
+	marty.destroy(function(err){
+		if (err){
+			error('user not deleted from database');
+		} else {
+			success('user deleted from database');
+			marty = null; //blow away the local object
+			runner(step);
+		}
+	});
+
+}
+
+function createExistingEntity(step, marty) {
+
+	var options = {
+		type:'dogs',
+		name:'einstein'
+	}
+
+	client.createEntity(options, function (err, dog) {
+		if (err) {
+			error('Create new entity to use for existing entity failed');
+		} else {
+			success('Create new entity to use for existing entity succeeded');
+
+			var uuid = dog.get('uuid');
+			//now create new entity, but use same entity name of einstein.  This means that
+			//the original einstein entity now exists.  Thus, the new einstein entity should
+			//be the same as the original + any data differences from the options var:
+
+			options = {
+				type:'dogs',
+				name:'einstein',
+				breed:'mutt'
+			}
+			client.createEntity(options, function (err, newdog) {
+				if (err) {
+					error('Create new entity to use for existing entity failed');
+				} else {
+					success('Create new entity to use for existing entity succeeded');
+
+					var newuuid = newdog.get('uuid');
+					if (newuuid === uuid) {
+						success('UUIDs of new and old entities match');
+					} else {
+						error('UUIDs of new and old entities do not match');
+					}
+
+					var breed = newdog.get('breed');
+					if (breed === 'mutt') {
+						success('attribute sucesfully set on new entity');
+					} else {
+						error('attribute not sucesfully set on new entity');
+					}
+
+					newdog.destroy(function(err){
+						if (err){
+							error('existing entity not deleted from database');
+						} else {
+							success('existing entity deleted from database');
+							dog = null; //blow away the local object
+							newdog = null; //blow away the local object
+							runner(step);
+						}
+					});
+
+				}
+			});
+		}
+	});
+
+}
+
+function createNewEntityNoName(step, marty) {
+
+	var options = {
+   type:"something",
+   othervalue:"something else"
+	}
+
+	client.createEntity(options, function (err, entity) {
+		if (err) {
+			error('Create new entity with no name failed');
+		} else {
+			success('Create new entity with no name succeeded');
+
+      entity.destroy();
+      runner(step);
+		}
+	});
+
+}
+
+});
\ No newline at end of file


[18/27] git commit: built with the new Events module included

Posted by sn...@apache.org.
built with the new Events module included


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

Branch: refs/pull/34/merge
Commit: 8367ea49bb900444556d9ea1c41758bb8b58dcfd
Parents: ef53b3b
Author: ryan bridges <rb...@apigee.com>
Authored: Tue Jan 21 11:14:16 2014 -0500
Committer: ryan bridges <rb...@apigee.com>
Committed: Tue Jan 21 11:14:16 2014 -0500

----------------------------------------------------------------------
 sdks/html5-javascript/usergrid.js     | 3056 ++++++++++++++--------------
 sdks/html5-javascript/usergrid.min.js |    3 +-
 2 files changed, 1556 insertions(+), 1503 deletions(-)
----------------------------------------------------------------------