Deutschland United States United Kingdom
ContentLion - Open Source CMS

jquery.mobile.custom.js

Blame | Last modification | View Log

/*
* jQuery Mobile v1.3.1
* http://jquerymobile.com
*
* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
*/


(function ( root, doc, factory ) {
        if ( typeof define === "function" && define.amd ) {
                // AMD. Register as an anonymous module.
                define( [ "jquery" ], function ( $ ) {
                        factory( $, root, doc );
                        return $.mobile;
                });
        } else {
                // Browser globals
                factory( root.jQuery, root, doc );
        }
}( this, document, function ( jQuery, window, document, undefined ) {
// Script: jQuery hashchange event
//
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub       - http://github.com/cowboy/jquery-hashchange/
// Source       - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified)   - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
// Copyright (c) 2010 "Cowboy" Ben Alman,
// Dual licensed under the MIT and GPL licenses.
// http://benalman.com/about/license/
//
// About: Examples
//
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
// Information about what version or versions of jQuery this plugin has been
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
//                   Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests      - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3   - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
//         "removable" for mobile-only development. Added IE6/7 document.title
//         support. Attempted to make Iframe as hidden as possible by using
//         techniques from http://www.paciellogroup.com/blog/?p=604. Added
//         support for the "shortcut" format $(window).hashchange( fn ) and
//         $(window).hashchange() like jQuery provides for built-in events.
//         Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
//         lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
//         and <jQuery.fn.hashchange.src> properties plus document-domain.html
//         file to address access denied issues when setting document.domain in
//         IE6/7.
// 1.2   - (2/11/2010) Fixed a bug where coming back to a page using this plugin
//         from a page on another domain would cause an error in Safari 4. Also,
//         IE6/7 Iframe is now inserted after the body (this actually works),
//         which prevents the page from scrolling when the event is first bound.
//         Event can also now be bound before DOM ready, but it won't be usable
//         before then in IE6/7.
// 1.1   - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug
//         where browser version is incorrectly reported as 8.0, despite
//         inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag.
// 1.0   - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special
//         window.onhashchange functionality into a separate plugin for users
//         who want just the basic event & back button support, without all the
//         extra awesomeness that BBQ provides. This plugin will be included as
//         part of jQuery BBQ, but also be available separately.

(function( $, window, undefined ) {
  // Reused string.
  var str_hashchange = 'hashchange',
   
    // Method / object references.
    doc = document,
    fake_onhashchange,
    special = $.event.special,
   
    // Does the browser support window.onhashchange? Note that IE8 running in
    // IE7 compatibility mode reports true for 'onhashchange' in window, even
    // though the event isn't supported, so also test document.documentMode.
    doc_mode = doc.documentMode,
    supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
 
  // Get location.hash (or what you'd expect location.hash to be) sans any
  // leading #. Thanks for making this necessary, Firefox!
  function get_fragment( url ) {
    url = url || location.href;
    return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
  };
 
  // Method: jQuery.fn.hashchange
  //
  // Bind a handler to the window.onhashchange event or trigger all bound
  // window.onhashchange event handlers. This behavior is consistent with
  // jQuery's built-in event handlers.
  //
  // Usage:
  //
  // > jQuery(window).hashchange( [ handler ] );
  //
  // Arguments:
  //
  //  handler - (Function) Optional handler to be bound to the hashchange
  //    event. This is a "shortcut" for the more verbose form:
  //    jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
  //    all bound window.onhashchange event handlers will be triggered. This
  //    is a shortcut for the more verbose
  //    jQuery(window).trigger( 'hashchange' ). These forms are described in
  //    the <hashchange event> section.
  //
  // Returns:
  //
  //  (jQuery) The initial jQuery collection of elements.
 
  // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
  // $(elem).hashchange() for triggering, like jQuery does for built-in events.
  $.fn[ str_hashchange ] = function( fn ) {
    return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
  };
 
  // Property: jQuery.fn.hashchange.delay
  //
  // The numeric interval (in milliseconds) at which the <hashchange event>
  // polling loop executes. Defaults to 50.
 
  // Property: jQuery.fn.hashchange.domain
  //
  // If you're setting document.domain in your JavaScript, and you want hash
  // history to work in IE6/7, not only must this property be set, but you must
  // also set document.domain BEFORE jQuery is loaded into the page. This
  // property is only applicable if you are supporting IE6/7 (or IE8 operating
  // in "IE7 compatibility" mode).
  //
  // In addition, the <jQuery.fn.hashchange.src> property must be set to the
  // path of the included "document-domain.html" file, which can be renamed or
  // modified if necessary (note that the document.domain specified must be the
  // same in both your main JavaScript as well as in this file).
  //
  // Usage:
  //
  // jQuery.fn.hashchange.domain = document.domain;
 
  // Property: jQuery.fn.hashchange.src
  //
  // If, for some reason, you need to specify an Iframe src file (for example,
  // when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
  // do so using this property. Note that when using this property, history
  // won't be recorded in IE6/7 until the Iframe src file loads. This property
  // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
  // compatibility" mode).
  //
  // Usage:
  //
  // jQuery.fn.hashchange.src = 'path/to/file.html';
 
  $.fn[ str_hashchange ].delay = 50;
  /*
  $.fn[ str_hashchange ].domain = null;
  $.fn[ str_hashchange ].src = null;
  */

 
  // Event: hashchange event
  //
  // Fired when location.hash changes. In browsers that support it, the native
  // HTML5 window.onhashchange event is used, otherwise a polling loop is
  // initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
  // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
  // compatibility" mode), a hidden Iframe is created to allow the back button
  // and hash-based history to work.
  //
  // Usage as described in <jQuery.fn.hashchange>:
  //
  // > // Bind an event handler.
  // > jQuery(window).hashchange( function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // >
  // > // Manually trigger the event handler.
  // > jQuery(window).hashchange();
  //
  // A more verbose usage that allows for event namespacing:
  //
  // > // Bind an event handler.
  // > jQuery(window).bind( 'hashchange', function(e) {
  // >   var hash = location.hash;
  // >   ...
  // > });
  // >
  // > // Manually trigger the event handler.
  // > jQuery(window).trigger( 'hashchange' );
  //
  // Additional Notes:
  //
  // * The polling loop and Iframe are not created until at least one handler
  //   is actually bound to the 'hashchange' event.
  // * If you need the bound handler(s) to execute immediately, in cases where
  //   a location.hash exists on page load, via bookmark or page refresh for
  //   example, use jQuery(window).hashchange() or the more verbose
  //   jQuery(window).trigger( 'hashchange' ).
  // * The event can be bound before DOM ready, but since it won't be usable
  //   before then in IE6/7 (due to the necessary Iframe), recommended usage is
  //   to bind it inside a DOM ready handler.
 
  // Override existing $.event.special.hashchange methods (allowing this plugin
  // to be defined after jQuery BBQ in BBQ's source code).
  special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
   
    // Called only when the first 'hashchange' event is bound to window.
    setup: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
     
      // Otherwise, we need to create our own. And we don't want to call this
      // until the user binds to the event, just in case they never do, since it
      // will create a polling loop and possibly even a hidden Iframe.
      $( fake_onhashchange.start );
    },
   
    // Called only when the last 'hashchange' event is unbound from window.
    teardown: function() {
      // If window.onhashchange is supported natively, there's nothing to do..
      if ( supports_onhashchange ) { return false; }
     
      // Otherwise, we need to stop ours (if possible).
      $( fake_onhashchange.stop );
    }
   
  });
 
  // fake_onhashchange does all the work of triggering the window.onhashchange
  // event for browsers that don't natively support it, including creating a
  // polling loop to watch for hash changes and in IE 6/7 creating a hidden
  // Iframe to enable back and forward.
  fake_onhashchange = (function() {
    var self = {},
      timeout_id,
     
      // Remember the initial hash so it doesn't get triggered immediately.
      last_hash = get_fragment(),
     
      fn_retval = function( val ) { return val; },
      history_set = fn_retval,
      history_get = fn_retval;
   
    // Start the polling loop.
    self.start = function() {
      timeout_id || poll();
    };
   
    // Stop the polling loop.
    self.stop = function() {
      timeout_id && clearTimeout( timeout_id );
      timeout_id = undefined;
    };
   
    // This polling loop checks every $.fn.hashchange.delay milliseconds to see
    // if location.hash has changed, and triggers the 'hashchange' event on
    // window when necessary.
    function poll() {
      var hash = get_fragment(),
        history_hash = history_get( last_hash );
     
      if ( hash !== last_hash ) {
        history_set( last_hash = hash, history_hash );
       
        $(window).trigger( str_hashchange );
       
      } else if ( history_hash !== last_hash ) {
        location.href = location.href.replace( /#.*/, '' ) + history_hash;
      }
     
      timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
    };
   
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv
    // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    window.attachEvent && !window.addEventListener && !supports_onhashchange && (function() {
      // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8
      // when running in "IE7 compatibility" mode.
     
      var iframe,
        iframe_src;
     
      // When the event is bound and polling starts in IE 6/7, create a hidden
      // Iframe for history handling.
      self.start = function() {
        if ( !iframe ) {
          iframe_src = $.fn[ str_hashchange ].src;
          iframe_src = iframe_src && iframe_src + get_fragment();
         
          // Create hidden Iframe. Attempt to make Iframe as hidden as possible
          // by using techniques from http://www.paciellogroup.com/blog/?p=604.
          iframe = $('<iframe tabindex="-1" title="empty"/>').hide()
           
            // When Iframe has completely loaded, initialize the history and
            // start polling.
            .one( 'load', function() {
              iframe_src || history_set( get_fragment() );
              poll();
            })
           
            // Load Iframe src if specified, otherwise nothing.
            .attr( 'src', iframe_src || 'javascript:0' )
           
            // Append Iframe after the end of the body to prevent unnecessary
            // initial page scrolling (yes, this works).
            .insertAfter( 'body' )[0].contentWindow;
         
          // Whenever `document.title` changes, update the Iframe's title to
          // prettify the back/next history menu entries. Since IE sometimes
          // errors with "Unspecified error" the very first time this is set
          // (yes, very useful) wrap this with a try/catch block.
          doc.onpropertychange = function() {
            try {
              if ( event.propertyName === 'title' ) {
                iframe.document.title = doc.title;
              }
            } catch(e) {}
          };
         
        }
      };
     
      // Override the "stop" method since an IE6/7 Iframe was created. Even
      // if there are no longer any bound event handlers, the polling loop
      // is still necessary for back/next to work at all!
      self.stop = fn_retval;
     
      // Get history by looking at the hidden Iframe's location.hash.
      history_get = function() {
        return get_fragment( iframe.location.href );
      };
     
      // Set a new history item by opening and then closing the Iframe
      // document, *then* setting its location.hash. If document.domain has
      // been set, update that as well.
      history_set = function( hash, history_hash ) {
        var iframe_doc = iframe.document,
          domain = $.fn[ str_hashchange ].domain;
       
        if ( hash !== history_hash ) {
          // Update Iframe with any initial `document.title` that might be set.
          iframe_doc.title = doc.title;
         
          // Opening the Iframe's document after it has been closed is what
          // actually adds a history entry.
          iframe_doc.open();
         
          // Set document.domain for the Iframe document as well, if necessary.
          domain && iframe_doc.write( '<script>document.domain="' + domain + '"</script>' );
         
          iframe_doc.close();
         
          // Update the Iframe's hash, for great justice.
          iframe.location.hash = hash;
        }
      };
     
    })();
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^ REMOVE IF NOT SUPPORTING IE6/7/8 ^^^^^^^^^^^^^^^^^^^
    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   
    return self;
  })();
 
})(jQuery,this);

(function( $ ) {
        $.mobile = {};
}( jQuery ));
(function( $, window, undefined ) {
        var nsNormalizeDict = {};

        // jQuery.mobile configurable options
        $.mobile = $.extend($.mobile, {

                // Version of the jQuery Mobile Framework
                version: "1.3.1",

                // Namespace used framework-wide for data-attrs. Default is no namespace
                ns: "",

                // Define the url parameter used for referencing widget-generated sub-pages.
                // Translates to to example.html&ui-page=subpageIdentifier
                // hash segment before &ui-page= is used to make Ajax request
                subPageUrlKey: "ui-page",

                // Class assigned to page currently in view, and during transitions
                activePageClass: "ui-page-active",

                // Class used for "active" button state, from CSS framework
                activeBtnClass: "ui-btn-active",

                // Class used for "focus" form element state, from CSS framework
                focusClass: "ui-focus",

                // Automatically handle clicks and form submissions through Ajax, when same-domain
                ajaxEnabled: true,

                // Automatically load and show pages based on location.hash
                hashListeningEnabled: true,

                // disable to prevent jquery from bothering with links
                linkBindingEnabled: true,

                // Set default page transition - 'none' for no transitions
                defaultPageTransition: "fade",

                // Set maximum window width for transitions to apply - 'false' for no limit
                maxTransitionWidth: false,

                // Minimum scroll distance that will be remembered when returning to a page
                minScrollBack: 250,

                // DEPRECATED: the following property is no longer in use, but defined until 2.0 to prevent conflicts
                touchOverflowEnabled: false,

                // Set default dialog transition - 'none' for no transitions
                defaultDialogTransition: "pop",

                // Error response message - appears when an Ajax page request fails
                pageLoadErrorMessage: "Error Loading Page",

                // For error messages, which theme does the box uses?
                pageLoadErrorMessageTheme: "e",

                // replace calls to window.history.back with phonegaps navigation helper
                // where it is provided on the window object
                phonegapNavigationEnabled: false,

                //automatically initialize the DOM when it's ready
                autoInitializePage: true,

                pushStateEnabled: true,

                // allows users to opt in to ignoring content by marking a parent element as
                // data-ignored
                ignoreContentEnabled: false,

                // turn of binding to the native orientationchange due to android orientation behavior
                orientationChangeEnabled: true,

                buttonMarkup: {
                        hoverDelay: 200
                },

                // define the window and the document objects
                window: $( window ),
                document: $( document ),

                // TODO might be useful upstream in jquery itself ?
                keyCode: {
                        ALT: 18,
                        BACKSPACE: 8,
                        CAPS_LOCK: 20,
                        COMMA: 188,
                        COMMAND: 91,
                        COMMAND_LEFT: 91, // COMMAND
                        COMMAND_RIGHT: 93,
                        CONTROL: 17,
                        DELETE: 46,
                        DOWN: 40,
                        END: 35,
                        ENTER: 13,
                        ESCAPE: 27,
                        HOME: 36,
                        INSERT: 45,
                        LEFT: 37,
                        MENU: 93, // COMMAND_RIGHT
                        NUMPAD_ADD: 107,
                        NUMPAD_DECIMAL: 110,
                        NUMPAD_DIVIDE: 111,
                        NUMPAD_ENTER: 108,
                        NUMPAD_MULTIPLY: 106,
                        NUMPAD_SUBTRACT: 109,
                        PAGE_DOWN: 34,
                        PAGE_UP: 33,
                        PERIOD: 190,
                        RIGHT: 39,
                        SHIFT: 16,
                        SPACE: 32,
                        TAB: 9,
                        UP: 38,
                        WINDOWS: 91 // COMMAND
                },

                // Place to store various widget extensions
                behaviors: {},

                // Scroll page vertically: scroll to 0 to hide iOS address bar, or pass a Y value
                silentScroll: function( ypos ) {
                        if ( $.type( ypos ) !== "number" ) {
                                ypos = $.mobile.defaultHomeScroll;
                        }

                        // prevent scrollstart and scrollstop events
                        $.event.special.scrollstart.enabled = false;

                        setTimeout( function() {
                                window.scrollTo( 0, ypos );
                                $.mobile.document.trigger( "silentscroll", { x: 0, y: ypos });
                        }, 20 );

                        setTimeout( function() {
                                $.event.special.scrollstart.enabled = true;
                        }, 150 );
                },

                // Expose our cache for testing purposes.
                nsNormalizeDict: nsNormalizeDict,

                // Take a data attribute property, prepend the namespace
                // and then camel case the attribute string. Add the result
                // to our nsNormalizeDict so we don't have to do this again.
                nsNormalize: function( prop ) {
                        if ( !prop ) {
                                return;
                        }

                        return nsNormalizeDict[ prop ] || ( nsNormalizeDict[ prop ] = $.camelCase( $.mobile.ns + prop ) );
                },

                // Find the closest parent with a theme class on it. Note that
                // we are not using $.fn.closest() on purpose here because this
                // method gets called quite a bit and we need it to be as fast
                // as possible.
                getInheritedTheme: function( el, defaultTheme ) {
                        var e = el[ 0 ],
                                ltr = "",
                                re = /ui-(bar|body|overlay)-([a-z])\b/,
                                c, m;

                        while ( e ) {
                                c = e.className || "";
                                if ( c && ( m = re.exec( c ) ) && ( ltr = m[ 2 ] ) ) {
                                        // We found a parent with a theme class
                                        // on it so bail from this loop.
                                        break;
                                }

                                e = e.parentNode;
                        }

                        // Return the theme letter we found, if none, return the
                        // specified default.

                        return ltr || defaultTheme || "a";
                },

                // TODO the following $ and $.fn extensions can/probably should be moved into jquery.mobile.core.helpers
                //
                // Find the closest javascript page element to gather settings data jsperf test
                // http://jsperf.com/single-complex-selector-vs-many-complex-selectors/edit
                // possibly naive, but it shows that the parsing overhead for *just* the page selector vs
                // the page and dialog selector is negligable. This could probably be speed up by
                // doing a similar parent node traversal to the one found in the inherited theme code above
                closestPageData: function( $target ) {
                        return $target
                                .closest( ':jqmData(role="page"), :jqmData(role="dialog")' )
                                .data( "mobile-page" );
                },

                enhanceable: function( $set ) {
                        return this.haveParents( $set, "enhance" );
                },

                hijackable: function( $set ) {
                        return this.haveParents( $set, "ajax" );
                },

                haveParents: function( $set, attr ) {
                        if ( !$.mobile.ignoreContentEnabled ) {
                                return $set;
                        }

                        var count = $set.length,
                                $newSet = $(),
                                e, $element, excluded;

                        for ( var i = 0; i < count; i++ ) {
                                $element = $set.eq( i );
                                excluded = false;
                                e = $set[ i ];

                                while ( e ) {
                                        var c = e.getAttribute ? e.getAttribute( "data-" + $.mobile.ns + attr ) : "";

                                        if ( c === "false" ) {
                                                excluded = true;
                                                break;
                                        }

                                        e = e.parentNode;
                                }

                                if ( !excluded ) {
                                        $newSet = $newSet.add( $element );
                                }
                        }

                        return $newSet;
                },

                getScreenHeight: function() {
                        // Native innerHeight returns more accurate value for this across platforms,
                        // jQuery version is here as a normalized fallback for platforms like Symbian
                        return window.innerHeight || $.mobile.window.height();
                }
        }, $.mobile );

        // Mobile version of data and removeData and hasData methods
        // ensures all data is set and retrieved using jQuery Mobile's data namespace
        $.fn.jqmData = function( prop, value ) {
                var result;
                if ( typeof prop !== "undefined" ) {
                        if ( prop ) {
                                prop = $.mobile.nsNormalize( prop );
                        }

                        // undefined is permitted as an explicit input for the second param
                        // in this case it returns the value and does not set it to undefined
                        if( arguments.length < 2 || value === undefined ){
                                result = this.data( prop );
                        } else {
                                result = this.data( prop, value );
                        }
                }
                return result;
        };

        $.jqmData = function( elem, prop, value ) {
                var result;
                if ( typeof prop !== "undefined" ) {
                        result = $.data( elem, prop ? $.mobile.nsNormalize( prop ) : prop, value );
                }
                return result;
        };

        $.fn.jqmRemoveData = function( prop ) {
                return this.removeData( $.mobile.nsNormalize( prop ) );
        };

        $.jqmRemoveData = function( elem, prop ) {
                return $.removeData( elem, $.mobile.nsNormalize( prop ) );
        };

        $.fn.removeWithDependents = function() {
                $.removeWithDependents( this );
        };

        $.removeWithDependents = function( elem ) {
                var $elem = $( elem );

                ( $elem.jqmData( 'dependents' ) || $() ).remove();
                $elem.remove();
        };

        $.fn.addDependents = function( newDependents ) {
                $.addDependents( $( this ), newDependents );
        };

        $.addDependents = function( elem, newDependents ) {
                var dependents = $( elem ).jqmData( 'dependents' ) || $();

                $( elem ).jqmData( 'dependents', $.merge( dependents, newDependents ) );
        };

        // note that this helper doesn't attempt to handle the callback
        // or setting of an html element's text, its only purpose is
        // to return the html encoded version of the text in all cases. (thus the name)
        $.fn.getEncodedText = function() {
                return $( "<div/>" ).text( $( this ).text() ).html();
        };

        // fluent helper function for the mobile namespaced equivalent
        $.fn.jqmEnhanceable = function() {
                return $.mobile.enhanceable( this );
        };

        $.fn.jqmHijackable = function() {
                return $.mobile.hijackable( this );
        };

        // Monkey-patching Sizzle to filter the :jqmData selector
        var oldFind = $.find,
                jqmDataRE = /:jqmData\(([^)]*)\)/g;

        $.find = function( selector, context, ret, extra ) {
                selector = selector.replace( jqmDataRE, "[data-" + ( $.mobile.ns || "" ) + "$1]" );

                return oldFind.call( this, selector, context, ret, extra );
        };

        $.extend( $.find, oldFind );

        $.find.matches = function( expr, set ) {
                return $.find( expr, null, null, set );
        };

        $.find.matchesSelector = function( node, expr ) {
                return $.find( expr, null, null, [ node ] ).length > 0;
        };
})( jQuery, this );


