shell, wip
diff --git a/planetstack/core/dashboard/shell/constants.js b/planetstack/core/dashboard/shell/constants.js
index c7498d8..dd267e2 100644
--- a/planetstack/core/dashboard/shell/constants.js
+++ b/planetstack/core/dashboard/shell/constants.js
@@ -25,7 +25,7 @@
 var DownArrowKeyCode = 40;

 

 var PTAG = function(str) {

-  return "<pre>" + str + "</pre>";

+  return '<pre class="terminal_help">' + str + '</pre>';

 }

 

 var BR = function() {

@@ -36,4 +36,4 @@
 

 var JavascriptClassNames = ['Array', 'String', 'Object']

 

-var MongoKeywords = ['help'];

+var MongoKeywords = ['help','tutorial','next','back','t0','t1','t2'];

diff --git a/planetstack/core/dashboard/shell/opencloud.js b/planetstack/core/dashboard/shell/opencloud.js
new file mode 100644
index 0000000..52c9e5c
--- /dev/null
+++ b/planetstack/core/dashboard/shell/opencloud.js
@@ -0,0 +1,35 @@
+var opencloud_data = [];
+var opencloud_data_received = false;
+
+function updateOpenCloud(onLoaded) {
+    $.ajax({url: "/admin/shelldata",
+        dataType: "json",
+        type: "GET",
+        success: function(data) {
+            opencloud_data = data;
+            if (!opencloud_data_received) {
+                opencloud_data_received = true;
+                if (onLoaded!=null) {
+                    onLoaded();
+                }
+            }
+            // do this again in 30 seconds
+            setTimeout(function() {updateOpenCloud(onLoaded)}, 10000);
+        },
+        error: function() {
+            console.log("something went wrong. trying again");
+            // do this again in 30 seconds
+            setTimeout(function() {updateOpenCloud(onLoaded)}, 10000);
+        }
+    });
+}
+
+function Slices() {
+    this.listAll = function() { return opencloud_data["slices"] }
+    this.__str__ = function() { return '["listAll"]'; }
+}
+
+function OpenCloud() {
+    this.slices = new Slices()
+    this.__str__ = function() { return '["slices"]'; }
+};
diff --git a/planetstack/core/dashboard/shell/opencloud_shell.css b/planetstack/core/dashboard/shell/opencloud_shell.css
index 1d64961..108004b 100644
--- a/planetstack/core/dashboard/shell/opencloud_shell.css
+++ b/planetstack/core/dashboard/shell/opencloud_shell.css
@@ -22,15 +22,26 @@
   color: #45FF17;
   font-size: 18px;
   font-family: Monaco, monospace;
+  border-radius:0;
 }
 
-#terminal p, #terminal pre {
+#terminal p {
   margin: 2px;
   color: #45FF17;
   font-size: 18px;
   font-family: Monaco, serif;
 }
 
+.terminal_help {
+  margin: 2px;
+  color: #45FF17;
+  font-size: 18px;
+  font-family: Monaco, serif;
+  background:black;
+  padding:0;
+  line-height:normal;
+}
+
 #terminal a {
   color: #6495ED;
 }
