From 1beed456ccaeb68095572081ab7d3cb84952c257 Mon Sep 17 00:00:00 2001
From: Brian Pilati <brian.pilati@domo.com>
Date: Sat, 8 Mar 2014 00:46:59 -0700
Subject: [PATCH] updates to add "ask" functionality

---
 .gitignore                       |   1 +
 img/ask-bottom.png               | Bin 0 -> 909 bytes
 img/ask-button.png               | Bin 0 -> 1933 bytes
 img/playerStartFlag.png          | Bin 8076 -> 4829 bytes
 js/Reporter.js                   |  11 +-
 js/Sprite.js                     |  70 +++++-
 js/Stage.js                      |   1 +
 js/primitives/LooksPrims.js      |  14 ++
 player.css                       |  47 ++++-
 test/artifacts/IOMock.js         |  25 +++
 test/artifacts/TargetMock.js     |   4 +-
 test/artifacts/ask-artifact.js   |  16 +-
 test/artifacts/reporterValues.js |  91 ++++++++
 test/unit/looksPrimitiveSpec.js  |  54 ++++-
 test/unit/reporterSpec.js        |  96 +++++++++
 test/unit/spriteSpec.js          | 352 +++++++++++++++++++++++++++++++
 test/unit/stageSpec.js           |  51 +++++
 17 files changed, 809 insertions(+), 24 deletions(-)
 create mode 100644 img/ask-bottom.png
 create mode 100644 img/ask-button.png
 create mode 100644 test/artifacts/IOMock.js
 create mode 100644 test/artifacts/reporterValues.js
 create mode 100644 test/unit/reporterSpec.js
 create mode 100644 test/unit/spriteSpec.js
 create mode 100644 test/unit/stageSpec.js