(function( $, undefined ) {

        /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
        window.matchMedia = window.matchMedia || (function( doc, undefined ) {

               

                var bool,
                        docElem = doc.documentElement,
                        refNode = docElem.firstElementChild || docElem.firstChild,
                        // fakeBody required for <FF4 when executed in <head>
                        fakeBody = doc.createElement( "body" ),
                        div = doc.createElement( "div" );

                div.id = "mq-test-1";
                div.style.cssText = "position:absolute;top:-100em";
                fakeBody.style.background = "none";
                fakeBody.appendChild(div);

                return function(q){

                        div.innerHTML = "&shy;<style media=\"" + q + "\"> #mq-test-1 { width: 42px; }</style>";

                        docElem.insertBefore( fakeBody, refNode );
                        bool = div.offsetWidth === 42;
                        docElem.removeChild( fakeBody );

                        return {
                                matches: bool,
                                media: q
                        };

                };

        }( document ));

        // $.mobile.media uses matchMedia to return a boolean.
        $.mobile.media = function( q ) {
                return window.matchMedia( q ).matches;
        };

})(jQuery);

        (function( $, undefined ) {
                var support = {
                        touch: "ontouchend" in document
                };

                $.mobile.support = $.mobile.support || {};
                $.extend( $.support, support );
                $.extend( $.mobile.support, support );
        }( jQuery ));

        (function( $, undefined ) {
                $.extend( $.support, {
                        orientation: "orientation" in window && "onorientationchange" in window
                });
        }( jQuery ));

(function( $, undefined ) {

// thx Modernizr
function propExists( prop ) {
        var uc_prop = prop.charAt( 0 ).toUpperCase() + prop.substr( 1 ),
                props = ( prop + " " + vendors.join( uc_prop + " " ) + uc_prop ).split( " " );

        for ( var v in props ) {
                if ( fbCSS[ props[ v ] ] !== undefined ) {
                        return true;
                }
        }
}

var fakeBody = $( "<body>" ).prependTo( "html" ),
        fbCSS = fakeBody[ 0 ].style,
        vendors = [ "Webkit", "Moz", "O" ],
        webos = "palmGetResource" in window, //only used to rule out scrollTop
        opera = window.opera,
        operamini = window.operamini && ({}).toString.call( window.operamini ) === "[object OperaMini]",
        bb = window.blackberry && !propExists( "-webkit-transform" ); //only used to rule out box shadow, as it's filled opaque on BB 5 and lower


function validStyle( prop, value, check_vend ) {
        var div = document.createElement( 'div' ),
                uc = function( txt ) {
                        return txt.charAt( 0 ).toUpperCase() + txt.substr( 1 );
                },
                vend_pref = function( vend ) {
                        if( vend === "" ) {
                                return "";
                        } else {
                                return  "-" + vend.charAt( 0 ).toLowerCase() + vend.substr( 1 ) + "-";
                        }
                },
                check_style = function( vend ) {
                        var vend_prop = vend_pref( vend ) + prop + ": " + value + ";",
                                uc_vend = uc( vend ),
                                propStyle = uc_vend + ( uc_vend === "" ? prop : uc( prop ) );

                        div.setAttribute( "style", vend_prop );

                        if ( !!div.style[ propStyle ] ) {
                                ret = true;
                        }
                },
                check_vends = check_vend ? check_vend : vendors,
                ret;

        for( var i = 0; i < check_vends.length; i++ ) {
                check_style( check_vends[i] );
        }
        return !!ret;
}

function transform3dTest() {
        var mqProp = "transform-3d",
                // Because the `translate3d` test below throws false positives in Android:
                ret = $.mobile.media( "(-" + vendors.join( "-" + mqProp + "),(-" ) + "-" + mqProp + "),(" + mqProp + ")" );

        if( ret ) {
                return !!ret;
        }

        var el = document.createElement( "div" ),
                transforms = {
                        // We’re omitting Opera for the time being; MS uses unprefixed.
                        'MozTransform':'-moz-transform',
                        'transform':'transform'
                };

        fakeBody.append( el );

        for ( var t in transforms ) {
                if( el.style[ t ] !== undefined ){
                        el.style[ t ] = 'translate3d( 100px, 1px, 1px )';
                        ret = window.getComputedStyle( el ).getPropertyValue( transforms[ t ] );
                }
        }
        return ( !!ret && ret !== "none" );
}

// Test for dynamic-updating base tag support ( allows us to avoid href,src attr rewriting )
function baseTagTest() {
        var fauxBase = location.protocol + "//" + location.host + location.pathname + "ui-dir/",
                base = $( "head base" ),
                fauxEle = null,
                href = "",
                link, rebase;

        if ( !base.length ) {
                base = fauxEle = $( "<base>", { "href": fauxBase }).appendTo( "head" );
        } else {
                href = base.attr( "href" );
        }

        link = $( "<a href='testurl' />" ).prependTo( fakeBody );
        rebase = link[ 0 ].href;
        base[ 0 ].href = href || location.pathname;

        if ( fauxEle ) {
                fauxEle.remove();
        }
        return rebase.indexOf( fauxBase ) === 0;
}

// Thanks Modernizr
function cssPointerEventsTest() {
        var element = document.createElement( 'x' ),
                documentElement = document.documentElement,
                getComputedStyle = window.getComputedStyle,
                supports;

        if ( !( 'pointerEvents' in element.style ) ) {
                return false;
        }

        element.style.pointerEvents = 'auto';
        element.style.pointerEvents = 'x';
        documentElement.appendChild( element );
        supports = getComputedStyle &&
        getComputedStyle( element, '' ).pointerEvents === 'auto';
        documentElement.removeChild( element );
        return !!supports;
}

function boundingRect() {
        var div = document.createElement( "div" );
        return typeof div.getBoundingClientRect !== "undefined";
}

// non-UA-based IE version check by James Padolsey, modified by jdalton - from http://gist.github.com/527683
// allows for inclusion of IE 6+, including Windows Mobile 7
$.extend( $.mobile, { browser: {} } );
$.mobile.browser.oldIE = (function() {
        var v = 3,
                div = document.createElement( "div" ),
                a = div.all || [];

        do {
                div.innerHTML = "<!--[if gt IE " + ( ++v ) + "]><br><![endif]-->";
        } while( a[0] );

        return v > 4 ? v : !v;
})();

function fixedPosition() {
        var w = window,
                ua = navigator.userAgent,
                platform = navigator.platform,
                // Rendering engine is Webkit, and capture major version
                wkmatch = ua.match( /AppleWebKit\/([0-9]+)/ ),
                wkversion = !!wkmatch && wkmatch[ 1 ],
                ffmatch = ua.match( /Fennec\/([0-9]+)/ ),
                ffversion = !!ffmatch && ffmatch[ 1 ],
                operammobilematch = ua.match( /Opera Mobi\/([0-9]+)/ ),
                omversion = !!operammobilematch && operammobilematch[ 1 ];

        if(
                // iOS 4.3 and older : Platform is iPhone/Pad/Touch and Webkit version is less than 534 (ios5)
                ( ( platform.indexOf( "iPhone" ) > -1 || platform.indexOf( "iPad" ) > -1  || platform.indexOf( "iPod" ) > -1 ) && wkversion && wkversion < 534 ) ||
                // Opera Mini
                ( w.operamini && ({}).toString.call( w.operamini ) === "[object OperaMini]" ) ||
                ( operammobilematch && omversion < 7458 )       ||
                //Android lte 2.1: Platform is Android and Webkit version is less than 533 (Android 2.2)
                ( ua.indexOf( "Android" ) > -1 && wkversion && wkversion < 533 ) ||
                // Firefox Mobile before 6.0 -
                ( ffversion && ffversion < 6 ) ||
                // WebOS less than 3
                ( "palmGetResource" in window && wkversion && wkversion < 534 ) ||
                // MeeGo
                ( ua.indexOf( "MeeGo" ) > -1 && ua.indexOf( "NokiaBrowser/8.5.0" ) > -1 ) ) {
                return false;
        }

        return true;
}

$.extend( $.support, {
        cssTransitions: "WebKitTransitionEvent" in window ||
                validStyle( 'transition', 'height 100ms linear', [ "Webkit", "Moz", "" ] ) &&
                !$.mobile.browser.oldIE && !opera,

        // Note, Chrome for iOS has an extremely quirky implementation of popstate.
        // We've chosen to take the shortest path to a bug fix here for issue #5426
        // See the following link for information about the regex chosen
        // https://developers.google.com/chrome/mobile/docs/user-agent#chrome_for_ios_user-agent
        pushState: "pushState" in history &&
                "replaceState" in history &&
                // When running inside a FF iframe, calling replaceState causes an error
                !( window.navigator.userAgent.indexOf( "Firefox" ) >= 0 && window.top !== window ) &&
                ( window.navigator.userAgent.search(/CriOS/) === -1 ),

        mediaquery: $.mobile.media( "only all" ),
        cssPseudoElement: !!propExists( "content" ),
        touchOverflow: !!propExists( "overflowScrolling" ),
        cssTransform3d: transform3dTest(),
        boxShadow: !!propExists( "boxShadow" ) && !bb,
        fixedPosition: fixedPosition(),
        scrollTop: ("pageXOffset" in window ||
                "scrollTop" in document.documentElement ||
                "scrollTop" in fakeBody[ 0 ]) && !webos && !operamini,

        dynamicBaseTag: baseTagTest(),
        cssPointerEvents: cssPointerEventsTest(),
        boundingRect: boundingRect()
});

fakeBody.remove();


// $.mobile.ajaxBlacklist is used to override ajaxEnabled on platforms that have known conflicts with hash history updates (BB5, Symbian)
// or that generally work better browsing in regular http for full page refreshes (Opera Mini)
// Note: This detection below is used as a last resort.
// We recommend only using these detection methods when all other more reliable/forward-looking approaches are not possible
var nokiaLTE7_3 = (function() {

        var ua = window.navigator.userAgent;

        //The following is an attempt to match Nokia browsers that are running Symbian/s60, with webkit, version 7.3 or older
        return ua.indexOf( "Nokia" ) > -1 &&
                        ( ua.indexOf( "Symbian/3" ) > -1 || ua.indexOf( "Series60/5" ) > -1 ) &&
                        ua.indexOf( "AppleWebKit" ) > -1 &&
                        ua.match( /(BrowserNG|NokiaBrowser)\/7\.[0-3]/ );
})();

// Support conditions that must be met in order to proceed
// default enhanced qualifications are media query support OR IE 7+

$.mobile.gradeA = function() {
        return ( $.support.mediaquery || $.mobile.browser.oldIE && $.mobile.browser.oldIE >= 7 ) && ( $.support.boundingRect || $.fn.jquery.match(/1\.[0-7+]\.[0-9+]?/) !== null );
};

$.mobile.ajaxBlacklist =
                        // BlackBerry browsers, pre-webkit
                        window.blackberry && !window.WebKitPoint ||
                        // Opera Mini
                        operamini ||
                        // Symbian webkits pre 7.3
                        nokiaLTE7_3;

// Lastly, this workaround is the only way we've found so far to get pre 7.3 Symbian webkit devices
// to render the stylesheets when they're referenced before this script, as we'd recommend doing.
// This simply reappends the CSS in place, which for some reason makes it apply
if ( nokiaLTE7_3 ) {
        $(function() {
                $( "head link[rel='stylesheet']" ).attr( "rel", "alternate stylesheet" ).attr( "rel", "stylesheet" );
        });
}

// For ruling out shadows via css
if ( !$.support.boxShadow ) {
        $( "html" ).addClass( "ui-mobile-nosupport-boxshadow" );
}

})( jQuery );


(function( $, undefined ) {
        var $win = $.mobile.window, self, history;

        $.event.special.navigate = self = {
                bound: false,

                pushStateEnabled: true,

                originalEventName: undefined,

                // If pushstate support is present and push state support is defined to
                // be true on the mobile namespace.
                isPushStateEnabled: function() {
                        return $.support.pushState &&
                                $.mobile.pushStateEnabled === true &&
                                this.isHashChangeEnabled();
                },

                // !! assumes mobile namespace is present
                isHashChangeEnabled: function() {
                        return $.mobile.hashListeningEnabled === true;
                },

                // TODO a lot of duplication between popstate and hashchange
                popstate: function( event ) {
                        var newEvent = new $.Event( "navigate" ),
                                beforeNavigate = new $.Event( "beforenavigate" ),
                                state = event.originalEvent.state || {},
                                href = location.href;

                        $win.trigger( beforeNavigate );

                        if( beforeNavigate.isDefaultPrevented() ){
                                return;
                        }

                        if( event.historyState ){
                                $.extend(state, event.historyState);
                        }

                        // Make sure the original event is tracked for the end
                        // user to inspect incase they want to do something special
                        newEvent.originalEvent = event;

                        // NOTE we let the current stack unwind because any assignment to
                        //      location.hash will stop the world and run this event handler. By
                        //      doing this we create a similar behavior to hashchange on hash
                        //      assignment
                        setTimeout(function() {
                                $win.trigger( newEvent, {
                                        state: state
                                });
                        }, 0);
                },

                hashchange: function( event, data ) {
                        var newEvent = new $.Event( "navigate" ),
                                beforeNavigate = new $.Event( "beforenavigate" );

                        $win.trigger( beforeNavigate );

                        if( beforeNavigate.isDefaultPrevented() ){
                                return;
                        }

                        // Make sure the original event is tracked for the end
                        // user to inspect incase they want to do something special
                        newEvent.originalEvent = event;

                        // Trigger the hashchange with state provided by the user
                        // that altered the hash
                        $win.trigger( newEvent, {
                                // Users that want to fully normalize the two events
                                // will need to do history management down the stack and
                                // add the state to the event before this binding is fired
                                // TODO consider allowing for the explicit addition of callbacks
                                //      to be fired before this value is set to avoid event timing issues
                                state: event.hashchangeState || {}
                        });
                },

                // TODO We really only want to set this up once
                //      but I'm not clear if there's a beter way to achieve
                //      this with the jQuery special event structure
                setup: function( data, namespaces ) {
                        if( self.bound ) {
                                return;
                        }

                        self.bound = true;

                        if( self.isPushStateEnabled() ) {
                                self.originalEventName = "popstate";
                                $win.bind( "popstate.navigate", self.popstate );
                        } else if ( self.isHashChangeEnabled() ){
                                self.originalEventName = "hashchange";
                                $win.bind( "hashchange.navigate", self.hashchange );
                        }
                }
        };
})( jQuery );



        // throttled resize event
        (function( $ ) {
                $.event.special.throttledresize = {
                        setup: function() {
                                $( this ).bind( "resize", handler );
                        },
                        teardown: function() {
                                $( this ).unbind( "resize", handler );
                        }
                };

                var throttle = 250,
                        handler = function() {
                                curr = ( new Date() ).getTime();
                                diff = curr - lastCall;

                                if ( diff >= throttle ) {

                                        lastCall = curr;
                                        $( this ).trigger( "throttledresize" );

                                } else {

                                        if ( heldCall ) {
                                                clearTimeout( heldCall );
                                        }

                                        // Promise a held call will still execute
                                        heldCall = setTimeout( handler, throttle - diff );
                                }
                        },
                        lastCall = 0,
                        heldCall,
                        curr,
                        diff;
        })( jQuery );