diff --git a/planetstack/core/dashboard/shell/opencloud_shell.js b/planetstack/core/dashboard/shell/opencloud_shell.js
index 634788a..8d850be 100644
--- a/planetstack/core/dashboard/shell/opencloud_shell.js
+++ b/planetstack/core/dashboard/shell/opencloud_shell.js
@@ -95,7 +95,7 @@
   },
 
   insertResponse: function(response) {
-    if(response.length < 3) {
+    if((response.length < 1) || (response=='"donotprintme"')) {
       this.activeLine.parent().append("<p class='response'></p>");
     }
     else {
@@ -116,7 +116,7 @@
   this._rawCommand     = "";
   this._commandStack   = 0;
   this._tutorialPtr    = 0;
-  this._tutorialMax    = 10;
+  this._tutorialMax    = 2;
 
   this._mongo          = {};
   this._mongo.test     = [];
@@ -128,7 +128,7 @@
   _process: function(inputString, errorCheck) {
     this._rawCommand += ' ' + inputString;
 
-//    try {
+    try {
       inputString += '  '; // fixes certain bugs with the tokenizer.
       var tokens    = inputString.tokens();
       var mongoFunc = this._getCommand(tokens);
@@ -142,19 +142,22 @@
       else {
         return this._evaluator(tokens);
       }
-//    }
+    }
 
-//    catch(err) {
-//        this._resetCurrentCommand();
-//        return {stack: 0, result: "JS Error: " + err};
-//    }
+    catch(err) {
+        this._resetCurrentCommand();
+        console.trace();
+        return {stack: 0, result: "JS Error: " + err};
+    }
   },
 
   // Calls eval on the input string when ready.
   _evaluator: function(tokens) {
+    isAssignment = tokens.length>=2 && tokens[0].type=="name" && tokens[1].type=="operator" && tokens[1].value=="=";
+
     this._currentCommand += " " + this._massageTokens(tokens);
     if(this._shouldEvaluateCommand(tokens))  {
-        db = "scott";
+        opencloud = new OpenCloud();
         print = this.print;
 
         // So this eval statement is the heart of the REPL.
@@ -165,8 +168,11 @@
           result = $htmlFormat(result);
         }
         this._resetCurrentCommand();
-        console.log(result);
-        return {stack: this._commandStack, result: result};
+        if (isAssignment) {
+            return {stack: this._commandStack, result: ""};
+        } else {
+            return {stack: this._commandStack, result: result};
+        }
       }
 
     else {
@@ -233,8 +239,8 @@
   // print output to the screen, e.g., in a loop
   // TODO: remove dependency here
   print: function() {
-   $('.readLine.active').parent().append('<p>' + arguments[0] + '</p>');
-   return "";
+   $('.readLine.active').parent().append('<p>' + JSON.stringify(arguments[0]) + '</p>');
+   return "donotprintme";
   },
 
   /* MongoDB     */
@@ -242,27 +248,98 @@
 
   // help command
   _help: function() {
-      return PTAG('HELP');
+      return PTAG('HELP') +
+             PTAG('opencloud.slices.listAll()       get all slices');
 
   },
 
+  _tutorial: function() {
+    this._tutorialPtr = 0;

+    return PTAG("This is a self-guided tutorial on the OpenCloud shell.") +

+           PTAG("The tutorial is simple, more or less a few basic commands to try.") +

+           PTAG("To go directly to any part tutorial, enter one of the commands t0, t1, t2...t10") +

+           PTAG("Otherwise, use 'next' and 'back'. Start by typing 'next' and pressing enter.");

+  },
+
+  // go to the next step in the tutorial.
+  _next: function() {

+    if(this._tutorialPtr < this._tutorialMax) {

+      return this['_t' + (this._tutorialPtr + 1)]();

+    }

+    else {

+      return "You've reached the end of the tutorial. To go to the beginning, type 'tutorial'";

+    }

+  },

+

+  // go to the previous step in the tutorial.

+  _back: function() {

+    if(this._tutorialPtr > 1) {

+      return this['_t' + (this._tutorialPtr - 1)]();

+    }

+    else {

+      return this._tutorial();

+    }

+  },
+
+  _t1: function() {
+    this._tutorialPtr = 1;

+    return PTAG('1. JavaScript Shell') +

+           PTAG('The first thing to notice is that the MongoDB shell is JavaScript-based.') +

+           PTAG('So you can do things like:') +

+           PTAG('  a = 5; ') +

+           PTAG('  a * 10; ') +

+           PTAG('  print(a); ') +

+           PTAG("  for(i=0; i<10; i++) { print('hello'); }; ") +

+           PTAG("Try a few JS commands; when you're ready to move on, enter 'next'");

+

+  },
+
+  _t2: function() {
+    this._tutorialPtr = 2;

+    return PTAG('2. List some slices') +

+           PTAG('Type this:') +

+           PTAG('    opencloud.slices.listAll();');

+

+  },
+
   _getCommand: function(tokens) {
     if(tokens[0] && MongoKeywords.include((tokens[0].value + '').toLowerCase())) {
       switch(tokens[0].value.toLowerCase()) {
         case 'help':
           return this._help;
+
+        case 'tutorial':
+          return this._tutorial;

+        case 'next':

+          return this._next;

+        case 'back':

+          return this._back;

+        case 't0':

+          return this._tutorial;

+        case 't1':

+          return this._t1;
+        case 't2':
+          return this._t2;
       }
     }
   }
 };
 
 $htmlFormat = function(obj) {
-  return tojson(obj, ' ', ' ', true);
+  result=tojson(obj, ' ', ' ', true);
+  return result;
 }
 
-$(document).ready(function() {
+function startTerminal() {
   var mongo       = new MongoHandler();
   var terminal    = new ReadLine({htmlForInput: DefaultInputHtml,
                                   handler: mongo._process,
                                   scoper: mongo});
+  $("#terminal_help1").show();
+  $("#terminal_help2").show();
+  $("#terminal_wait").hide();
+};
+
+$(document).ready(function() {
+    updateOpenCloud(onLoaded = startTerminal);
 });
diff --git a/planetstack/core/dashboard/shell/shell.html b/planetstack/core/dashboard/shell/shell.html
index 416bbd5..968ef99 100644
--- a/planetstack/core/dashboard/shell/shell.html
+++ b/planetstack/core/dashboard/shell/shell.html
@@ -1,17 +1,19 @@
   <div id="terminal">
     <p class="response">OpenCloud Shell</p>
     <br />
-    <p>type "help" for help</p>
-    <p>type "tutorial" to start the tutorial</p>
+    <p id="terminal_help1" style="display: none;">type "help" for help</p>
+    <p id="terminal_help2" style="display: none;">type "tutorial" to start the tutorial</p>
+    <p id="terminal_wait">Please wait while we talk to the OpenCloud server...</p>
 
   </div>
-  <link rel="stylesheet" type="text/css" href="{% static 'opencloud_shell.css' %}" media="all">
-  <script src="{% static 'opencloud_shell.js' %}"></script>
-  <script src="{% static 'object_id.js' %}"></script>
-  <script src="{% static 'constants.js' %}"></script>
-  <script src="{% static 'utils.js' %}"></script>
-  <script src="{% static 'shell_utils.js' %}"></script>
-  <script src="{% static 'tokens.js' %}"></script>
+  <link rel="stylesheet" type="text/css" href="{% static 'shell/opencloud_shell.css' %}" media="all">
+  <script src="{% static 'shell/opencloud.js' %}"></script>
+  <script src="{% static 'shell/opencloud_shell.js' %}"></script>
+  <script src="{% static 'shell/object_id.js' %}"></script>
+  <script src="{% static 'shell/constants.js' %}"></script>
+  <script src="{% static 'shell/utils.js' %}"></script>
+  <script src="{% static 'shell/shell_utils.js' %}"></script>
+  <script src="{% static 'shell/tokens.js' %}"></script>
 
 
     <!-- script type="text/javascript" src="js/jquery-1.3.2.min.js"></script-->
diff --git a/planetstack/core/dashboard/shell/shell.py b/planetstack/core/dashboard/shell/shell.py
new file mode 100644
index 0000000..850dd02
--- /dev/null
+++ b/planetstack/core/dashboard/shell/shell.py
@@ -0,0 +1,20 @@
+# /opt/planetstack/core/dashboard/views/helloworld.py
+import os
+import sys
+import json
+from django.http import HttpResponse, HttpResponseServerError, HttpResponseForbidden
+from django.views.generic import TemplateView, View
+from core.models import *
+from django.forms.models import model_to_dict
+
+class ShellDataView(View):
+    url = r'^shelldata/'
+
+    def get(self, request, **kwargs):
+        allSlices = []
+        for slice in Slice.objects.all():
+            allSlices.append(model_to_dict(slice))
+
+        result = {"slices": allSlices}
+
+        return HttpResponse(json.dumps(result), mimetype='application/json')
diff --git a/planetstack/core/dashboard/shell/shell_utils.js b/planetstack/core/dashboard/shell/shell_utils.js
index 79b9565..8ed5f4f 100644
--- a/planetstack/core/dashboard/shell/shell_utils.js
+++ b/planetstack/core/dashboard/shell/shell_utils.js
@@ -350,16 +350,20 @@
       var lineEnding = nolint ? " " : "\n";
       var tabSpace = nolint ? "" : "\t";
     }
-    
+
     assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );
 
-    if (!indent) 
+    if (!indent)
         indent = "";
-    
+
+    if ( x.hasOwnProperty("__str__")) {
+        return x.__str__();
+    }
+
     if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
         return x.tojson(indent,nolint,html);
     }
-    
+
     if ( typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
         return x.constructor.tojson( x, indent , nolint, html );
     }
@@ -368,12 +372,12 @@
         return "{ $maxKey : 1 }";
     if ( x.toString() == "[object MinKey]" )
         return "{ $minKey : 1 }";
-    
+
     var s = "{" + lineEnding;
 
     // push one level of indent
     indent += tabSpace;
-    
+
     var total = 0;
     for ( var k in x ) total++;
     if ( total == 0 ) {
@@ -385,7 +389,6 @@
         keys = x._simpleKeys();
     var num = 1;
     for ( var k in keys ){
-        
         var val = x[k];
 
         s += indent + "\"" + k + "\" : " + tojson( val, indent , nolint );