diff --git a/.gitignore b/.gitignore
index ca4d940..1d5cbb2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 *.swp
 test/lib/*
+.DS_Store
 
 logs
 
diff --git a/img/ask-bottom.png b/img/ask-bottom.png
new file mode 100644
index 0000000000000000000000000000000000000000..9823a430aa3477e626d124c5d8fa0e78997a1875
GIT binary patch
literal 909
zcmV;819JR{P)<h;3K|Lk000e1NJLTq001fg000sQ1^@s6E$U3000004XF*Lt006JZ
zHwB960000PbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU#A4x<(RCwBA
zy!HOae-36Q23cNKMg}yn>gI?43$MNhv*Wb|8N$>B7-$7ve*Mj`=g}92J0E^AoO=EZ
zLmnW2SX2er8L?@6^Zn2N6HpB@ysQk4vOF|#;LUeG8BPN2IrZWj!?!>G7`RxN;Bq=5
z91QHtj12ZNJPZH<#DdF!<Ilc<4FLgXIUWX4E*7de?#r*g3};_`XE^rs8^eQ7zZjl;
z{*5B9B*4aCB*w{LD#^v5Bg_E~NPqysYWvsU|Nes<3IdYctPD<a)CtY&?|v{`e*J^t
z7|`t7?|-7mX$f;MaI!!`PhX6KK?KA>0ssNTf-5vHzWxqon@DhiG*J|Kr(S*sr@IFq
ze=$5p3q2J9b_O*;HU@iOV8B8T8vqC(7Hpxp?fxe)Tb!GP?9jaS77}`(wD<AnKZfUD
zf1{+mzyJO-*aOqOr4$!N=wSl@0fgbu3$K2_)24|y7tputB!%8ZpySQ}Ll6|T_kkgZ
z4Ag;UsQ^RIOoAH}Q;ei|93X%&9J=e_XLxA3$rBfv_dot*IPv^D!*yUNzWnwFC3Ap6
z?>~^XmF6Zo^soVd077x-*_Yq{gF*!a<apVDzGuf9dgp<mclO11aLz@~9NNIl0m{9g
zSRpm^umOMoLUHKEJ0BTtK%?D9nHQ^udmny+b1kS~egzD@ho4ZR*GQa`K^GW`mQvhU
zD-m)5Kmf5IhbAy1f!T(@G7J<F$YB5DFAO)|{$#ifbm$kLI`rt3045b%V9}x}#LmFY
z%EU<RiUA;i;0`_U>?=Gp16BFp)!Ko_UxDS{PlmTY{s2Q0HS~;up$BrL6)^N<s2F<K
z06+kN9SRJk|M#Fd6c`!|-+%vSm~`$nFx37qd;+G$$5=wo4j6hGGzvXz03d)E|NsBb
zFyZX$|GOW4!K)CIIY5O!C=IIMXdloL00a=r9bjnQL5ou4(Bo%k23KnaVjTRy(EG$N
zKmZ_sST^7Ngi$bq90*E(0~LDM06+k-h;y;RIo7~J85(**z|ecoFo*y^0D;mdJR>Rb
jvvB~apA3T#00bBSHz77eF$;b_00000NkvXXu0mjf{(^||

literal 0
HcmV?d00001

diff --git a/img/ask-button.png b/img/ask-button.png
new file mode 100644
index 0000000000000000000000000000000000000000..713927add0c1ba49aef6172c49b7243b04106660
GIT binary patch
literal 1933
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
J*Bm1(`#-kDcuoKS

literal 0
HcmV?d00001

diff --git a/img/playerStartFlag.png b/img/playerStartFlag.png
index 11a8e72b970d14beda936bcd68e7acb1be7da02a..f2211d1ddad2a80ee4c4ad703a8df910fdbe2c2b 100644
GIT binary patch
literal 4829
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

literal 8076
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
a{|^A`{-UaIXEC4v0000<MNUMnLSTZ6SUZLQ

diff --git a/js/Reporter.js b/js/Reporter.js
index a6acd66..c55f0d2 100644
--- a/js/Reporter.js
+++ b/js/Reporter.js
@@ -19,7 +19,6 @@ var Reporter = function(data) {
     this.cmd = data.cmd;
     this.color = data.color;
     this.isDiscrete = data.isDiscrete;
-    this.label = data.label;
     this.mode = data.mode;
     this.param = data.param;
     this.sliderMin = data.sliderMin;
@@ -35,11 +34,19 @@ var Reporter = function(data) {
     this.slider = null; // slider jQ element
 };
 
+Reporter.prototype.determineReporterLabel = function() {
+  if (this.target === 'Stage') {
+    return this.param;
+  } else {
+    return this.target + ': ' + this.param;
+  }
+}
+
 Reporter.prototype.attach = function(scene) {
     switch (this.mode) {
         case 1: // Normal
         case 3: // Slider
-            this.el = $('<div class="reporter-normal">' + this.label + '</div>');
+            this.el = $('<div class="reporter-normal">' + this.determineReporterLabel() + '</div>');
             this.valueEl = $('<div class="reporter-inset">null</div>');
             this.el.append(this.valueEl);
             if (this.mode == 3) {
diff --git a/js/Sprite.js b/js/Sprite.js
index 026d17e..07d7621 100644
--- a/js/Sprite.js
+++ b/js/Sprite.js
@@ -73,7 +73,14 @@ var Sprite = function(data) {
     this.talkBubbleStyler = null;
     this.talkBubbleOn = false;
 
+    // HTML element for the ask bubbles
+    this.askInput = null;
+    this.askInputField = null;
+    this.askInputButton = null;
+    this.askInputOn = false;
+
     // Internal variables used for rendering meshes.
+    this.askAnswer = null; //this is a private variable
     this.textures = [];
     this.materials = [];
     this.geometries = [];
@@ -142,14 +149,26 @@ Sprite.prototype.attach = function(scene) {
     this.updateVisible();
     this.updateTransform();
 
-    this.talkBubble = $('<div class="bubble-container"></div>');
-    this.talkBubble.css('display', 'none');
-    this.talkBubbleBox = $('<div class="bubble"></div>');
-    this.talkBubbleStyler = $('<div class="bubble-say"></div>');
-    this.talkBubble.append(this.talkBubbleBox);
-    this.talkBubble.append(this.talkBubbleStyler);
+    if (! this.isStage) {
+      this.talkBubble = $('<div class="bubble-container"></div>');
+      this.talkBubble.css('display', 'none');
+      this.talkBubbleBox = $('<div class="bubble"></div>');
+      this.talkBubbleStyler = $('<div class="bubble-say"></div>');
+      this.talkBubble.append(this.talkBubbleBox);
+      this.talkBubble.append(this.talkBubbleStyler);
+    }
+
+    this.askInput = $('<div class="ask-container"></div>');
+    this.askInput.css('display', 'none');
+    this.askInputField = $('<div class="ask-field"></div>');
+    this.askInputTextField = $('<input class="ask-text-field"></input>');
+    this.askInputField.append(this.askInputTextField);
+    this.askInputButton = $('<div class="ask-button"></div>');
+    this.askInput.append(this.askInputField);
+    this.askInput.append(this.askInputButton);
 
     runtime.scene.append(this.talkBubble);
+    runtime.scene.append(this.askInput);
 };
 
 // Load sounds from the server and buffer them
@@ -254,20 +273,22 @@ Sprite.prototype.onClick = function(evt) {
 };
 
 Sprite.prototype.setVisible = function(v) {
+  if (v === true || v === false) {
     this.visible = v;
     this.updateVisible();
+  }
 };
 
 Sprite.prototype.updateLayer = function() {
     $(this.mesh).css('z-index', this.z);
-    if (this.talkBubble) this.talkBubble.css('z-index', this.z);
+    if (this.talkBubble) $(this.talkBubble).css('z-index', this.z);
+    if (this.askInput) this.askInput.css('z-index', this.z);
 };
 
 Sprite.prototype.updateVisible = function() {
     $(this.mesh).css('display', this.visible ? 'inline' : 'none');
-    if (this.talkBubbleOn) {
-        this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
-    }
+    if (this.talkBubbleOn) this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
+    if (this.askInputOn) this.askInput.css('display', this.visible ? 'inline-block' : 'none');
 };
 
 Sprite.prototype.updateTransform = function() {
@@ -347,13 +368,21 @@ Sprite.prototype.showBubble = function(text, type) {
     this.talkBubble.css('left', xy[0] + 'px');
     this.talkBubble.css('top', xy[1] + 'px');
 
-
+    this.talkBubble.removeClass('say-think-border');
+    this.talkBubble.removeClass('ask-border');
+    
     this.talkBubbleStyler.removeClass('bubble-say');
     this.talkBubbleStyler.removeClass('bubble-think');
+    this.talkBubbleStyler.removeClass('bubble-ask');
     if (type == 'say') {
+        this.talkBubbleBox.addClass('say-think-border');
         this.talkBubbleStyler.addClass('bubble-say');
     } else if (type == 'think') {
+        this.talkBubbleBox.addClass('say-think-border');
         this.talkBubbleStyler.addClass('bubble-think');
+    } else if (type == 'doAsk') {
+        this.talkBubbleBox.addClass('ask-border');
+        this.talkBubbleStyler.addClass('bubble-ask');
     }
 
     if (this.visible) {
@@ -367,6 +396,25 @@ Sprite.prototype.hideBubble = function() {
     this.talkBubble.css('display', 'none');
 };
 
+Sprite.prototype.showAsk = function() {
+    this.askInputOn = true;
+    this.askInput.css('z-index', this.z);
+    this.askInput.css('left', '15px');
+    this.askInput.css('right', '15px');
+    this.askInput.css('bottom', '7px');
+    this.askInput.css('height', '25px');
+
+    if (this.visible) {
+        this.askInput.css('display', 'inline-block');
+        this.askInputTextField.focus();
+    }
+};
+
+Sprite.prototype.hideAsk = function() {
+    this.askInputOn = false;
+    this.askInput.css('display', 'none');
+};
+
 Sprite.prototype.setXY = function(x, y) {
     this.scratchX = x;
     this.scratchY = y;
diff --git a/js/Stage.js b/js/Stage.js
index c425e10..8146e93 100644
--- a/js/Stage.js
+++ b/js/Stage.js
@@ -33,6 +33,7 @@ var Stage = function(data) {
     this.lineCanvas.width = 480;
     this.lineCanvas.height = 360;
     this.lineCache = this.lineCanvas.getContext('2d');
+    this.isStage = true;
 
     Sprite.call(this, data);
 };
diff --git a/js/primitives/LooksPrims.js b/js/primitives/LooksPrims.js
index e56f646..b63c7f2 100644
--- a/js/primitives/LooksPrims.js
+++ b/js/primitives/LooksPrims.js
@@ -43,6 +43,9 @@ LooksPrims.prototype.addPrimsTo = function(primTable) {
     primTable['setGraphicEffect:to:']    = this.primSetEffect;
     primTable['filterReset']             = this.primClearEffects;
 
+    primTable['doAsk']              = this.primDoAsk;
+    primTable['answer']             = this.primAnswer;
+
     primTable['say:'] = function(b) { showBubble(b, 'say'); };
     primTable['say:duration:elapsed:from:'] = function(b) { showBubbleAndWait(b, 'say'); };
     primTable['think:'] = function(b) { showBubble(b, 'think'); };
@@ -170,6 +173,17 @@ LooksPrims.prototype.primClearEffects = function(b) {
     s.updateFilters();
 };
 
+LooksPrims.prototype.primDoAsk= function(b) {
+    showBubble(b, "doAsk");
+    var s = interp.targetSprite();
+    if (s != null) s.showAsk();
+};
+
+LooksPrims.prototype.primAnswer = function() {
+    var s = interp.targetSprite();
+    return ((s != null) ? s.answer : undefined);
+};
+
 var showBubble = function(b, type) {
     var s = interp.targetSprite();
     if (s != null) s.showBubble(interp.arg(b, 0), type);
diff --git a/player.css b/player.css
index 3fcff6c..40ca47e 100644
--- a/player.css
+++ b/player.css
@@ -398,7 +398,7 @@ button#trigger-stop:hover {
 }
 
 /* Say/think bubble styles */
