Added TreeSearch and lots of cleaning up/improvements.

* Added watch for gulp.
* Updated README
* Various bug fixes and improvements.

Cleaning up and debugging. Gulp can now watch.

Change-Id: Ice679a326ff693fa030caf429c3c29ba94ae00cd
diff --git a/client/catalog-dev/background.jpg b/client/catalog-dev/background.jpg
deleted file mode 100644
index 7196c30..0000000
--- a/client/catalog-dev/background.jpg
+++ /dev/null
Binary files differ
diff --git a/client/catalog-dev/config-example.json b/client/catalog-dev/config-example.json
index 5a0455b..9c37d97 100644
--- a/client/catalog-dev/config-example.json
+++ b/client/catalog-dev/config-example.json
@@ -2,7 +2,7 @@
 	"global": {
 		"catalogPrefix": "/catalog",
 		"faceConfig": {
-			"host": "atmos-csu.research-lan.colostate.edu",
+			"host": "atmos-nwsc.ucar.edu",
 			"port": 9696
 		}
 	},
@@ -12,7 +12,7 @@
 			"priv": "MIIEpQIBAAKCAQEAuAmnWYKE7E8G+hyy4TiTU7t91KyIGvglEeT6HWEkW4LKzXLO22a1jVS9+yP96I6vp7N5vpS1t7oXtgWuzkO+O85u6gfbvwp+67zJe2I89eHO4dmNnP4fx/j7WcCUCyzZfbyW67h5IoouoBIdQge2Xdvh9rFdex9UUhyjEZv5676zlcqlhz8xGBrJmQHsqpD9ijY1XhKBvoSIoQ0ZKkpmwVk8QYM9PbjUqzSQBj4aYXS+BPV6aRudVvyDt2DBXp2FNP0CGrosCXKnSl4Yv8BYp0k0RmFZDuJuntLb/XIvPEfMX5li7g3zHzAlIJIVSwT+FRkd3H5cECFSIZFUYIuSQQIDAQABAoIBAQCKBftzfxavn6lM5T8m+GZN0vzRBsBg8Z/jpsYKSLOayiHNKYCIPaSFpXuCIYEo6/JDJLB2xVLvwupLgkGSwm2mrvCyJkihI38Cz6iQF6I+iia9bYrupgwxzsK7klm1c+J9kXXivYxj4hyLwmoc/mnARMtYV7cTQvDbUEzgRQmPykWKBv6Y0SL1WprfiRfKIMwSqQk91ffj6whKxBLAuUdseVBmo/ivLPq0a+wDrcvaJAxSB4eIwCHzAugkRA/NoK0vG3mra0lK5jvQrcNIuffxNAnresDVDTnYRc42etjePLAhlpeK/4sjYE/wPdeP8yzLHUg/hsSpAPIjLXJNZqUBAoGBANxPmUQNf1lGHo/nLY3dVMD3+kYNnTUD8XwS81qdg8/dNyF8t+7DOdJ1j7Itb+zGA1XXAGfTm6JoUG+eKKR2OSuyZcxygpOgzxAFanXKhTWZsKbG70xNmX0sOAEhtTGsgFTEGEv977MwIlFa6n2bsp3Luj/AGmvNsOYvBDPXOklxAoGBANXZyXAaE7M5JALusLuEFxLGvWVz6TRdQ//c+FWvKrnh+nFlTlAPpDvlaPJJca8ViNevxJ2UhGtbENXAqgwTYpnAi/yQD4dATViIveK6Pn4t12mpPAlkMbbMTR8jtp5l1oHchcwe8QuEOKuTX5+STpNGlWs+tsMb12mhCpc3eO3RAoGAMxjDE2WOA8afkACuMBkFbzwUb+r4azNe7sf2aS3fRHaqMroabuYYoxdhHJItQ10pqN8U2P/bOO+4uCqWgo5o9BmMQr7MSjEh1TVsW6V8/9GFhyjcl3XoA4Ad/SU0QTEhEofomrdqwMSJMRVFDZzu8Gov6FlFx3sNbFW7Q8rHWgECgYEAq/TVz3iIgsLdvCXmosHSM9zvCpcr3FlqhmFOpseVmaamVWxajnIlY6xSuRBpg5nTUWwas4Nq/1BYtyiXE+K6lFuJtOq6Mc145EoANkIAYkHGR0Y36m1QtGaPVQzImZHV7NJAHCR9Ov90+jIk4BErca1+FKB3IWhPzLYb6ABJEyECgYEAthhzWSxPkqyiLl+2vnhdR3EEkvDX6MV6hGu4tDAf2A1Y0GSApyEaSAA31hlxu5EgneLD7Ns2HMpIfQMydB5lcwKQc9g/tVI1eRzuk6Myi+2JmPEM2BLyiX8yI+xnZlKDiZleQitCS4RQGz5HbXT70aYQIGxuvkQ/uf68jdrL6o8="
 		},
 		"destinations": [
-			"/retrieve/demo"
+			"/retrieve/ucar"
 		]
 	}
 }
