Refactoring
diff --git a/asterix-examples/src/main/resources/black-cherry/cherry.tpl b/asterix-examples/src/main/resources/black-cherry/cherry.tpl
index 778043e..af3220f 100755
--- a/asterix-examples/src/main/resources/black-cherry/cherry.tpl
+++ b/asterix-examples/src/main/resources/black-cherry/cherry.tpl
@@ -201,10 +201,6 @@
         <div class="modal fade" id="drilldown_modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
           <div class="modal-dialog">
             <div class="modal-content">
-              <div class="modal-header">
-                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-                <h4 class="modal-title">Explore Tweets</h4>
-              </div>
               <div class="modal-body" id="drilldown_modal_body">
               
                 <!-- Tweet -->
diff --git a/asterix-examples/src/main/resources/black-cherry/static/js/asterix-sdk-stable.js b/asterix-examples/src/main/resources/black-cherry/static/js/asterix-sdk-stable.js
index a6b3978..cd467ce 100755
--- a/asterix-examples/src/main/resources/black-cherry/static/js/asterix-sdk-stable.js
+++ b/asterix-examples/src/main/resources/black-cherry/static/js/asterix-sdk-stable.js
@@ -1,7 +1,25 @@
+/**
+* Asterix SDK - Beta Version
+* @author Eugenia Gabrielov <genia.likes.science@gmail.com>
+* 
+* This is a Javascript helper file for generating AQL queries for AsterixDB (https://code.google.com/p/asterixdb/) 
+*/
+
+/**
+* AsterixDBConnection
+* 
+* This is a handler for connections to a local AsterixDB REST API Endpoint. 
+* This initialization takes as input a configuraiton object, and initializes
+* same basic functionality. 
+*/
 function AsterixDBConnection(configuration) {
     this._properties = {};
     this._properties["dataverse"] = "";
     this._properties["mode"] = "synchronous";
+    this._properties["error"] = function (e) {
+        // TODO Needs to be more informative
+        //alert(e);
+    }
 
     // This is a demo setup related fix. Enabled by proxy to Asterix REST API.
     this._properties["endpoint_root"] = "/";
@@ -16,6 +34,11 @@
 }
 
 
+/**
+* dataverse
+*
+* Sets dataverse for execution for the AsterixDBConnection.
+*/
 AsterixDBConnection.prototype.dataverse = function(dataverseName) {
     this._properties["dataverse"] = dataverseName;
     
@@ -23,6 +46,14 @@
 };
 
 