(function( $, window ) {
        var win = $( window ),
                event_name = "orientationchange",
                special_event,
                get_orientation,
                last_orientation,
                initial_orientation_is_landscape,
                initial_orientation_is_default,
                portrait_map = { "0": true, "180": true };

        // It seems that some device/browser vendors use window.orientation values 0 and 180 to
        // denote the "default" orientation. For iOS devices, and most other smart-phones tested,
        // the default orientation is always "portrait", but in some Android and RIM based tablets,
        // the default orientation is "landscape". The following code attempts to use the window
        // dimensions to figure out what the current orientation is, and then makes adjustments
        // to the to the portrait_map if necessary, so that we can properly decode the
        // window.orientation value whenever get_orientation() is called.
        //
        // Note that we used to use a media query to figure out what the orientation the browser
        // thinks it is in:
        //
        //     initial_orientation_is_landscape = $.mobile.media("all and (orientation: landscape)");
        //
        // but there was an iPhone/iPod Touch bug beginning with iOS 4.2, up through iOS 5.1,
        // where the browser *ALWAYS* applied the landscape media query. This bug does not
        // happen on iPad.

        if ( $.support.orientation ) {

                // Check the window width and height to figure out what the current orientation
                // of the device is at this moment. Note that we've initialized the portrait map
                // values to 0 and 180, *AND* we purposely check for landscape so that if we guess
                // wrong, , we default to the assumption that portrait is the default orientation.
                // We use a threshold check below because on some platforms like iOS, the iPhone
                // form-factor can report a larger width than height if the user turns on the
                // developer console. The actual threshold value is somewhat arbitrary, we just
                // need to make sure it is large enough to exclude the developer console case.

                var ww = window.innerWidth || win.width(),
                        wh = window.innerHeight || win.height(),
                        landscape_threshold = 50;

                initial_orientation_is_landscape = ww > wh && ( ww - wh ) > landscape_threshold;


                // Now check to see if the current window.orientation is 0 or 180.
                initial_orientation_is_default = portrait_map[ window.orientation ];

                // If the initial orientation is landscape, but window.orientation reports 0 or 180, *OR*
                // if the initial orientation is portrait, but window.orientation reports 90 or -90, we
                // need to flip our portrait_map values because landscape is the default orientation for
                // this device/browser.
                if ( ( initial_orientation_is_landscape && initial_orientation_is_default ) || ( !initial_orientation_is_landscape && !initial_orientation_is_default ) ) {
                        portrait_map = { "-90": true, "90": true };
                }
        }

        $.event.special.orientationchange = $.extend( {}, $.event.special.orientationchange, {
                setup: function() {
                        // If the event is supported natively, return false so that jQuery
                        // will bind to the event using DOM methods.
                        if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
                                return false;
                        }

                        // Get the current orientation to avoid initial double-triggering.
                        last_orientation = get_orientation();

                        // Because the orientationchange event doesn't exist, simulate the
                        // event by testing window dimensions on resize.
                        win.bind( "throttledresize", handler );
                },
                teardown: function() {
                        // If the event is not supported natively, return false so that
                        // jQuery will unbind the event using DOM methods.
                        if ( $.support.orientation && !$.event.special.orientationchange.disabled ) {
                                return false;
                        }

                        // Because the orientationchange event doesn't exist, unbind the
                        // resize event handler.
                        win.unbind( "throttledresize", handler );
                },
                add: function( handleObj ) {
                        // Save a reference to the bound event handler.
                        var old_handler = handleObj.handler;


                        handleObj.handler = function( event ) {
                                // Modify event object, adding the .orientation property.
                                event.orientation = get_orientation();

                                // Call the originally-bound event handler and return its result.
                                return old_handler.apply( this, arguments );
                        };
                }
        });

        // If the event is not supported natively, this handler will be bound to
        // the window resize event to simulate the orientationchange event.
        function handler() {
                // Get the current orientation.
                var orientation = get_orientation();

                if ( orientation !== last_orientation ) {
                        // The orientation has changed, so trigger the orientationchange event.
                        last_orientation = orientation;
                        win.trigger( event_name );
                }
        }

        // Get the current page orientation. This method is exposed publicly, should it
        // be needed, as jQuery.event.special.orientationchange.orientation()
        $.event.special.orientationchange.orientation = get_orientation = function() {
                var isPortrait = true, elem = document.documentElement;

                // prefer window orientation to the calculation based on screensize as
                // the actual screen resize takes place before or after the orientation change event
                // has been fired depending on implementation (eg android 2.3 is before, iphone after).
                // More testing is required to determine if a more reliable method of determining the new screensize
                // is possible when orientationchange is fired. (eg, use media queries + element + opacity)
                if ( $.support.orientation ) {
                        // if the window orientation registers as 0 or 180 degrees report
                        // portrait, otherwise landscape
                        isPortrait = portrait_map[ window.orientation ];
                } else {
                        isPortrait = elem && elem.clientWidth / elem.clientHeight < 1.1;
                }

                return isPortrait ? "portrait" : "landscape";
        };

        $.fn[ event_name ] = function( fn ) {
                return fn ? this.bind( event_name, fn ) : this.trigger( event_name );
        };

        // jQuery < 1.8
        if ( $.attrFn ) {
                $.attrFn[ event_name ] = true;
        }

}( jQuery, this ));


// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
// The idea here is to allow the developer to register listeners for the
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
// and the plugin will take care of registering the correct listeners
// behind the scenes to invoke the listener at the fastest possible time
// for that device, while still retaining the order of event firing in
// the traditional mouse environment, should multiple handlers be registered
// on the same element for different events.
//
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"

(function( $, window, document, undefined ) {

var dataPropertyName = "virtualMouseBindings",
        touchTargetPropertyName = "virtualTouchID",
        virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
        touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
        mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [],
        mouseEventProps = $.event.props.concat( mouseHookProps ),
        activeDocHandlers = {},
        resetTimerID = 0,
        startX = 0,
        startY = 0,
        didScroll = false,
        clickBlockList = [],
        blockMouseTriggers = false,
        blockTouchTriggers = false,
        eventCaptureSupported = "addEventListener" in document,
        $document = $( document ),
        nextTouchID = 1,
        lastTouchID = 0, threshold;

$.vmouse = {
        moveDistanceThreshold: 10,
        clickDistanceThreshold: 10,
        resetTimerDuration: 1500
};

function getNativeEvent( event ) {

        while ( event && typeof event.originalEvent !== "undefined" ) {
                event = event.originalEvent;
        }
        return event;
}

function createVirtualEvent( event, eventType ) {

        var t = event.type,
                oe, props, ne, prop, ct, touch, i, j, len;

        event = $.Event( event );
        event.type = eventType;

        oe = event.originalEvent;
        props = $.event.props;

        // addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
        // https://github.com/jquery/jquery-mobile/issues/3280
        if ( t.search( /^(mouse|click)/ ) > -1 ) {
                props = mouseEventProps;
        }

        // copy original event properties over to the new event
        // this would happen if we could call $.event.fix instead of $.Event
        // but we don't have a way to force an event to be fixed multiple times
        if ( oe ) {
                for ( i = props.length, prop; i; ) {
                        prop = props[ --i ];
                        event[ prop ] = oe[ prop ];
                }
        }

        // make sure that if the mouse and click virtual events are generated
        // without a .which one is defined
        if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ) {
                event.which = 1;
        }

        if ( t.search(/^touch/) !== -1 ) {
                ne = getNativeEvent( oe );
                t = ne.touches;
                ct = ne.changedTouches;
                touch = ( t && t.length ) ? t[0] : ( ( ct && ct.length ) ? ct[ 0 ] : undefined );

                if ( touch ) {
                        for ( j = 0, len = touchEventProps.length; j < len; j++) {
                                prop = touchEventProps[ j ];
                                event[ prop ] = touch[ prop ];
                        }
                }
        }

        return event;
}

function getVirtualBindingFlags( element ) {

        var flags = {},
                b, k;

        while ( element ) {

                b = $.data( element, dataPropertyName );

                for (  k in b ) {
                        if ( b[ k ] ) {
                                flags[ k ] = flags.hasVirtualBinding = true;
                        }
                }
                element = element.parentNode;
        }
        return flags;
}

function getClosestElementWithVirtualBinding( element, eventType ) {
        var b;
        while ( element ) {

                b = $.data( element, dataPropertyName );

                if ( b && ( !eventType || b[ eventType ] ) ) {
                        return element;
                }
                element = element.parentNode;
        }
        return null;
}

function enableTouchBindings() {
        blockTouchTriggers = false;
}

function disableTouchBindings() {
        blockTouchTriggers = true;
}

function enableMouseBindings() {
        lastTouchID = 0;
        clickBlockList.length = 0;
        blockMouseTriggers = false;

        // When mouse bindings are enabled, our
        // touch bindings are disabled.
        disableTouchBindings();
}

function disableMouseBindings() {
        // When mouse bindings are disabled, our
        // touch bindings are enabled.
        enableTouchBindings();
}

function startResetTimer() {
        clearResetTimer();
        resetTimerID = setTimeout( function() {
                resetTimerID = 0;
                enableMouseBindings();
        }, $.vmouse.resetTimerDuration );
}

function clearResetTimer() {
        if ( resetTimerID ) {
                clearTimeout( resetTimerID );
                resetTimerID = 0;
        }
}

function triggerVirtualEvent( eventType, event, flags ) {
        var ve;

        if ( ( flags && flags[ eventType ] ) ||
                                ( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {

                ve = createVirtualEvent( event, eventType );

                $( event.target).trigger( ve );
        }

        return ve;
}

function mouseEventCallback( event ) {
        var touchID = $.data( event.target, touchTargetPropertyName );

        if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ) {
                var ve = triggerVirtualEvent( "v" + event.type, event );
                if ( ve ) {
                        if ( ve.isDefaultPrevented() ) {
                                event.preventDefault();
                        }
                        if ( ve.isPropagationStopped() ) {
                                event.stopPropagation();
                        }
                        if ( ve.isImmediatePropagationStopped() ) {
                                event.stopImmediatePropagation();
                        }
                }
        }
}

function handleTouchStart( event ) {

        var touches = getNativeEvent( event ).touches,
                target, flags;

        if ( touches && touches.length === 1 ) {

                target = event.target;
                flags = getVirtualBindingFlags( target );

                if ( flags.hasVirtualBinding ) {

                        lastTouchID = nextTouchID++;
                        $.data( target, touchTargetPropertyName, lastTouchID );

                        clearResetTimer();

                        disableMouseBindings();
                        didScroll = false;

                        var t = getNativeEvent( event ).touches[ 0 ];
                        startX = t.pageX;
                        startY = t.pageY;

                        triggerVirtualEvent( "vmouseover", event, flags );
                        triggerVirtualEvent( "vmousedown", event, flags );
                }
        }
}

function handleScroll( event ) {
        if ( blockTouchTriggers ) {
                return;
        }

        if ( !didScroll ) {
                triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
        }

        didScroll = true;
        startResetTimer();
}

function handleTouchMove( event ) {
        if ( blockTouchTriggers ) {
                return;
        }

        var t = getNativeEvent( event ).touches[ 0 ],
                didCancel = didScroll,
                moveThreshold = $.vmouse.moveDistanceThreshold,
                flags = getVirtualBindingFlags( event.target );

                didScroll = didScroll ||
                        ( Math.abs( t.pageX - startX ) > moveThreshold ||
                                Math.abs( t.pageY - startY ) > moveThreshold );


        if ( didScroll && !didCancel ) {
                triggerVirtualEvent( "vmousecancel", event, flags );
        }

        triggerVirtualEvent( "vmousemove", event, flags );
        startResetTimer();
}

function handleTouchEnd( event ) {
        if ( blockTouchTriggers ) {
                return;
        }

        disableTouchBindings();

        var flags = getVirtualBindingFlags( event.target ),
                t;
        triggerVirtualEvent( "vmouseup", event, flags );

        if ( !didScroll ) {
                var ve = triggerVirtualEvent( "vclick", event, flags );
                if ( ve && ve.isDefaultPrevented() ) {
                        // The target of the mouse events that follow the touchend
                        // event don't necessarily match the target used during the
                        // touch. This means we need to rely on coordinates for blocking
                        // any click that is generated.
                        t = getNativeEvent( event ).changedTouches[ 0 ];
                        clickBlockList.push({
                                touchID: lastTouchID,
                                x: t.clientX,
                                y: t.clientY
                        });

                        // Prevent any mouse events that follow from triggering
                        // virtual event notifications.
                        blockMouseTriggers = true;
                }
        }
        triggerVirtualEvent( "vmouseout", event, flags);
        didScroll = false;

        startResetTimer();
}

function hasVirtualBindings( ele ) {
        var bindings = $.data( ele, dataPropertyName ),
                k;

        if ( bindings ) {
                for ( k in bindings ) {
                        if ( bindings[ k ] ) {
                                return true;
                        }
                }
        }
        return false;
}

function dummyMouseHandler() {}

function getSpecialEventObject( eventType ) {
        var realType = eventType.substr( 1 );

        return {
                setup: function( data, namespace ) {
                        // If this is the first virtual mouse binding for this element,
                        // add a bindings object to its data.

                        if ( !hasVirtualBindings( this ) ) {
                                $.data( this, dataPropertyName, {} );
                        }

                        // If setup is called, we know it is the first binding for this
                        // eventType, so initialize the count for the eventType to zero.
                        var bindings = $.data( this, dataPropertyName );
                        bindings[ eventType ] = true;

                        // If this is the first virtual mouse event for this type,
                        // register a global handler on the document.

                        activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;

                        if ( activeDocHandlers[ eventType ] === 1 ) {
                                $document.bind( realType, mouseEventCallback );
                        }

                        // Some browsers, like Opera Mini, won't dispatch mouse/click events
                        // for elements unless they actually have handlers registered on them.
                        // To get around this, we register dummy handlers on the elements.

                        $( this ).bind( realType, dummyMouseHandler );

                        // For now, if event capture is not supported, we rely on mouse handlers.
                        if ( eventCaptureSupported ) {
                                // If this is the first virtual mouse binding for the document,
                                // register our touchstart handler on the document.

                                activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;

                                if ( activeDocHandlers[ "touchstart" ] === 1 ) {
                                        $document.bind( "touchstart", handleTouchStart )
                                                .bind( "touchend", handleTouchEnd )

                                                // On touch platforms, touching the screen and then dragging your finger
                                                // causes the window content to scroll after some distance threshold is
                                                // exceeded. On these platforms, a scroll prevents a click event from being
                                                // dispatched, and on some platforms, even the touchend is suppressed. To
                                                // mimic the suppression of the click event, we need to watch for a scroll
                                                // event. Unfortunately, some platforms like iOS don't dispatch scroll
                                                // events until *AFTER* the user lifts their finger (touchend). This means
                                                // we need to watch both scroll and touchmove events to figure out whether
                                                // or not a scroll happenens before the touchend event is fired.

                                                .bind( "touchmove", handleTouchMove )
                                                .bind( "scroll", handleScroll );
                                }
                        }
                },

                teardown: function( data, namespace ) {
                        // If this is the last virtual binding for this eventType,
                        // remove its global handler from the document.

                        --activeDocHandlers[ eventType ];

                        if ( !activeDocHandlers[ eventType ] ) {
                                $document.unbind( realType, mouseEventCallback );
                        }

                        if ( eventCaptureSupported ) {
                                // If this is the last virtual mouse binding in existence,
                                // remove our document touchstart listener.

                                --activeDocHandlers[ "touchstart" ];

                                if ( !activeDocHandlers[ "touchstart" ] ) {
                                        $document.unbind( "touchstart", handleTouchStart )
                                                .unbind( "touchmove", handleTouchMove )
                                                .unbind( "touchend", handleTouchEnd )
                                                .unbind( "scroll", handleScroll );
                                }
                        }

                        var $this = $( this ),
                                bindings = $.data( this, dataPropertyName );

                        // teardown may be called when an element was
                        // removed from the DOM. If this is the case,
                        // jQuery core may have already stripped the element
                        // of any data bindings so we need to check it before
                        // using it.
                        if ( bindings ) {
                                bindings[ eventType ] = false;
                        }

                        // Unregister the dummy event handler.

                        $this.unbind( realType, dummyMouseHandler );

                        // If this is the last virtual mouse binding on the
                        // element, remove the binding data from the element.

                        if ( !hasVirtualBindings( this ) ) {
                                $this.removeData( dataPropertyName );
                        }
                }
        };
}

// Expose our custom events to the jQuery bind/unbind mechanism.

for ( var i = 0; i < virtualEventNames.length; i++ ) {
        $.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
}

// Add a capture click handler to block clicks.
// Note that we require event capture support for this so if the device
// doesn't support it, we punt for now and rely solely on mouse events.
if ( eventCaptureSupported ) {
        document.addEventListener( "click", function( e ) {
                var cnt = clickBlockList.length,
                        target = e.target,
                        x, y, ele, i, o, touchID;

                if ( cnt ) {
                        x = e.clientX;
                        y = e.clientY;
                        threshold = $.vmouse.clickDistanceThreshold;

                        // The idea here is to run through the clickBlockList to see if
                        // the current click event is in the proximity of one of our
                        // vclick events that had preventDefault() called on it. If we find
                        // one, then we block the click.
                        //
                        // Why do we have to rely on proximity?
                        //
                        // Because the target of the touch event that triggered the vclick
                        // can be different from the target of the click event synthesized
                        // by the browser. The target of a mouse/click event that is syntehsized
                        // from a touch event seems to be implementation specific. For example,
                        // some browsers will fire mouse/click events for a link that is near
                        // a touch event, even though the target of the touchstart/touchend event
                        // says the user touched outside the link. Also, it seems that with most
                        // browsers, the target of the mouse/click event is not calculated until the
                        // time it is dispatched, so if you replace an element that you touched
                        // with another element, the target of the mouse/click will be the new
                        // element underneath that point.
                        //
                        // Aside from proximity, we also check to see if the target and any
                        // of its ancestors were the ones that blocked a click. This is necessary
                        // because of the strange mouse/click target calculation done in the
                        // Android 2.1 browser, where if you click on an element, and there is a
                        // mouse/click handler on one of its ancestors, the target will be the
                        // innermost child of the touched element, even if that child is no where
                        // near the point of touch.

                        ele = target;

                        while ( ele ) {
                                for ( i = 0; i < cnt; i++ ) {
                                        o = clickBlockList[ i ];
                                        touchID = 0;

                                        if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
                                                                $.data( ele, touchTargetPropertyName ) === o.touchID ) {
                                                // XXX: We may want to consider removing matches from the block list
                                                //      instead of waiting for the reset timer to fire.
                                                e.preventDefault();
                                                e.stopPropagation();
                                                return;
                                        }
                                }
                                ele = ele.parentNode;
                        }
                }
        }, true);
}
})( jQuery, window, document );