diff --git a/client/catalog-dev/css/style.css b/client/catalog-dev/css/style.css
index 94ea89f..17ba979 100644
--- a/client/catalog-dev/css/style.css
+++ b/client/catalog-dev/css/style.css
@@ -142,6 +142,10 @@
   cursor: pointer;
 }
 
+.treeExplorer .treeExplorerNode .nodeContent {
+  display: inline-block;
+}
+
 .treeExplorer .treeExplorerNode > .nodeChildren {
   display: none;
 }
@@ -168,6 +172,14 @@
   content: "\e022"
 }
 
+.treeExplorer .treeSearch{
+  display: none;
+}
+
+.treeExplorer .nodeContent:hover > .treeSearch {
+  display: inline-block;
+}
+
 #popup {
   top: 0;
   left: 0;
diff --git a/client/catalog-dev/index.html b/client/catalog-dev/index.html
index 590fcfb..6f43aa0 100644
--- a/client/catalog-dev/index.html
+++ b/client/catalog-dev/index.html
@@ -22,6 +22,7 @@
 
 <!-- Scripts -->
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-scrollTo/2.1.0/jquery.scrollTo.min.js"></script>
 <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
 <script src="../ndn-js/build/ndn.min.js"></script>
 <script src="js/autocomplete.js"></script>
@@ -168,7 +169,7 @@
           <p>Select a destination and press submit if you are sure you want to download the selected data to the selected destination.</p>
           <div class="dropdown">
             <button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">
-              Destination
+              <span id="requestDropText">Destination<span>
               <span class="caret"></span>
             </button>
             <ul id="requestDest" class="dropdown-menu"></ul>
