diff --git a/breath_plot.html b/breath_plot.html
index b89e506799db6cabb208fb43780675cc0d7c1c61..42b8fcbee4a70bc69a24d5b71be64ca6fee42172 100644
--- a/breath_plot.html
+++ b/breath_plot.html
@@ -325,7 +325,7 @@ an interactive or static analysis of a respiration. It's primary purpose is
                   </div>
                 </div>
                 <div>
-                  <label for="taip">TAIP (ms): </label>
+                  <label for="taip">Rise Time (ms): </label>
                   <div class="value_and_fences">
                     <div class="calcnum">
                       <label id="taip"> </label>
@@ -343,7 +343,7 @@ an interactive or static analysis of a respiration. It&#39;s primary purpose is
                 </div>
               </div>
                 <div>
-                  <label for="taip">TRIP (ms): </label>
+                  <label for="taip">Fall Time (ms): </label>
                   <div class="value_and_fences">
                     <div class="calcnum">
                       <label id="trip"> </label>
@@ -359,6 +359,23 @@ an interactive or static analysis of a respiration. It&#39;s primary purpose is
                     </div>
                   </div>
                 </div>
+                <div>
+                  <label for="wob">W. of B. (J/L): </label>
+                  <div class="value_and_fences">
+                    <div class="calcnum">
+                      <label id="wob"> </label>
+                    </div>
+                    <div class="vertical_alarms">
+                      <div class="limit max">
+                        <label for="wob_h">H:</label>
+                        <input class="fence" id="wob_h" type='text'> </input>
+                    </div>
+                    <div class="limit min">
+                      <label for="wob_l">L:</label>
+                      <input class="fence" id="wob_l" type='text'> </input>
+                    </div>
+                  </div>
+                </div>
               </div>
             </div>
           </div>
@@ -370,11 +387,11 @@ an interactive or static analysis of a respiration. It&#39;s primary purpose is
   <div>
   Parameters:
   <div>
-        <label for="tarip_h">TAIP/TRIP High Pressure (cm H2O):</label>
+        <label for="tarip_h">Rise/Fall High Pressure (cm H2O):</label>
   <input class="fence" id="tarip_h" type='text'> </input>
   </div>
   <div>
-        <label for="tarip_l">TAIP/TRIP Low Pressure (cm H2O):</label>
+        <label for="tarip_l">Rise/Fall Low Pressure (cm H2O):</label>
   <input class="fence" id="tarip_l" type='text'> </input>
   </div>
 </div>
@@ -667,10 +684,30 @@ function plot(samples, trans, breaths) {
         ,0);
       var max_v = Math.max(max_inh,max_exh);
 
+      // not sure why I have null work, have to understand.
+      var max_work_per_liter = 0;
+      var work_per_liter = [];
+      for(var i = 0; i < breaths.length; i++) {
+        var b = breaths[i];
+        if (b.work != null) {
+          var wpl = b.work / b.vol_i;
+          if (wpl > max_work_per_liter)
+            max_work_per_liter = wpl;
+          var center = ((trans[b.trans_begin_inhale].ms + trans[b.trans_cross_zero].ms) - 2*min) / (2.0 * 1000.0);
+          work_per_liter.push({ wpl: wpl, center: center });
+        }
+      }
+
       var exh_v = unpack(breaths, 'vol_e').map(e => 100 * e / max_v);
       var t_exh_v =  unpack(breaths, 'vol_e').map(e => Math.round(e*1000.0)+"ml exh");
       var inh_v = unpack(breaths, 'vol_i').map(i => 100 * i / max_v);
       var t_inh_v = unpack(breaths, 'vol_i').map(e => Math.round(e*1000.0)+"ml inh");
+
+
+      var work_v = work_per_liter.map(w => (1/3) * (100 * w.wpl / max_work_per_liter));
+      var t_work = work_per_liter.map(w => w.wpl.toFixed(2)+"J/L");
+      var work_centers = unpack(work_per_liter, 'center');
+
       // now to graph properly, I must find the center of an inhalation.
       // I have packed these into the breaths...
       var inhale_centers = breaths.map(b => ((trans[b.trans_begin_inhale].ms + trans[b.trans_cross_zero].ms) - 2*min) / (2.0 * 1000.0));
@@ -698,6 +735,17 @@ function plot(samples, trans, breaths) {
                      text: t_exh_v,
 
                     };