(function( $, window, undefined ) {
        var $document = $( document );

        // add new event shortcuts
        $.each( ( "touchstart touchmove touchend " +
                "tap taphold " +
                "swipe swipeleft swiperight " +
                "scrollstart scrollstop" ).split( " " ), function( i, name ) {

                $.fn[ name ] = function( fn ) {
                        return fn ? this.bind( name, fn ) : this.trigger( name );
                };

                // jQuery < 1.8
                if ( $.attrFn ) {
                        $.attrFn[ name ] = true;
                }
        });

        var supportTouch = $.mobile.support.touch,
                scrollEvent = "touchmove scroll",
                touchStartEvent = supportTouch ? "touchstart" : "mousedown",
                touchStopEvent = supportTouch ? "touchend" : "mouseup",
                touchMoveEvent = supportTouch ? "touchmove" : "mousemove";

        function triggerCustomEvent( obj, eventType, event ) {
                var originalType = event.type;
                event.type = eventType;
                $.event.dispatch.call( obj, event );
                event.type = originalType;
        }

        // also handles scrollstop
        $.event.special.scrollstart = {

                enabled: true,

                setup: function() {

                        var thisObject = this,
                                $this = $( thisObject ),
                                scrolling,
                                timer;

                        function trigger( event, state ) {
                                scrolling = state;
                                triggerCustomEvent( thisObject, scrolling ? "scrollstart" : "scrollstop", event );
                        }

                        // iPhone triggers scroll after a small delay; use touchmove instead
                        $this.bind( scrollEvent, function( event ) {

                                if ( !$.event.special.scrollstart.enabled ) {
                                        return;
                                }

                                if ( !scrolling ) {
                                        trigger( event, true );
                                }

                                clearTimeout( timer );
                                timer = setTimeout( function() {
                                        trigger( event, false );
                                }, 50 );
                        });
                }
        };

        // also handles taphold
        $.event.special.tap = {
                tapholdThreshold: 750,

                setup: function() {
                        var thisObject = this,
                                $this = $( thisObject );

                        $this.bind( "vmousedown", function( event ) {

                                if ( event.which && event.which !== 1 ) {
                                        return false;
                                }

                                var origTarget = event.target,
                                        origEvent = event.originalEvent,
                                        timer;

                                function clearTapTimer() {
                                        clearTimeout( timer );
                                }

                                function clearTapHandlers() {
                                        clearTapTimer();

                                        $this.unbind( "vclick", clickHandler )
                                                .unbind( "vmouseup", clearTapTimer );
                                        $document.unbind( "vmousecancel", clearTapHandlers );
                                }

                                function clickHandler( event ) {
                                        clearTapHandlers();

                                        // ONLY trigger a 'tap' event if the start target is
                                        // the same as the stop target.
                                        if ( origTarget === event.target ) {
                                                triggerCustomEvent( thisObject, "tap", event );
                                        }
                                }

                                $this.bind( "vmouseup", clearTapTimer )
                                        .bind( "vclick", clickHandler );
                                $document.bind( "vmousecancel", clearTapHandlers );

                                timer = setTimeout( function() {
                                        triggerCustomEvent( thisObject, "taphold", $.Event( "taphold", { target: origTarget } ) );
                                }, $.event.special.tap.tapholdThreshold );
                        });
                }
        };

        // also handles swipeleft, swiperight
        $.event.special.swipe = {
                scrollSupressionThreshold: 30, // More than this horizontal displacement, and we will suppress scrolling.

                durationThreshold: 1000, // More time than this, and it isn't a swipe.

                horizontalDistanceThreshold: 30,  // Swipe horizontal displacement must be more than this.

                verticalDistanceThreshold: 75,  // Swipe vertical displacement must be less than this.

                start: function( event ) {
                        var data = event.originalEvent.touches ?
                                        event.originalEvent.touches[ 0 ] : event;
                        return {
                                                time: ( new Date() ).getTime(),
                                                coords: [ data.pageX, data.pageY ],
                                                origin: $( event.target )
                                        };
                },

                stop: function( event ) {
                        var data = event.originalEvent.touches ?
                                        event.originalEvent.touches[ 0 ] : event;
                        return {
                                                time: ( new Date() ).getTime(),
                                                coords: [ data.pageX, data.pageY ]
                                        };
                },

                handleSwipe: function( start, stop ) {
                        if ( stop.time - start.time < $.event.special.swipe.durationThreshold &&
                                Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.horizontalDistanceThreshold &&
                                Math.abs( start.coords[ 1 ] - stop.coords[ 1 ] ) < $.event.special.swipe.verticalDistanceThreshold ) {

                                start.origin.trigger( "swipe" )
                                        .trigger( start.coords[0] > stop.coords[ 0 ] ? "swipeleft" : "swiperight" );
                        }
                },

                setup: function() {
                        var thisObject = this,
                                $this = $( thisObject );

                        $this.bind( touchStartEvent, function( event ) {
                                var start = $.event.special.swipe.start( event ),
                                        stop;

                                function moveHandler( event ) {
                                        if ( !start ) {
                                                return;
                                        }

                                        stop = $.event.special.swipe.stop( event );

                                        // prevent scrolling
                                        if ( Math.abs( start.coords[ 0 ] - stop.coords[ 0 ] ) > $.event.special.swipe.scrollSupressionThreshold ) {
                                                event.preventDefault();
                                        }
                                }

                                $this.bind( touchMoveEvent, moveHandler )
                                        .one( touchStopEvent, function() {
                                                $this.unbind( touchMoveEvent, moveHandler );

                                                if ( start && stop ) {
                                                        $.event.special.swipe.handleSwipe( start, stop );
                                                }
                                                start = stop = undefined;
                                        });
                        });
                }
        };
        $.each({
                scrollstop: "scrollstart",
                taphold: "tap",
                swipeleft: "swipe",
                swiperight: "swipe"
        }, function( event, sourceEvent ) {

                $.event.special[ event ] = {
                        setup: function() {
                                $( this ).bind( sourceEvent, $.noop );
                        }
                };
        });

})( jQuery, this );

(function( $, undefined ) {

// This function calls getAttribute, which should be safe for data-* attributes
var getAttrFixed = function( e, key ) {
        var value = e.getAttribute( key );

        return value === "true" ? true :
                value === "false" ? false :
                value === null ? undefined : value;
};

$.fn.buttonMarkup = function( options ) {
        var $workingSet = this,
                nsKey = "data-" + $.mobile.ns,
                key;

        // Enforce options to be of type string
        options = ( options && ( $.type( options ) === "object" ) )? options : {};
        for ( var i = 0; i < $workingSet.length; i++ ) {
                var el = $workingSet.eq( i ),
                        e = el[ 0 ],
                        o = $.extend( {}, $.fn.buttonMarkup.defaults, {
                                icon:       options.icon       !== undefined ? options.icon       : getAttrFixed( e, nsKey + "icon" ),
                                iconpos:    options.iconpos    !== undefined ? options.iconpos    : getAttrFixed( e, nsKey + "iconpos" ),
                                theme:      options.theme      !== undefined ? options.theme      : getAttrFixed( e, nsKey + "theme" ) || $.mobile.getInheritedTheme( el, "c" ),
                                inline:     options.inline     !== undefined ? options.inline     : getAttrFixed( e, nsKey + "inline" ),
                                shadow:     options.shadow     !== undefined ? options.shadow     : getAttrFixed( e, nsKey + "shadow" ),
                                corners:    options.corners    !== undefined ? options.corners    : getAttrFixed( e, nsKey + "corners" ),
                                iconshadow: options.iconshadow !== undefined ? options.iconshadow : getAttrFixed( e, nsKey + "iconshadow" ),
                                mini:       options.mini       !== undefined ? options.mini       : getAttrFixed( e, nsKey + "mini" )
                        }, options ),

                        // Classes Defined
                        innerClass = "ui-btn-inner",
                        textClass = "ui-btn-text",
                        buttonClass, iconClass,
                        hover = false,
                        state = "up",
                        // Button inner markup
                        buttonInner,
                        buttonText,
                        buttonIcon,
                        buttonElements;

                for ( key in o ) {
                        if ( o[ key ] === undefined || o[ key ] === null ) {
                                el.removeAttr( nsKey + key );
                        } else {
                                e.setAttribute( nsKey + key, o[ key ] );
                        }
                }

                if ( getAttrFixed( e, nsKey + "rel" ) === "popup" && el.attr( "href" ) ) {
                        e.setAttribute( "aria-haspopup", true );
                        e.setAttribute( "aria-owns", el.attr( "href" ) );
                }

                // Check if this element is already enhanced
                buttonElements = $.data( ( ( e.tagName === "INPUT" || e.tagName === "BUTTON" ) ? e.parentNode : e ), "buttonElements" );

                if ( buttonElements ) {
                        e = buttonElements.outer;
                        el = $( e );
                        buttonInner = buttonElements.inner;
                        buttonText = buttonElements.text;
                        // We will recreate this icon below
                        $( buttonElements.icon ).remove();
                        buttonElements.icon = null;
                        hover = buttonElements.hover;
                        state = buttonElements.state;
                }
                else {
                        buttonInner = document.createElement( o.wrapperEls );
                        buttonText = document.createElement( o.wrapperEls );
                }
                buttonIcon = o.icon ? document.createElement( "span" ) : null;

                if ( attachEvents && !buttonElements ) {
                        attachEvents();
                }

                // if not, try to find closest theme container
                if ( !o.theme ) {
                        o.theme = $.mobile.getInheritedTheme( el, "c" );
                }

                buttonClass = "ui-btn ";
                buttonClass += ( hover ? "ui-btn-hover-" + o.theme : "" );
                buttonClass += ( state ? " ui-btn-" + state + "-" + o.theme : "" );
                buttonClass += o.shadow ? " ui-shadow" : "";
                buttonClass += o.corners ? " ui-btn-corner-all" : "";

                if ( o.mini !== undefined ) {
                        // Used to control styling in headers/footers, where buttons default to `mini` style.
                        buttonClass += o.mini === true ? " ui-mini" : " ui-fullsize";
                }

                if ( o.inline !== undefined ) {
                        // Used to control styling in headers/footers, where buttons default to `inline` style.
                        buttonClass += o.inline === true ? " ui-btn-inline" : " ui-btn-block";
                }

                if ( o.icon ) {
                        o.icon = "ui-icon-" + o.icon;
                        o.iconpos = o.iconpos || "left";

                        iconClass = "ui-icon " + o.icon;

                        if ( o.iconshadow ) {
                                iconClass += " ui-icon-shadow";
                        }
                }

                if ( o.iconpos ) {
                        buttonClass += " ui-btn-icon-" + o.iconpos;

                        if ( o.iconpos === "notext" && !el.attr( "title" ) ) {
                                el.attr( "title", el.getEncodedText() );
                        }
                }

                if ( buttonElements ) {
                        el.removeClass( buttonElements.bcls || "" );
                }
                el.removeClass( "ui-link" ).addClass( buttonClass );

                buttonInner.className = innerClass;
                buttonText.className = textClass;
                if ( !buttonElements ) {
                        buttonInner.appendChild( buttonText );
                }
                if ( buttonIcon ) {
                        buttonIcon.className = iconClass;
                        if ( !( buttonElements && buttonElements.icon ) ) {
                                buttonIcon.innerHTML = "&#160;";
                                buttonInner.appendChild( buttonIcon );
                        }
                }

                while ( e.firstChild && !buttonElements ) {
                        buttonText.appendChild( e.firstChild );
                }

                if ( !buttonElements ) {
                        e.appendChild( buttonInner );
                }

                // Assign a structure containing the elements of this button to the elements of this button. This
                // will allow us to recognize this as an already-enhanced button in future calls to buttonMarkup().
                buttonElements = {
                        hover : hover,
                        state : state,
                        bcls  : buttonClass,
                        outer : e,
                        inner : buttonInner,
                        text  : buttonText,
                        icon  : buttonIcon
                };

                $.data( e,           'buttonElements', buttonElements );
                $.data( buttonInner, 'buttonElements', buttonElements );
                $.data( buttonText,  'buttonElements', buttonElements );
                if ( buttonIcon ) {
                        $.data( buttonIcon, 'buttonElements', buttonElements );
                }
        }

        return this;
};

$.fn.buttonMarkup.defaults = {
        corners: true,
        shadow: true,
        iconshadow: true,
        wrapperEls: "span"
};

function closestEnabledButton( element ) {
    var cname;

    while ( element ) {
                // Note that we check for typeof className below because the element we
                // handed could be in an SVG DOM where className on SVG elements is defined to
                // be of a different type (SVGAnimatedString). We only operate on HTML DOM
                // elements, so we look for plain "string".
        cname = ( typeof element.className === 'string' ) && ( element.className + ' ' );
        if ( cname && cname.indexOf( "ui-btn " ) > -1 && cname.indexOf( "ui-disabled " ) < 0 ) {
            break;
        }

        element = element.parentNode;
    }

    return element;
}

function updateButtonClass( $btn, classToRemove, classToAdd, hover, state ) {
        var buttonElements = $.data( $btn[ 0 ], "buttonElements" );
        $btn.removeClass( classToRemove ).addClass( classToAdd );
        if ( buttonElements ) {
                buttonElements.bcls = $( document.createElement( "div" ) )
                        .addClass( buttonElements.bcls + " " + classToAdd )
                        .removeClass( classToRemove )
                        .attr( "class" );
                if ( hover !== undefined ) {
                        buttonElements.hover = hover;
                }
                buttonElements.state = state;
        }
}

var attachEvents = function() {
        var hoverDelay = $.mobile.buttonMarkup.hoverDelay, hov, foc;

        $.mobile.document.bind( {
                "vmousedown vmousecancel vmouseup vmouseover vmouseout focus blur scrollstart": function( event ) {
                        var theme,
                                $btn = $( closestEnabledButton( event.target ) ),
                                isTouchEvent = event.originalEvent && /^touch/.test( event.originalEvent.type ),
                                evt = event.type;

                        if ( $btn.length ) {
                                theme = $btn.attr( "data-" + $.mobile.ns + "theme" );

                                if ( evt === "vmousedown" ) {
                                        if ( isTouchEvent ) {
                                                // Use a short delay to determine if the user is scrolling before highlighting
                                                hov = setTimeout( function() {
                                                        updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
                                                }, hoverDelay );
                                        } else {
                                                updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-down-" + theme, undefined, "down" );
                                        }
                                } else if ( evt === "vmousecancel" || evt === "vmouseup" ) {
                                        updateButtonClass( $btn, "ui-btn-down-" + theme, "ui-btn-up-" + theme, undefined, "up" );
                                } else if ( evt === "vmouseover" || evt === "focus" ) {
                                        if ( isTouchEvent ) {
                                                // Use a short delay to determine if the user is scrolling before highlighting
                                                foc = setTimeout( function() {
                                                        updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
                                                }, hoverDelay );
                                        } else {
                                                updateButtonClass( $btn, "ui-btn-up-" + theme, "ui-btn-hover-" + theme, true, "" );
                                        }
                                } else if ( evt === "vmouseout" || evt === "blur" || evt === "scrollstart" ) {
                                        updateButtonClass( $btn, "ui-btn-hover-" + theme  + " ui-btn-down-" + theme, "ui-btn-up-" + theme, false, "up" );
                                        if ( hov ) {
                                                clearTimeout( hov );
                                        }
                                        if ( foc ) {
                                                clearTimeout( foc );
                                        }
                                }
                        }
                },
                "focusin focus": function( event ) {
                        $( closestEnabledButton( event.target ) ).addClass( $.mobile.focusClass );
                },
                "focusout blur": function( event ) {
                        $( closestEnabledButton( event.target ) ).removeClass( $.mobile.focusClass );
                }
        });

        attachEvents = null;
};

//links in bars, or those with  data-role become buttons
//auto self-init widgets
$.mobile.document.bind( "pagecreate create", function( e ) {

        $( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
                .jqmEnhanceable()
                .not( "button, input, .ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
                .buttonMarkup();
});

})( jQuery );


/*!
 * jQuery UI Widget v1.10.0pre - 2012-11-13 (ff055a0c353c3c8ce6e5bfa07ad7cb03e8885bc5)
 * http://jqueryui.com
 *
 * Copyright 2010, 2013 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/jQuery.widget/
 */

(function( $, undefined ) {

var uuid = 0,
        slice = Array.prototype.slice,
        _cleanData = $.cleanData;
$.cleanData = function( elems ) {
        for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
                try {
                        $( elem ).triggerHandler( "remove" );
                // http://bugs.jquery.com/ticket/8235
                } catch( e ) {}
        }
        _cleanData( elems );
};

$.widget = function( name, base, prototype ) {
        var fullName, existingConstructor, constructor, basePrototype,
                namespace = name.split( "." )[ 0 ];

        name = name.split( "." )[ 1 ];
        fullName = namespace + "-" + name;

        if ( !prototype ) {
                prototype = base;
                base = $.Widget;
        }

        // create selector for plugin
        $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
                return !!$.data( elem, fullName );
        };

        $[ namespace ] = $[ namespace ] || {};
        existingConstructor = $[ namespace ][ name ];
        constructor = $[ namespace ][ name ] = function( options, element ) {
                // allow instantiation without "new" keyword
                if ( !this._createWidget ) {
                        return new constructor( options, element );
                }

                // allow instantiation without initializing for simple inheritance
                // must use "new" keyword (the code above always passes args)
                if ( arguments.length ) {
                        this._createWidget( options, element );
                }
        };
        // extend with the existing constructor to carry over any static properties
        $.extend( constructor, existingConstructor, {
                version: prototype.version,
                // copy the object used to create the prototype in case we need to
                // redefine the widget later
                _proto: $.extend( {}, prototype ),
                // track widgets that inherit from this widget in case this widget is
                // redefined after a widget inherits from it
                _childConstructors: []
        });

        basePrototype = new base();
        // we need to make the options hash a property directly on the new instance
        // otherwise we'll modify the options hash on the prototype that we're
        // inheriting from
        basePrototype.options = $.widget.extend( {}, basePrototype.options );
        $.each( prototype, function( prop, value ) {
                if ( $.isFunction( value ) ) {
                        prototype[ prop ] = (function() {
                                var _super = function() {
                                                return base.prototype[ prop ].apply( this, arguments );
                                        },
                                        _superApply = function( args ) {
                                                return base.prototype[ prop ].apply( this, args );
                                        };
                                return function() {
                                        var __super = this._super,
                                                __superApply = this._superApply,
                                                returnValue;

                                        this._super = _super;
                                        this._superApply = _superApply;

                                        returnValue = value.apply( this, arguments );

                                        this._super = __super;
                                        this._superApply = __superApply;

                                        return returnValue;
                                };
                        })();
                }
        });
        constructor.prototype = $.widget.extend( basePrototype, {
                // TODO: remove support for widgetEventPrefix
                // always use the name + a colon as the prefix, e.g., draggable:start
                // don't prefix for widgets that aren't DOM-based
                widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name
        }, prototype, {
                constructor: constructor,
                namespace: namespace,
                widgetName: name,
                widgetFullName: fullName
        });

        // If this widget is being redefined then we need to find all widgets that
        // are inheriting from it and redefine all of them so that they inherit from
        // the new version of this widget. We're essentially trying to replace one
        // level in the prototype chain.
        if ( existingConstructor ) {
                $.each( existingConstructor._childConstructors, function( i, child ) {
                        var childPrototype = child.prototype;

                        // redefine the child widget using the same prototype that was
                        // originally used, but inherit from the new version of the base
                        $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
                });
                // remove the list of existing child constructors from the old constructor
                // so the old child constructors can be garbage collected
                delete existingConstructor._childConstructors;
        } else {
                base._childConstructors.push( constructor );
        }

        $.widget.bridge( name, constructor );
};

$.widget.extend = function( target ) {
        var input = slice.call( arguments, 1 ),
                inputIndex = 0,
                inputLength = input.length,
                key,
                value;
        for ( ; inputIndex < inputLength; inputIndex++ ) {
                for ( key in input[ inputIndex ] ) {
                        value = input[ inputIndex ][ key ];
                        if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
                                // Clone objects
                                if ( $.isPlainObject( value ) ) {
                                        target[ key ] = $.isPlainObject( target[ key ] ) ?
                                                $.widget.extend( {}, target[ key ], value ) :
                                                // Don't extend strings, arrays, etc. with objects
                                                $.widget.extend( {}, value );
                                // Copy everything else by reference
                                } else {
                                        target[ key ] = value;
                                }
                        }
                }
        }
        return target;
};

$.widget.bridge = function( name, object ) {
        var fullName = object.prototype.widgetFullName || name;
        $.fn[ name ] = function( options ) {
                var isMethodCall = typeof options === "string",
                        args = slice.call( arguments, 1 ),
                        returnValue = this;

                // allow multiple hashes to be passed on init
                options = !isMethodCall && args.length ?
                        $.widget.extend.apply( null, [ options ].concat(args) ) :
                        options;

                if ( isMethodCall ) {
                        this.each(function() {
                                var methodValue,
                                        instance = $.data( this, fullName );
                                if ( !instance ) {
                                        return $.error( "cannot call methods on " + name + " prior to initialization; " +
                                                "attempted to call method '" + options + "'" );
                                }
                                if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
                                        return $.error( "no such method '" + options + "' for " + name + " widget instance" );
                                }
                                methodValue = instance[ options ].apply( instance, args );
                                if ( methodValue !== instance && methodValue !== undefined ) {
                                        returnValue = methodValue && methodValue.jquery ?
                                                returnValue.pushStack( methodValue.get() ) :
                                                methodValue;
                                        return false;
                                }
                        });
                } else {
                        this.each(function() {
                                var instance = $.data( this, fullName );
                                if ( instance ) {
                                        instance.option( options || {} )._init();
                                } else {
                                        $.data( this, fullName, new object( options, this ) );
                                }
                        });
                }

                return returnValue;
        };
};