+/**
+* query (http://asterix.ics.uci.edu/documentation/api.html#QueryApi)
+* 
+* @param statements, statements of an AQL query
+* @param successFn, a function to execute if this query is run successfully
+* @param mode, a string either "synchronous" or "asynchronous", depending on preferred
+*               execution mode. 
+*/
 AsterixDBConnection.prototype.query = function(statements, successFn, mode) {
  
     if ( typeof statements === 'string') {
@@ -30,7 +61,7 @@
     }
     
     var m = typeof mode ? mode : "synchronous";
-    
+     
     var query = "use dataverse " + this._properties["dataverse"] + ";\n" + statements.join("\n");
     
     this._api(
@@ -45,11 +76,17 @@
     return this;
 };
 
-
-AsterixDBConnection.prototype.query_status = function(data, successFn) {
-
+/**
+* query_status (http://asterix.ics.uci.edu/documentation/api.html#QueryStatusApi)
+* 
+* @param handle, a json object of the form {"handle" : handleObject}, where
+*                   the handle object is an opaque handle previously returned
+*                   from an asynchronous call.
+* @param successFn, a function to call on successful execution of this API call.
+*/
+AsterixDBConnection.prototype.query_status = function(handle, successFn) {
     this._api(
-        data,
+        handle,
         successFn,
         "query/status"
     );
@@ -58,9 +95,17 @@
 };
 
 
-AsterixDBConnection.prototype.query_result = function(data, successFn) {
+/**
+* query_result (http://asterix.ics.uci.edu/documentation/api.html#AsynchronousResultApi)
+* 
+* handle, a json object of the form {"handle" : handleObject}, where
+*           the handle object is an opaque handle previously returned
+*           from an asynchronous call.
+* successFn, a function to call on successful execution of this API call.
+*/
+AsterixDBConnection.prototype.query_result = function(handle, successFn) {
     this._api(
-        data,
+        handle,
         successFn,
         "query/result"
     ); 
@@ -69,6 +114,12 @@
 };
 
 
+/**
+* ddl (http://asterix.ics.uci.edu/documentation/api.html#DdlApi)
+* 
+* @param statements, statements to run through ddl api
+* @param successFn, a function to execute if they are successful
+*/
 AsterixDBConnection.prototype.ddl = function(statements, successFn) {
     if ( typeof statements === 'string') {
         statements = [ statements ];
@@ -84,6 +135,15 @@
 }
 
 
+/**
+* update (http://asterix.ics.uci.edu/documentation/api.html#UpdateApi)
+*
+* @param statements, statement(s) for an update API call
+* @param successFn, a function to run if this is executed successfully.
+* 
+* This is an AsterixDBConnection handler for the update API. It passes statements provided
+* to the internal API endpoint handler.
+*/
 AsterixDBConnection.prototype.update = function(statements, successFn) {
     if ( typeof statements === 'string') {
         statements = [ statements ];
@@ -99,8 +159,51 @@
 }
 
 
+/**
+* meta
+* @param statements, a string or a list of strings representing an Asterix query object
+* @param successFn, a function to execute if call succeeds
+*
+* Queries without a dataverse. This is a work-around for an Asterix REST API behavior
+* that sometiems throws an error. This is handy for Asterix Metadata queries.
+*/
+AsterixDBConnection.prototype.meta = function(statements, successFn) {
+
+    if ( typeof statements === 'string') {
+        statements = [ statements ];
+    }
+    
+    var query = statements.join("\n");
+    
+    this._api(
+        {
+            "query" : query,
+            "mode"  : "synchronous"
+        },
+        successFn, 
+        "query"
+    );
+
+    return this;
+}
+
+
+/**
+* _api
+*
+* @param json, the data to be passed with the request
+* @param onSuccess, the success function to be run if this succeeds
+* @param endpoint, a string representing one of the Asterix API endpoints 
+* 
+* Documentation of endpoints is here:
+* http://asterix.ics.uci.edu/documentation/api.html
+*
+* This is treated as an internal method for making the actual call to the API.
+* TODO Fix jquery dependency
+*/
 AsterixDBConnection.prototype._api = function(json, onSuccess, endpoint) {
     var success_fn = onSuccess;
+    var error_fn = this._properties["error"];
     var endpoint_url = this._properties["endpoint_root"] + endpoint;    
 
     $.ajax({
@@ -112,12 +215,14 @@
             success_fn(data);
         },
         error: function(xhr, status, error) {
+            error_fn(error);
         }
     });
     
     return this;
 };
 
+// TODO Better documentation below here.
 
 // Asterix Expressions - Base
 function AExpression () {
diff --git a/asterix-examples/src/main/resources/black-cherry/static/js/cherry.js b/asterix-examples/src/main/resources/black-cherry/static/js/cherry.js
index 7918648..6268758 100755
--- a/asterix-examples/src/main/resources/black-cherry/static/js/cherry.js
+++ b/asterix-examples/src/main/resources/black-cherry/static/js/cherry.js
@@ -240,7 +240,7 @@
 		        "data" : formData
 		    };
 		
-		    // TODO
+		    // TODO Make dialog work correctly.
 		    //$('#dialog').html(APIqueryTracker["query"]);
         
             if (build_cherry_mode == "synchronous") {
@@ -297,11 +297,6 @@
 
 
 /**
-* 
-*/
-
-
-/**
 * getAllDataverseTweetbooks
 * 
 * no params
@@ -309,31 +304,38 @@
 * Returns all datasets of type TweetbookEntry, populates review_mode_tweetbooks
 */
 function getAllDataverseTweetbooks(fn_tweetbooks) {
-    // Tweetbook Metadata Query
-    var getTweetbooks = new FLWOGRExpression()
+
+    // This creates a query to the Metadata for datasets of type
+    // TweetBookEntry. Note that if we throw in a WhereClause (commented out below)
+    // there is an odd error. This is being fixed and will be removed from this demo.
+    var getTweetbooksQuery = new FLWOGRExpression()
         .ForClause("$ds", new AExpression("dataset Metadata.Dataset"))
-        .WhereClause(new AExpression('$ds.DataTypeName = "TweetbookEntry"'))
+        //.WhereClause(new AExpression('$ds.DataTypeName = "TweetbookEntry"'))
         .ReturnClause({
-            "tweetbookTitle" : "$ds.DatasetName",
+            "DataTypeName" : "$ds.DataTypeName",
+            "DatasetName" : "$ds.DatasetName"
         });
     
-    // Run query
-    A.query(getTweetbooks.val(), function(r) {
+    // Now create a function that will be called when tweetbooks succeed.
+    // In this case, we want to parse out the results object from the Asterix
+    // REST API response.
+    var tweetbooksSuccess = function(r) {
         // Parse tweetbook metadata results
-        var tweetbookMetadata = r["results"];
-        
-        // Add existing tweetbooks
-        review_mode_tweetbooks = [];
-        $.each(tweetbookMetadata, function (i, v) {
-            review_mode_tweetbooks.push(tweetbookMetadata[i].split(": \"")[1].split("\"")[0]);
+        $.each(r.results, function(i, data) {
+            if ($.parseJSON(data)["DataTypeName"] == "TweetbookEntry") {
+                review_mode_tweetbooks.push($.parseJSON(data)["DatasetName"]);
+            }
         });
         
-        // Populate review screen, if possible.
+        // Now, if any tweetbooks already exist, opulate review screen.
         $('#review-tweetbook-titles').html('');
-        for (tb in review_mode_tweetbooks) {
-            addTweetBookDropdownItem(review_mode_tweetbooks[tb]);
-        }
-    });
+        $.each(review_mode_tweetbooks, function(i, tweetbook) {
+            addTweetBookDropdownItem(tweetbook);
+        });
+    };
+    
+    // Now, we are ready to run a query. 
+    A.meta(getTweetbooksQuery.val(), tweetbooksSuccess);
     
 }
 
@@ -468,48 +470,65 @@
 *
 * { "cell": { rectangle: [{ point: [22.5, 64.5]}, { point: [24.5, 66.5]}]}, "count": { int64: 5 }}
 */
-function getRecord(cell_count_record) {
-    // This is a really hacky way to pull out the digits, but it works for now. 
-    var values = cell_count_record.replace("int64","").match(/[-+]?[0-9]*\.?[0-9]+/g);
-    var record_representation = {};
-    
-    record_representation["latSW"] = parseFloat(values[0]);
-    record_representation["lngSW"] = parseFloat(values[1]);
-    record_representation["latNE"] = parseFloat(values[2]);
-    record_representation["lngNE"] = parseFloat(values[3]);
-    record_representation["weight"] = parseInt(values[4]);
-    
-    return record_representation;
+
+/**
+* cleanJSON
+*
+* @param json, a JSON string that is not correctly formatted.
+*
+* Quick and dirty little function to clean up an Asterix JSON quirk.
+*/
+function cleanJSON(json) {
+    return json
+            .replace("rectangle", '"rectangle"')
+            .replace("point:", '"point":')
+            .replace("point:", '"point":')
+            .replace("int64", '"int64"');
 }
 
+
 /**
 * A spatial data cleaning and mapping call
 * @param    {Object}    res, a result object from a cherry geospatial query
 */
 function cherryQuerySyncCallback(res) {
-    records = res["results"];
     
-    if (typeof res["results"][0] == "object") {
-        records = res["results"][0];
-    }
-
+    // Initialize coordinates and weights, to store
+    // coordinates of map cells and their weights
+    // TODO these are all included in coordinates already...
     var coordinates = [];
     var weights = [];
+    var al = 1;
+    
+    // Parse resulting JSON objects. Here is an example record:
+    // { "cell": { rectangle: [{ point: [22.5, 64.5]}, { point: [24.5, 66.5]}]}, "count": { int64: 5 }}
+    $.each(res.results, function(i, data) {
+        
+        // First, parse a JSON object from a cleaned up string.
+        var record = $.parseJSON(cleanJSON(data));
+        
+        // Parse Coordinates and Weights into a record
+        var sw = record.cell.rectangle[0].point;
+        var ne = record.cell.rectangle[1].point;
                 
-    for (var subrecord in records) {
-        var coordinate = getRecord(records[subrecord]);
+        var coordinate = {
+            "latSW"     : sw[0],
+            "lngSW"     : sw[1],
+            "latNE"     : ne[0],
+            "lngNE"     : ne[1],
+            "weight"    : record.count.int64
+        }
+        
         weights.push(coordinate["weight"]);
         coordinates.push(coordinate);
-    }
+    });
     
     triggerUIUpdate(coordinates, weights);
-    $("#submit-button").attr("disabled", false);
 }
 
 /**
 * Triggers a map update based on a set of spatial query result cells
 * @param    [Array]     mapPlotData, an array of coordinate and weight objects
-* @param    [Array]     params, an object containing original query parameters [LEGACY]
 * @param    [Array]     plotWeights, a list of weights of the spatial cells - e.g., number of tweets
 */
 function triggerUIUpdate(mapPlotData, plotWeights) {
@@ -547,7 +566,6 @@
             };
             var map_circle = new google.maps.Circle(map_circle_options);
             map_circle.val = mapPlotData[m];
-            map_circle.ind = m;
             
             map_info_windows[m] = new google.maps.InfoWindow({
                 content: mapPlotData[m].weight + "",
@@ -557,7 +575,9 @@
             // Clicking on a circle drills down map to that value, hovering over it displays a count
             // of tweets at that location.
             google.maps.event.addListener(map_circle, 'click', function (event) {
-                map_info_windows[m].close();
+                $.each(map_info_windows, function(i) {
+                    map_info_windows[i].close();
+                });
                 onMapPointDrillDown(map_circle.val);
             });
             
@@ -707,10 +727,14 @@
             var save_metacomment_target_tweet = '"' + tweetId + '"';
         
             // Make sure content is entered, and then save this comment.
-            if (save_metacomment_target_tweetbook.length == 0) {
-                alert("Please enter a tweetbook.");
-            } else if ($("#modal-body-add-note").val() == "") {
-                alert("Please enter a comment.");
+            if ($("#modal-body-add-note").val() == "") {
+            
+                addFailureBlock("Please enter a comment.", "modal-body-message-holder");
+            
+            } else if ($("#modal-body-add-to").val() == "") {
+            
+                addFailureBlock("Please enter a tweetbook.", "modal-body-message-holder");
+            
             } else {
         
                 // Check if tweetbook exists. If not, create it.
@@ -729,10 +753,11 @@
             
                 var successMessage = "Saved comment on <b>Tweet #" + tweetId + 
                     "</b> in dataset <b>" + save_metacomment_target_tweetbook + "</b>.";
-                    addSuccessBlock(successMessage, "modal-body-message-holder");
+                addSuccessBlock(successMessage, "modal-body-message-holder");
             
                 $("#modal-body-add-to").val('');
                 $("#modal-body-add-note").val('');
+                $("#modal-body-message-holder").html('');
             }   
         });
     }
@@ -1106,6 +1131,8 @@
         map_tweet_markers[m].setMap(null);
     }
     map_tweet_markers = [];
+    
+    $("#submit-button").attr("disabled", false);
 }
 
 /**