text: /**
   * @class Ext.is
   * 
   * Determines information about the current platform the application is running on.
   * 
   * @singleton
   */
  Ext.is = {
      init : function(navigator) {
          var platforms = this.platforms,
              ln = platforms.length,
              i, platform;
  
          navigator = navigator || window.navigator;
  
          for (i = 0; i < ln; i++) {
              platform = platforms[i];
              this[platform.identity] = platform.regex.test(navigator[platform.property]);
          }
  
          /**
           * @property Desktop True if the browser is running on a desktop machine
           * @type {Boolean}
           */
          this.Desktop = this.Mac || this.Windows || (this.Linux && !this.Android);
          /**
           * @property Tablet True if the browser is running on a tablet (iPad)
           */
          this.Tablet = this.iPad;
          /**
           * @property Phone True if the browser is running on a phone.
           * @type {Boolean}
           */
          this.Phone = !this.Desktop && !this.Tablet;
          /**
           * @property iOS True if the browser is running on iOS
           * @type {Boolean}
           */
          this.iOS = this.iPhone || this.iPad || this.iPod;
          
          /**
           * @property Standalone Detects when application has been saved to homescreen.
           * @type {Boolean}
           */
          this.Standalone = !!window.navigator.standalone;
      },
      
      /**
       * @property iPhone True when the browser is running on a iPhone
       * @type {Boolean}
       */
      platforms: [{
          property: 'platform',
          regex: /iPhone/i,
          identity: 'iPhone'
      },
      
      /**
       * @property iPod True when the browser is running on a iPod
       * @type {Boolean}
       */
      {
          property: 'platform',
          regex: /iPod/i,
          identity: 'iPod'
      },
      
      /**
       * @property iPad True when the browser is running on a iPad
       * @type {Boolean}
       */
      {
          property: 'userAgent',
          regex: /iPad/i,
          identity: 'iPad'
      },
      
      /**
       * @property Blackberry True when the browser is running on a Blackberry
       * @type {Boolean}
       */
      {
          property: 'userAgent',
          regex: /Blackberry/i,
          identity: 'Blackberry'
      },
      
      /**
       * @property Android True when the browser is running on an Android device
       * @type {Boolean}
       */
      {
          property: 'userAgent',
          regex: /Android/i,
          identity: 'Android'
      },
      
      /**
       * @property Mac True when the browser is running on a Mac
       * @type {Boolean}
       */
      {
          property: 'platform',
          regex: /Mac/i,
          identity: 'Mac'
      },
      
      /**
       * @property Windows True when the browser is running on Windows
       * @type {Boolean}
       */
      {
          property: 'platform',
          regex: /Win/i,
          identity: 'Windows'
      },
      
      /**
       * @property Linux True when the browser is running on Linux
       * @type {Boolean}
       */
      {
          property: 'platform',
          regex: /Linux/i,
          identity: 'Linux'
      }]
  };
  
  Ext.is.init();
  
  /**
   * @class Ext.supports
   *
   * Determines information about features are supported in the current environment
   * 
   * @singleton
   */
  (function(){
  
      // this is a local copy of certain logic from (Abstract)Element.getStyle
      // to break a dependancy between the supports mechanism and Element
      // use this instead of element references to check for styling info
      var getStyle = function(element, styleName){
          var view = element.ownerDocument.defaultView,
              style = (view ? view.getComputedStyle(element, null) : element.currentStyle) || element.style;
          return style[styleName];
      };
  
  Ext.supports = {
      /**
       * Runs feature detection routines and sets the various flags. This is called when
       * the scripts loads (very early) and again at {@link Ext#onReady}. Some detections
       * are flagged as `early` and run immediately. Others that require the document body
       * will not run until ready.
       *
       * Each test is run only once, so calling this method from an onReady function is safe
       * and ensures that all flags have been set.
       * @markdown
       * @private
       */
      init : function() {
          var me = this,
              doc = document,
              tests = me.tests,
              n = tests.length,
              div = n && Ext.isReady && doc.createElement('div'),
              test, notRun = [];
  
          if (div) {
              div.innerHTML = [
                  '<div style="height:30px;width:50px;">',
                      '<div style="height:20px;width:20px;"></div>',
                  '</div>',
                  '<div style="width: 200px; height: 200px; position: relative; padding: 5px;">',
                      '<div style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></div>',
                  '</div>',
                  '<div style="position: absolute; left: 10%; top: 10%;"></div>',
                  '<div style="float:left; background-color:transparent;"></div>'
              ].join('');
  
              doc.body.appendChild(div);
          }
  
          while (n--) {
              test = tests[n];
              if (div || test.early) {
                  me[test.identity] = test.fn.call(me, doc, div);
              } else {
                  notRun.push(test);
              }
          }
  
          if (div) {
              doc.body.removeChild(div);
          }
  
          me.tests = notRun;
      },
  
      /**
       * @property PointerEvents True if document environment supports the CSS3 pointer-events style.
       * @type {Boolean}
       */
      PointerEvents: 'pointerEvents' in document.documentElement.style,
  
      /**
       * @property CSS3BoxShadow True if document environment supports the CSS3 box-shadow style.
       * @type {Boolean}
       */
      CSS3BoxShadow: 'boxShadow' in document.documentElement.style || 'WebkitBoxShadow' in document.documentElement.style || 'MozBoxShadow' in document.documentElement.style,
  
      /**
       * @property ClassList True if document environment supports the HTML5 classList API.
       * @type {Boolean}
       */
      ClassList: !!document.documentElement.classList,
  
      /**
       * @property OrientationChange True if the device supports orientation change
       * @type {Boolean}
       */
      OrientationChange: ((typeof window.orientation != 'undefined') && ('onorientationchange' in window)),
  
      /**
       * @property DeviceMotion True if the device supports device motion (acceleration and rotation rate)
       * @type {Boolean}
       */
      DeviceMotion: ('ondevicemotion' in window),
  
      /**
       * @property Touch True if the device supports touch
       * @type {Boolean}
       */
      // is.Desktop is needed due to the bug in Chrome 5.0.375, Safari 3.1.2
      // and Safari 4.0 (they all have 'ontouchstart' in the window object).
      Touch: ('ontouchstart' in window) && (!Ext.is.Desktop),
  
      /**
       * @property TimeoutActualLateness True if the browser passes the "actualLateness" parameter to
       * setTimeout. See: https://developer.mozilla.org/en/DOM/window.setTimeout
       * @type {Boolean}
       */
      TimeoutActualLateness: (function(){
          setTimeout(function(){
              Ext.supports.TimeoutActualLateness = arguments.length !== 0;
          }, 0);
      }()),
  
      tests: [
          /**
           * @property Transitions True if the device supports CSS3 Transitions
           * @type {Boolean}
           */
          {
              identity: 'Transitions',
              fn: function(doc, div) {
                  var prefix = [
                          'webkit',
                          'Moz',
                          'o',
                          'ms',
                          'khtml'
                      ],
                      TE = 'TransitionEnd',
                      transitionEndName = [
                          prefix[0] + TE,
                          'transitionend', //Moz bucks the prefixing convention
                          prefix[2] + TE,
                          prefix[3] + TE,
                          prefix[4] + TE
                      ],
                      ln = prefix.length,
                      i = 0,
                      out = false;
  
                  for (; i < ln; i++) {
                      if (getStyle(div, prefix[i] + "TransitionProperty")) {
                          Ext.supports.CSS3Prefix = prefix[i];
                          Ext.supports.CSS3TransitionEnd = transitionEndName[i];
                          out = true;
                          break;
                      }
                  }
                  return out;
              }
          },
  
          /**
           * @property RightMargin True if the device supports right margin.
           * See https://bugs.webkit.org/show_bug.cgi?id=13343 for why this is needed.
           * @type {Boolean}
           */
          {
              identity: 'RightMargin',
              fn: function(doc, div) {
                  var view = doc.defaultView;
                  return !(view && view.getComputedStyle(div.firstChild.firstChild, null).marginRight != '0px');
              }
          },
  
          /**
           * @property DisplayChangeInputSelectionBug True if INPUT elements lose their
           * selection when their display style is changed. Essentially, if a text input
           * has focus and its display style is changed, the I-beam disappears.
           *
           * This bug is encountered due to the work around in place for the {@link #RightMargin}
           * bug. This has been observed in Safari 4.0.4 and older, and appears to be fixed
           * in Safari 5. It's not clear if Safari 4.1 has the bug, but it has the same WebKit
           * version number as Safari 5 (according to http://unixpapa.com/js/gecko.html).
           */
          {
              identity: 'DisplayChangeInputSelectionBug',
              early: true,
              fn: function() {
                  var webKitVersion = Ext.webKitVersion;
                  // WebKit but older than Safari 5 or Chrome 6:
                  return 0 < webKitVersion && webKitVersion < 533;
              }
          },
  
          /**
           * @property DisplayChangeTextAreaSelectionBug True if TEXTAREA elements lose their
           * selection when their display style is changed. Essentially, if a text area has
           * focus and its display style is changed, the I-beam disappears.
           *
           * This bug is encountered due to the work around in place for the {@link #RightMargin}
           * bug. This has been observed in Chrome 10 and Safari 5 and older, and appears to
           * be fixed in Chrome 11.
           */
          {
              identity: 'DisplayChangeTextAreaSelectionBug',
              early: true,
              fn: function() {
                  var webKitVersion = Ext.webKitVersion;
  
                  /*
                  Has bug w/textarea:
  
                  (Chrome) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-US)
                              AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.127
                              Safari/534.16
                  (Safari) Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_7; en-us)
                              AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5
                              Safari/533.21.1
  
                  No bug:
  
                  (Chrome) Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_7)
                              AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.57
                              Safari/534.24
                  */
                  return 0 < webKitVersion && webKitVersion < 534.24;
              }
          },
  
          /**
           * @property TransparentColor True if the device supports transparent color
           * @type {Boolean}
           */
          {
              identity: 'TransparentColor',
              fn: function(doc, div, view) {
                  view = doc.defaultView;
                  return !(view && view.getComputedStyle(div.lastChild, null).backgroundColor != 'transparent');
              }
          },
  
          /**
           * @property ComputedStyle True if the browser supports document.defaultView.getComputedStyle()
           * @type {Boolean}
           */
          {
              identity: 'ComputedStyle',
              fn: function(doc, div, view) {
                  view = doc.defaultView;
                  return view && view.getComputedStyle;
              }
          },
  
          /**
           * @property SVG True if the device supports SVG
           * @type {Boolean}
           */
          {
              identity: 'Svg',
              fn: function(doc) {
                  return !!doc.createElementNS && !!doc.createElementNS( "http:/" + "/www.w3.org/2000/svg", "svg").createSVGRect;
              }
          },
  
          /**
           * @property Canvas True if the device supports Canvas
           * @type {Boolean}
           */
          {
              identity: 'Canvas',
              fn: function(doc) {
                  return !!doc.createElement('canvas').getContext;
              }
          },
  
          /**
           * @property VML True if the device supports VML
           * @type {Boolean}
           */
          {
              identity: 'Vml',
              fn: function(doc) {
                  var d = doc.createElement("div");
                  d.innerHTML = "<!--[if vml]><br/><br/><![endif]-->";
                  return (d.childNodes.length == 2);
              }
          },
  
          /**
           * @property Float True if the device supports CSS float
           * @type {Boolean}
           */
          {
              identity: 'Float',
              fn: function(doc, div) {
                  return !!div.lastChild.style.cssFloat;
              }
          },
  
          /**
           * @property AudioTag True if the device supports the HTML5 audio tag
           * @type {Boolean}
           */
          {
              identity: 'AudioTag',
              fn: function(doc) {
                  return !!doc.createElement('audio').canPlayType;
              }
          },
  
          /**
           * @property History True if the device supports HTML5 history
           * @type {Boolean}
           */
          {
              identity: 'History',
              fn: function() {
                  var history = window.history;
                  return !!(history && history.pushState);
              }
          },
  
          /**
           * @property CSS3DTransform True if the device supports CSS3DTransform
           * @type {Boolean}
           */
          {
              identity: 'CSS3DTransform',
              fn: function() {
                  return (typeof WebKitCSSMatrix != 'undefined' && new WebKitCSSMatrix().hasOwnProperty('m41'));
              }
          },
  
  		/**
           * @property CSS3LinearGradient True if the device supports CSS3 linear gradients
           * @type {Boolean}
           */
          {
              identity: 'CSS3LinearGradient',
              fn: function(doc, div) {
                  var property = 'background-image:',
                      webkit   = '-webkit-gradient(linear, left top, right bottom, from(black), to(white))',
                      w3c      = 'linear-gradient(left top, black, white)',
                      moz      = '-moz-' + w3c,
                      opera    = '-o-' + w3c,
                      options  = [property + webkit, property + w3c, property + moz, property + opera];
  
                  div.style.cssText = options.join(';');
  
                  return ("" + div.style.backgroundImage).indexOf('gradient') !== -1;
              }
          },
  
          /**
           * @property CSS3BorderRadius True if the device supports CSS3 border radius
           * @type {Boolean}
           */
          {
              identity: 'CSS3BorderRadius',
              fn: function(doc, div) {
                  var domPrefixes = ['borderRadius', 'BorderRadius', 'MozBorderRadius', 'WebkitBorderRadius', 'OBorderRadius', 'KhtmlBorderRadius'],
                      pass = false,
                      i;
                  for (i = 0; i < domPrefixes.length; i++) {
                      if (document.body.style[domPrefixes[i]] !== undefined) {
                          return true;
                      }
                  }
                  return pass;
              }
          },
  
          /**
           * @property GeoLocation True if the device supports GeoLocation
           * @type {Boolean}
           */
          {
              identity: 'GeoLocation',
              fn: function() {
                  return (typeof navigator != 'undefined' && typeof navigator.geolocation != 'undefined') || (typeof google != 'undefined' && typeof google.gears != 'undefined');
              }
          },
          /**
           * @property MouseEnterLeave True if the browser supports mouseenter and mouseleave events
           * @type {Boolean}
           */
          {
              identity: 'MouseEnterLeave',
              fn: function(doc, div){
                  return ('onmouseenter' in div && 'onmouseleave' in div);
              }
          },
          /**
           * @property MouseWheel True if the browser supports the mousewheel event
           * @type {Boolean}
           */
          {
              identity: 'MouseWheel',
              fn: function(doc, div) {
                  return ('onmousewheel' in div);
              }
          },
          /**
           * @property Opacity True if the browser supports normal css opacity
           * @type {Boolean}
           */
          {
              identity: 'Opacity',
              fn: function(doc, div){
                  // Not a strict equal comparison in case opacity can be converted to a number.
                  if (Ext.isIE6 || Ext.isIE7 || Ext.isIE8) {
                      return false;
                  }
                  div.firstChild.style.cssText = 'opacity:0.73';
                  return div.firstChild.style.opacity == '0.73';
              }
          },
          /**
           * @property Placeholder True if the browser supports the HTML5 placeholder attribute on inputs
           * @type {Boolean}
           */
          {
              identity: 'Placeholder',
              fn: function(doc) {
                  return 'placeholder' in doc.createElement('input');
              }
          },
  
          /**
           * @property Direct2DBug True if when asking for an element's dimension via offsetWidth or offsetHeight,
           * getBoundingClientRect, etc. the browser returns the subpixel width rounded to the nearest pixel.
           * @type {Boolean}
           */
          {
              identity: 'Direct2DBug',
              fn: function() {
                  return Ext.isString(document.body.style.msTransformOrigin);
              }
          },
          /**
           * @property BoundingClientRect True if the browser supports the getBoundingClientRect method on elements
           * @type {Boolean}
           */
          {
              identity: 'BoundingClientRect',
              fn: function(doc, div) {
                  return Ext.isFunction(div.getBoundingClientRect);
              }
          },
          {
              identity: 'IncludePaddingInWidthCalculation',
              fn: function(doc, div){
                  return div.childNodes[1].firstChild.offsetWidth == 210;
              }
          },
          {
              identity: 'IncludePaddingInHeightCalculation',
              fn: function(doc, div){
                  return div.childNodes[1].firstChild.offsetHeight == 210;
              }
          },
  
          /**
           * @property ArraySort True if the Array sort native method isn't bugged.
           * @type {Boolean}
           */
          {
              identity: 'ArraySort',
              fn: function() {
                  var a = [1,2,3,4,5].sort(function(){ return 0; });
                  return a[0] === 1 && a[1] === 2 && a[2] === 3 && a[3] === 4 && a[4] === 5;
              }
          },
          /**
           * @property Range True if browser support document.createRange native method.
           * @type {Boolean}
           */
          {
              identity: 'Range',
              fn: function() {
                  return !!document.createRange;
              }
          },
          /**
           * @property CreateContextualFragment True if browser support CreateContextualFragment range native methods.
           * @type {Boolean}
           */
          {
              identity: 'CreateContextualFragment',
              fn: function() {
                  var range = Ext.supports.Range ? document.createRange() : false;
  
                  return range && !!range.createContextualFragment;
              }
          },
  
          /**
           * @property WindowOnError True if browser supports window.onerror.
           * @type {Boolean}
           */
          {
              identity: 'WindowOnError',
              fn: function () {
                  // sadly, we cannot feature detect this...
                  return Ext.isIE || Ext.isGecko || Ext.webKitVersion >= 534.16; // Chrome 10+
              }
          },
  
          /**
           * @property TextAreaMaxLength True if the browser supports maxlength on textareas.
           * @type {Boolean}
           */
          {
              identity: 'TextAreaMaxLength',
              fn: function(){
                  var el = document.createElement('textarea');
                  return ('maxlength' in el);
              }
          },
          /**
           * @property GetPositionPercentage True if the browser will return the left/top/right/bottom
           * position as a percentage when explicitly set as a percentage value.
           * @type {Boolean}
           */
          // Related bug: https://bugzilla.mozilla.org/show_bug.cgi?id=707691#c7
          {
              identity: 'GetPositionPercentage',
              fn: function(doc, div){
                 return getStyle(div.childNodes[2], 'left') == '10%';
              }
          }
      ]
  };
  }());
  
  Ext.supports.init(); // run the "early" detections now
  