$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];

$.Widget.prototype = {
        widgetName: "widget",
        widgetEventPrefix: "",
        defaultElement: "<div>",
        options: {
                disabled: false,

                // callbacks
                create: null
        },
        _createWidget: function( options, element ) {
                element = $( element || this.defaultElement || this )[ 0 ];
                this.element = $( element );
                this.uuid = uuid++;
                this.eventNamespace = "." + this.widgetName + this.uuid;
                this.options = $.widget.extend( {},
                        this.options,
                        this._getCreateOptions(),
                        options );

                this.bindings = $();
                this.hoverable = $();
                this.focusable = $();

                if ( element !== this ) {
                        $.data( element, this.widgetFullName, this );
                        this._on( true, this.element, {
                                remove: function( event ) {
                                        if ( event.target === element ) {
                                                this.destroy();
                                        }
                                }
                        });
                        this.document = $( element.style ?
                                // element within the document
                                element.ownerDocument :
                                // element is window or document
                                element.document || element );
                        this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
                }

                this._create();
                this._trigger( "create", null, this._getCreateEventData() );
                this._init();
        },
        _getCreateOptions: $.noop,
        _getCreateEventData: $.noop,
        _create: $.noop,
        _init: $.noop,

        destroy: function() {
                this._destroy();
                // we can probably remove the unbind calls in 2.0
                // all event bindings should go through this._on()
                this.element
                        .unbind( this.eventNamespace )
                        // 1.9 BC for #7810
                        // TODO remove dual storage
                        .removeData( this.widgetName )
                        .removeData( this.widgetFullName )
                        // support: jquery <1.6.3
                        // http://bugs.jquery.com/ticket/9413
                        .removeData( $.camelCase( this.widgetFullName ) );
                this.widget()
                        .unbind( this.eventNamespace )
                        .removeAttr( "aria-disabled" )
                        .removeClass(
                                this.widgetFullName + "-disabled " +
                                "ui-state-disabled" );

                // clean up events and states
                this.bindings.unbind( this.eventNamespace );
                this.hoverable.removeClass( "ui-state-hover" );
                this.focusable.removeClass( "ui-state-focus" );
        },
        _destroy: $.noop,

        widget: function() {
                return this.element;
        },

        option: function( key, value ) {
                var options = key,
                        parts,
                        curOption,
                        i;

                if ( arguments.length === 0 ) {
                        // don't return a reference to the internal hash
                        return $.widget.extend( {}, this.options );
                }

                if ( typeof key === "string" ) {
                        // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
                        options = {};
                        parts = key.split( "." );
                        key = parts.shift();
                        if ( parts.length ) {
                                curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
                                for ( i = 0; i < parts.length - 1; i++ ) {
                                        curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
                                        curOption = curOption[ parts[ i ] ];
                                }
                                key = parts.pop();
                                if ( value === undefined ) {
                                        return curOption[ key ] === undefined ? null : curOption[ key ];
                                }
                                curOption[ key ] = value;
                        } else {
                                if ( value === undefined ) {
                                        return this.options[ key ] === undefined ? null : this.options[ key ];
                                }
                                options[ key ] = value;
                        }
                }

                this._setOptions( options );

                return this;
        },
        _setOptions: function( options ) {
                var key;

                for ( key in options ) {
                        this._setOption( key, options[ key ] );
                }

                return this;
        },
        _setOption: function( key, value ) {
                this.options[ key ] = value;

                if ( key === "disabled" ) {
                        this.widget()
                                .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value )
                                .attr( "aria-disabled", value );
                        this.hoverable.removeClass( "ui-state-hover" );
                        this.focusable.removeClass( "ui-state-focus" );
                }

                return this;
        },

        enable: function() {
                return this._setOption( "disabled", false );
        },
        disable: function() {
                return this._setOption( "disabled", true );
        },

        _on: function( suppressDisabledCheck, element, handlers ) {
                var delegateElement,
                        instance = this;

                // no suppressDisabledCheck flag, shuffle arguments
                if ( typeof suppressDisabledCheck !== "boolean" ) {
                        handlers = element;
                        element = suppressDisabledCheck;
                        suppressDisabledCheck = false;
                }

                // no element argument, shuffle and use this.element
                if ( !handlers ) {
                        handlers = element;
                        element = this.element;
                        delegateElement = this.widget();
                } else {
                        // accept selectors, DOM elements
                        element = delegateElement = $( element );
                        this.bindings = this.bindings.add( element );
                }

                $.each( handlers, function( event, handler ) {
                        function handlerProxy() {
                                // allow widgets to customize the disabled handling
                                // - disabled as an array instead of boolean
                                // - disabled class as method for disabling individual parts
                                if ( !suppressDisabledCheck &&
                                                ( instance.options.disabled === true ||
                                                        $( this ).hasClass( "ui-state-disabled" ) ) ) {
                                        return;
                                }
                                return ( typeof handler === "string" ? instance[ handler ] : handler )
                                        .apply( instance, arguments );
                        }

                        // copy the guid so direct unbinding works
                        if ( typeof handler !== "string" ) {
                                handlerProxy.guid = handler.guid =
                                        handler.guid || handlerProxy.guid || $.guid++;
                        }

                        var match = event.match( /^(\w+)\s*(.*)$/ ),
                                eventName = match[1] + instance.eventNamespace,
                                selector = match[2];
                        if ( selector ) {
                                delegateElement.delegate( selector, eventName, handlerProxy );
                        } else {
                                element.bind( eventName, handlerProxy );
                        }
                });
        },

        _off: function( element, eventName ) {
                eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
                element.unbind( eventName ).undelegate( eventName );
        },

        _delay: function( handler, delay ) {
                function handlerProxy() {
                        return ( typeof handler === "string" ? instance[ handler ] : handler )
                                .apply( instance, arguments );
                }
                var instance = this;
                return setTimeout( handlerProxy, delay || 0 );
        },

        _hoverable: function( element ) {
                this.hoverable = this.hoverable.add( element );
                this._on( element, {
                        mouseenter: function( event ) {
                                $( event.currentTarget ).addClass( "ui-state-hover" );
                        },
                        mouseleave: function( event ) {
                                $( event.currentTarget ).removeClass( "ui-state-hover" );
                        }
                });
        },

        _focusable: function( element ) {
                this.focusable = this.focusable.add( element );
                this._on( element, {
                        focusin: function( event ) {
                                $( event.currentTarget ).addClass( "ui-state-focus" );
                        },
                        focusout: function( event ) {
                                $( event.currentTarget ).removeClass( "ui-state-focus" );
                        }
                });
        },

        _trigger: function( type, event, data ) {
                var prop, orig,
                        callback = this.options[ type ];

                data = data || {};
                event = $.Event( event );
                event.type = ( type === this.widgetEventPrefix ?
                        type :
                        this.widgetEventPrefix + type ).toLowerCase();
                // the original event may come from any element
                // so we need to reset the target on the new event
                event.target = this.element[ 0 ];

                // copy original event properties over to the new event
                orig = event.originalEvent;
                if ( orig ) {
                        for ( prop in orig ) {
                                if ( !( prop in event ) ) {
                                        event[ prop ] = orig[ prop ];
                                }
                        }
                }

                this.element.trigger( event, data );
                return !( $.isFunction( callback ) &&
                        callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
                        event.isDefaultPrevented() );
        }
};

$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
        $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
                if ( typeof options === "string" ) {
                        options = { effect: options };
                }
                var hasOptions,
                        effectName = !options ?
                                method :
                                options === true || typeof options === "number" ?
                                        defaultEffect :
                                        options.effect || defaultEffect;
                options = options || {};
                if ( typeof options === "number" ) {
                        options = { duration: options };
                }
                hasOptions = !$.isEmptyObject( options );
                options.complete = callback;
                if ( options.delay ) {
                        element.delay( options.delay );
                }
                if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
                        element[ method ]( options );
                } else if ( effectName !== method && element[ effectName ] ) {
                        element[ effectName ]( options.duration, options.easing, callback );
                } else {
                        element.queue(function( next ) {
                                $( this )[ method ]();
                                if ( callback ) {
                                        callback.call( element[ 0 ] );
                                }
                                next();
                        });
                }
        };
});

})( jQuery );

(function( $, undefined ) {

$.widget( "mobile.widget", {
        // decorate the parent _createWidget to trigger `widgetinit` for users
        // who wish to do post post `widgetcreate` alterations/additions
        //
        // TODO create a pull request for jquery ui to trigger this event
        // in the original _createWidget
        _createWidget: function() {
                $.Widget.prototype._createWidget.apply( this, arguments );
                this._trigger( 'init' );
        },

        _getCreateOptions: function() {

                var elem = this.element,
                        options = {};

                $.each( this.options, function( option ) {

                        var value = elem.jqmData( option.replace( /[A-Z]/g, function( c ) {
                                                        return "-" + c.toLowerCase();
                                                })
                                        );

                        if ( value !== undefined ) {
                                options[ option ] = value;
                        }
                });

                return options;
        },

        enhanceWithin: function( target, useKeepNative ) {
                this.enhance( $( this.options.initSelector, $( target )), useKeepNative );
        },

        enhance: function( targets, useKeepNative ) {
                var page, keepNative, $widgetElements = $( targets ), self = this;

                // if ignoreContentEnabled is set to true the framework should
                // only enhance the selected elements when they do NOT have a
                // parent with the data-namespace-ignore attribute
                $widgetElements = $.mobile.enhanceable( $widgetElements );

                if ( useKeepNative && $widgetElements.length ) {
                        // TODO remove dependency on the page widget for the keepNative.
                        // Currently the keepNative value is defined on the page prototype so
                        // the method is as well
                        page = $.mobile.closestPageData( $widgetElements );
                        keepNative = ( page && page.keepNativeSelector()) || "";

                        $widgetElements = $widgetElements.not( keepNative );
                }

                $widgetElements[ this.widgetName ]();
        },

        raise: function( msg ) {
                throw "Widget [" + this.widgetName + "]: " + msg;
        }
});

})( jQuery );

(function( $, undefined ) {

$.widget( "mobile.page", $.mobile.widget, {
        options: {
                theme: "c",
                domCache: false,
                keepNativeDefault: ":jqmData(role='none'), :jqmData(role='nojs')"
        },

        _create: function() {
                // if false is returned by the callbacks do not create the page
                if ( this._trigger( "beforecreate" ) === false ) {
                        return false;
                }

                this.element
                        .attr( "tabindex", "0" )
                        .addClass( "ui-page ui-body-" + this.options.theme );

                this._on( this.element, {
                        pagebeforehide: "removeContainerBackground",
                        pagebeforeshow: "_handlePageBeforeShow"
                });
        },

        _handlePageBeforeShow: function( e ) {
                this.setContainerBackground();
        },

        removeContainerBackground: function() {
                $.mobile.pageContainer.removeClass( "ui-overlay-" + $.mobile.getInheritedTheme( this.element.parent() ) );
        },

        // set the page container background to the page theme
        setContainerBackground: function( theme ) {
                if ( this.options.theme ) {
                        $.mobile.pageContainer.addClass( "ui-overlay-" + ( theme || this.options.theme ) );
                }
        },

        keepNativeSelector: function() {
                var options = this.options,
                        keepNativeDefined = options.keepNative && $.trim( options.keepNative );

                if ( keepNativeDefined && options.keepNative !== options.keepNativeDefault ) {
                        return [options.keepNative, options.keepNativeDefault].join( ", " );
                }

                return options.keepNativeDefault;
        }
});
})( jQuery );

