text: /*
   * MBP - Mobile boilerplate helper functions
   */
  
  (function(document){
  
  window.MBP = window.MBP || {}; 
  
  
  /* 
    * Fix for iPhone viewport scale bug 
    * http://www.blog.highub.com/mobile-2/a-fix-for-iphone-viewport-scale-bug/
  */
  
  MBP.viewportmeta = document.querySelector && document.querySelector('meta[name="viewport"]');
  MBP.ua = navigator.userAgent;
  
  MBP.scaleFix = function () {
    if (MBP.viewportmeta && /iPhone|iPad|iPod/.test(MBP.ua) && !/Opera Mini/.test(MBP.ua)) {
      MBP.viewportmeta.content = "width=device-width, minimum-scale=1.0, maximum-scale=1.0";
      document.addEventListener("gesturestart", MBP.gestureStart, false);
    }
  };
  MBP.gestureStart = function () {
    MBP.viewportmeta.content = "width=device-width, minimum-scale=0.25, maximum-scale=1.6";
  };
  
  
  /*
    * Normalized hide address bar for iOS & Android
    * (c) Scott Jehl, scottjehl.com
    * MIT License
  */
  
  // If we split this up into two functions we can reuse
  // this function if we aren't doing full page reloads.
  
  // If we cache this we don't need to re-calibrate everytime we call
  // the hide url bar
  MBP.BODY_SCROLL_TOP = false;
  
  // So we don't redefine this function everytime we
  // we call hideUrlBar
  MBP.getScrollTop = function(){
    var win = window,
        doc = document;
  
    return win.pageYOffset || doc.compatMode === "CSS1Compat" && doc.documentElement.scrollTop || doc.body.scrollTop || 0;
  };
  
  // It should be up to the mobile
  MBP.hideUrlBar = function(){
      var win = window;
  
      // if there is a hash, or MBP.BODY_SCROLL_TOP hasn't been set yet, wait till that happens
      if( !location.hash && MBP.BODY_SCROLL_TOP !== false){
          win.scrollTo( 0, MBP.BODY_SCROLL_TOP === 1 ? 0 : 1 );
      }
  };
  
  MBP.hideUrlBarOnLoad = function () {
    var win = window,
        doc = win.document,
        bodycheck;
  
    // If there's a hash, or addEventListener is undefined, stop here
    if( !location.hash && win.addEventListener ) {
  
      //scroll to 1
      window.scrollTo( 0, 1 );
      MBP.BODY_SCROLL_TOP = 1;
  
      //reset to 0 on bodyready, if needed
      bodycheck = setInterval(function() {
        if( doc.body ) {
          clearInterval( bodycheck );
          MBP.BODY_SCROLL_TOP = MBP.getScrollTop();
          MBP.hideUrlBar();
        }
      }, 15 );
  
      win.addEventListener( "load", function() {
        setTimeout(function() {
          //at load, if user hasn't scrolled more than 20 or so...
          if( MBP.getScrollTop() < 20 ) {
            //reset to hide addr bar at onload
            MBP.hideUrlBar();
          }
        }, 0);
      } );
    }
  };
  
  
  /* 
     * Fast Buttons - read wiki below before using
     * https://github.com/h5bp/mobile-boilerplate/wiki/JavaScript-Helper
  */
  
  MBP.fastButton = function (element, handler) {
    this.handler = handler;
  	
  	if (element.length && element.length > 1) {
      for (var singleElIdx in element) {
        this.addClickEvent(element[singleElIdx]);
      }
    } else {
      this.addClickEvent(element);
    }
  };
   
  MBP.fastButton.prototype.handleEvent = function(event) {
  	event = event || window.event;
    switch (event.type) {
      case 'touchstart': this.onTouchStart(event); break;
      case 'touchmove': this.onTouchMove(event); break;
      case 'touchend': this.onClick(event); break;
      case 'click': this.onClick(event); break;
    }
  };
  
  MBP.fastButton.prototype.onTouchStart = function(event) {
    var element = event.srcElement;
    event.stopPropagation();
    element.addEventListener('touchend', this, false);
    document.body.addEventListener('touchmove', this, false);
    this.startX = event.touches[0].clientX;
    this.startY = event.touches[0].clientY;
    element.style.backgroundColor = "rgba(0,0,0,.7)";
  };
  
  MBP.fastButton.prototype.onTouchMove = function(event) {
    if(Math.abs(event.touches[0].clientX - this.startX) > 10 || 
      Math.abs(event.touches[0].clientY - this.startY) > 10    ) {
      this.reset(element);
    }
  };
  
  MBP.fastButton.prototype.onClick = function(event) {
  	event = event || window.event;
    var element = event.srcElement;
    if (event.stopPropagation) { event.stopPropagation(); }
    this.reset(event);
    this.handler.apply(event.currentTarget, [event]);
    if(event.type == 'touchend') {
      MBP.preventGhostClick(this.startX, this.startY);
    }
    element.style.backgroundColor = "";
  };
  
  MBP.fastButton.prototype.reset = function(event) {
    var element = event.srcElement;
  	rmEvt(element, "touchend", this, false);
  	rmEvt(document.body, "touchmove", this, false);
    element.style.backgroundColor = "";
  };
  
  MBP.fastButton.prototype.addClickEvent = function(element) {
    addEvt(element, "touchstart", this, false);
    addEvt(element, "click", this, false);
  };
  
  MBP.preventGhostClick = function (x, y) {
    MBP.coords.push(x, y);
    window.setTimeout(function (){
      MBP.coords.splice(0, 2);
    }, 2500);
  };
  
  MBP.ghostClickHandler = function (event) {
    if (!MBP.hadTouchEvent && MBP.dodgyAndroid) {
      // This is a bit of fun for Android 2.3...
      // If you change window.location via fastButton, a click event will fire
      // on the new page, as if the events are continuing from the previous page.
      // We pick that event up here, but MBP.coords is empty, because it's a new page,
      // so we don't prevent it. Here's we're assuming that click events on touch devices
      // that occur without a preceding touchStart are to be ignored. 
      event.stopPropagation();
      event.preventDefault();
      return;
    }
    for(var i = 0, len = MBP.coords.length; i < len; i += 2) {
      var x = MBP.coords[i];
      var y = MBP.coords[i + 1];
      if(Math.abs(event.clientX - x) < 25 && Math.abs(event.clientY - y) < 25) {
        event.stopPropagation();
        event.preventDefault();
      }
    }
  };
  
  // This bug only affects touch Android 2.3 devices, but a simple ontouchstart test creates a false positive on
  // some Blackberry devices. https://github.com/Modernizr/Modernizr/issues/372
  // The browser sniffing is to avoid the Blackberry case. Bah
  MBP.dodgyAndroid = ('ontouchstart' in window) && (navigator.userAgent.indexOf('Android 2.3') != -1);
  
  if (document.addEventListener) {
    document.addEventListener('click', MBP.ghostClickHandler, true);
  }
  
  addEvt( document.documentElement, 'touchstart', function() {
    MBP.hadTouchEvent = true;
  }, false);
                              
  MBP.coords = [];
  
  // fn arg can be an object or a function, thanks to handleEvent
  // read more about the explanation at: http://www.thecssninja.com/javascript/handleevent
  function addEvt(el, evt, fn, bubble) {
    if("addEventListener" in el) {
      // BBOS6 doesn't support handleEvent, catch and polyfill
      try {
        el.addEventListener(evt, fn, bubble);
      } catch(e) {
        if(typeof fn == "object" && fn.handleEvent) {
          el.addEventListener(evt, function(e){
          // Bind fn as this and set first arg as event object
          fn.handleEvent.call(fn,e);
          }, bubble);
        } else {
          throw e;
        }
      }
    } else if("attachEvent" in el) {
      // check if the callback is an object and contains handleEvent
      if(typeof fn == "object" && fn.handleEvent) {
        el.attachEvent("on" + evt, function(){
          // Bind fn as this
          fn.handleEvent.call(fn);
        });
      } else {
        el.attachEvent("on" + evt, fn);
      }
    }
  }
  
  function rmEvt(el, evt, fn, bubble) {
    if("removeEventListener" in el) {
      // BBOS6 doesn't support handleEvent, catch and polyfill
      try {
        el.removeEventListener(evt, fn, bubble);
      } catch(e) {
        if(typeof fn == "object" && fn.handleEvent) {
          el.removeEventListener(evt, function(e){
            // Bind fn as this and set first arg as event object
            fn.handleEvent.call(fn,e);
          }, bubble);
        } else {
          throw e;
        }
      }
    } else if("detachEvent" in el) {
      // check if the callback is an object and contains handleEvent
      if(typeof fn == "object" && fn.handleEvent) {
        el.detachEvent("on" + evt, function(){
          // Bind fn as this
          fn.handleEvent.call(fn);
        });
      } else {
        el.detachEvent("on" + evt, fn);
      }
    }
  }
  
  
  /* 
    * Autogrow
    * http://googlecode.blogspot.com/2009/07/gmail-for-mobile-html5-series.html
  */
  
  MBP.autogrow = function (element, lh) {
    function handler(e){
      var newHeight = this.scrollHeight,
          currentHeight = this.clientHeight;
      if (newHeight > currentHeight) {
        this.style.height = newHeight + 3 * textLineHeight + "px";
      }
    }
  
    var setLineHeight = (lh) ? lh : 12,
        textLineHeight = element.currentStyle ? element.currentStyle.lineHeight : 
                         getComputedStyle(element, null).lineHeight;
  
    textLineHeight = (textLineHeight.indexOf("px") == -1) ? setLineHeight :
                     parseInt(textLineHeight, 10);
  
    element.style.overflow = "hidden";
    element.addEventListener ? element.addEventListener('keyup', handler, false) :
                               element.attachEvent('onkeyup', handler);
  };
  
  
  /* 
    * Enable active
    * Enable CSS active pseudo styles in Mobile Safari
    * http://miniapps.co.uk/blog/post/enable-css-active-pseudo-styles-in-mobile-safari/
  */
  
  MBP.enableActive = function () {
    document.addEventListener("touchstart", function() {}, false);
  };
  
  
  /* 
    * Prevent iOS from zooming onfocus
    * https://github.com/h5bp/mobile-boilerplate/pull/108
  */
  
  MBP.preventZoom = function () {
    var formFields = document.querySelectorAll('input, select, textarea'),
    	  contentString = 'width=device-width,initial-scale=1,maximum-scale=',
    	  i = 0;
    for(i = 0; i < formFields.length; i++) {
      formFields[i].onfocus = function() {
        MBP.viewportmeta.content = contentString + '1';
      };
      formFields[i].onblur = function() {
        MBP.viewportmeta.content = contentString + '10';
      };
    }
  };
  
  
  /* 
    * Original jQuery snippet for Prevent iOS from zooming onfocus
    *  http://nerd.vasilis.nl/prevent-ios-from-zooming-onfocus/
  */
  // $('input, select, textarea').bind('focus blur', function(event) {	  	
  //	MBP.viewportmeta.content = 'width=device-width,initial-scale=1,maximum-scale=' + (event.type == 'blur' ? 10 : 1);  	
  // });
  
  })(document);
  