function initialize () {

  setupTangle();
  setupFlapjax();
  setupFlapjaxDrag();
}

// Setup Tangle Model
function setupTangle () {
  var element = document.getElementById("tangle");

  new Tangle(element, {
    initialize: function () {
      this.cookies = 4;
    },
    update: function () {
      this.calories = this.cookies * 50;
    }
  });
}

// Setup Flapjax
function setupFlapjax () {
  var behavior = extractValueB("cookies");
  var colories = behavior.liftB(function (n) { return n * 50; });
  insertDomB(colories, "calories");
}

// Setup Flapjax Adjustable Number Widget
function setupFlapjaxDrag () {
  var element = document.getElementById("cookies-drag");
  var behavior = makeAdjustableNumber(element);
  var colories = behavior.liftB(function (n) { return n * 50; });
  insertDomB(colories, "calories-drag");
}

// Return a higher order event stream to start dragging
function mouseDownMove (element) {
  return extractEventE(element,'mousedown').mapE(function(md) {
    var initValue = parseInt(element.value);
    var offset = md.layerX;

    return extractEventE(document,'mousemove').mapE(function(mm) {
      var delta = mm.layerX - offset;
      return Math.max(1, Math.round(delta / 20 + initValue));
    });
  });
}

// Return a higher order event stream to stop dragging
function mouseUp (element) {
  return extractEventE(document,'mouseup').mapE(function() {
    return zeroE();
  });
}

// Merge mousedown and mouseup, then convert it to event stream of number
function mouseDownMoveUp(element) {
  var downMoveUp = mouseDownMove(element).mergeE(mouseUp(element));
  return downMoveUp.switchE();
}

// Make an AdjustableNumber Widget and return the behavior
function makeAdjustableNumber (element) {
  var drag = mouseDownMoveUp(element);
  drag.mapE(function(n) { element.value = n; });
  return drag.startsWith(element.value);
}