(function( $, undefined ) {

$.mobile.page.prototype.options.degradeInputs = {
        color: false,
        date: false,
        datetime: false,
        "datetime-local": false,
        email: false,
        month: false,
        number: false,
        range: "number",
        search: "text",
        tel: false,
        time: false,
        url: false,
        week: false
};


//auto self-init widgets
$.mobile.document.bind( "pagecreate create", function( e ) {

        var page = $.mobile.closestPageData( $( e.target ) ), options;

        if ( !page ) {
                return;
        }

        options = page.options;

        // degrade inputs to avoid poorly implemented native functionality
        $( e.target ).find( "input" ).not( page.keepNativeSelector() ).each(function() {
                var $this = $( this ),
                        type = this.getAttribute( "type" ),
                        optType = options.degradeInputs[ type ] || "text";

                if ( options.degradeInputs[ type ] ) {
                        var html = $( "<div>" ).html( $this.clone() ).html(),
                                // In IE browsers, the type sometimes doesn't exist in the cloned markup, so we replace the closing tag instead
                                hasType = html.indexOf( " type=" ) > -1,
                                findstr = hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/,
                                repstr = " type=\"" + optType + "\" data-" + $.mobile.ns + "type=\"" + type + "\"" + ( hasType ? "" : ">" );

                        $this.replaceWith( html.replace( findstr, repstr ) );
                }
        });

});

})( jQuery );


(function( $, undefined ) {

// filter function removes whitespace between label and form element so we can use inline-block (nodeType 3 = text)
$.fn.fieldcontain = function( options ) {
        return this
                .addClass( "ui-field-contain ui-body ui-br" )
                .contents().filter( function() {
                        return ( this.nodeType === 3 && !/\S/.test( this.nodeValue ) );
                }).remove();
};

//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ) {
        $( ":jqmData(role='fieldcontain')", e.target ).jqmEnhanceable().fieldcontain();
});

})( jQuery );

(function( $, undefined ) {

$.fn.grid = function( options ) {
        return this.each(function() {

                var $this = $( this ),
                        o = $.extend({
                                grid: null
                        }, options ),
                        $kids = $this.children(),
                        gridCols = { solo:1, a:2, b:3, c:4, d:5 },
                        grid = o.grid,
                        iterator;

                        if ( !grid ) {
                                if ( $kids.length <= 5 ) {
                                        for ( var letter in gridCols ) {
                                                if ( gridCols[ letter ] === $kids.length ) {
                                                        grid = letter;
                                                }
                                        }
                                } else {
                                        grid = "a";
                                        $this.addClass( "ui-grid-duo" );
                                }
                        }
                        iterator = gridCols[grid];

                $this.addClass( "ui-grid-" + grid );

                $kids.filter( ":nth-child(" + iterator + "n+1)" ).addClass( "ui-block-a" );

                if ( iterator > 1 ) {
                        $kids.filter( ":nth-child(" + iterator + "n+2)" ).addClass( "ui-block-b" );
                }
                if ( iterator > 2 ) {
                        $kids.filter( ":nth-child(" + iterator + "n+3)" ).addClass( "ui-block-c" );
                }
                if ( iterator > 3 ) {
                        $kids.filter( ":nth-child(" + iterator + "n+4)" ).addClass( "ui-block-d" );
                }
                if ( iterator > 4 ) {
                        $kids.filter( ":nth-child(" + iterator + "n+5)" ).addClass( "ui-block-e" );
                }
        });
};
})( jQuery );


