
function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}

function Viz(init, algo) {
  this.init = init; //function to initialize algorithm state each time it is run
  this.algo = algo; //generator to run the algorithm
  this.commentary = null; //div where commentary text is to be displayed
  this.playon = null; //function to visually on the play button
  this.playoff = null; //function to visually off the play button (and show pause)
  this.process = null;
  this.auto_next = false;
  this.timer = null;
  this.initialized = false;
}

Viz.prototype.initialize = function() {
  viz.process = viz.algo.apply(null, viz.init());
  if (viz.commentary) viz.commentary.innerHTML = 'Ready to start.';
  viz.initialized = true;
}

Viz.prototype.run = function() {
  var viz = this;
  if ((!viz.initialized) && viz.init && viz.algo) {
    viz.initialize();
    if (viz.auto_next)
      viz.timer = setTimeout(function() {viz.run();}, 2000);
    return;
  }
  var n = viz.process.next();
  if (n) {
    var f = n.value;
    if (f) {
      if (f[0] && viz.commentary) viz.commentary.innerHTML = f[0];
      var delay = 2000;
      var start_index = 1;
      if (typeof f[1] == 'number') {      
        delay = f[1];
        start_index = 2;
      }
      for (var i = start_index; i < f.length; i+=2)
        f[i].apply(null, f[i+1]);
      if (viz.auto_next)
        viz.timer = setTimeout(function() {viz.run();}, delay);
    } else {
      viz.pause(); viz.initialized = false;
      if (viz.commentary) viz.commentary.innerHTML = 'Finished!';
    }
  }
}

Viz.prototype.init_buttons = function(commentary, playbtn, nextbtn, stopbtn, playon, playoff) {
  viz = this;
  viz.commentary = commentary;
  viz.playon = playon;
  viz.playoff = playoff;
  if (playbtn)
    addEvent(playbtn, 'click', function(){
      if (viz.auto_next) viz.pause()
      else viz.play();
    });
  if (nextbtn)
    addEvent(nextbtn, 'click', function(){viz.pause(); viz.run();});
  if (stopbtn)
    addEvent(stopbtn, 'click', function(){viz.pause(); viz.initialize();});
}

Viz.prototype.play = function() {
  viz = this;
  if (viz.playoff) viz.playoff();
  viz.auto_next = true;
  viz.run();
}

Viz.prototype.pause = function() {
  viz = this;
  if (viz.playon) viz.playon();
  if (viz.timer) clearTimeout(viz.timer);
  viz.auto_next = false;
}

@@ -663,191 +663,998 @@
 %0A%7D%0A%0A
-Viz.prototype.initialize = function() %7B%0A  viz.process = viz.algo.apply(null, viz.init());%0A  if (viz.commentary) viz.commentary.innerHTML = 'Ready to start.';%0A  viz.initialized = true;
+function can_yield() %7B%0A  try %7B%0A    eval('(function*() %7B yield 5; %7D())');%0A    return true;%0A  %7D catch (e) %7B%0A    return false;%0A  %7D%0A%7D%0A%0Afunction yield_supported(silent) %7B%0A  var isChromium = window.chrome,%0A      vendorName = window.navigator.vendor,%0A      no_yield = ! can_yield();%0A  var error = null;%0A  if(isChromium !== null && vendorName === %22Google Inc.%22 && no_yield)%0A    error = 'You must Enable Experimental JavaScript in chrome://flags/ for visualization to work.'%0A  else if (no_yield)%0A    error = 'You must use a more recent browser for this visualization.'%0A  if (error && !silent) window.alert(error);%0A  return error;%0A%7D%0A%0Ayield_supported();%0A%0AViz.prototype.initialize = function() %7B%0A  var error = yield_supported(true);%0A  if (! error) %7B%0A    viz.initialized = true;%0A    if (viz.commentary) viz.commentary.innerHTML = 'Ready to start.';%0A    viz.process = viz.algo.apply(null, viz.init());%0A  %7D else %7B%0A    if (viz.commentary) viz.commentary.innerHTML = error;%0A    else window.alert(error);%0A  %7D
 %0A%7D%0A%0A

Check yield support