+      var workPlot = {type: "scatter", mode: "markers+text",
+                     name: "WoB J",
+                     textposition: 'bottom center',
+                     x: work_centers,
+                     y: work_v,
+                     text: t_work,
+                     marker: { size: 8,
+                               color: 'blue',
+                               symbol: 'triangle-right'}
+                     };
+      event_graph.push(workPlot);
       event_graph.push(inhPlot);
       event_graph.push(exhPlot);
     }
@@ -733,7 +781,7 @@ function plot(samples, trans, breaths) {
       // Basically, we will show only the first of these in a "run"
       // This is rather difficult; we will instead just use 200 ms
       // as a window.
-      const time_windwow_ms = 200;
+      const TIME_WINDOW_MS = 400;
 
       var lows = [];
       var highs = [];
@@ -741,10 +789,10 @@ function plot(samples, trans, breaths) {
       for(var i = 0; i < messages.length; i++) {
         var m = messages[i];
         if (m.buff == FLOW_TOO_LOW) {
-          if ((lows.length == 0) || ((lows.length > 0) && (lows[lows.length-1].ms < (m.ms - 200))))
+          if ((lows.length == 0) || ((lows.length > 0) && (lows[lows.length-1].ms < (m.ms - TIME_WINDOW_MS))))
             lows.push(m);
         } else if (m.buff == FLOW_TOO_HIGH) {
-          if ((highs.length == 0) || ((highs.length > 0) && (highs[highs.length-1].ms < (m.ms - 200))))
+          if ((highs.length == 0) || ((highs.length > 0) && (highs[highs.length-1].ms < (m.ms - TIME_WINDOW_MS))))
             highs.push(m);
         } else {
           others.push(m);
@@ -933,7 +981,13 @@ function compute_fio2_mean(secs,samples) {
   }
 }
 
-
+// returns:
+// [ respiration rate,
+// tidal volume (avg),
+// minute_volume
+// EIRatio,
+// Work-of-Breathing (avg)
+// ]
 function compute_respiration_rate(secs,samples,transitions,breaths) {
   // In order to compute the number of breaths
   // in the last s seconds, I compute those breaths
@@ -944,7 +998,7 @@ function compute_respiration_rate(secs,samples,transitions,breaths) {
   var first_inhale_ms = -1;
   var last_inhale_ms = -1;
   if (breaths.length == 0) {
-    return [0,0,0,"NA"];
+    return [0,0,0,"NA","NA"];
   } else {
     const recent_ms = samples[samples.length - 1].ms;
     var cur_ms = recent_ms;
@@ -959,6 +1013,9 @@ function compute_respiration_rate(secs,samples,transitions,breaths) {
     // divide by the inhlation_duration.
     var vol_ci = 0.0;
 
+    var wob = 0.0;
+    var wob_cnt = 0;
+
     while((i >=0) && (breaths[i].ms > (cur_ms - secs*1000))) {
       cnt++;
       vol_i += breaths[i].vol_i;
@@ -975,6 +1032,11 @@ function compute_respiration_rate(secs,samples,transitions,breaths) {
       const zero_ms = transitions[breaths[i].trans_cross_zero].ms;
       time_inh += (zero_ms - inh_ms);
       time_exh += (exh_ms -  zero_ms);
+
+      if (breaths[i].work != null)  {
+        wob += breaths[i].work / breaths[i].vol_i;
+        wob_cnt++;
+      }
       i--;
     }
     if ((cnt > 1) && (first_inhale_ms != last_inhale_ms)) {
@@ -990,16 +1052,18 @@ function compute_respiration_rate(secs,samples,transitions,breaths) {
       var tidal_volume = 1000.0 * vol_i / cnt;
 
       var EIratio = (time_inh == 0) ? null : time_exh / time_inh;
+      var WorkOfBreathing_J_per_L = wob / wob_cnt;
       return  [
         rr,
         tidal_volume,
         minute_volume,
-        EIratio];
+        EIratio,
+        WorkOfBreathing_J_per_L];
     } else {
-      return [0,0,0,"NA"];
+      return [0,0,0,"NA","NA"];
     }
   }
-      }
+}
 
 var LIMITS = {
   max: { h: 40,
@@ -1021,7 +1085,9 @@ var LIMITS = {
   taip: { h: 100, // These are in ms
          l: 0},
   trip: { h: 100, // These are in ms
-         l: 0},
+          l: 0},
+  wob: { h: 3,
+         l: 0.2},
 }
 
 function load_ui_with_defaults(limits) {
@@ -1067,13 +1133,19 @@ function process(samples) {
   var [transitions,breaths] = computeMovingWindowTrace(samples,t,v);
   plot(samples,transitions,breaths);
   // How many seconds backwards should we look? Perhaps 20?
-  var [bpm,tv,mv,EIratio,fio2] = compute_respiration_rate(RESPIRATION_RATE_WINDOW_SECONDS,samples,transitions,breaths);
+  var [bpm,tv,mv,EIratio,wob] = compute_respiration_rate(RESPIRATION_RATE_WINDOW_SECONDS,samples,transitions,breaths);
 
   var alarms = [];
 
   $("#bpm").text(bpm.toFixed(1));
   $("#tv").text(tv.toFixed(0));
-  $("#mv").text((mv).toFixed(2));
+  $("#mv").text(mv.toFixed(2));
+
+  if (wob == "NA") {
+    $("#wob").text("NA");
+  } else {
+    $("#wob").text(wob.toFixed(2));
+  }
   if (EIratio == "NA") {
     $("#ier").text("NA");
   } else {
@@ -1096,8 +1168,10 @@ function process(samples) {
 
   alarms = alarms.concat(check_high_and_low(LIMITS,"bpm",bpm.toFixed(1),b_ms));
   alarms = alarms.concat(check_high_and_low(LIMITS,"tv",tv.toFixed(0),b_ms));
-  alarms = alarms.concat(check_high_and_low(LIMITS,"mv",(mv).toFixed(2),b_ms));
+  alarms = alarms.concat(check_high_and_low(LIMITS,"mv",mv.toFixed(2),b_ms));
   alarms = alarms.concat(check_high_and_low(LIMITS,"ier",(1.0 / EIratio).toFixed(1),b_ms));
+  if (wob != "NA")
+    alarms = alarms.concat(check_high_and_low(LIMITS,"wob",wob.toFixed(2),b_ms));
 
   // These must be moved out; in fact,
   // they must be made configurable!
@@ -1182,26 +1256,34 @@ function retrieveAndPlot(){
               // WARNING: This is a hack...if the timestamp is negative,
               // we treat it as a limited (beyond range of sensor) measurement.
               // Our goal is to warn about this, but for now we will just
-              // ignore and correct.
+            // ignore and correct.
+            if (cur_sam == null) {
+              console.log("No return");
+              return;
+            }
             if (cur_sam && cur_sam.length == 0) {
               console.log("no samples; potential misconfiguration!");
             } else {
-              cur_sam = sanitize_samples(cur_sam);
-	      if (INITS_ONLY) {
-	        samples = cur_sam;
-	        INITS_ONLY = false;
-	      } else {
-                var discard = Math.max(0,
-                                       samples.length + cur_sam.length - MAX_SAMPLES_TO_STORE_S);
-	        samples = samples.slice(discard);
-	      }
-
-
-	      samples = samples.concat(cur_sam);
-	      // We are not guaranteeed to get samples in order
-	      // we sort them....
-	      samples = samples.sort((a,b) => a.ms - b.ms);
-              process(samples);
+              if (typeof(cur_sam) == "string") {
+                console.log(cur_sam);
+              } else {
+                cur_sam = sanitize_samples(cur_sam);
+	        if (INITS_ONLY) {
+	          samples = cur_sam;
+	          INITS_ONLY = false;
+	        } else {
+                  var discard = Math.max(0,
+                                         samples.length + cur_sam.length - MAX_SAMPLES_TO_STORE_S);
+	          samples = samples.slice(discard);
+	        }
+
+
+	        samples = samples.concat(cur_sam);
+	        // We are not guaranteeed to get samples in order
+	        // we sort them....
+	        samples = samples.sort((a,b) => a.ms - b.ms);
+                process(samples);
+              }
             }
           },
           error: function(xhr, ajaxOptions, thrownError) {
@@ -1416,11 +1498,10 @@ function PressureVolumeWork(breath, transitions, samples) {
     var beginTime_ms = beginTransition.ms;
     var endTransition = transitions[breath.trans_cross_zero];
     var endTime_ms = endTransition.ms;
-    var flows = samples.filter(s => s.event == 'M' && s.type == 'F' && s.ms >= beginTime_ms && s.ms <= endTime_ms);
-    var pressures = samples.filter(s => s.event == 'M' && s.type == 'D' && s.loc == 'A'&& s.ms >= beginTime_ms && s.ms <= endTime_ms);
-
-    console.log(flows);
-    console.log(pressures);
+    var flows = samples.filter(s => s.event == 'M' && s.type == 'F' &&
+                               s.ms >= beginTime_ms && s.ms <= endTime_ms);
+    var pressures = samples.filter(s => s.event == 'M' && s.type == 'D' &&
+                                   s.loc == 'A'&& s.ms >= beginTime_ms && s.ms <= endTime_ms);
 
     // Note: The algorithm below relies on the fact that there is
     // only one flow or pressure with a single ms value; and that
@@ -1433,8 +1514,8 @@ function PressureVolumeWork(breath, transitions, samples) {
     var ct = Math.min(flows[0].ms,pressures[0].ms);
     var lfp = { val : flows[0].val, ms: flows[0].ms } ; // last flow point
     var lpp = { val : pressures[0].val, ms: pressures[0].ms }; // last pressure_point
-    var fi = increment_past(flows,ct,0); // Index of next flow sample
-    var pi = increment_past(pressures,ct,0); // Index of next pressure sample
+    var fi = increment_past(flows,flows[0].ms,0); // Index of next flow sample
+    var pi = increment_past(pressures,pressures[0].ms,0); // Index of next pressure sample
     var w = 0; // current work
 
     // compute flow at time ms give index and last point
@@ -1445,17 +1526,24 @@ function PressureVolumeWork(breath, transitions, samples) {
       return last.val + (cur.val - last.val)*(ms - ms0)/(ms1 - ms0);
     }
     function increment_past(array,ms,index) {
+      var begin = index;
       while(index < array.length && array[index].ms <= ms)
         index++;
+      if (index == begin) debugger;
       if (index >= array.length)
         return null;
       else
         return index;
     }
 
+    // A fundamental invariant:
+    // pressures[pi].ms > lpp.ms
+    // flows[pi].ms > lfp.ms
     while ((fi + pi) < (flows.length +  pressures.length)) {
       // Invariant always increment fi or pi
       // fi and pi point to unprocessed value
+      console.assert(pressures[pi].ms > lpp.ms);
+      console.assert(flows[fi].ms > lfp.ms);
       var ms;
       if (pressures[pi].ms <= flows[fi].ms) { // process pressure
         ms = pressures[pi].ms;
@@ -1473,7 +1561,8 @@ function PressureVolumeWork(breath, transitions, samples) {
       if ((fi === null) || (pi === null))
         break;
       var dur_s = (ms - ct) / 1000;
-      console.log("dur_s",dur_s);
+      console.assert(pressures[pi].ms > lpp.ms);
+      console.assert(flows[fi].ms > lfp.ms);
       var nf = f(ms,flows[fi],lfp);
       var np = f(ms,pressures[pi],lpp);
       var f1 = (lfp.val + nf)/2;
@@ -1490,48 +1579,6 @@ function PressureVolumeWork(breath, transitions, samples) {
       lpp = { val : p1, ms: ms };
       ct = ms;
     }
-    console.log("begin transition time, end transition time:",beginTime_ms,endTime_ms);
-
-    console.log("ms,w",ms,w);
-    //var pressureVolume_prod= 0;
-    //for(var j = a; j < z-1; j++) {
-    //  // I'll use qadrilateral approximation.
-    //  // We'll form each quadrilateral between two samples.
-    //  var ms = flows[j+1].ms - flows[j].ms;
-    //  var ht = (((flows[j+1].val*pressures[j+1].val) + (flows[j].val*pressures[j+1].val ))/2) * CONVERT_PIRDS_TO_SLM;
-    //  // Flow in standard liters per minute,
-    //  // divide by 60000 to get liters/s
-    //  pressureVolume_prod += ms * ht/60000;
-    //  if (isNaN(pressureVolume_prod)) {
-    //    debugger;
-    //  }
-    // }
-    // pressure cm H2O --> atm (divide by 1033)
-    // return pressureVolume_prod/1033
-
-    // average pressure * average flow ~ approximation of work
-    var pAv_cm = 0;
-    for (var i = 0; i<pressures.length; i++) {
-      pAv_cm += pressures[i].val/10;
-    }
-    pAv_cm /= pressures.length;
-    var pressures_pascales = pAv_cm * 98.0665; //cm to pasc.
-    var fAv_lpm = 0;
-    for (var i = 0; i<flows.length; i++) {
-      fAv_lpm += flows[i].val/1000;
-    }
-    fAv_lpm /= flows.length;
-    console.log("flows:",flows,"\npressures:",pressures)
-    console.log("pAv, vAv = ",pAv_cm,fAv_lpm);
-    var flow_cubicMetersPerSecond = fAv_lpm/1000/60; //lpm to cmps
-    var avPower = pressures_pascales*flow_cubicMetersPerSecond; // Watts
-    var avWork = avPower * (endTime_ms - beginTime_ms)/1000; // Joules
-
-
-    console.log("Power (Watts):",avPower);
-    console.log("Work (Joules):",avWork);
-
-    console.log("ms, Work main (Joules)",ms,w);
     return w;
   }
 }
@@ -1542,42 +1589,52 @@ function generate_synthetic_trace() {
   const SAMPLES_MS_PER_SAMPLE = 1;
   var trace = [];
   var cur = 0;
-  function push_samples(start,num,d,f) {
+  // p is a probability of occuring.
+  function push_samples(start,num,d,f,pd,pf) {
     for(var i = start; i < start+num; i++) {
-      trace.push(
-      {
-        event: "M",
-        loc: "A",
-        ms: i,
-        num: 0,
-        type: "D",
-        val: d
-      });
-      trace.push(
-      {
-        event: "M",
-        loc: "A",
-        ms: i,
-        num: 0,
-        type: "F",
-        val: f
-      });
+      if (Math.random() < pd) {
+        trace.push(
+          {
+            event: "M",
+            loc: "A",
+            ms: i,
+            num: 0,
+            type: "D",
+            val: d
+          });
+      }
+      if (Math.random() < pf) {
+        trace.push(
+          {
+            event: "M",
+            loc: "A",
+            ms: i,
+            num: 0,
+            type: "F",
+            val: f
+          });
+      }
     }
   }
-  push_samples(0,SAMPLES_PER_PHASE,-200,-50000);
-  push_samples(SAMPLES_PER_PHASE,SAMPLES_PER_PHASE,200,50000);
-  push_samples(SAMPLES_PER_PHASE*2,SAMPLES_PER_PHASE,-200,-50000);
-  push_samples(SAMPLES_PER_PHASE*3,SAMPLES_PER_PHASE,200,50000);
+  const P1 = 1/2;
+  const P2 = 1/2;
+  push_samples(SAMPLES_PER_PHASE,SAMPLES_PER_PHASE,200,50000,P1,P2);
+  push_samples(0,SAMPLES_PER_PHASE,-200,-50000,P1,P2);
+  push_samples(SAMPLES_PER_PHASE,SAMPLES_PER_PHASE,200,50000,P1,P2);
+  push_samples(SAMPLES_PER_PHASE*2,SAMPLES_PER_PHASE,-200,-50000,P1,P2);
+  push_samples(SAMPLES_PER_PHASE*3,SAMPLES_PER_PHASE,200,50000,P1,P2);
   return trace;
 }
 
+function nearp(x,y,d) {
+  return Math.abs(x - y) <= d;
+}
 
 function testWorkSynthetic(){ // breaths give us inspiration transition points
   var samples = generate_synthetic_trace();
 
   const JOULES_IN_BREATH = 1 * 1961.33 * 50000 / (60e+6);
 
-
   var flows = samples.filter(s => s.event == 'M' && s.type == 'F');
     var first_time = flows[0].ms;
     var last_time = flows[flows.length - 1].ms;
@@ -1592,10 +1649,10 @@ function testWorkSynthetic(){ // breaths give us inspiration transition points
     console.log(breaths);
     for(i = 0; i<breaths.length; i++) {
       var w = PressureVolumeWork(breaths[i], transitions, samples);
-      console.assert((w == null) || (w == JOULES_IN_BREATH));
-      console.log("final = ",w);
+      console.assert((w == null) || (nearp(w,JOULES_IN_BREATH),0.1));
+      console.log("final (Joules) = ",w);
     }
-
+  return true;
 }
 
 
@@ -1680,6 +1737,8 @@ function testWorkSynthetic(){ // breaths give us inspiration transition points
                        trans_end_exhale: i,
 		     }
 		    );
+        var w = PressureVolumeWork(breaths[breaths.length-1], transitions, samples);
+        breaths[breaths.length-1].work = w;
         beg = i;
         expiring = false;
         vole = integrateSamples(last,transitions[i].sample,flows);
@@ -1758,6 +1817,8 @@ function computeMovingWindowTrace(samples,t,v) {
                        trans_end_exhale: i,
 		     }
 		    );
+        var w = PressureVolumeWork(breaths[0], transitions, samples);
+        breaths[0].work = w;
         beg = i;
         expiring = false;
         vole = integrateSamples(last,transitions[i].sample,flows);