(function( $, undefined ) {
                var path, documentBase, $base, dialogHashKey = "&ui-state=dialog";

                $.mobile.path = path = {
                        uiStateKey: "&ui-state",

                        // This scary looking regular expression parses an absolute URL or its relative
                        // variants (protocol, site, document, query, and hash), into the various
                        // components (protocol, host, path, query, fragment, etc that make up the
                        // URL as well as some other commonly used sub-parts. When used with RegExp.exec()
                        // or String.match, it parses the URL into a results array that looks like this:
                        //
                        //     [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
                        //     [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
                        //     [2]: http://jblas:password@mycompany.com:8080/mail/inbox
                        //     [3]: http://jblas:password@mycompany.com:8080
                        //     [4]: http:
                        //     [5]: //
                        //     [6]: jblas:password@mycompany.com:8080
                        //     [7]: jblas:password
                        //     [8]: jblas
                        //     [9]: password
                        //    [10]: mycompany.com:8080
                        //    [11]: mycompany.com
                        //    [12]: 8080
                        //    [13]: /mail/inbox
                        //    [14]: /mail/
                        //    [15]: inbox
                        //    [16]: ?msg=1234&type=unread
                        //    [17]: #msg-content
                        //
                        urlParseRE: /^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,

                        // Abstraction to address xss (Issue #4787) by removing the authority in
                        // browsers that auto   decode it. All references to location.href should be
                        // replaced with a call to this method so that it can be dealt with properly here
                        getLocation: function( url ) {
                                var uri = url ? this.parseUrl( url ) : location,
                                        hash = this.parseUrl( url || location.href ).hash;

                                // mimic the browser with an empty string when the hash is empty
                                hash = hash === "#" ? "" : hash;

                                // Make sure to parse the url or the location object for the hash because using location.hash
                                // is autodecoded in firefox, the rest of the url should be from the object (location unless
                                // we're testing) to avoid the inclusion of the authority
                                return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
                        },

                        parseLocation: function() {
                                return this.parseUrl( this.getLocation() );
                        },

                        //Parse a URL into a structure that allows easy access to
                        //all of the URL components by name.
                        parseUrl: function( url ) {
                                // If we're passed an object, we'll assume that it is
                                // a parsed url object and just return it back to the caller.
                                if ( $.type( url ) === "object" ) {
                                        return url;
                                }

                                var matches = path.urlParseRE.exec( url || "" ) || [];

                                        // Create an object that allows the caller to access the sub-matches
                                        // by name. Note that IE returns an empty string instead of undefined,
                                        // like all other browsers do, so we normalize everything so its consistent
                                        // no matter what browser we're running on.
                                        return {
                                                href:         matches[  0 ] || "",
                                                hrefNoHash:   matches[  1 ] || "",
                                                hrefNoSearch: matches[  2 ] || "",
                                                domain:       matches[  3 ] || "",
                                                protocol:     matches[  4 ] || "",
                                                doubleSlash:  matches[  5 ] || "",
                                                authority:    matches[  6 ] || "",
                                                username:     matches[  8 ] || "",
                                                password:     matches[  9 ] || "",
                                                host:         matches[ 10 ] || "",
                                                hostname:     matches[ 11 ] || "",
                                                port:         matches[ 12 ] || "",
                                                pathname:     matches[ 13 ] || "",
                                                directory:    matches[ 14 ] || "",
                                                filename:     matches[ 15 ] || "",
                                                search:       matches[ 16 ] || "",
                                                hash:         matches[ 17 ] || ""
                                        };
                        },

                        //Turn relPath into an asbolute path. absPath is
                        //an optional absolute path which describes what
                        //relPath is relative to.
                        makePathAbsolute: function( relPath, absPath ) {
                                if ( relPath && relPath.charAt( 0 ) === "/" ) {
                                        return relPath;
                                }

                                relPath = relPath || "";
                                absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";

                                var absStack = absPath ? absPath.split( "/" ) : [],
                                        relStack = relPath.split( "/" );
                                for ( var i = 0; i < relStack.length; i++ ) {
                                        var d = relStack[ i ];
                                        switch ( d ) {
                                                case ".":
                                                        break;
                                                case "..":
                                                        if ( absStack.length ) {
                                                                absStack.pop();
                                                        }
                                                        break;
                                                default:
                                                        absStack.push( d );
                                                        break;
                                        }
                                }
                                return "/" + absStack.join( "/" );
                        },

                        //Returns true if both urls have the same domain.
                        isSameDomain: function( absUrl1, absUrl2 ) {
                                return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
                        },

                        //Returns true for any relative variant.
                        isRelativeUrl: function( url ) {
                                // All relative Url variants have one thing in common, no protocol.
                                return path.parseUrl( url ).protocol === "";
                        },

                        //Returns true for an absolute url.
                        isAbsoluteUrl: function( url ) {
                                return path.parseUrl( url ).protocol !== "";
                        },

                        //Turn the specified realtive URL into an absolute one. This function
                        //can handle all relative variants (protocol, site, document, query, fragment).
                        makeUrlAbsolute: function( relUrl, absUrl ) {
                                if ( !path.isRelativeUrl( relUrl ) ) {
                                        return relUrl;
                                }

                                if ( absUrl === undefined ) {
                                        absUrl = this.documentBase;
                                }

                                var relObj = path.parseUrl( relUrl ),
                                        absObj = path.parseUrl( absUrl ),
                                        protocol = relObj.protocol || absObj.protocol,
                                        doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
                                        authority = relObj.authority || absObj.authority,
                                        hasPath = relObj.pathname !== "",
                                        pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
                                        search = relObj.search || ( !hasPath && absObj.search ) || "",
                                        hash = relObj.hash;

                                return protocol + doubleSlash + authority + pathname + search + hash;
                        },

                        //Add search (aka query) params to the specified url.
                        addSearchParams: function( url, params ) {
                                var u = path.parseUrl( url ),
                                        p = ( typeof params === "object" ) ? $.param( params ) : params,
                                        s = u.search || "?";
                                return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
                        },

                        convertUrlToDataUrl: function( absUrl ) {
                                var u = path.parseUrl( absUrl );
                                if ( path.isEmbeddedPage( u ) ) {
                                        // For embedded pages, remove the dialog hash key as in getFilePath(),
                                        // and remove otherwise the Data Url won't match the id of the embedded Page.
                                        return u.hash
                                                .split( dialogHashKey )[0]
                                                .replace( /^#/, "" )
                                                .replace( /\?.*$/, "" );
                                } else if ( path.isSameDomain( u, this.documentBase ) ) {
                                        return u.hrefNoHash.replace( this.documentBase.domain, "" ).split( dialogHashKey )[0];
                                }

                                return window.decodeURIComponent(absUrl);
                        },

                        //get path from current hash, or from a file path
                        get: function( newPath ) {
                                if ( newPath === undefined ) {
                                        newPath = path.parseLocation().hash;
                                }
                                return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
                        },

                        //set location hash to path
                        set: function( path ) {
                                location.hash = path;
                        },

                        //test if a given url (string) is a path
                        //NOTE might be exceptionally naive
                        isPath: function( url ) {
                                return ( /\// ).test( url );
                        },

                        //return a url path with the window's location protocol/hostname/pathname removed
                        clean: function( url ) {
                                return url.replace( this.documentBase.domain, "" );
                        },

                        //just return the url without an initial #
                        stripHash: function( url ) {
                                return url.replace( /^#/, "" );
                        },

                        stripQueryParams: function( url ) {
                                return url.replace( /\?.*$/, "" );
                        },

                        //remove the preceding hash, any query params, and dialog notations
                        cleanHash: function( hash ) {
                                return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
                        },

                        isHashValid: function( hash ) {
                                return ( /^#[^#]+$/ ).test( hash );
                        },

                        //check whether a url is referencing the same domain, or an external domain or different protocol
                        //could be mailto, etc
                        isExternal: function( url ) {
                                var u = path.parseUrl( url );
                                return u.protocol && u.domain !== this.documentUrl.domain ? true : false;
                        },

                        hasProtocol: function( url ) {
                                return ( /^(:?\w+:)/ ).test( url );
                        },

                        isEmbeddedPage: function( url ) {
                                var u = path.parseUrl( url );

                                //if the path is absolute, then we need to compare the url against
                                //both the this.documentUrl and the documentBase. The main reason for this
                                //is that links embedded within external documents will refer to the
                                //application document, whereas links embedded within the application
                                //document will be resolved against the document base.
                                if ( u.protocol !== "" ) {
                                        return ( !this.isPath(u.hash) && u.hash && ( u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ) ) );
                                }
                                return ( /^#/ ).test( u.href );
                        },

                        squash: function( url, resolutionUrl ) {
                                var state, href, cleanedUrl, search, stateIndex,
                                        isPath = this.isPath( url ),
                                        uri = this.parseUrl( url ),
                                        preservedHash = uri.hash,
                                        uiState = "";

                                // produce a url against which we can resole the provided path
                                resolutionUrl = resolutionUrl || (path.isPath(url) ? path.getLocation() : path.getDocumentUrl());

                                // If the url is anything but a simple string, remove any preceding hash
                                // eg #foo/bar -> foo/bar
                                //    #foo -> #foo
                                cleanedUrl = isPath ? path.stripHash( url ) : url;

                                // If the url is a full url with a hash check if the parsed hash is a path
                                // if it is, strip the #, and use it otherwise continue without change
                                cleanedUrl = path.isPath( uri.hash ) ? path.stripHash( uri.hash ) : cleanedUrl;

                                // Split the UI State keys off the href
                                stateIndex = cleanedUrl.indexOf( this.uiStateKey );

                                // store the ui state keys for use
                                if( stateIndex > -1 ){
                                        uiState = cleanedUrl.slice( stateIndex );
                                        cleanedUrl = cleanedUrl.slice( 0, stateIndex );
                                }

                                // make the cleanedUrl absolute relative to the resolution url
                                href = path.makeUrlAbsolute( cleanedUrl, resolutionUrl );

                                // grab the search from the resolved url since parsing from
                                // the passed url may not yield the correct result
                                search = this.parseUrl( href ).search;

                                // TODO all this crap is terrible, clean it up
                                if ( isPath ) {
                                        // reject the hash if it's a path or it's just a dialog key
                                        if( path.isPath( preservedHash ) || preservedHash.replace("#", "").indexOf( this.uiStateKey ) === 0) {
                                                preservedHash = "";
                                        }

                                        // Append the UI State keys where it exists and it's been removed
                                        // from the url
                                        if( uiState && preservedHash.indexOf( this.uiStateKey ) === -1){
                                                preservedHash += uiState;
                                        }

                                        // make sure that pound is on the front of the hash
                                        if( preservedHash.indexOf( "#" ) === -1 && preservedHash !== "" ){
                                                preservedHash = "#" + preservedHash;
                                        }

                                        // reconstruct each of the pieces with the new search string and hash
                                        href = path.parseUrl( href );
                                        href = href.protocol + "//" + href.host + href.pathname + search + preservedHash;
                                } else {
                                        href += href.indexOf( "#" ) > -1 ? uiState : "#" + uiState;
                                }

                                return href;
                        },

                        isPreservableHash: function( hash ) {
                                return hash.replace( "#", "" ).indexOf( this.uiStateKey ) === 0;
                        }
                };

                path.documentUrl = path.parseLocation();

                $base = $( "head" ).find( "base" );

                path.documentBase = $base.length ?
                        path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), path.documentUrl.href ) ) :
                        path.documentUrl;

                path.documentBaseDiffers = (path.documentUrl.hrefNoHash !== path.documentBase.hrefNoHash);

                //return the original document url
                path.getDocumentUrl = function( asParsedObject ) {
                        return asParsedObject ? $.extend( {}, path.documentUrl ) : path.documentUrl.href;
                };

                //return the original document base url
                path.getDocumentBase = function( asParsedObject ) {
                        return asParsedObject ? $.extend( {}, path.documentBase ) : path.documentBase.href;
                };
})( jQuery );



(function( $, undefined ) {
        var path = $.mobile.path;

        $.mobile.History = function( stack, index ) {
                this.stack = stack || [];
                this.activeIndex = index || 0;
        };

        $.extend($.mobile.History.prototype, {
                getActive: function() {
                        return this.stack[ this.activeIndex ];
                },

                getLast: function() {
                        return this.stack[ this.previousIndex ];
                },

                getNext: function() {
                        return this.stack[ this.activeIndex + 1 ];
                },

                getPrev: function() {
                        return this.stack[ this.activeIndex - 1 ];
                },

                // addNew is used whenever a new page is added
                add: function( url, data ){
                        data = data || {};

                        //if there's forward history, wipe it
                        if ( this.getNext() ) {
                                this.clearForward();
                        }

                        // if the hash is included in the data make sure the shape
                        // is consistent for comparison
                        if( data.hash && data.hash.indexOf( "#" ) === -1) {
                                data.hash = "#" + data.hash;
                        }

                        data.url = url;
                        this.stack.push( data );
                        this.activeIndex = this.stack.length - 1;
                },

                //wipe urls ahead of active index
                clearForward: function() {
                        this.stack = this.stack.slice( 0, this.activeIndex + 1 );
                },

                find: function( url, stack, earlyReturn ) {
                        stack = stack || this.stack;

                        var entry, i, length = stack.length, index;

                        for ( i = 0; i < length; i++ ) {
                                entry = stack[i];

                                if ( decodeURIComponent(url) === decodeURIComponent(entry.url) ||
                                        decodeURIComponent(url) === decodeURIComponent(entry.hash) ) {
                                        index = i;

                                        if( earlyReturn ) {
                                                return index;
                                        }
                                }
                        }

                        return index;
                },

                closest: function( url ) {
                        var closest, a = this.activeIndex;

                        // First, take the slice of the history stack before the current index and search
                        // for a url match. If one is found, we'll avoid avoid looking through forward history
                        // NOTE the preference for backward history movement is driven by the fact that
                        //      most mobile browsers only have a dedicated back button, and users rarely use
                        //      the forward button in desktop browser anyhow
                        closest = this.find( url, this.stack.slice(0, a) );

                        // If nothing was found in backward history check forward. The `true`
                        // value passed as the third parameter causes the find method to break
                        // on the first match in the forward history slice. The starting index
                        // of the slice must then be added to the result to get the element index
                        // in the original history stack :( :(
                        //
                        // TODO this is hyper confusing and should be cleaned up (ugh so bad)
                        if( closest === undefined ) {
                                closest = this.find( url, this.stack.slice(a), true );
                                closest = closest === undefined ? closest : closest + a;
                        }

                        return closest;
                },

                direct: function( opts ) {
                        var newActiveIndex = this.closest( opts.url ), a = this.activeIndex;

                        // save new page index, null check to prevent falsey 0 result
                        // record the previous index for reference
                        if( newActiveIndex !== undefined ) {
                                this.activeIndex = newActiveIndex;
                                this.previousIndex = a;
                        }

                        // invoke callbacks where appropriate
                        //
                        // TODO this is also convoluted and confusing
                        if ( newActiveIndex < a ) {
                                ( opts.present || opts.back || $.noop )( this.getActive(), 'back' );
                        } else if ( newActiveIndex > a ) {
                                ( opts.present || opts.forward || $.noop )( this.getActive(), 'forward' );
                        } else if ( newActiveIndex === undefined && opts.missing ){
                                opts.missing( this.getActive() );
                        }
                }
        });
})( jQuery );


(function( $, undefined ) {
        var path = $.mobile.path,
                initialHref = location.href;

        $.mobile.Navigator = function( history ) {
                this.history = history;
                this.ignoreInitialHashChange = true;

                $.mobile.window.bind({
                        "popstate.history": $.proxy( this.popstate, this ),
                        "hashchange.history": $.proxy( this.hashchange, this )
                });
        };

        $.extend($.mobile.Navigator.prototype, {
                squash: function( url, data ) {
                        var state, href, hash = path.isPath(url) ? path.stripHash(url) : url;

                        href = path.squash( url );

                        // make sure to provide this information when it isn't explicitly set in the
                        // data object that was passed to the squash method
                        state = $.extend({
                                hash: hash,
                                url: href
                        }, data);

                        // replace the current url with the new href and store the state
                        // Note that in some cases we might be replacing an url with the
                        // same url. We do this anyways because we need to make sure that
                        // all of our history entries have a state object associated with
                        // them. This allows us to work around the case where $.mobile.back()
                        // is called to transition from an external page to an embedded page.
                        // In that particular case, a hashchange event is *NOT* generated by the browser.
                        // Ensuring each history entry has a state object means that onPopState()
                        // will always trigger our hashchange callback even when a hashchange event
                        // is not fired.
                        window.history.replaceState( state, state.title || document.title, href );

                        return state;
                },

                hash: function( url, href ) {
                        var parsed, loc, hash;

                        // Grab the hash for recording. If the passed url is a path
                        // we used the parsed version of the squashed url to reconstruct,
                        // otherwise we assume it's a hash and store it directly
                        parsed = path.parseUrl( url );
                        loc = path.parseLocation();

                        if( loc.pathname + loc.search === parsed.pathname + parsed.search ) {
                                // If the pathname and search of the passed url is identical to the current loc
                                // then we must use the hash. Otherwise there will be no event
                                // eg, url = "/foo/bar?baz#bang", location.href = "http://example.com/foo/bar?baz"
                                hash = parsed.hash ? parsed.hash : parsed.pathname + parsed.search;
                        } else if ( path.isPath(url) ) {
                                var resolved = path.parseUrl( href );
                                // If the passed url is a path, make it domain relative and remove any trailing hash
                                hash = resolved.pathname + resolved.search + (path.isPreservableHash( resolved.hash )? resolved.hash.replace( "#", "" ) : "");
                        } else {
                                hash = url;
                        }

                        return hash;
                },

                // TODO reconsider name
                go: function( url, data, noEvents ) {
                        var state, href, hash, popstateEvent,
                                isPopStateEvent = $.event.special.navigate.isPushStateEnabled();

                        // Get the url as it would look squashed on to the current resolution url
                        href = path.squash( url );

                        // sort out what the hash sould be from the url
                        hash = this.hash( url, href );

                        // Here we prevent the next hash change or popstate event from doing any
                        // history management. In the case of hashchange we don't swallow it
                        // if there will be no hashchange fired (since that won't reset the value)
                        // and will swallow the following hashchange
                        if( noEvents && hash !== path.stripHash(path.parseLocation().hash) ) {
                                this.preventNextHashChange = noEvents;
                        }

                        // IMPORTANT in the case where popstate is supported the event will be triggered
                        //      directly, stopping further execution - ie, interupting the flow of this
                        //      method call to fire bindings at this expression. Below the navigate method
                        //      there is a binding to catch this event and stop its propagation.
                        //
                        //      We then trigger a new popstate event on the window with a null state
                        //      so that the navigate events can conclude their work properly
                        //
                        // if the url is a path we want to preserve the query params that are available on
                        // the current url.
                        this.preventHashAssignPopState = true;
                        window.location.hash = hash;

                        // If popstate is enabled and the browser triggers `popstate` events when the hash
                        // is set (this often happens immediately in browsers like Chrome), then the
                        // this flag will be set to false already. If it's a browser that does not trigger
                        // a `popstate` on hash assignement or `replaceState` then we need avoid the branch
                        // that swallows the event created by the popstate generated by the hash assignment
                        // At the time of this writing this happens with Opera 12 and some version of IE
                        this.preventHashAssignPopState = false;

                        state = $.extend({
                                url: href,
                                hash: hash,
                                title: document.title
                        }, data);

                        if( isPopStateEvent ) {
                                popstateEvent = new $.Event( "popstate" );
                                popstateEvent.originalEvent = {
                                        type: "popstate",
                                        state: null
                                };

                                this.squash( url, state );

                                // Trigger a new faux popstate event to replace the one that we
                                // caught that was triggered by the hash setting above.
                                if( !noEvents ) {
                                        this.ignorePopState = true;
                                        $.mobile.window.trigger( popstateEvent );
                                }
                        }

                        // record the history entry so that the information can be included
                        // in hashchange event driven navigate events in a similar fashion to
                        // the state that's provided by popstate
                        this.history.add( state.url, state );
                },


                // This binding is intended to catch the popstate events that are fired
                // when execution of the `$.navigate` method stops at window.location.hash = url;
                // and completely prevent them from propagating. The popstate event will then be
                // retriggered after execution resumes
                //
                // TODO grab the original event here and use it for the synthetic event in the
                //      second half of the navigate execution that will follow this binding
                popstate: function( event ) {
                        var active, hash, state, closestIndex;

                        // Partly to support our test suite which manually alters the support
                        // value to test hashchange. Partly to prevent all around weirdness
                        if( !$.event.special.navigate.isPushStateEnabled() ){
                                return;
                        }

                        // If this is the popstate triggered by the actual alteration of the hash
                        // prevent it completely. History is tracked manually
                        if( this.preventHashAssignPopState ) {
                                this.preventHashAssignPopState = false;
                                event.stopImmediatePropagation();
                                return;
                        }

                        // if this is the popstate triggered after the `replaceState` call in the go
                        // method, then simply ignore it. The history entry has already been captured
                        if( this.ignorePopState ) {
                                this.ignorePopState = false;
                                return;
                        }

                        // If there is no state, and the history stack length is one were
                        // probably getting the page load popstate fired by browsers like chrome
                        // avoid it and set the one time flag to false.
                        // TODO: Do we really need all these conditions? Comparing location hrefs
                        // should be sufficient.
                        if( !event.originalEvent.state &&
                                this.history.stack.length === 1 &&
                                this.ignoreInitialHashChange ) {
                                this.ignoreInitialHashChange = false;

                                if ( location.href === initialHref ) {
                                        event.preventDefault();
                                        return;
                                }
                        }

                        // account for direct manipulation of the hash. That is, we will receive a popstate
                        // when the hash is changed by assignment, and it won't have a state associated. We
                        // then need to squash the hash. See below for handling of hash assignment that
                        // matches an existing history entry
                        // TODO it might be better to only add to the history stack
                        //      when the hash is adjacent to the active history entry
                        hash = path.parseLocation().hash;
                        if( !event.originalEvent.state && hash ) {
                                // squash the hash that's been assigned on the URL with replaceState
                                // also grab the resulting state object for storage
                                state = this.squash( hash );

                                // record the new hash as an additional history entry
                                // to match the browser's treatment of hash assignment
                                this.history.add( state.url, state );

                                // pass the newly created state information
                                // along with the event
                                event.historyState = state;

                                // do not alter history, we've added a new history entry
                                // so we know where we are
                                return;
                        }

                        // If all else fails this is a popstate that comes from the back or forward buttons
                        // make sure to set the state of our history stack properly, and record the directionality
                        this.history.direct({
                                url: (event.originalEvent.state || {}).url || hash,

                                // When the url is either forward or backward in history include the entry
                                // as data on the event object for merging as data in the navigate event
                                present: function( historyEntry, direction ) {
                                        // make sure to create a new object to pass down as the navigate event data
                                        event.historyState = $.extend({}, historyEntry);
                                        event.historyState.direction = direction;
                                }
                        });
                },

                // NOTE must bind before `navigate` special event hashchange binding otherwise the
                //      navigation data won't be attached to the hashchange event in time for those
                //      bindings to attach it to the `navigate` special event
                // TODO add a check here that `hashchange.navigate` is bound already otherwise it's
                //      broken (exception?)
                hashchange: function( event ) {
                        var history, hash;

                        // If hashchange listening is explicitly disabled or pushstate is supported
                        // avoid making use of the hashchange handler.
                        if(!$.event.special.navigate.isHashChangeEnabled() ||
                                $.event.special.navigate.isPushStateEnabled() ) {
                                return;
                        }

                        // On occasion explicitly want to prevent the next hash from propogating because we only
                        // with to alter the url to represent the new state do so here
                        if( this.preventNextHashChange ){
                                this.preventNextHashChange = false;
                                event.stopImmediatePropagation();
                                return;
                        }

                        history = this.history;
                        hash = path.parseLocation().hash;

                        // If this is a hashchange caused by the back or forward button
                        // make sure to set the state of our history stack properly
                        this.history.direct({
                                url: hash,

                                // When the url is either forward or backward in history include the entry
                                // as data on the event object for merging as data in the navigate event
                                present: function( historyEntry, direction ) {
                                        // make sure to create a new object to pass down as the navigate event data
                                        event.hashchangeState = $.extend({}, historyEntry);
                                        event.hashchangeState.direction = direction;
                                },

                                // When we don't find a hash in our history clearly we're aiming to go there
                                // record the entry as new for future traversal
                                //
                                // NOTE it's not entirely clear that this is the right thing to do given that we
                                //      can't know the users intention. It might be better to explicitly _not_
                                //      support location.hash assignment in preference to $.navigate calls
                                // TODO first arg to add should be the href, but it causes issues in identifying
                                //      embeded pages
                                missing: function() {
                                        history.add( hash, {
                                                hash: hash,
                                                title: document.title
                                        });
                                }
                        });
                }
        });
})( jQuery );



(function( $, undefined ) {
        // TODO consider queueing navigation activity until previous activities have completed
        //      so that end users don't have to think about it. Punting for now
        // TODO !! move the event bindings into callbacks on the navigate event
        $.mobile.navigate = function( url, data, noEvents ) {
                $.mobile.navigate.navigator.go( url, data, noEvents );
        };

        // expose the history on the navigate method in anticipation of full integration with
        // existing navigation functionalty that is tightly coupled to the history information
        $.mobile.navigate.history = new $.mobile.History();

        // instantiate an instance of the navigator for use within the $.navigate method
        $.mobile.navigate.navigator = new $.mobile.Navigator( $.mobile.navigate.history );

        var loc = $.mobile.path.parseLocation();
        $.mobile.navigate.history.add( loc.href, {hash: loc.hash} );
})( jQuery );


(function( $, window, undefined ) {

var createHandler = function( sequential ) {

        // Default to sequential
        if ( sequential === undefined ) {
                sequential = true;
        }

        return function( name, reverse, $to, $from ) {

                var deferred = new $.Deferred(),
                        reverseClass = reverse ? " reverse" : "",
                        active  = $.mobile.urlHistory.getActive(),
                        toScroll = active.lastScroll || $.mobile.defaultHomeScroll,
                        screenHeight = $.mobile.getScreenHeight(),
                        maxTransitionOverride = $.mobile.maxTransitionWidth !== false && $.mobile.window.width() > $.mobile.maxTransitionWidth,
                        none = !$.support.cssTransitions || maxTransitionOverride || !name || name === "none" || Math.max( $.mobile.window.scrollTop(), toScroll ) > $.mobile.getMaxScrollForTransition(),
                        toPreClass = " ui-page-pre-in",
                        toggleViewportClass = function() {
                                $.mobile.pageContainer.toggleClass( "ui-mobile-viewport-transitioning viewport-" + name );
                        },
                        scrollPage = function() {
                                // By using scrollTo instead of silentScroll, we can keep things better in order
                                // Just to be precautios, disable scrollstart listening like silentScroll would
                                $.event.special.scrollstart.enabled = false;

                                window.scrollTo( 0, toScroll );

                                // reenable scrollstart listening like silentScroll would
                                setTimeout( function() {
                                        $.event.special.scrollstart.enabled = true;
                                }, 150 );
                        },
                        cleanFrom = function() {
                                $from
                                        .removeClass( $.mobile.activePageClass + " out in reverse " + name )
                                        .height( "" );
                        },
                        startOut = function() {
                                // if it's not sequential, call the doneOut transition to start the TO page animating in simultaneously
                                if ( !sequential ) {
                                        doneOut();
                                }
                                else {
                                        $from.animationComplete( doneOut );
                                }

                                // Set the from page's height and start it transitioning out
                                // Note: setting an explicit height helps eliminate tiling in the transitions
                                $from
                                        .height( screenHeight + $.mobile.window.scrollTop() )
                                        .addClass( name + " out" + reverseClass );
                        },

                        doneOut = function() {

                                if ( $from && sequential ) {
                                        cleanFrom();
                                }

                                startIn();
                        },

                        startIn = function() {

                                // Prevent flickering in phonegap container: see comments at #4024 regarding iOS
                                $to.css( "z-index", -10 );

                                $to.addClass( $.mobile.activePageClass + toPreClass );

                                // Send focus to page as it is now display: block
                                $.mobile.focusPage( $to );

                                // Set to page height
                                $to.height( screenHeight + toScroll );

                                scrollPage();

                                // Restores visibility of the new page: added together with $to.css( "z-index", -10 );
                                $to.css( "z-index", "" );

                                if ( !none ) {
                                        $to.animationComplete( doneIn );
                                }

                                $to
                                        .removeClass( toPreClass )
                                        .addClass( name + " in" + reverseClass );

                                if ( none ) {
                                        doneIn();
                                }

                        },

                        doneIn = function() {

                                if ( !sequential ) {

                                        if ( $from ) {
                                                cleanFrom();
                                        }
                                }

                                $to
                                        .removeClass( "out in reverse " + name )
                                        .height( "" );

                                toggleViewportClass();

                                // In some browsers (iOS5), 3D transitions block the ability to scroll to the desired location during transition
                                // This ensures we jump to that spot after the fact, if we aren't there already.
                                if ( $.mobile.window.scrollTop() !== toScroll ) {
                                        scrollPage();
                                }

                                deferred.resolve( name, reverse, $to, $from, true );
                        };

                toggleViewportClass();

                if ( $from && !none ) {
                        startOut();
                }
                else {
                        doneOut();
                }

                return deferred.promise();
        };
};

// generate the handlers from the above
var sequentialHandler = createHandler(),
        simultaneousHandler = createHandler( false ),
        defaultGetMaxScrollForTransition = function() {
                return $.mobile.getScreenHeight() * 3;
        };

// Make our transition handler the public default.
$.mobile.defaultTransitionHandler = sequentialHandler;

//transition handler dictionary for 3rd party transitions
$.mobile.transitionHandlers = {
        "default": $.mobile.defaultTransitionHandler,
        "sequential": sequentialHandler,
        "simultaneous": simultaneousHandler
};

$.mobile.transitionFallbacks = {};

// If transition is defined, check if css 3D transforms are supported, and if not, if a fallback is specified
$.mobile._maybeDegradeTransition = function( transition ) {
                if ( transition && !$.support.cssTransform3d && $.mobile.transitionFallbacks[ transition ] ) {
                        transition = $.mobile.transitionFallbacks[ transition ];
                }

                return transition;
};

// Set the getMaxScrollForTransition to default if no implementation was set by user
$.mobile.getMaxScrollForTransition = $.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition;
})( jQuery, this );

(function( $, undefined ) {

        //define vars for interal use
        var $window = $.mobile.window,
                $html = $( 'html' ),
                $head = $( 'head' ),

                // NOTE: path extensions dependent on core attributes. Moved here to remove deps from
                //       $.mobile.path definition
                path = $.extend($.mobile.path, {

                        //return the substring of a filepath before the sub-page key, for making a server request
                        getFilePath: function( path ) {
                                var splitkey = '&' + $.mobile.subPageUrlKey;
                                return path && path.split( splitkey )[0].split( dialogHashKey )[0];
                        },

                        //check if the specified url refers to the first page in the main application document.
                        isFirstPageUrl: function( url ) {
                                // We only deal with absolute paths.
                                var u = path.parseUrl( path.makeUrlAbsolute( url, this.documentBase ) ),

                                        // Does the url have the same path as the document?
                                        samePath = u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ),

                                        // Get the first page element.
                                        fp = $.mobile.firstPage,

                                        // Get the id of the first page element if it has one.
                                        fpId = fp && fp[0] ? fp[0].id : undefined;

                                // The url refers to the first page if the path matches the document and
                                // it either has no hash value, or the hash is exactly equal to the id of the
                                // first page element.
                                return samePath && ( !u.hash || u.hash === "#" || ( fpId && u.hash.replace( /^#/, "" ) === fpId ) );
                        },

                        // Some embedded browsers, like the web view in Phone Gap, allow cross-domain XHR
                        // requests if the document doing the request was loaded via the file:// protocol.
                        // This is usually to allow the application to "phone home" and fetch app specific
                        // data. We normally let the browser handle external/cross-domain urls, but if the
                        // allowCrossDomainPages option is true, we will allow cross-domain http/https
                        // requests to go through our page loading logic.
                        isPermittedCrossDomainRequest: function( docUrl, reqUrl ) {
                                return $.mobile.allowCrossDomainPages &&
                                        docUrl.protocol === "file:" &&
                                        reqUrl.search( /^https?:/ ) !== -1;
                        }
                }),

                // used to track last vclicked element to make sure its value is added to form data
                $lastVClicked = null,

                //will be defined when a link is clicked and given an active class
                $activeClickedLink = null,

                // resolved on domready
                domreadyDeferred = $.Deferred(),

                //urlHistory is purely here to make guesses at whether the back or forward button was clicked
                //and provide an appropriate transition
                urlHistory = $.mobile.navigate.history,

                //define first selector to receive focus when a page is shown
                focusable = "[tabindex],a,button:visible,select:visible,input",

                //queue to hold simultanious page transitions
                pageTransitionQueue = [],

                //indicates whether or not page is in process of transitioning
                isPageTransitioning = false,

                //nonsense hash change key for dialogs, so they create a history entry
                dialogHashKey = "&ui-state=dialog",

                //existing base tag?
                $base = $head.children( "base" ),

                //tuck away the original document URL minus any fragment.
                documentUrl = path.documentUrl,

                //if the document has an embedded base tag, documentBase is set to its
                //initial value. If a base tag does not exist, then we default to the documentUrl.
                documentBase = path.documentBase,

                //cache the comparison once.
                documentBaseDiffers = path.documentBaseDiffers,

                getScreenHeight = $.mobile.getScreenHeight;

                //base element management, defined depending on dynamic base tag support
                var base = $.support.dynamicBaseTag ? {

                        //define base element, for use in routing asset urls that are referenced in Ajax-requested markup
                        element: ( $base.length ? $base : $( "<base>", { href: documentBase.hrefNoHash } ).prependTo( $head ) ),

                        //set the generated BASE element's href attribute to a new page's base path
                        set: function( href ) {
                                href = path.parseUrl(href).hrefNoHash;
                                base.element.attr( "href", path.makeUrlAbsolute( href, documentBase ) );
                        },

                        //set the generated BASE element's href attribute to a new page's base path
                        reset: function() {
                                base.element.attr( "href", documentBase.hrefNoSearch );
                        }

                } : undefined;


        //return the original document url
        $.mobile.getDocumentUrl = path.getDocumentUrl;

        //return the original document base url
        $.mobile.getDocumentBase = path.getDocumentBase;

        /* internal utility functions */

        // NOTE Issue #4950 Android phonegap doesn't navigate back properly
        //      when a full page refresh has taken place. It appears that hashchange
        //      and replacestate history alterations work fine but we need to support
        //      both forms of history traversal in our code that uses backward history
        //      movement
        $.mobile.back = function() {
                var nav = window.navigator;

                // if the setting is on and the navigator object is
                // available use the phonegap navigation capability
                if( this.phonegapNavigationEnabled &&
                        nav &&
                        nav.app &&
                        nav.app.backHistory ){
                        nav.app.backHistory();
                } else {
                        window.history.back();
                }
        };

        //direct focus to the page title, or otherwise first focusable element
        $.mobile.focusPage = function ( page ) {
                var autofocus = page.find( "[autofocus]" ),
                        pageTitle = page.find( ".ui-title:eq(0)" );

                if ( autofocus.length ) {
                        autofocus.focus();
                        return;
                }

                if ( pageTitle.length ) {
                        pageTitle.focus();
                } else{
                        page.focus();
                }
        };

        //remove active classes after page transition or error
        function removeActiveLinkClass( forceRemoval ) {
                if ( !!$activeClickedLink && ( !$activeClickedLink.closest( "." + $.mobile.activePageClass ).length || forceRemoval ) ) {
                        $activeClickedLink.removeClass( $.mobile.activeBtnClass );
                }
                $activeClickedLink = null;
        }

        function releasePageTransitionLock() {
                isPageTransitioning = false;
                if ( pageTransitionQueue.length > 0 ) {
                        $.mobile.changePage.apply( null, pageTransitionQueue.pop() );
                }
        }

        // Save the last scroll distance per page, before it is hidden
        var setLastScrollEnabled = true,
                setLastScroll, delayedSetLastScroll;

        setLastScroll = function() {
                // this barrier prevents setting the scroll value based on the browser
                // scrolling the window based on a hashchange
                if ( !setLastScrollEnabled ) {
                        return;
                }

                var active = $.mobile.urlHistory.getActive();

                if ( active ) {
                        var lastScroll = $window.scrollTop();

                        // Set active page's lastScroll prop.
                        // If the location we're scrolling to is less than minScrollBack, let it go.
                        active.lastScroll = lastScroll < $.mobile.minScrollBack ? $.mobile.defaultHomeScroll : lastScroll;
                }
        };

        // bind to scrollstop to gather scroll position. The delay allows for the hashchange
        // event to fire and disable scroll recording in the case where the browser scrolls
        // to the hash targets location (sometimes the top of the page). once pagechange fires
        // getLastScroll is again permitted to operate
        delayedSetLastScroll = function() {
                setTimeout( setLastScroll, 100 );
        };

        // disable an scroll setting when a hashchange has been fired, this only works
        // because the recording of the scroll position is delayed for 100ms after
        // the browser might have changed the position because of the hashchange
        $window.bind( $.support.pushState ? "popstate" : "hashchange", function() {
                setLastScrollEnabled = false;
        });

        // handle initial hashchange from chrome :(
        $window.one( $.support.pushState ? "popstate" : "hashchange", function() {
                setLastScrollEnabled = true;
        });

        // wait until the mobile page container has been determined to bind to pagechange
        $window.one( "pagecontainercreate", function() {
                // once the page has changed, re-enable the scroll recording
                $.mobile.pageContainer.bind( "pagechange", function() {

                        setLastScrollEnabled = true;

                        // remove any binding that previously existed on the get scroll
                        // which may or may not be different than the scroll element determined for
                        // this page previously
                        $window.unbind( "scrollstop", delayedSetLastScroll );

                        // determine and bind to the current scoll element which may be the window
                        // or in the case of touch overflow the element with touch overflow
                        $window.bind( "scrollstop", delayedSetLastScroll );
                });
        });

        // bind to scrollstop for the first page as "pagechange" won't be fired in that case
        $window.bind( "scrollstop", delayedSetLastScroll );

        // No-op implementation of transition degradation
        $.mobile._maybeDegradeTransition = $.mobile._maybeDegradeTransition || function( transition ) {
                return transition;
        };

        //function for transitioning between two existing pages
        function transitionPages( toPage, fromPage, transition, reverse ) {
                if ( fromPage ) {
                        //trigger before show/hide events
                        fromPage.data( "mobile-page" )._trigger( "beforehide", null, { nextPage: toPage } );
                }

                toPage.data( "mobile-page" )._trigger( "beforeshow", null, { prevPage: fromPage || $( "" ) } );

                //clear page loader
                $.mobile.hidePageLoadingMsg();

                transition = $.mobile._maybeDegradeTransition( transition );

                //find the transition handler for the specified transition. If there
                //isn't one in our transitionHandlers dictionary, use the default one.
                //call the handler immediately to kick-off the transition.
                var th = $.mobile.transitionHandlers[ transition || "default" ] || $.mobile.defaultTransitionHandler,
                        promise = th( transition, reverse, toPage, fromPage );

                promise.done(function() {
                        //trigger show/hide events
                        if ( fromPage ) {
                                fromPage.data( "mobile-page" )._trigger( "hide", null, { nextPage: toPage } );
                        }

                        //trigger pageshow, define prevPage as either fromPage or empty jQuery obj
                        toPage.data( "mobile-page" )._trigger( "show", null, { prevPage: fromPage || $( "" ) } );
                });

                return promise;
        }

        //simply set the active page's minimum height to screen height, depending on orientation
        $.mobile.resetActivePageHeight = function resetActivePageHeight( height ) {
                var aPage = $( "." + $.mobile.activePageClass ),
                        aPagePadT = parseFloat( aPage.css( "padding-top" ) ),
                        aPagePadB = parseFloat( aPage.css( "padding-bottom" ) ),
                        aPageBorderT = parseFloat( aPage.css( "border-top-width" ) ),
                        aPageBorderB = parseFloat( aPage.css( "border-bottom-width" ) );

                height = ( typeof height === "number" )? height : getScreenHeight();
               
                aPage.css( "min-height", height - aPagePadT - aPagePadB - aPageBorderT - aPageBorderB );
        };

        //shared page enhancements
        function enhancePage( $page, role ) {
                // If a role was specified, make sure the data-role attribute
                // on the page element is in sync.
                if ( role ) {
                        $page.attr( "data-" + $.mobile.ns + "role", role );
                }

                //run page plugin
                $page.page();
        }

        // determine the current base url
        function findBaseWithDefault() {
                var closestBase = ( $.mobile.activePage && getClosestBaseUrl( $.mobile.activePage ) );
                return closestBase || documentBase.hrefNoHash;
        }

        /* exposed $.mobile methods */

        //animation complete callback
        $.fn.animationComplete = function( callback ) {
                if ( $.support.cssTransitions ) {
                        return $( this ).one( 'webkitAnimationEnd animationend', callback );
                }
                else{
                        // defer execution for consistency between webkit/non webkit
                        setTimeout( callback, 0 );
                        return $( this );
                }
        };

        //expose path object on $.mobile
        $.mobile.path = path;

        //expose base object on $.mobile
        $.mobile.base = base;

        //history stack
        $.mobile.urlHistory = urlHistory;

        $.mobile.dialogHashKey = dialogHashKey;

        //enable cross-domain page support
        $.mobile.allowCrossDomainPages = false;

        $.mobile._bindPageRemove = function() {
                var page = $( this );

                // when dom caching is not enabled or the page is embedded bind to remove the page on hide
                if ( !page.data( "mobile-page" ).options.domCache &&
                        page.is( ":jqmData(external-page='true')" ) ) {

                        page.bind( 'pagehide.remove', function( e ) {
                                var $this = $( this ),
                                        prEvent = new $.Event( "pageremove" );

                                $this.trigger( prEvent );

                                if ( !prEvent.isDefaultPrevented() ) {
                                        $this.removeWithDependents();
                                }
                        });
                }
        };

        // Load a page into the DOM.
        $.mobile.loadPage = function( url, options ) {
                // This function uses deferred notifications to let callers
                // know when the page is done loading, or if an error has occurred.
                var deferred = $.Deferred(),

                        // The default loadPage options with overrides specified by
                        // the caller.
                        settings = $.extend( {}, $.mobile.loadPage.defaults, options ),

                        // The DOM element for the page after it has been loaded.
                        page = null,

                        // If the reloadPage option is true, and the page is already
                        // in the DOM, dupCachedPage will be set to the page element
                        // so that it can be removed after the new version of the
                        // page is loaded off the network.
                        dupCachedPage = null,

                        // The absolute version of the URL passed into the function. This
                        // version of the URL may contain dialog/subpage params in it.
                        absUrl = path.makeUrlAbsolute( url, findBaseWithDefault() );

                // If the caller provided data, and we're using "get" request,
                // append the data to the URL.
                if ( settings.data && settings.type === "get" ) {
                        absUrl = path.addSearchParams( absUrl, settings.data );
                        settings.data = undefined;
                }

                // If the caller is using a "post" request, reloadPage must be true
                if ( settings.data && settings.type === "post" ) {
                        settings.reloadPage = true;
                }

                // The absolute version of the URL minus any dialog/subpage params.
                // In otherwords the real URL of the page to be loaded.
                var fileUrl = path.getFilePath( absUrl ),

                        // The version of the Url actually stored in the data-url attribute of
                        // the page. For embedded pages, it is just the id of the page. For pages
                        // within the same domain as the document base, it is the site relative
                        // path. For cross-domain pages (Phone Gap only) the entire absolute Url
                        // used to load the page.
                        dataUrl = path.convertUrlToDataUrl( absUrl );

                // Make sure we have a pageContainer to work with.
                settings.pageContainer = settings.pageContainer || $.mobile.pageContainer;

                // Check to see if the page already exists in the DOM.
                // NOTE do _not_ use the :jqmData psuedo selector because parenthesis
                //      are a valid url char and it breaks on the first occurence
                page = settings.pageContainer.children( "[data-" + $.mobile.ns +"url='" + dataUrl + "']" );

                // If we failed to find the page, check to see if the url is a
                // reference to an embedded page. If so, it may have been dynamically
                // injected by a developer, in which case it would be lacking a data-url
                // attribute and in need of enhancement.
                if ( page.length === 0 && dataUrl && !path.isPath( dataUrl ) ) {
                        page = settings.pageContainer.children( "#" + dataUrl )
                                .attr( "data-" + $.mobile.ns + "url", dataUrl )
                                .jqmData( "url", dataUrl );
                }

               
                // If we failed to find a page in the DOM, check the URL to see if it
                // refers to the first page in the application. If it isn't a reference
                // to the first page and refers to non-existent embedded page, error out.
                if ( page.length === 0 ) {
                        if ( $.mobile.firstPage && path.isFirstPageUrl( fileUrl ) ) {
                                // Check to make sure our cached-first-page is actually
                                // in the DOM. Some user deployed apps are pruning the first
                                // page from the DOM for various reasons, we check for this
                                // case here because we don't want a first-page with an id
                                // falling through to the non-existent embedded page error
                                // case. If the first-page is not in the DOM, then we let
                                // things fall through to the ajax loading code below so
                                // that it gets reloaded.
                                if ( $.mobile.firstPage.parent().length ) {
                                        page = $( $.mobile.firstPage );
                                }
                        } else if ( path.isEmbeddedPage( fileUrl )  ) {
                                deferred.reject( absUrl, options );
                                return deferred.promise();
                        }
                }
               
                // If the page we are interested in is already in the DOM,
                // and the caller did not indicate that we should force a
                // reload of the file, we are done. Otherwise, track the
                // existing page as a duplicated.
                if ( page.length ) {
                        if ( !settings.reloadPage ) {
                                enhancePage( page, settings.role );
                                deferred.resolve( absUrl, options, page );
                                //if we are reloading the page make sure we update the base if its not a prefetch
                                if( base && !options.prefetch ){
                                        base.set(url);
                                }
                                return deferred.promise();
                        }
                        dupCachedPage = page;
                }
                var mpc = settings.pageContainer,
                        pblEvent = new $.Event( "pagebeforeload" ),
                        triggerData = { url: url, absUrl: absUrl, dataUrl: dataUrl, deferred: deferred, options: settings };

                // Let listeners know we're about to load a page.
                mpc.trigger( pblEvent, triggerData );

                // If the default behavior is prevented, stop here!
                if ( pblEvent.isDefaultPrevented() ) {
                        return deferred.promise();
                }

                if ( settings.showLoadMsg ) {

                        // This configurable timeout allows cached pages a brief delay to load without showing a message
                        var loadMsgDelay = setTimeout(function() {
                                        $.mobile.showPageLoadingMsg();
                                }, settings.loadMsgDelay ),

                                // Shared logic for clearing timeout and removing message.
                                hideMsg = function() {

                                        // Stop message show timer
                                        clearTimeout( loadMsgDelay );

                                        // Hide loading message
                                        $.mobile.hidePageLoadingMsg();
                                };
                }
                // Reset base to the default document base.
                // only reset if we are not prefetching
                if ( base && typeof options.prefetch === "undefined" ) {
                        base.reset();
                }

                if ( !( $.mobile.allowCrossDomainPages || path.isSameDomain( documentUrl, absUrl ) ) ) {
                        deferred.reject( absUrl, options );
                } else {
                        // Load the new page.
                        $.ajax({
                                url: fileUrl,
                                type: settings.type,
                                data: settings.data,
                                contentType: settings.contentType,
                                dataType: "html",
                                success: function( html, textStatus, xhr ) {
                                        //pre-parse html to check for a data-url,
                                        //use it as the new fileUrl, base path, etc
                                        var all = $( "<div></div>" ),

                                                //page title regexp
                                                newPageTitle = html.match( /<title[^>]*>([^<]*)/ ) && RegExp.$1,

                                                // TODO handle dialogs again
                                                pageElemRegex = new RegExp( "(<[^>]+\\bdata-" + $.mobile.ns + "role=[\"']?page[\"']?[^>]*>)" ),
                                                dataUrlRegex = new RegExp( "\\bdata-" + $.mobile.ns + "url=[\"']?([^\"'>]*)[\"']?" );


                                        // data-url must be provided for the base tag so resource requests can be directed to the
                                        // correct url. loading into a temprorary element makes these requests immediately
                                        if ( pageElemRegex.test( html ) &&
                                                        RegExp.$1 &&
                                                        dataUrlRegex.test( RegExp.$1 ) &&
                                                        RegExp.$1 ) {
                                                url = fileUrl = path.getFilePath( $( "<div>" + RegExp.$1 + "</div>" ).text() );
                                        }
                                        //dont update the base tag if we are prefetching
                                        if ( base && typeof options.prefetch === "undefined") {
                                                base.set( fileUrl );
                                        }

                                        //workaround to allow scripts to execute when included in page divs
                                        all.get( 0 ).innerHTML = html;
                                        page = all.find( ":jqmData(role='page'), :jqmData(role='dialog')" ).first();

                                        //if page elem couldn't be found, create one and insert the body element's contents
                                        if ( !page.length ) {
                                                page = $( "<div data-" + $.mobile.ns + "role='page'>" + ( html.split( /<\/?body[^>]*>/gmi )[1] || "" ) + "</div>" );
                                        }

                                        if ( newPageTitle && !page.jqmData( "title" ) ) {
                                                if ( ~newPageTitle.indexOf( "&" ) ) {
                                                        newPageTitle = $(