diff --git a/client/catalog-dev/js/catalog.js b/client/catalog-dev/js/catalog.js
index d013fda..446a7c5 100644
--- a/client/catalog-dev/js/catalog.js
+++ b/client/catalog-dev/js/catalog.js
@@ -158,14 +158,40 @@
     $('#treeSearch div').treeExplorer(function(path, callback){
       console.log("Tree Explorer request", path);
       ga('send', 'event', 'tree', 'request');
-      scope.autoComplete(path, function(list){
+      scope.autoComplete(path, function(data){
+        var list = data.next;
+        var last = (data.lastComponent === true);
         console.log("Autocomplete response", list);
         callback(list.map(function(element){
-          return (path == "/"?"/":"") + element + "/";
+          return (path == "/"?"/":"") + element + (!last?"/":"");
         }));
       })
     });
 
+    $('#treeSearch').on('click', '.treeSearch', function(){
+      var t = $(this);
+
+      scope.clearResults();
+
+      var path = t.parent().parent().attr('id');
+
+      console.log("Stringing tree search:", path);
+
+      scope.query(scope.catalog, {'??': path},
+      function(interest, data){ //Success
+        console.log("Tree search response", interest, data);
+
+        scope.name = data.getContent().toString().replace(/[\n\0]+/g,'');
+
+        scope.getResults(0);
+      },
+      function(interest){ //Failure
+        console.warn("Request failed! Timeout", interest);
+        scope.createAlert("Request timed out.\""+ interest.getName().toUri() + "\" See console for details.");
+      });
+
+    });
+
     this.setupRequestForm();
 
   }
@@ -245,7 +271,7 @@
       function(interest, data){
 
         if (data.getContent().length !== 0){
-          callback(JSON.parse(data.getContent().toString().replace(/[\n\0]/g, "")).next);
+          callback(JSON.parse(data.getContent().toString().replace(/[\n\0]/g, "")));
         } else {
           callback([]);
         }
@@ -308,6 +334,8 @@
       $('#results').removeClass('hidden').slideDown();
     }
 
+    $.scrollTo("#results", 700);
+
     if ((this.results.length === this.resultCount) || (this.resultsPerPage * (index + 1) < this.results.length)){
       //console.log("We already have index", index);
       this.page = index;
@@ -452,7 +480,8 @@
 
         $('#request').modal('hide')//Initial params are ok. We can close the form.
         .remove('.alert') //Remove any alerts
-        .find('.active').removeClass('active'); //Disable the active destination
+
+        scope.cleanRequestForm();
 
         $(this).off(e); //Don't fire this again, the request must be regenerated
 
@@ -500,12 +529,13 @@
           scope.face.expressInterest(interest,
             function(interest, data){ //Success
               console.log("Request for", prefix.toUri(), "succeeded.", interest, data);
+              scope.createAlert("Data retrieval has initiated.", "alert-success");
             }, function(interest){ //Failure
-              console.error("Failure to request", prefix.toUri(), interest);
-              scope.createAlert("Failed to request " + prefix.toUri() + ". This means that the retrieve failed! See console for more details.");
+              console.error("Request for", prefix.toUri(), "timed out.", interest);
+              scope.createAlert("Request for " + prefix.toUri() + " timed out. This means that the retrieve failed! See console for more details.");
             }
           );
-        }, 10000); //Wait 10 seconds
+        }, 5000); //Wait 5 seconds
 
         scope.face.registerPrefix(retrievePrefix,
           function(prefix, interest, face, interestFilterId, filter){ //On Interest
@@ -519,7 +549,6 @@
             try {
               face.putData(data);
               console.log("Responded for", interest.getName().toUri(), data);
-              scope.createAlert("Data retrieval has initiated.", "alert-success");
             } catch (e) {
               console.error("Failed to respond to", interest.getName().toUri(), data);
               scope.createAlert("Data retrieval failed.");
@@ -644,10 +673,20 @@
 
   }
 
+  Atmos.prototype.cleanRequestForm = function(){
+    $('#requestDest').prev().removeClass('btn-success').addClass('btn-default');
+    $('#requestDropText').text('Destination');
+    $('#requestDest .active').removeClass('active');
+  }
+
   Atmos.prototype.setupRequestForm = function(){
+
+    var scope = this;
+
     this.requestForm.find('#requestCancel').click(function(){
       $('#request').unbind('submit') //Removes all event handlers.
       .modal('hide'); //Hides the form.
+      scope.cleanRequestForm();
     });
 
     var dests = $(this.config['retrieval']['destinations'].reduce(function(prev, current){
@@ -660,7 +699,10 @@
     this.requestForm.find('#requestDest').append(dests)
     .on('click', 'a', function(e){
       $('#requestDest .active').removeClass('active');
-      $(this).parent().addClass('active');
+      var t = $(this);
+      t.parent().addClass('active');
+      $('#requestDropText').text(t.text());
+      $('#requestDest').prev().removeClass('btn-default').addClass('btn-success');
     });
 
     //This code will remain unused until users must use their own keys instead of the demo key.
diff --git a/client/catalog-dev/js/treeExplorer.js b/client/catalog-dev/js/treeExplorer.js
index 5037629..6b67804 100644
--- a/client/catalog-dev/js/treeExplorer.js
+++ b/client/catalog-dev/js/treeExplorer.js
@@ -27,7 +27,8 @@
           var el = $('<div class="treeExplorerNode"></div>');
           if (current.match(/\/$/)){
             el.attr('id', path + current);
-            el.append(['<a href="#' , path , current , '">' , current , '</a>'].join(""));
+            el.append(['<div class="nodeContent"><a href="#', path, current, '">', current,
+              '</a>&nbsp;<button class="treeSearch btn btn-success btn-xs">Search from here</button></div>'].join(""));
           } else {
             el.addClass('file');
             el.text(current);
@@ -36,8 +37,8 @@
         });
       }
 
-      tree.on('click', '.treeExplorerNode > a', function(){
-        var node = $(this).parent();
+      tree.on('click', '.treeExplorerNode > .nodeContent > a', function(){
+        var node = $(this).parent().parent();
 
         if (node.hasClass('open')){ //Are we open already?
           node.removeClass('open');