- .bubble-container {
+.bubble-container {
     position: absolute;
 }
 .bubble {
@@ -407,7 +407,6 @@ button#trigger-stop:hover {
     max-width: 120px;
     min-width: 40px;
     padding: 6px 11px 6px 11px;
-    border: 3px solid rgb(160, 160, 160);
     border-radius: 10px;
     background: #fff;
     font-family: sans-serif;
@@ -416,6 +415,20 @@ button#trigger-stop:hover {
     color: #000;
     text-align: center;
 }
+.bubble.say-think-border {
+    border: 3px solid rgb(160, 160, 160);
+}
+.bubble.ask-border, .ask-container {
+    border: 3px solid rgb(74, 173, 222);
+}
+.bubble-ask {
+    position: absolute;
+    margin-top: -3px;
+    margin-left: 8px;
+    width: 44px;
+    height: 18px;
+    background: url(img/ask-bottom.png) transparent no-repeat;
+}
 .bubble-say {
     position: absolute;
     margin-top: -3px;
@@ -432,3 +445,33 @@ button#trigger-stop:hover {
     height: 19px;
     background: url(img/think-bottom.png) transparent no-repeat;
 }
+.ask-container {
+    position: absolute;
+    display: inline-block;
+    padding: 5px 0px 0px 5px;
+    border-radius: 5px;
+    background: #fff;
+    font-family: sans-serif;
+    font-weight: bold;
+    font-size: 14px;
+    color: #000;
+}
+.ask-container .ask-field .ask-text-field {
+    width: 405px;
+    height: 16px;
+    font-family: sans-serif;
+    font-weight: light;
+    font-size: 12px;
+    background: #EAEAEA;
+}
+
+.ask-container .ask-button {
+    position: absolute;
+    right: 2px;
+    top: 2px;
+    width: 25px;
+    height: 25px;
+    background: url(img/ask-button.png) transparent no-repeat;
+}
+
+
diff --git a/test/artifacts/IOMock.js b/test/artifacts/IOMock.js
new file mode 100644
index 0000000..6a7a118
--- /dev/null
+++ b/test/artifacts/IOMock.js
@@ -0,0 +1,25 @@
+'use strict';
+
+var ioMock = function() {
+  var args = createArgs(arguments);
+
+  function getArgs(argKey) {
+    return ((argKey in args) ? args[argKey] : null);
+  }
+
+  function createArgs(methodArgs) {
+    var args = {};
+    if (methodArgs.length) {
+      _.each(methodArgs, function(newObject) {
+        _.each(newObject, function(value, key) {
+          args[key] = value;
+        });
+      });
+    }
+    return args;
+  }
+
+  return {
+    'getCount' : function() { return getArgs('getCount'); }
+  }
+};
diff --git a/test/artifacts/TargetMock.js b/test/artifacts/TargetMock.js
index 9121a00..8071a39 100644
--- a/test/artifacts/TargetMock.js
+++ b/test/artifacts/TargetMock.js
@@ -2,7 +2,9 @@
 
 var targetMock = function() {
   return {
-    'showBubble' : function() {}
+    'showBubble' : function() {},
+    'showAsk' : function() {},
+    'answer' : 22
   };
 
 }
diff --git a/test/artifacts/ask-artifact.js b/test/artifacts/ask-artifact.js
index 4f0852a..654a07d 100644
--- a/test/artifacts/ask-artifact.js
+++ b/test/artifacts/ask-artifact.js
@@ -1,7 +1,10 @@
-'use strict';
-
 var sensingData = {
   "objName": "Stage",
+  "variables": [{
+      "name": "myAnswer",
+      "value": 0,
+      "isPersistent": false
+    }],
   "costumes": [{
       "costumeName": "backdrop1",
       "baseLayerID": -1,
@@ -16,6 +19,15 @@ var sensingData = {
   "videoAlpha": 0.5,
   "children": [{
       "objName": "Sprite1",
+      "variables": [{
+          "name": "myAnswer2",
+          "value": 0,
+          "isPersistent": false
+        }, {
+          "name": "answer",
+          "value": 0,
+          "isPersistent": false
+        }],
       "scripts": [[42, 40.5, [["whenGreenFlag"], ["doAsk", "What's your name?"]]],
         [44.5,
           155.5,
diff --git a/test/artifacts/reporterValues.js b/test/artifacts/reporterValues.js
new file mode 100644
index 0000000..484b990
--- /dev/null
+++ b/test/artifacts/reporterValues.js
@@ -0,0 +1,91 @@
+'use Strict;'
+
+var ReporterValues = function() {
+  return {
+    'getStageVariables': function() {
+      return {
+        'cmd' : "getVar:",
+        'color' : 15629590,
+        'isDiscrete' :  true,
+        'mode' : 1,
+        'param' : "myAnswer",
+        'sliderMax' : 100,
+        'sliderMin' : 0,
+        'target' : "Stage",
+        'visible' : true,
+        'x' : 5,
+        'y' : 5,
+      };
+    }
+  }
+};
+/*
+cmd
+  "getVar:"
+  
+color
+  15629590
+  
+isDiscrete
+  true
+  
+mode
+  1
+  
+param
+  "myAnswer2"
+  
+sliderMax
+  100
+  
+sliderMin
+  0
+  
+target
+  "Sprite1"
+  
+visible
+  true
+  
+x
+  5
+  
+y
+  32
+*/
+
+/*
+  
+cmd
+  "getVar:"
+  
+color
+  15629590
+  
+isDiscrete
+  true
+  
+mode
+  1
+  
+param
+  "answer"
+  
+sliderMax
+  100
+  
+sliderMin
+  0
+  
+target
+  "Sprite1"
+  
+visible
+  true
+  
+x
+  5
+  
+y
+  59
+*/
diff --git a/test/unit/looksPrimitiveSpec.js b/test/unit/looksPrimitiveSpec.js
index cadbc6e..a46f747 100644
--- a/test/unit/looksPrimitiveSpec.js
+++ b/test/unit/looksPrimitiveSpec.js
@@ -1,23 +1,65 @@
 /* jasmine specs for primitives/LooksPrims.js go here */
 
 describe ('LooksPrims', function() {
-  var looksPrims;
+  var looksPrims, targetSpriteMock;
   beforeEach(function() {
     looksPrims = LooksPrims;
+    targetSpriteMock = targetMock();
   });
 
-  describe('showBubble', function(){
-    var sayBlock, targetSpriteMock;
+  describe('showBubble for Say', function(){
+    var sayBlock;
     beforeEach(function() {
       sayBlock = {'args': ['what to say']};
-      targetSpriteMock = targetMock();
       interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': sayBlock});
-
     });
-    it('should return do something', function() {
+
+    it('should call the showBubble method on the targetedSprite', function() {
       spyOn(targetSpriteMock, "showBubble");
       showBubble(sayBlock, "say");
       expect(targetSpriteMock.showBubble).toHaveBeenCalled;
     });
   });
+
+  describe('showBubble for Think', function(){
+    var thinkBlock;
+    beforeEach(function() {
+      thinkBlock = {'args': ['what to think']};
+      interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': thinkBlock});
+    });
+
+    it('should call the showBubble method on the targetedSprite', function() {
+      spyOn(targetSpriteMock, "showBubble");
+      showBubble(thinkBlock, "think");
+      expect(targetSpriteMock.showBubble).toHaveBeenCalled;
+    });
+  });
+
+
+  describe('showBubble for Ask', function(){
+    var askBlock;
+    beforeEach(function() {
+      askBlock = {'args': 'what to ask'};
+      interp = interpreterMock({'targetSprite': targetSpriteMock }, {'arg': askBlock});
+
+    });
+
+    it('should call the showBubble method on the targetedSprite', function() {
+      spyOn(targetSpriteMock, "showBubble");
+      spyOn(targetSpriteMock, "showAsk");
+      looksPrims.prototype.primDoAsk(askBlock);
+      expect(targetSpriteMock.showBubble).toHaveBeenCalled;
+      expect(targetSpriteMock.showAsk).toHaveBeenCalled;
+    });
+  });
+
+  describe('primAnswer', function(){
+    beforeEach(function() {
+      interp = interpreterMock({'targetSprite': targetSpriteMock });
+    });
+
+    it('should return the answer variable from the targetedSprite', function() {
+      expect(looksPrims.prototype.primAnswer()).toBe(22);
+    });
+  });
 });
diff --git a/test/unit/reporterSpec.js b/test/unit/reporterSpec.js
new file mode 100644
index 0000000..c879f58
--- /dev/null
+++ b/test/unit/reporterSpec.js
@@ -0,0 +1,96 @@
+/* jasmine specs for Reporter.js go here */
+
+describe ('Reporter', function() {
+  var reporter, reporterValues;
+
+  beforeEach(function() {
+    reporter = Reporter;
+    reporterValues = new ReporterValues();
+  });
+
+  describe('Instantization variables', function() {
+    var initReporter;
+    beforeEach(function() {
+      io = new ioMock({'getCount': 4});
+      initReporter = new reporter(reporterValues.getStageVariables());
+    });
+
+    describe('Reporter Variables', function() {
+      it('should have a cmd variable', function() {
+        expect(initReporter.cmd).toBe('getVar:');
+      });
+
+      it('should have a color variable', function() {
+        expect(initReporter.color).toBe(15629590);
+      });
+
+      it('should have a isDiscrete variable', function() {
+        expect(initReporter.isDiscrete).toBe(true);
+      });
+
+      it('should have a mode variable', function() {
+        expect(initReporter.mode).toBe(1);
+      });
+
+      it('should have a param variable', function() {
+        expect(initReporter.param).toBe('myAnswer');
+      });
+
+      it('should have a sliderMax variable', function() {
+        expect(initReporter.sliderMax).toBe(100);
+      });
+
+      it('should have a sliderMin variable', function() {
+        expect(initReporter.sliderMin).toBe(0);
+      });
+
+      it('should have a target variable', function() {
+        expect(initReporter.target).toBe('Stage');
+      });
+
+      it('should have a visible variable', function() {
+        expect(initReporter.visible).toBe(true);
+      });
+
+      it('should have a x variable', function() {
+        expect(initReporter.x).toBe(5);
+      });
+
+      it('should have a y variable', function() {
+        expect(initReporter.y).toBe(5);
+      });
+
+      it('should have a z variable', function() {
+        expect(initReporter.z).toBe(4);
+      });
+
+      it('should have an el variable', function() {
+        expect(initReporter.el).toBe(null);
+      });
+
+      it('should have an valueEl variable', function() {
+        expect(initReporter.valueEl).toBe(null);
+      });
+
+      it('should have an slider variable', function() {
+        expect(initReporter.slider).toBe(null);
+      });
+    });
+  });
+  describe('determineReporterLabel', function() {
+
+    it('should return a stage variable', function() {
+      reporter.prototype.target = "Stage";
+      reporter.prototype.param = "myAnswer";
+      expect(reporter.prototype.determineReporterLabel()).toBe('myAnswer');
+    });
+
+    it('should return a sprite variable', function() {
+      reporter.prototype.target = "Sprite 1";
+      reporter.prototype.param = "localAnswer";
+      expect(reporter.prototype.determineReporterLabel()).toBe('Sprite 1: localAnswer');
+
+    });
+
+  });
+});
diff --git a/test/unit/spriteSpec.js b/test/unit/spriteSpec.js
new file mode 100644
index 0000000..feeb11c
--- /dev/null
+++ b/test/unit/spriteSpec.js
@@ -0,0 +1,352 @@
+/* jasmine specs for Sprite.js go here */
+
+describe ('Sprite', function() {
+  var sprite;
+
+
+  beforeEach(function() {
+    sprite = Sprite;
+  });
+
+  describe('Instantization variables', function() {
+    var initSprite;
+    beforeEach(function() {
+      var spriteObject = sensingData.children[0];
+      initSprite = new sprite(spriteObject);
+    });
+
+    describe('Sprite Variables', function() {
+      it('should have a visible variable', function() {
+        expect(initSprite.visible).toBe(true);
+      });
+    });
+
+    describe('Pen Variables', function() {
+      it('should have a penIsDown variable', function() {
+        expect(initSprite.penIsDown).toBe(false);
+      });
+
+      it('should have a penWidth variable', function() {
+        expect(initSprite.penWidth).toBe(1);
+      });
+
+      it('should have a penHue variable', function() {
+        expect(initSprite.penHue).toBe(120);
+      });
+
+      it('should have a penShade variable', function() {
+        expect(initSprite.penShade).toBe(50);
+      });
+
+      it('should have a penColorCache variable', function() {
+        expect(initSprite.penColorCache).toBe(0x0000FF);
+      });
+    });
+
+    describe('Ask Bubble', function() {
+      it('should have an askInput variable', function() {
+        expect(initSprite.askInput).toBe(null);
+      });
+
+      it('should have an askInputBox variable', function() {
+        expect(initSprite.askInputField).toBe(null);
+      });
+
+      it('should have an askInputStyler variable', function() {
+        expect(initSprite.askInputButton).toBe(null);
+      });
+
+      it('should have an askInputOn variable', function() {
+        expect(initSprite.askInputOn).toBe(false);
+      });
+
+      it('should have an answer variable', function() {
+        expect(initSprite.askAnswer).toBe(null);
+      });
+    });
+  })
+
+  describe('showBubble', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      spriteProto.visible = true;
+      setFixtures('<div class="bubble-container"></div>');
+      spriteProto.talkBubble = $('.bubble-container');
+      spriteProto.talkBubble.css('display', 'none');
+      spriteProto.talkBubbleBox = $('<div class="bubble"></div>');
+      spriteProto.talkBubbleStyler = $('<div class="bubble-say"></div>');
+      spriteProto.talkBubble.append(spriteProto.talkBubbleBox);
+      spriteProto.talkBubble.append(spriteProto.talkBubbleStyler);
+    });
+
+    describe('Say', function(){
+      it('should call the showBubble method on the Sprite', function() {
+        var text = "What to say";
+        spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
+        spriteProto.showBubble(text, "say");
+        expect($('.bubble').html()).toBe(text);
+        expect($('.bubble-say').hasClass('bubble-say')).toBe(true);
+        expect($('.bubble').hasClass('say-think-border')).toBe(true);
+        expect($('.bubble-container').css('display')).toBe('inline-block');
+      });
+    });
+
+    describe('Think', function(){
+      it('should call the showBubble method on the Sprite', function() {
+        var text = "What to think";
+        spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
+        spriteProto.showBubble(text, "think");
+        expect($('.bubble').html()).toBe(text);
+        expect($('.bubble-think').hasClass('bubble-think')).toBe(true);
+        expect($('.bubble').hasClass('say-think-border')).toBe(true);
+        expect($('.bubble-container').css('display')).toBe('inline-block');
+      });
+    });
+
+    describe('Ask', function(){
+      it('should call the showBubble method on the Sprite', function() {
+        var text = "What to Ask";
+        spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
+        spriteProto.showBubble(text, "doAsk");
+        expect($('.bubble').html()).toBe(text);
+        expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true);
+        expect($('.bubble').hasClass('ask-border')).toBe(true);
+        expect($('.bubble-container').css('display')).toBe('inline-block');
+      });
+    });
+
+    describe('Any Bubble with visible false', function(){
+      it('should call the showBubble method on the Sprite and not display it', function() {
+        spriteProto.visible = false;
+        var text = "What to Ask";
+        spyOn(spriteProto, "getTalkBubbleXY").andReturn([50,50]);;
+        spriteProto.showBubble(text, "doAsk");
+        expect($('.bubble').html()).toBe(text);
+        expect($('.bubble-ask').hasClass('bubble-ask')).toBe(true);
+        expect($('.bubble').hasClass('ask-border')).toBe(true);
+        expect($('.bubble-container').css('display')).toBe('none');
+      });
+    });
+  });
+
+  describe('hideBubble', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      setFixtures('<div class="bubble-container"></div>');
+      spriteProto.talkBubble = $('.bubble-container');
+      spriteProto.talkBubble.css('display', 'inline');
+    });
+
+    it('should hide the bubble', function() {
+      spriteProto.hideBubble();
+      expect($('.bubble-container').css('display')).toBe('none');
+      expect(spriteProto.talkBubbleOn).toBe(false);
+
+    });
+  });
+
+  describe('showAsk', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      spriteProto.visible = true;
+      spriteProto.z = 22;
+      setFixtures('<div class="ask-container"></div>');
+      spriteProto.askInput= $('.ask-container');
+      spriteProto.askInput.css('display','none');
+      spriteProto.askInput.css('position','relative');
+      spriteProto.askInputField = $('<div class="ask-input"></div>');
+      spriteProto.askInputTextField = $('<input class="ask-text-field"></input>');
+      spriteProto.askInputField.append(spriteProto.askInputTextField);
+      spriteProto.askInputButton = $('<div class="ask-button"></div>');
+      spriteProto.askInput.append(spriteProto.askInputField);
+      spriteProto.askInput.append(spriteProto.askInputButton);
+    });
+
+    it('should show the ask input if visible is true', function() {
+      spriteProto.showAsk();
+      expect($('.ask-container').css('display')).toBe('inline-block');
+      expect($('.ask-container').css('z-index')).toBe('22');
+      expect($('.ask-container').css('left')).toBe('15px');
+      expect($('.ask-container').css('right')).toBe('15px');
+      expect($('.ask-container').css('bottom')).toBe('7px');
+      expect($('.ask-container').css('height')).toBe('25px');
+      expect($('.ask-container').css('height')).toBe('25px');
+      expect($('.ask-text-field').is(':focus')).toBe(true);
+      expect(spriteProto.askInputOn).toBe(true);
+    });
+
+    it('should not show the ask input if visible is false', function() {
+      spriteProto.visible = false;
+      spriteProto.showAsk();
+      expect($('.ask-container').css('display')).toBe('none');
+      expect($('.ask-text-field').is(':focus')).toBe(false);
+    });
+  });
+
+  describe('hideAsk', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      setFixtures('<div class="ask-container"></div>');
+      spriteProto.askInput = $('.ask-container');
+      spriteProto.askInput.css('display', 'inline');
+    });
+
+    it('should hide the ask input', function() {
+      spriteProto.hideAsk();
+      expect($('.ask-container').css('display')).toBe('none');
+      expect(spriteProto.askInputOn).toBe(false);
+
+    });
+  });
+
+  describe('updateLayer', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
+      spriteProto.talkBubble = $('.bubble-container');
+      spriteProto.talkBubble.css('position', 'relative');
+      spriteProto.askInput = $('.ask-container');
+      spriteProto.askInput.css('position', 'relative');
+      spriteProto.mesh = $('.mesh');
+      spriteProto.mesh.css('position', 'relative');
+      spriteProto.z = 22;
+    });
+
+    it('should update the mesh z-index', function() {
+      expect($('.mesh').css('z-index')).toBe('auto');
+      spriteProto.updateLayer();
+      expect($('.mesh').css('z-index')).toBe('22');
+    });
+
+    it('should update the talkBubble z-index', function() {
+      expect($('.bubble-container').css('z-index')).toBe('auto');
+      spriteProto.updateLayer();
+      expect($('.bubble-container').css('z-index')).toBe('22');
+    });
+
+    it('should update the askInput z-index', function() {
+      expect($('.ask-container').css('z-index')).toBe('auto');
+      spriteProto.updateLayer();
+      expect($('.ask-container').css('z-index')).toBe('22');
+    });
+  });
+
+  describe('updateVisible', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      setFixtures('<img class="mesh"></img><div class="bubble-container"></div><div class="ask-container"></div>');
+      spriteProto.talkBubble = $('.bubble-container');
+      spriteProto.talkBubble.css('display', 'none');
+      spriteProto.askInput = $('.ask-container');
+      spriteProto.askInput.css('display', 'none');
+      spriteProto.mesh = $('.mesh');
+      spriteProto.mesh.css('display', 'none');
+    });
+
+    describe('mesh', function() {
+      it('should update the mesh display on false', function() {
+        expect($('.mesh').css('display')).toBe('none');
+        spriteProto.visible = false;
+        spriteProto.updateVisible();
+        expect($('.mesh').css('display')).toBe('none');
+      });
+
+      it('should update the mesh display on true', function() {
+        expect($('.mesh').css('display')).toBe('none');
+        spriteProto.visible = true; 
+        spriteProto.updateVisible();
+        expect($('.mesh').css('display')).toBe('inline');
+      });
+
+    });
+
+    describe('talkBubble', function() {
+      it('should update the talkBubble on talkBubble true and visible true', function() {
+        expect($('.bubble-container').css('display')).toBe('none');
+        spriteProto.talkBubbleOn = true; 
+        spriteProto.visible = true; 
+        spriteProto.updateVisible();
+        expect($('.bubble-container').css('display')).toBe('inline-block');
+      });
+
+      it('should update the talkBubble on talkBubble false and visible true', function() {
+        expect($('.bubble-container').css('display')).toBe('none');
+        spriteProto.talkBubbleOn = false; 
+        spriteProto.visible = true; 
+        spriteProto.updateVisible();
+        expect($('.bubble-container').css('display')).toBe('none');
+      });
+
+      it('should update the talkBubble on talkBubble true and visible false', function() {
+        expect($('.bubble-container').css('display')).toBe('none');
+        spriteProto.talkBubbleOn = true; 
+        spriteProto.visible = false; 
+        spriteProto.updateVisible();
+        expect($('.bubble-container').css('display')).toBe('none');
+      });
+    });
+
+    describe('askContainer', function() {
+      it('should update the askInput on askInput true and visible true', function() {
+        expect($('.ask-container').css('display')).toBe('none');
+        spriteProto.askInputOn = true; 
+        spriteProto.visible = true; 
+        spriteProto.updateVisible();
+        expect($('.ask-container').css('display')).toBe('inline-block');
+      });
+
+      it('should update the askInput on askInput false and visible true', function() {
+        expect($('.ask-container').css('display')).toBe('none');
+        spriteProto.askInputOn = false; 
+        spriteProto.visible = true; 
+        spriteProto.updateVisible();
+        expect($('.ask-container').css('display')).toBe('none');
+      });
+
+      it('should update the askInput on askInput true and visible false', function() {
+        expect($('.ask-container').css('display')).toBe('none');
+        spriteProto.askInputOn = true; 
+        spriteProto.visible = false; 
+        spriteProto.updateVisible();
+        expect($('.ask-container').css('display')).toBe('none');
+      });
+    });
+
+  });
+
+  describe('setVisible', function() {
+    var spriteProto;
+    beforeEach(function() {
+      spriteProto = sprite.prototype;
+      spyOn(spriteProto, "updateVisible");
+    });
+
+    it('should set visible to true', function() {
+      expect(spriteProto.visible).toBe(false);
+      spriteProto.setVisible(true);
+      expect(spriteProto.visible).toBe(true);
+      expect(spriteProto.updateVisible).toHaveBeenCalled();
+    });
+
+    it('should set visible to false', function() {
+      spriteProto.visible = true;
+      spriteProto.setVisible(false);
+      expect(spriteProto.visible).toBe(false);
+      expect(spriteProto.updateVisible).toHaveBeenCalled();
+    });
+
+    it('should set take no action on an invalid character', function() {
+      spriteProto.visible = true;
+      spriteProto.setVisible('hello');
+      expect(spriteProto.visible).toBe(true);
+      expect(spriteProto.updateVisible).not.toHaveBeenCalled();
+    });
+
+  });
+});
diff --git a/test/unit/stageSpec.js b/test/unit/stageSpec.js
new file mode 100644
index 0000000..330a451
--- /dev/null
+++ b/test/unit/stageSpec.js
@@ -0,0 +1,51 @@
+/* jasmine specs for Stage.js go here */
+
+describe ('Stage', function() {
+  var stage;
+
+  beforeEach(function() {
+    stage = Stage;
+  });
+
+  describe('Instantization variables', function() {
+    var initStage, lineCanvas;
+    beforeEach(function() {
+      spyOn(Sprite, "call");
+      initStage = new stage(sensingData);
+    });
+
+    describe('Stage Variables', function() {
+      it('should have a z variable', function() {
+        expect(initStage.z).toBe(-2);
+      });
+
+      it('should have a penLayerLoaded variable', function() {
+        expect(initStage.penLayerLoaded).toBe(false);
+      });
+
+      it('should have a lineCanvas element', function() {
+        expect(initStage.lineCanvas).toBeDefined();
+      });
+
+      it('should have a lineCanvas width', function() {
+        expect(initStage.lineCanvas.width).toBe(480);
+      });
+
+      it('should have a lineCanvas height', function() {
+        expect(initStage.lineCanvas.height).toBe(360);
+      });
+
+      it('should have a lineCache variable', function() {
+        expect(initStage.lineCache).toBeDefined();
+      });
+
+      it('should have a isStage variable', function() {
+        expect(initStage.isStage).toBe(true);
+      });
+
+      it('should have called Sprite.call', function() {
+        expect(Sprite.call).toHaveBeenCalled();
+      });
+    });
+  });
+});