text: /*!
   * jQuery JavaScript Library v1.11.1
   * http://jquery.com/
   *
   * Includes Sizzle.js
   * http://sizzlejs.com/
   *
   * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
   * Released under the MIT license
   * http://jquery.org/license
   *
   * Date: 2014-05-01T17:42Z
   */
  
  (function( global, factory ) {
  
  	if ( typeof module === "object" && typeof module.exports === "object" ) {
  		// For CommonJS and CommonJS-like environments where a proper window is present,
  		// execute the factory and get jQuery
  		// For environments that do not inherently posses a window with a document
  		// (such as Node.js), expose a jQuery-making factory as module.exports
  		// This accentuates the need for the creation of a real window
  		// e.g. var jQuery = require("jquery")(window);
  		// See ticket #14549 for more info
  		module.exports = global.document ?
  			factory( global, true ) :
  			function( w ) {
  				if ( !w.document ) {
  					throw new Error( "jQuery requires a window with a document" );
  				}
  				return factory( w );
  			};
  	} else {
  		factory( global );
  	}
  
  // Pass this if window is not defined yet
  }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
  
  // Can't do this because several apps including ASP.NET trace
  // the stack via arguments.caller.callee and Firefox dies if
  // you try to trace through "use strict" call chains. (#13335)
  // Support: Firefox 18+
  //
  
  var deletedIds = [];
  
  var slice = deletedIds.slice;
  
  var concat = deletedIds.concat;
  
  var push = deletedIds.push;
  
  var indexOf = deletedIds.indexOf;
  
  var class2type = {};
  
  var toString = class2type.toString;
  
  var hasOwn = class2type.hasOwnProperty;
  
  var support = {};
  
  
  
  var
  	version = "1.11.1",
  
  	// Define a local copy of jQuery
  	jQuery = function( selector, context ) {
  		// The jQuery object is actually just the init constructor 'enhanced'
  		// Need init if jQuery is called (just allow error to be thrown if not included)
  		return new jQuery.fn.init( selector, context );
  	},
  
  	// Support: Android<4.1, IE<9
  	// Make sure we trim BOM and NBSP
  	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
  
  	// Matches dashed string for camelizing
  	rmsPrefix = /^-ms-/,
  	rdashAlpha = /-([\da-z])/gi,
  
  	// Used by jQuery.camelCase as callback to replace()
  	fcamelCase = function( all, letter ) {
  		return letter.toUpperCase();
  	};
  
  jQuery.fn = jQuery.prototype = {
  	// The current version of jQuery being used
  	jquery: version,
  
  	constructor: jQuery,
  
  	// Start with an empty selector
  	selector: "",
  
  	// The default length of a jQuery object is 0
  	length: 0,
  
  	toArray: function() {
  		return slice.call( this );
  	},
  
  	// Get the Nth element in the matched element set OR
  	// Get the whole matched element set as a clean array
  	get: function( num ) {
  		return num != null ?
  
  			// Return just the one element from the set
  			( num < 0 ? this[ num + this.length ] : this[ num ] ) :
  
  			// Return all the elements in a clean array
  			slice.call( this );
  	},
  
  	// Take an array of elements and push it onto the stack
  	// (returning the new matched element set)
  	pushStack: function( elems ) {
  
  		// Build a new jQuery matched element set
  		var ret = jQuery.merge( this.constructor(), elems );
  
  		// Add the old object onto the stack (as a reference)
  		ret.prevObject = this;
  		ret.context = this.context;
  
  		// Return the newly-formed element set
  		return ret;
  	},
  
  	// Execute a callback for every element in the matched set.
  	// (You can seed the arguments with an array of args, but this is
  	// only used internally.)
  	each: function( callback, args ) {
  		return jQuery.each( this, callback, args );
  	},
  
  	map: function( callback ) {
  		return this.pushStack( jQuery.map(this, function( elem, i ) {
  			return callback.call( elem, i, elem );
  		}));
  	},
  
  	slice: function() {
  		return this.pushStack( slice.apply( this, arguments ) );
  	},
  
  	first: function() {
  		return this.eq( 0 );
  	},
  
  	last: function() {
  		return this.eq( -1 );
  	},
  
  	eq: function( i ) {
  		var len = this.length,
  			j = +i + ( i < 0 ? len : 0 );
  		return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
  	},
  
  	end: function() {
  		return this.prevObject || this.constructor(null);
  	},
  
  	// For internal use only.
  	// Behaves like an Array's method, not like a jQuery method.
  	push: push,
  	sort: deletedIds.sort,
  	splice: deletedIds.splice
  };
  
  jQuery.extend = jQuery.fn.extend = function() {
  	var src, copyIsArray, copy, name, options, clone,
  		target = arguments[0] || {},
  		i = 1,
  		length = arguments.length,
  		deep = false;
  
  	// Handle a deep copy situation
  	if ( typeof target === "boolean" ) {
  		deep = target;
  
  		// skip the boolean and the target
  		target = arguments[ i ] || {};
  		i++;
  	}
  
  	// Handle case when target is a string or something (possible in deep copy)
  	if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
  		target = {};
  	}
  
  	// extend jQuery itself if only one argument is passed
  	if ( i === length ) {
  		target = this;
  		i--;
  	}
  
  	for ( ; i < length; i++ ) {
  		// Only deal with non-null/undefined values
  		if ( (options = arguments[ i ]) != null ) {
  			// Extend the base object
  			for ( name in options ) {
  				src = target[ name ];
  				copy = options[ name ];
  
  				// Prevent never-ending loop
  				if ( target === copy ) {
  					continue;
  				}
  
  				// Recurse if we're merging plain objects or arrays
  				if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
  					if ( copyIsArray ) {
  						copyIsArray = false;
  						clone = src && jQuery.isArray(src) ? src : [];
  
  					} else {
  						clone = src && jQuery.isPlainObject(src) ? src : {};
  					}
  
  					// Never move original objects, clone them
  					target[ name ] = jQuery.extend( deep, clone, copy );
  
  				// Don't bring in undefined values
  				} else if ( copy !== undefined ) {
  					target[ name ] = copy;
  				}
  			}
  		}
  	}
  
  	// Return the modified object
  	return target;
  };
  
  jQuery.extend({
  	// Unique for each copy of jQuery on the page
  	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
  
  	// Assume jQuery is ready without the ready module
  	isReady: true,
  
  	error: function( msg ) {
  		throw new Error( msg );
  	},
  
  	noop: function() {},
  
  	// See test/unit/core.js for details concerning isFunction.
  	// Since version 1.3, DOM methods and functions like alert
  	// aren't supported. They return false on IE (#2968).
  	isFunction: function( obj ) {
  		return jQuery.type(obj) === "function";
  	},
  
  	isArray: Array.isArray || function( obj ) {
  		return jQuery.type(obj) === "array";
  	},
  
  	isWindow: function( obj ) {
  		/* jshint eqeqeq: false */
  		return obj != null && obj == obj.window;
  	},
  
  	isNumeric: function( obj ) {
  		// parseFloat NaNs numeric-cast false positives (null|true|false|"")
  		// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
  		// subtraction forces infinities to NaN
  		return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
  	},
  
  	isEmptyObject: function( obj ) {
  		var name;
  		for ( name in obj ) {
  			return false;
  		}
  		return true;
  	},
  
  	isPlainObject: function( obj ) {
  		var key;
  
  		// Must be an Object.
  		// Because of IE, we also have to check the presence of the constructor property.
  		// Make sure that DOM nodes and window objects don't pass through, as well
  		if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
  			return false;
  		}
  
  		try {
  			// Not own constructor property must be Object
  			if ( obj.constructor &&
  				!hasOwn.call(obj, "constructor") &&
  				!hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
  				return false;
  			}
  		} catch ( e ) {
  			// IE8,9 Will throw exceptions on certain host objects #9897
  			return false;
  		}
  
  		// Support: IE<9
  		// Handle iteration over inherited properties before own properties.
  		if ( support.ownLast ) {
  			for ( key in obj ) {
  				return hasOwn.call( obj, key );
  			}
  		}
  
  		// Own properties are enumerated firstly, so to speed up,
  		// if last one is own, then all properties are own.
  		for ( key in obj ) {}
  
  		return key === undefined || hasOwn.call( obj, key );
  	},
  
  	type: function( obj ) {
  		if ( obj == null ) {
  			return obj + "";
  		}
  		return typeof obj === "object" || typeof obj === "function" ?
  			class2type[ toString.call(obj) ] || "object" :
  			typeof obj;
  	},
  
  	// Evaluates a script in a global context
  	// Workarounds based on findings by Jim Driscoll
  	// http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
  	globalEval: function( data ) {
  		if ( data && jQuery.trim( data ) ) {
  			// We use execScript on Internet Explorer
  			// We use an anonymous function so that context is window
  			// rather than jQuery in Firefox
  			( window.execScript || function( data ) {
  				window[ "eval" ].call( window, data );
  			} )( data );
  		}
  	},
  
  	// Convert dashed to camelCase; used by the css and data modules
  	// Microsoft forgot to hump their vendor prefix (#9572)
  	camelCase: function( string ) {
  		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
  	},
  
  	nodeName: function( elem, name ) {
  		return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
  	},
  
  	// args is for internal usage only
  	each: function( obj, callback, args ) {
  		var value,
  			i = 0,
  			length = obj.length,
  			isArray = isArraylike( obj );
  
  		if ( args ) {
  			if ( isArray ) {
  				for ( ; i < length; i++ ) {
  					value = callback.apply( obj[ i ], args );
  
  					if ( value === false ) {
  						break;
  					}
  				}
  			} else {
  				for ( i in obj ) {
  					value = callback.apply( obj[ i ], args );
  
  					if ( value === false ) {
  						break;
  					}
  				}
  			}
  
  		// A special, fast, case for the most common use of each
  		} else {
  			if ( isArray ) {
  				for ( ; i < length; i++ ) {
  					value = callback.call( obj[ i ], i, obj[ i ] );
  
  					if ( value === false ) {
  						break;
  					}
  				}
  			} else {
  				for ( i in obj ) {
  					value = callback.call( obj[ i ], i, obj[ i ] );
  
  					if ( value === false ) {
  						break;
  					}
  				}
  			}
  		}
  
  		return obj;
  	},
  
  	// Support: Android<4.1, IE<9
  	trim: function( text ) {
  		return text == null ?
  			"" :
  			( text + "" ).replace( rtrim, "" );
  	},
  
  	// results is for internal usage only
  	makeArray: function( arr, results ) {
  		var ret = results || [];
  
  		if ( arr != null ) {
  			if ( isArraylike( Object(arr) ) ) {
  				jQuery.merge( ret,
  					typeof arr === "string" ?
  					[ arr ] : arr
  				);
  			} else {
  				push.call( ret, arr );
  			}
  		}
  
  		return ret;
  	},
  
  	inArray: function( elem, arr, i ) {
  		var len;
  
  		if ( arr ) {
  			if ( indexOf ) {
  				return indexOf.call( arr, elem, i );
  			}
  
  			len = arr.length;
  			i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
  
  			for ( ; i < len; i++ ) {
  				// Skip accessing in sparse arrays
  				if ( i in arr && arr[ i ] === elem ) {
  					return i;
  				}
  			}
  		}
  
  		return -1;
  	},
  
  	merge: function( first, second ) {
  		var len = +second.length,
  			j = 0,
  			i = first.length;
  
  		while ( j < len ) {
  			first[ i++ ] = second[ j++ ];
  		}
  
  		// Support: IE<9
  		// Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists)
  		if ( len !== len ) {
  			while ( second[j] !== undefined ) {
  				first[ i++ ] = second[ j++ ];
  			}
  		}
  
  		first.length = i;
  
  		return first;
  	},
  
  	grep: function( elems, callback, invert ) {
  		var callbackInverse,
  			matches = [],
  			i = 0,
  			length = elems.length,
  			callbackExpect = !invert;
  
  		// Go through the array, only saving the items
  		// that pass the validator function
  		for ( ; i < length; i++ ) {
  			callbackInverse = !callback( elems[ i ], i );
  			if ( callbackInverse !== callbackExpect ) {
  				matches.push( elems[ i ] );
  			}
  		}
  
  		return matches;
  	},
  
  	// arg is for internal usage only
  	map: function( elems, callback, arg ) {
  		var value,
  			i = 0,
  			length = elems.length,
  			isArray = isArraylike( elems ),
  			ret = [];
  
  		// Go through the array, translating each of the items to their new values
  		if ( isArray ) {
  			for ( ; i < length; i++ ) {
  				value = callback( elems[ i ], i, arg );
  
  				if ( value != null ) {
  					ret.push( value );
  				}
  			}
  
  		// Go through every key on the object,
  		} else {
  			for ( i in elems ) {
  				value = callback( elems[ i ], i, arg );
  
  				if ( value != null ) {
  					ret.push( value );
  				}
  			}
  		}
  
  		// Flatten any nested arrays
  		return concat.apply( [], ret );
  	},
  
  	// A global GUID counter for objects
  	guid: 1,
  
  	// Bind a function to a context, optionally partially applying any
  	// arguments.
  	proxy: function( fn, context ) {
  		var args, proxy, tmp;
  
  		if ( typeof context === "string" ) {
  			tmp = fn[ context ];
  			context = fn;
  			fn = tmp;
  		}
  
  		// Quick check to determine if target is callable, in the spec
  		// this throws a TypeError, but we will just return undefined.
  		if ( !jQuery.isFunction( fn ) ) {
  			return undefined;
  		}
  
  		// Simulated bind
  		args = slice.call( arguments, 2 );
  		proxy = function() {
  			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
  		};
  
  		// Set the guid of unique handler to the same of original handler, so it can be removed
  		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
  
  		return proxy;
  	},
  
  	now: function() {
  		return +( new Date() );
  	},
  
  	// jQuery.support is not used in Core but other projects attach their
  	// properties to it so it needs to exist.
  	support: support
  });
  
  // Populate the class2type map
  jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
  	class2type[ "[object " + name + "]" ] = name.toLowerCase();
  });
  
  function isArraylike( obj ) {
  	var length = obj.length,
  		type = jQuery.type( obj );
  
  	if ( type === "function" || jQuery.isWindow( obj ) ) {
  		return false;
  	}
  
  	if ( obj.nodeType === 1 && length ) {
  		return true;
  	}
  
  	return type === "array" || length === 0 ||
  		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
  }
  var Sizzle =
  /*!
   * Sizzle CSS Selector Engine v1.10.19
   * http://sizzlejs.com/
   *
   * Copyright 2013 jQuery Foundation, Inc. and other contributors
   * Released under the MIT license
   * http://jquery.org/license
   *
   * Date: 2014-04-18
   */
  (function( window ) {
  
  var i,
  	support,
  	Expr,
  	getText,
  	isXML,
  	tokenize,
  	compile,
  	select,
  	outermostContext,
  	sortInput,
  	hasDuplicate,
  
  	// Local document vars
  	setDocument,
  	document,
  	docElem,
  	documentIsHTML,
  	rbuggyQSA,
  	rbuggyMatches,
  	matches,
  	contains,
  
  	// Instance-specific data
  	expando = "sizzle" + -(new Date()),
  	preferredDoc = window.document,
  	dirruns = 0,
  	done = 0,
  	classCache = createCache(),
  	tokenCache = createCache(),
  	compilerCache = createCache(),
  	sortOrder = function( a, b ) {
  		if ( a === b ) {
  			hasDuplicate = true;
  		}
  		return 0;
  	},
  
  	// General-purpose constants
  	strundefined = typeof undefined,
  	MAX_NEGATIVE = 1 << 31,
  
  	// Instance methods
  	hasOwn = ({}).hasOwnProperty,
  	arr = [],
  	pop = arr.pop,
  	push_native = arr.push,
  	push = arr.push,
  	slice = arr.slice,
  	// Use a stripped-down indexOf if we can't use a native one
  	indexOf = arr.indexOf || function( elem ) {
  		var i = 0,
  			len = this.length;
  		for ( ; i < len; i++ ) {
  			if ( this[i] === elem ) {
  				return i;
  			}
  		}
  		return -1;
  	},
  
  	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
  
  	// Regular expressions
  
  	// Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
  	whitespace = "[\\x20\\t\\r\\n\\f]",
  	// http://www.w3.org/TR/css3-syntax/#characters
  	characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
  
  	// Loosely modeled on CSS identifier characters
  	// An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
  	// Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
  	identifier = characterEncoding.replace( "w", "w#" ),
  
  	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
  	attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
  		// Operator (capture 2)
  		"*([*^$|!~]?=)" + whitespace +
  		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
  		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
  		"*\\]",
  
  	pseudos = ":(" + characterEncoding + ")(?:\\((" +
  		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
  		// 1. quoted (capture 3; capture 4 or capture 5)
  		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
  		// 2. simple (capture 6)
  		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
  		// 3. anything else (capture 2)
  		".*" +
  		")\\)|)",
  
  	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
  	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
  
  	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
  	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
  
  	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
  
  	rpseudo = new RegExp( pseudos ),
  	ridentifier = new RegExp( "^" + identifier + "$" ),
  
  	matchExpr = {
  		"ID": new RegExp( "^#(" + characterEncoding + ")" ),
  		"CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
  		"TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
  		"ATTR": new RegExp( "^" + attributes ),
  		"PSEUDO": new RegExp( "^" + pseudos ),
  		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
  			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
  			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
  		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
  		// For use in libraries implementing .is()
  		// We use this for POS matching in `select`
  		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
  			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
  	},
  
  	rinputs = /^(?:input|select|textarea|button)$/i,
  	rheader = /^h\d$/i,
  
  	rnative = /^[^{]+\{\s*\[native \w/,
  
  	// Easily-parseable/retrievable ID or TAG or CLASS selectors
  	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
  
  	rsibling = /[+~]/,
  	rescape = /'|\\/g,
  
  	// CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
  	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
  	funescape = function( _, escaped, escapedWhitespace ) {
  		var high = "0x" + escaped - 0x10000;
  		// NaN means non-codepoint
  		// Support: Firefox<24
  		// Workaround erroneous numeric interpretation of +"0x"
  		return high !== high || escapedWhitespace ?
  			escaped :
  			high < 0 ?
  				// BMP codepoint
  				String.fromCharCode( high + 0x10000 ) :
  				// Supplemental Plane codepoint (surrogate pair)
  				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
  	};
  
  // Optimize for push.apply( _, NodeList )
  try {
  	push.apply(
  		(arr = slice.call( preferredDoc.childNodes )),
  		preferredDoc.childNodes
  	);
  	// Support: Android<4.0
  	// Detect silently failing push.apply
  	arr[ preferredDoc.childNodes.length ].nodeType;
  } catch ( e ) {
  	push = { apply: arr.length ?
  
  		// Leverage slice if possible
  		function( target, els ) {
  			push_native.apply( target, slice.call(els) );
  		} :
  
  		// Support: IE<9
  		// Otherwise append directly
  		function( target, els ) {
  			var j = target.length,
  				i = 0;
  			// Can't trust NodeList.length
  			while ( (target[j++] = els[i++]) ) {}
  			target.length = j - 1;
  		}
  	};
  }
  
  function Sizzle( selector, context, results, seed ) {
  	var match, elem, m, nodeType,
  		// QSA vars
  		i, groups, old, nid, newContext, newSelector;
  
  	if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
  		setDocument( context );
  	}
  
  	context = context || document;
  	results = results || [];
  
  	if ( !selector || typeof selector !== "string" ) {
  		return results;
  	}
  
  	if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
  		return [];
  	}
  
  	if ( documentIsHTML && !seed ) {
  
  		// Shortcuts
  		if ( (match = rquickExpr.exec( selector )) ) {
  			// Speed-up: Sizzle("#ID")
  			if ( (m = match[1]) ) {
  				if ( nodeType === 9 ) {
  					elem = context.getElementById( m );
  					// Check parentNode to catch when Blackberry 4.6 returns
  					// nodes that are no longer in the document (jQuery #6963)
  					if ( elem && elem.parentNode ) {
  						// Handle the case where IE, Opera, and Webkit return items
  						// by name instead of ID
  						if ( elem.id === m ) {
  							results.push( elem );
  							return results;
  						}
  					} else {
  						return results;
  					}
  				} else {
  					// Context is not a document
  					if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
  						contains( context, elem ) && elem.id === m ) {
  						results.push( elem );
  						return results;
  					}
  				}
  
  			// Speed-up: Sizzle("TAG")
  			} else if ( match[2] ) {
  				push.apply( results, context.getElementsByTagName( selector ) );
  				return results;
  
  			// Speed-up: Sizzle(".CLASS")
  			} else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
  				push.apply( results, context.getElementsByClassName( m ) );
  				return results;
  			}
  		}
  
  		// QSA path
  		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
  			nid = old = expando;
  			newContext = context;
  			newSelector = nodeType === 9 && selector;
  
  			// qSA works strangely on Element-rooted queries
  			// We can work around this by specifying an extra ID on the root
  			// and working up from there (Thanks to Andrew Dupont for the technique)
  			// IE 8 doesn't work on object elements
  			if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
  				groups = tokenize( selector );
  
  				if ( (old = context.getAttribute("id")) ) {
  					nid = old.replace( rescape, "\\$&" );
  				} else {
  					context.setAttribute( "id", nid );
  				}
  				nid = "[id='" + nid + "'] ";
  
  				i = groups.length;
  				while ( i-- ) {
  					groups[i] = nid + toSelector( groups[i] );
  				}
  				newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
  				newSelector = groups.join(",");
  			}
  
  			if ( newSelector ) {
  				try {
  					push.apply( results,
  						newContext.querySelectorAll( newSelector )
  					);
  					return results;
  				} catch(qsaError) {
  				} finally {
  					if ( !old ) {
  						context.removeAttribute("id");
  					}
  				}
  			}
  		}
  	}
  
  	// All others
  	return select( selector.replace( rtrim, "$1" ), context, results, seed );
  }
  
  /**
   * Create key-value caches of limited size
   * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
   *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
   *	deleting the oldest entry
   */
  function createCache() {
  	var keys = [];
  
  	function cache( key, value ) {
  		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
  		if ( keys.push( key + " " ) > Expr.cacheLength ) {
  			// Only keep the most recent entries
  			delete cache[ keys.shift() ];
  		}
  		return (cache[ key + " " ] = value);
  	}
  	return cache;
  }
  
  /**
   * Mark a function for special use by Sizzle
   * @param {Function} fn The function to mark
   */
  function markFunction( fn ) {
  	fn[ expando ] = true;
  	return fn;
  }
  
  /**
   * Support testing using an element
   * @param {Function} fn Passed the created div and expects a boolean result
   */
  function assert( fn ) {
  	var div = document.createElement("div");
  
  	try {
  		return !!fn( div );
  	} catch (e) {
  		return false;
  	} finally {
  		// Remove from its parent by default
  		if ( div.parentNode ) {
  			div.parentNode.removeChild( div );
  		}
  		// release memory in IE
  		div = null;
  	}
  }
  
  /**
   * Adds the same handler for all of the specified attrs
   * @param {String} attrs Pipe-separated list of attributes
   * @param {Function} handler The method that will be applied
   */
  function addHandle( attrs, handler ) {
  	var arr = attrs.split("|"),
  		i = attrs.length;
  
  	while ( i-- ) {
  		Expr.attrHandle[ arr[i] ] = handler;
  	}
  }
  
  /**
   * Checks document order of two siblings
   * @param {Element} a
   * @param {Element} b
   * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
   */
  function siblingCheck( a, b ) {
  	var cur = b && a,
  		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
  			( ~b.sourceIndex || MAX_NEGATIVE ) -
  			( ~a.sourceIndex || MAX_NEGATIVE );
  
  	// Use IE sourceIndex if available on both nodes
  	if ( diff ) {
  		return diff;
  	}
  
  	// Check if b follows a
  	if ( cur ) {
  		while ( (cur = cur.nextSibling) ) {
  			if ( cur === b ) {
  				return -1;
  			}
  		}
  	}
  
  	return a ? 1 : -1;
  }
  
  /**
   * Returns a function to use in pseudos for input types
   * @param {String} type
   */
  function createInputPseudo( type ) {
  	return function( elem ) {
  		var name = elem.nodeName.toLowerCase();
  		return name === "input" && elem.type === type;
  	};
  }
  
  /**
   * Returns a function to use in pseudos for buttons
   * @param {String} type
   */
  function createButtonPseudo( type ) {
  	return function( elem ) {
  		var name = elem.nodeName.toLowerCase();
  		return (name === "input" || name === "button") && elem.type === type;
  	};
  }
  
  /**
   * Returns a function to use in pseudos for positionals
   * @param {Function} fn
   */
  function createPositionalPseudo( fn ) {
  	return markFunction(function( argument ) {
  		argument = +argument;
  		return markFunction(function( seed, matches ) {
  			var j,
  				matchIndexes = fn( [], seed.length, argument ),
  				i = matchIndexes.length;
  
  			// Match elements found at the specified indexes
  			while ( i-- ) {
  				if ( seed[ (j = matchIndexes[i]) ] ) {
  					seed[j] = !(matches[j] = seed[j]);
  				}
  			}
  		});
  	});
  }
  
  /**
   * Checks a node for validity as a Sizzle context
   * @param {Element|Object=} context
   * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
   */
  function testContext( context ) {
  	return context && typeof context.getElementsByTagName !== strundefined && context;
  }
  
  // Expose support vars for convenience
  support = Sizzle.support = {};
  
  /**
   * Detects XML nodes
   * @param {Element|Object} elem An element or a document
   * @returns {Boolean} True iff elem is a non-HTML XML node
   */
  isXML = Sizzle.isXML = function( elem ) {
  	// documentElement is verified for cases where it doesn't yet exist
  	// (such as loading iframes in IE - #4833)
  	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
  	return documentElement ? documentElement.nodeName !== "HTML" : false;
  };
  
  /**
   * Sets document-related variables once based on the current document
   * @param {Element|Object} [doc] An element or document object to use to set the document
   * @returns {Object} Returns the current document
   */
  setDocument = Sizzle.setDocument = function( node ) {
  	var hasCompare,
  		doc = node ? node.ownerDocument || node : preferredDoc,
  		parent = doc.defaultView;
  
  	// If no document and documentElement is available, return
  	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
  		return document;
  	}
  
  	// Set our document
  	document = doc;
  	docElem = doc.documentElement;
  
  	// Support tests
  	documentIsHTML = !isXML( doc );
  
  	// Support: IE>8
  	// If iframe document is assigned to "document" variable and if iframe has been reloaded,
  	// IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
  	// IE6-8 do not support the defaultView property so parent will be undefined
  	if ( parent && parent !== parent.top ) {
  		// IE11 does not have attachEvent, so all must suffer
  		if ( parent.addEventListener ) {
  			parent.addEventListener( "unload", function() {
  				setDocument();
  			}, false );
  		} else if ( parent.attachEvent ) {
  			parent.attachEvent( "onunload", function() {
  				setDocument();
  			});
  		}
  	}
  
  	/* Attributes
  	---------------------------------------------------------------------- */
  
  	// Support: IE<8
  	// Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
  	support.attributes = assert(function( div ) {
  		div.className = "i";
  		return !div.getAttribute("className");
  	});
  
  	/* getElement(s)By*
  	---------------------------------------------------------------------- */
  
  	// Check if getElementsByTagName("*") returns only elements
  	support.getElementsByTagName = assert(function( div ) {
  		div.appendChild( doc.createComment("") );
  		return !div.getElementsByTagName("*").length;
  	});
  
  	// Check if getElementsByClassName can be trusted
  	support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
  		div.innerHTML = "<div class='a'></div><div class='a i'></div>";
  
  		// Support: Safari<4
  		// Catch class over-caching
  		div.firstChild.className = "i";
  		// Support: Opera<10
  		// Catch gEBCN failure to find non-leading classes
  		return div.getElementsByClassName("i").length === 2;
  	});
  
  	// Support: IE<10
  	// Check if getElementById returns elements by name
  	// The broken getElementById methods don't pick up programatically-set names,
  	// so use a roundabout getElementsByName test
  	support.getById = assert(function( div ) {
  		docElem.appendChild( div ).id = expando;
  		return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
  	});
  
  	// ID find and filter
  	if ( support.getById ) {
  		Expr.find["ID"] = function( id, context ) {
  			if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
  				var m = context.getElementById( id );
  				// Check parentNode to catch when Blackberry 4.6 returns
  				// nodes that are no longer in the document #6963
  				return m && m.parentNode ? [ m ] : [];
  			}
  		};
  		Expr.filter["ID"] = function( id ) {
  			var attrId = id.replace( runescape, funescape );
  			return function( elem ) {
  				return elem.getAttribute("id") === attrId;
  			};
  		};
  	} else {
  		// Support: IE6/7
  		// getElementById is not reliable as a find shortcut
  		delete Expr.find["ID"];
  
  		Expr.filter["ID"] =  function( id ) {
  			var attrId = id.replace( runescape, funescape );
  			return function( elem ) {
  				var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
  				return node && node.value === attrId;
  			};
  		};
  	}
  
  	// Tag
  	Expr.find["TAG"] = support.getElementsByTagName ?
  		function( tag, context ) {
  			if ( typeof context.getElementsByTagName !== strundefined ) {
  				return context.getElementsByTagName( tag );
  			}
  		} :
  		function( tag, context ) {
  			var elem,
  				tmp = [],
  				i = 0,
  				results = context.getElementsByTagName( tag );
  
  			// Filter out possible comments
  			if ( tag === "*" ) {
  				while ( (elem = results[i++]) ) {
  					if ( elem.nodeType === 1 ) {
  						tmp.push( elem );
  					}
  				}
  
  				return tmp;
  			}
  			return results;
  		};
  
  	// Class
  	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
  		if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
  			return context.getElementsByClassName( className );
  		}
  	};
  
  	/* QSA/matchesSelector
  	---------------------------------------------------------------------- */
  
  	// QSA and matchesSelector support
  
  	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
  	rbuggyMatches = [];
  
  	// qSa(:focus) reports false when true (Chrome 21)
  	// We allow this because of a bug in IE8/9 that throws an error
  	// whenever `document.activeElement` is accessed on an iframe
  	// So, we allow :focus to pass through QSA all the time to avoid the IE error
  	// See http://bugs.jquery.com/ticket/13378
  	rbuggyQSA = [];
  
  	if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
  		// Build QSA regex
  		// Regex strategy adopted from Diego Perini
  		assert(function( div ) {
  			// Select is set to empty string on purpose
  			// This is to test IE's treatment of not explicitly
  			// setting a boolean content attribute,
  			// since its presence should be enough
  			// http://bugs.jquery.com/ticket/12359
  			div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
  
  			// Support: IE8, Opera 11-12.16
  			// Nothing should be selected when empty strings follow ^= or $= or *=
  			// The test attribute must be unknown in Opera but "safe" for WinRT
  			// http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
  			if ( div.querySelectorAll("[msallowclip^='']").length ) {
  				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
  			}
  
  			// Support: IE8
  			// Boolean attributes and "value" are not treated correctly
  			if ( !div.querySelectorAll("[selected]").length ) {
  				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
  			}
  
  			// Webkit/Opera - :checked should return selected option elements
  			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
  			// IE8 throws error here and will not see later tests
  			if ( !div.querySelectorAll(":checked").length ) {
  				rbuggyQSA.push(":checked");
  			}
  		});
  
  		assert(function( div ) {
  			// Support: Windows 8 Native Apps
  			// The type and name attributes are restricted during .innerHTML assignment
  			var input = doc.createElement("input");
  			input.setAttribute( "type", "hidden" );
  			div.appendChild( input ).setAttribute( "name", "D" );
  
  			// Support: IE8
  			// Enforce case-sensitivity of name attribute
  			if ( div.querySelectorAll("[name=d]").length ) {
  				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
  			}
  
  			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
  			// IE8 throws error here and will not see later tests
  			if ( !div.querySelectorAll(":enabled").length ) {
  				rbuggyQSA.push( ":enabled", ":disabled" );
  			}
  
  			// Opera 10-11 does not throw on post-comma invalid pseudos
  			div.querySelectorAll("*,:x");
  			rbuggyQSA.push(",.*:");
  		});
  	}
  
  	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
  		docElem.webkitMatchesSelector ||
  		docElem.mozMatchesSelector ||
  		docElem.oMatchesSelector ||
  		docElem.msMatchesSelector) )) ) {
  
  		assert(function( div ) {
  			// Check to see if it's possible to do matchesSelector
  			// on a disconnected node (IE 9)
  			support.disconnectedMatch = matches.call( div, "div" );
  
  			// This should fail with an exception
  			// Gecko does not error, returns false instead
  			matches.call( div, "[s!='']:x" );
  			rbuggyMatches.push( "!=", pseudos );
  		});
  	}
  
  	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
  	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
  
  	/* Contains
  	---------------------------------------------------------------------- */
  	hasCompare = rnative.test( docElem.compareDocumentPosition );
  
  	// Element contains another
  	// Purposefully does not implement inclusive descendent
  	// As in, an element does not contain itself
  	contains = hasCompare || rnative.test( docElem.contains ) ?
  		function( a, b ) {
  			var adown = a.nodeType === 9 ? a.documentElement : a,
  				bup = b && b.parentNode;
  			return a === bup || !!( bup && bup.nodeType === 1 && (
  				adown.contains ?
  					adown.contains( bup ) :
  					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
  			));
  		} :
  		function( a, b ) {
  			if ( b ) {
  				while ( (b = b.parentNode) ) {
  					if ( b === a ) {
  						return true;
  					}
  				}
  			}
  			return false;
  		};
  
  	/* Sorting
  	---------------------------------------------------------------------- */
  
  	// Document order sorting
  	sortOrder = hasCompare ?
  	function( a, b ) {
  
  		// Flag for duplicate removal
  		if ( a === b ) {
  			hasDuplicate = true;
  			return 0;
  		}
  
  		// Sort on method existence if only one input has compareDocumentPosition
  		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
  		if ( compare ) {
  			return compare;
  		}
  
  		// Calculate position if both inputs belong to the same document
  		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
  			a.compareDocumentPosition( b ) :
  
  			// Otherwise we know they are disconnected
  			1;
  
  		// Disconnected nodes
  		if ( compare & 1 ||
  			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
  
  			// Choose the first element that is related to our preferred document
  			if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
  				return -1;
  			}
  			if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
  				return 1;
  			}
  
  			// Maintain original order
  			return sortInput ?
  				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
  				0;
  		}
  
  		return compare & 4 ? -1 : 1;
  	} :
  	function( a, b ) {
  		// Exit early if the nodes are identical
  		if ( a === b ) {
  			hasDuplicate = true;
  			return 0;
  		}
  
  		var cur,
  			i = 0,
  			aup = a.parentNode,
  			bup = b.parentNode,
  			ap = [ a ],
  			bp = [ b ];
  
  		// Parentless nodes are either documents or disconnected
  		if ( !aup || !bup ) {
  			return a === doc ? -1 :
  				b === doc ? 1 :
  				aup ? -1 :
  				bup ? 1 :
  				sortInput ?
  				( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
  				0;
  
  		// If the nodes are siblings, we can do a quick check
  		} else if ( aup === bup ) {
  			return siblingCheck( a, b );
  		}
  
  		// Otherwise we need full lists of their ancestors for comparison
  		cur = a;
  		while ( (cur = cur.parentNode) ) {
  			ap.unshift( cur );
  		}
  		cur = b;
  		while ( (cur = cur.parentNode) ) {
  			bp.unshift( cur );
  		}
  
  		// Walk down the tree looking for a discrepancy
  		while ( ap[i] === bp[i] ) {
  			i++;
  		}
  
  		return i ?
  			// Do a sibling check if the nodes have a common ancestor
  			siblingCheck( ap[i], bp[i] ) :
  
  			// Otherwise nodes in our document sort first
  			ap[i] === preferredDoc ? -1 :
  			bp[i] === preferredDoc ? 1 :
  			0;
  	};
  
  	return doc;
  };
  
  Sizzle.matches = function( expr, elements ) {
  	return Sizzle( expr, null, null, elements );
  };
  
  Sizzle.matchesSelector = function( elem, expr ) {
  	// Set document vars if needed
  	if ( ( elem.ownerDocument || elem ) !== document ) {
  		setDocument( elem );
  	}
  
  	// Make sure that attribute selectors are quoted
  	expr = expr.replace( rattributeQuotes, "='$1']" );
  
  	if ( support.matchesSelector && documentIsHTML &&
  		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
  		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
  
  		try {
  			var ret = matches.call( elem, expr );
  
  			// IE 9's matchesSelector returns false on disconnected nodes
  			if ( ret || support.disconnectedMatch ||
  					// As well, disconnected nodes are said to be in a document
  					// fragment in IE 9
  					elem.document && elem.document.nodeType !== 11 ) {
  				return ret;
  			}
  		} catch(e) {}
  	}
  
  	return Sizzle( expr, document, null, [ elem ] ).length > 0;
  };
  
  Sizzle.contains = function( context, elem ) {
  	// Set document vars if needed
  	if ( ( context.ownerDocument || context ) !== document ) {
  		setDocument( context );
  	}
  	return contains( context, elem );
  };
  
  Sizzle.attr = function( elem, name ) {
  	// Set document vars if needed
  	if ( ( elem.ownerDocument || elem ) !== document ) {
  		setDocument( elem );
  	}
  
  	var fn = Expr.attrHandle[ name.toLowerCase() ],
  		// Don't get fooled by Object.prototype properties (jQuery #13807)
  		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
  			fn( elem, name, !documentIsHTML ) :
  			undefined;
  
  	return val !== undefined ?
  		val :
  		support.attributes || !documentIsHTML ?
  			elem.getAttribute( name ) :
  			(val = elem.getAttributeNode(name)) && val.specified ?
  				val.value :
  				null;
  };
  
  Sizzle.error = function( msg ) {
  	throw new Error( "Syntax error, unrecognized expression: " + msg );
  };
  
  /**
   * Document sorting and removing duplicates
   * @param {ArrayLike} results
   */
  Sizzle.uniqueSort = function( results ) {
  	var elem,
  		duplicates = [],
  		j = 0,
  		i = 0;
  
  	// Unless we *know* we can detect duplicates, assume their presence
  	hasDuplicate = !support.detectDuplicates;
  	sortInput = !support.sortStable && results.slice( 0 );
  	results.sort( sortOrder );
  
  	if ( hasDuplicate ) {
  		while ( (elem = results[i++]) ) {
  			if ( elem === results[ i ] ) {
  				j = duplicates.push( i );
  			}
  		}
  		while ( j-- ) {
  			results.splice( duplicates[ j ], 1 );
  		}
  	}
  
  	// Clear input after sorting to release objects
  	// See https://github.com/jquery/sizzle/pull/225
  	sortInput = null;
  
  	return results;
  };
  
  /**
   * Utility function for retrieving the text value of an array of DOM nodes
   * @param {Array|Element} elem
   */
  getText = Sizzle.getText = function( elem ) {
  	var node,
  		ret = "",
  		i = 0,
  		nodeType = elem.nodeType;
  
  	if ( !nodeType ) {
  		// If no nodeType, this is expected to be an array
  		while ( (node = elem[i++]) ) {
  			// Do not traverse comment nodes
  			ret += getText( node );
  		}
  	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
  		// Use textContent for elements
  		// innerText usage removed for consistency of new lines (jQuery #11153)
  		if ( typeof elem.textContent === "string" ) {
  			return elem.textContent;
  		} else {
  			// Traverse its children
  			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
  				ret += getText( elem );
  			}
  		}
  	} else if ( nodeType === 3 || nodeType === 4 ) {
  		return elem.nodeValue;
  	}
  	// Do not include comment or processing instruction nodes
  
  	return ret;
  };
  
  Expr = Sizzle.selectors = {
  
  	// Can be adjusted by the user
  	cacheLength: 50,
  
  	createPseudo: markFunction,
  
  	match: matchExpr,
  
  	attrHandle: {},
  
  	find: {},
  
  	relative: {
  		">": { dir: "parentNode", first: true },
  		" ": { dir: "parentNode" },
  		"+": { dir: "previousSibling", first: true },
  		"~": { dir: "previousSibling" }
  	},
  
  	preFilter: {
  		"ATTR": function( match ) {
  			match[1] = match[1].replace( runescape, funescape );
  
  			// Move the given value to match[3] whether quoted or unquoted
  			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
  
  			if ( match[2] === "~=" ) {
  				match[3] = " " + match[3] + " ";
  			}
  
  			return match.slice( 0, 4 );
  		},
  
  		"CHILD": function( match ) {
  			/* matches from matchExpr["CHILD"]
  				1 type (only|nth|...)
  				2 what (child|of-type)
  				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
  				4 xn-component of xn+y argument ([+-]?\d*n|)
  				5 sign of xn-component
  				6 x of xn-component
  				7 sign of y-component
  				8 y of y-component
  			*/
  			match[1] = match[1].toLowerCase();
  
  			if ( match[1].slice( 0, 3 ) === "nth" ) {
  				// nth-* requires argument
  				if ( !match[3] ) {
  					Sizzle.error( match[0] );
  				}
  
  				// numeric x and y parameters for Expr.filter.CHILD
  				// remember that false/true cast respectively to 0/1
  				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
  				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
  
  			// other types prohibit arguments
  			} else if ( match[3] ) {
  				Sizzle.error( match[0] );
  			}
  
  			return match;
  		},
  
  		"PSEUDO": function( match ) {
  			var excess,
  				unquoted = !match[6] && match[2];
  
  			if ( matchExpr["CHILD"].test( match[0] ) ) {
  				return null;
  			}
  
  			// Accept quoted arguments as-is
  			if ( match[3] ) {
  				match[2] = match[4] || match[5] || "";
  
  			// Strip excess characters from unquoted arguments
  			} else if ( unquoted && rpseudo.test( unquoted ) &&
  				// Get excess from tokenize (recursively)
  				(excess = tokenize( unquoted, true )) &&
  				// advance to the next closing parenthesis
  				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
  
  				// excess is a negative index
  				match[0] = match[0].slice( 0, excess );
  				match[2] = unquoted.slice( 0, excess );
  			}
  
  			// Return only captures needed by the pseudo filter method (type and argument)
  			return match.slice( 0, 3 );
  		}
  	},
  
  	filter: {
  
  		"TAG": function( nodeNameSelector ) {
  			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
  			return nodeNameSelector === "*" ?
  				function() { return true; } :
  				function( elem ) {
  					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
  				};
  		},
  
  		"CLASS": function( className ) {
  			var pattern = classCache[ className + " " ];
  
  			return pattern ||
  				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
  				classCache( className, function( elem ) {
  					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
  				});
  		},
  
  		"ATTR": function( name, operator, check ) {
  			return function( elem ) {
  				var result = Sizzle.attr( elem, name );
  
  				if ( result == null ) {
  					return operator === "!=";
  				}
  				if ( !operator ) {
  					return true;
  				}
  
  				result += "";
  
  				return operator === "=" ? result === check :
  					operator === "!=" ? result !== check :
  					operator === "^=" ? check && result.indexOf( check ) === 0 :
  					operator === "*=" ? check && result.indexOf( check ) > -1 :
  					operator === "$=" ? check && result.slice( -check.length ) === check :
  					operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
  					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
  					false;
  			};
  		},
  
  		"CHILD": function( type, what, argument, first, last ) {
  			var simple = type.slice( 0, 3 ) !== "nth",
  				forward = type.slice( -4 ) !== "last",
  				ofType = what === "of-type";
  
  			return first === 1 && last === 0 ?
  
  				// Shortcut for :nth-*(n)
  				function( elem ) {
  					return !!elem.parentNode;
  				} :
  
  				function( elem, context, xml ) {
  					var cache, outerCache, node, diff, nodeIndex, start,
  						dir = simple !== forward ? "nextSibling" : "previousSibling",
  						parent = elem.parentNode,
  						name = ofType && elem.nodeName.toLowerCase(),
  						useCache = !xml && !ofType;
  
  					if ( parent ) {
  
  						// :(first|last|only)-(child|of-type)
  						if ( simple ) {
  							while ( dir ) {
  								node = elem;
  								while ( (node = node[ dir ]) ) {
  									if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
  										return false;
  									}
  								}
  								// Reverse direction for :only-* (if we haven't yet done so)
  								start = dir = type === "only" && !start && "nextSibling";
  							}
  							return true;
  						}
  
  						start = [ forward ? parent.firstChild : parent.lastChild ];
  
  						// non-xml :nth-child(...) stores cache data on `parent`
  						if ( forward && useCache ) {
  							// Seek `elem` from a previously-cached index
  							outerCache = parent[ expando ] || (parent[ expando ] = {});
  							cache = outerCache[ type ] || [];
  							nodeIndex = cache[0] === dirruns && cache[1];
  							diff = cache[0] === dirruns && cache[2];
  							node = nodeIndex && parent.childNodes[ nodeIndex ];
  
  							while ( (node = ++nodeIndex && node && node[ dir ] ||
  
  								// Fallback to seeking `elem` from the start
  								(diff = nodeIndex = 0) || start.pop()) ) {
  
  								// When found, cache indexes on `parent` and break
  								if ( node.nodeType === 1 && ++diff && node === elem ) {
  									outerCache[ type ] = [ dirruns, nodeIndex, diff ];
  									break;
  								}
  							}
  
  						// Use previously-cached element index if available
  						} else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
  							diff = cache[1];
  
  						// xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
  						} else {
  							// Use the same loop as above to seek `elem` from the start
  							while ( (node = ++nodeIndex && node && node[ dir ] ||
  								(diff = nodeIndex = 0) || start.pop()) ) {
  
  								if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
  									// Cache the index of each encountered element
  									if ( useCache ) {
  										(node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
  									}
  
  									if ( node === elem ) {
  										break;
  									}
  								}
  							}
  						}
  
  						// Incorporate the offset, then check against cycle size
  						diff -= last;
  						return diff === first || ( diff % first === 0 && diff / first >= 0 );
  					}
  				};
  		},
  
  		"PSEUDO": function( pseudo, argument ) {
  			// pseudo-class names are case-insensitive
  			// http://www.w3.org/TR/selectors/#pseudo-classes
  			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
  			// Remember that setFilters inherits from pseudos
  			var args,
  				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
  					Sizzle.error( "unsupported pseudo: " + pseudo );
  
  			// The user may use createPseudo to indicate that
  			// arguments are needed to create the filter function
  			// just as Sizzle does
  			if ( fn[ expando ] ) {
  				return fn( argument );
  			}
  
  			// But maintain support for old signatures
  			if ( fn.length > 1 ) {
  				args = [ pseudo, pseudo, "", argument ];
  				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
  					markFunction(function( seed, matches ) {
  						var idx,
  							matched = fn( seed, argument ),
  							i = matched.length;
  						while ( i-- ) {
  							idx = indexOf.call( seed, matched[i] );
  							seed[ idx ] = !( matches[ idx ] = matched[i] );
  						}
  					}) :
  					function( elem ) {
  						return fn( elem, 0, args );
  					};
  			}
  
  			return fn;
  		}
  	},
  
  	pseudos: {
  		// Potentially complex pseudos
  		"not": markFunction(function( selector ) {
  			// Trim the selector passed to compile
  			// to avoid treating leading and trailing
  			// spaces as combinators
  			var input = [],
  				results = [],
  				matcher = compile( selector.replace( rtrim, "$1" ) );
  
  			return matcher[ expando ] ?
  				markFunction(function( seed, matches, context, xml ) {
  					var elem,
  						unmatched = matcher( seed, null, xml, [] ),
  						i = seed.length;
  
  					// Match elements unmatched by `matcher`
  					while ( i-- ) {
  						if ( (elem = unmatched[i]) ) {
  							seed[i] = !(matches[i] = elem);
  						}
  					}
  				}) :
  				function( elem, context, xml ) {
  					input[0] = elem;
  					matcher( input, null, xml, results );
  					return !results.pop();
  				};
  		}),
  
  		"has": markFunction(function( selector ) {
  			return function( elem ) {
  				return Sizzle( selector, elem ).length > 0;
  			};
  		}),
  
  		"contains": markFunction(function( text ) {
  			return function( elem ) {
  				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
  			};
  		}),
  
  		// "Whether an element is represented by a :lang() selector
  		// is based solely on the element's language value
  		// being equal to the identifier C,
  		// or beginning with the identifier C immediately followed by "-".
  		// The matching of C against the element's language value is performed case-insensitively.
  		// The identifier C does not have to be a valid language name."
  		// http://www.w3.org/TR/selectors/#lang-pseudo
  		"lang": markFunction( function( lang ) {
  			// lang value must be a valid identifier
  			if ( !ridentifier.test(lang || "") ) {
  				Sizzle.error( "unsupported lang: " + lang );
  			}
  			lang = lang.replace( runescape, funescape ).toLowerCase();
  			return function( elem ) {
  				var elemLang;
  				do {
  					if ( (elemLang = documentIsHTML ?
  						elem.lang :
  						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
  
  						elemLang = elemLang.toLowerCase();
  						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
  					}
  				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
  				return false;
  			};
  		}),
  
  		// Miscellaneous
  		"target": function( elem ) {
  			var hash = window.location && window.location.hash;
  			return hash && hash.slice( 1 ) === elem.id;
  		},
  
  		"root": function( elem ) {
  			return elem === docElem;
  		},
  
  		"focus": function( elem ) {
  			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
  		},
  
  		// Boolean properties
  		"enabled": function( elem ) {
  			return elem.disabled === false;
  		},
  
  		"disabled": function( elem ) {
  			return elem.disabled === true;
  		},
  
  		"checked": function( elem ) {
  			// In CSS3, :checked should return both checked and selected elements
  			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
  			var nodeName = elem.nodeName.toLowerCase();
  			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
  		},
  
  		"selected": function( elem ) {
  			// Accessing this property makes selected-by-default
  			// options in Safari work properly
  			if ( elem.parentNode ) {
  				elem.parentNode.selectedIndex;
  			}
  
  			return elem.selected === true;
  		},
  
  		// Contents
  		"empty": function( elem ) {
  			// http://www.w3.org/TR/selectors/#empty-pseudo
  			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
  			//   but not by others (comment: 8; processing instruction: 7; etc.)
  			// nodeType < 6 works because attributes (2) do not appear as children
  			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
  				if ( elem.nodeType < 6 ) {
  					return false;
  				}
  			}
  			return true;
  		},
  
  		"parent": function( elem ) {
  			return !Expr.pseudos["empty"]( elem );
  		},
  
  		// Element/input types
  		"header": function( elem ) {
  			return rheader.test( elem.nodeName );
  		},
  
  		"input": function( elem ) {
  			return rinputs.test( elem.nodeName );
  		},
  
  		"button": function( elem ) {
  			var name = elem.nodeName.toLowerCase();
  			return name === "input" && elem.type === "button" || name === "button";
  		},
  
  		"text": function( elem ) {
  			var attr;
  			return elem.nodeName.toLowerCase() === "input" &&
  				elem.type === "text" &&
  
  				// Support: IE<8
  				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
  				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
  		},
  
  		// Position-in-collection
  		"first": createPositionalPseudo(function() {
  			return [ 0 ];
  		}),
  
  		"last": createPositionalPseudo(function( matchIndexes, length ) {
  			return [ length - 1 ];
  		}),
  
  		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
  			return [ argument < 0 ? argument + length : argument ];
  		}),
  
  		"even": createPositionalPseudo(function( matchIndexes, length ) {
  			var i = 0;
  			for ( ; i < length; i += 2 ) {
  				matchIndexes.push( i );
  			}
  			return matchIndexes;
  		}),
  
  		"odd": createPositionalPseudo(function( matchIndexes, length ) {
  			var i = 1;
  			for ( ; i < length; i += 2 ) {
  				matchIndexes.push( i );
  			}
  			return matchIndexes;
  		}),
  
  		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
  			var i = argument < 0 ? argument + length : argument;
  			for ( ; --i >= 0; ) {
  				matchIndexes.push( i );
  			}
  			return matchIndexes;
  		}),
  
  		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
  			var i = argument < 0 ? argument + length : argument;
  			for ( ; ++i < length; ) {
  				matchIndexes.push( i );
  			}
  			return matchIndexes;
  		})
  	}
  };
  
  Expr.pseudos["nth"] = Expr.pseudos["eq"];
  
  // Add button/input type pseudos
  for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
  	Expr.pseudos[ i ] = createInputPseudo( i );
  }
  for ( i in { submit: true, reset: true } ) {
  	Expr.pseudos[ i ] = createButtonPseudo( i );
  }
  
  // Easy API for creating new setFilters
  function setFilters() {}
  setFilters.prototype = Expr.filters = Expr.pseudos;
  Expr.setFilters = new setFilters();
  
  tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
  	var matched, match, tokens, type,
  		soFar, groups, preFilters,
  		cached = tokenCache[ selector + " " ];
  
  	if ( cached ) {
  		return parseOnly ? 0 : cached.slice( 0 );
  	}
  
  	soFar = selector;
  	groups = [];
  	preFilters = Expr.preFilter;
  
  	while ( soFar ) {
  
  		// Comma and first run
  		if ( !matched || (match = rcomma.exec( soFar )) ) {
  			if ( match ) {
  				// Don't consume trailing commas as valid
  				soFar = soFar.slice( match[0].length ) || soFar;
  			}
  			groups.push( (tokens = []) );
  		}
  
  		matched = false;
  
  		// Combinators
  		if ( (match = rcombinators.exec( soFar )) ) {
  			matched = match.shift();
  			tokens.push({
  				value: matched,
  				// Cast descendant combinators to space
  				type: match[0].replace( rtrim, " " )
  			});
  			soFar = soFar.slice( matched.length );
  		}
  
  		// Filters
  		for ( type in Expr.filter ) {
  			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
  				(match = preFilters[ type ]( match ))) ) {
  				matched = match.shift();
  				tokens.push({
  					value: matched,
  					type: type,
  					matches: match
  				});
  				soFar = soFar.slice( matched.length );
  			}
  		}
  
  		if ( !matched ) {
  			break;
  		}
  	}
  
  	// Return the length of the invalid excess
  	// if we're just parsing
  	// Otherwise, throw an error or return tokens
  	return parseOnly ?
  		soFar.length :
  		soFar ?
  			Sizzle.error( selector ) :
  			// Cache the tokens
  			tokenCache( selector, groups ).slice( 0 );
  };
  
  function toSelector( tokens ) {
  	var i = 0,
  		len = tokens.length,
  		selector = "";
  	for ( ; i < len; i++ ) {
  		selector += tokens[i].value;
  	}
  	return selector;
  }
  
  function addCombinator( matcher, combinator, base ) {
  	var dir = combinator.dir,
  		checkNonElements = base && dir === "parentNode",
  		doneName = done++;
  
  	return combinator.first ?
  		// Check against closest ancestor/preceding element
  		function( elem, context, xml ) {
  			while ( (elem = elem[ dir ]) ) {
  				if ( elem.nodeType === 1 || checkNonElements ) {
  					return matcher( elem, context, xml );
  				}
  			}
  		} :
  
  		// Check against all ancestor/preceding elements
  		function( elem, context, xml ) {
  			var oldCache, outerCache,
  				newCache = [ dirruns, doneName ];
  
  			// We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
  			if ( xml ) {
  				while ( (elem = elem[ dir ]) ) {
  					if ( elem.nodeType === 1 || checkNonElements ) {
  						if ( matcher( elem, context, xml ) ) {
  							return true;
  						}
  					}
  				}
  			} else {
  				while ( (elem = elem[ dir ]) ) {
  					if ( elem.nodeType === 1 || checkNonElements ) {
  						outerCache = elem[ expando ] || (elem[ expando ] = {});
  						if ( (oldCache = outerCache[ dir ]) &&
  							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
  
  							// Assign to newCache so results back-propagate to previous elements
  							return (newCache[ 2 ] = oldCache[ 2 ]);
  						} else {
  							// Reuse newcache so results back-propagate to previous elements
  							outerCache[ dir ] = newCache;
  
  							// A match means we're done; a fail means we have to keep checking
  							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
  								return true;
  							}
  						}
  					}
  				}
  			}
  		};
  }
  
  function elementMatcher( matchers ) {
  	return matchers.length > 1 ?
  		function( elem, context, xml ) {
  			var i = matchers.length;
  			while ( i-- ) {
  				if ( !matchers[i]( elem, context, xml ) ) {
  					return false;
  				}
  			}
  			return true;
  		} :
  		matchers[0];
  }
  
  function multipleContexts( selector, contexts, results ) {
  	var i = 0,
  		len = contexts.length;
  	for ( ; i < len; i++ ) {
  		Sizzle( selector, contexts[i], results );
  	}
  	return results;
  }
  
  function condense( unmatched, map, filter, context, xml ) {
  	var elem,
  		newUnmatched = [],
  		i = 0,
  		len = unmatched.length,
  		mapped = map != null;
  
  	for ( ; i < len; i++ ) {
  		if ( (elem = unmatched[i]) ) {
  			if ( !filter || filter( elem, context, xml ) ) {
  				newUnmatched.push( elem );
  				if ( mapped ) {
  					map.push( i );
  				}
  			}
  		}
  	}
  
  	return newUnmatched;
  }
  
  function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
  	if ( postFilter && !postFilter[ expando ] ) {
  		postFilter = setMatcher( postFilter );
  	}
  	if ( postFinder && !postFinder[ expando ] ) {
  		postFinder = setMatcher( postFinder, postSelector );
  	}
  	return markFunction(function( seed, results, context, xml ) {
  		var temp, i, elem,
  			preMap = [],
  			postMap = [],
  			preexisting = results.length,
  
  			// Get initial elements from seed or context
  			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
  
  			// Prefilter to get matcher input, preserving a map for seed-results synchronization
  			matcherIn = preFilter && ( seed || !selector ) ?
  				condense( elems, preMap, preFilter, context, xml ) :
  				elems,
  
  			matcherOut = matcher ?
  				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
  				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
  
  					// ...intermediate processing is necessary
  					[] :
  
  					// ...otherwise use results directly
  					results :
  				matcherIn;
  
  		// Find primary matches
  		if ( matcher ) {
  			matcher( matcherIn, matcherOut, context, xml );
  		}
  
  		// Apply postFilter
  		if ( postFilter ) {
  			temp = condense( matcherOut, postMap );
  			postFilter( temp, [], context, xml );
  
  			// Un-match failing elements by moving them back to matcherIn
  			i = temp.length;
  			while ( i-- ) {
  				if ( (elem = temp[i]) ) {
  					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
  				}
  			}
  		}
  
  		if ( seed ) {
  			if ( postFinder || preFilter ) {
  				if ( postFinder ) {
  					// Get the final matcherOut by condensing this intermediate into postFinder contexts
  					temp = [];
  					i = matcherOut.length;
  					while ( i-- ) {
  						if ( (elem = matcherOut[i]) ) {
  							// Restore matcherIn since elem is not yet a final match
  							temp.push( (matcherIn[i] = elem) );
  						}
  					}
  					postFinder( null, (matcherOut = []), temp, xml );
  				}
  
  				// Move matched elements from seed to results to keep them synchronized
  				i = matcherOut.length;
  				while ( i-- ) {
  					if ( (elem = matcherOut[i]) &&
  						(temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
  
  						seed[temp] = !(results[temp] = elem);
  					}
  				}
  			}
  
  		// Add elements to results, through postFinder if defined
  		} else {
  			matcherOut = condense(
  				matcherOut === results ?
  					matcherOut.splice( preexisting, matcherOut.length ) :
  					matcherOut
  			);
  			if ( postFinder ) {
  				postFinder( null, results, matcherOut, xml );
  			} else {
  				push.apply( results, matcherOut );
  			}
  		}
  	});
  }
  
  function matcherFromTokens( tokens ) {
  	var checkContext, matcher, j,
  		len = tokens.length,
  		leadingRelative = Expr.relative[ tokens[0].type ],
  		implicitRelative = leadingRelative || Expr.relative[" "],
  		i = leadingRelative ? 1 : 0,
  
  		// The foundational matcher ensures that elements are reachable from top-level context(s)
  		matchContext = addCombinator( function( elem ) {
  			return elem === checkContext;
  		}, implicitRelative, true ),
  		matchAnyContext = addCombinator( function( elem ) {
  			return indexOf.call( checkContext, elem ) > -1;
  		}, implicitRelative, true ),
  		matchers = [ function( elem, context, xml ) {
  			return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
  				(checkContext = context).nodeType ?
  					matchContext( elem, context, xml ) :
  					matchAnyContext( elem, context, xml ) );
  		} ];
  
  	for ( ; i < len; i++ ) {
  		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
  			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
  		} else {
  			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
  
  			// Return special upon seeing a positional matcher
  			if ( matcher[ expando ] ) {
  				// Find the next relative operator (if any) for proper handling
  				j = ++i;
  				for ( ; j < len; j++ ) {
  					if ( Expr.relative[ tokens[j].type ] ) {
  						break;
  					}
  				}
  				return setMatcher(
  					i > 1 && elementMatcher( matchers ),
  					i > 1 && toSelector(
  						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
  						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
  					).replace( rtrim, "$1" ),
  					matcher,
  					i < j && matcherFromTokens( tokens.slice( i, j ) ),
  					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
  					j < len && toSelector( tokens )
  				);
  			}
  			matchers.push( matcher );
  		}
  	}
  
  	return elementMatcher( matchers );
  }
  
  function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
  	var bySet = setMatchers.length > 0,
  		byElement = elementMatchers.length > 0,
  		superMatcher = function( seed, context, xml, results, outermost ) {
  			var elem, j, matcher,
  				matchedCount = 0,
  				i = "0",
  				unmatched = seed && [],
  				setMatched = [],
  				contextBackup = outermostContext,
  				// We must always have either seed elements or outermost context
  				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
  				// Use integer dirruns iff this is the outermost matcher
  				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
  				len = elems.length;
  
  			if ( outermost ) {
  				outermostContext = context !== document && context;
  			}
  
  			// Add elements passing elementMatchers directly to results
  			// Keep `i` a string if there are no elements so `matchedCount` will be "00" below
  			// Support: IE<9, Safari
  			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
  			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
  				if ( byElement && elem ) {
  					j = 0;
  					while ( (matcher = elementMatchers[j++]) ) {
  						if ( matcher( elem, context, xml ) ) {
  							results.push( elem );
  							break;
  						}
  					}
  					if ( outermost ) {
  						dirruns = dirrunsUnique;
  					}
  				}
  
  				// Track unmatched elements for set filters
  				if ( bySet ) {
  					// They will have gone through all possible matchers
  					if ( (elem = !matcher && elem) ) {
  						matchedCount--;
  					}
  
  					// Lengthen the array for every element, matched or not
  					if ( seed ) {
  						unmatched.push( elem );
  					}
  				}
  			}
  
  			// Apply set filters to unmatched elements
  			matchedCount += i;
  			if ( bySet && i !== matchedCount ) {
  				j = 0;
  				while ( (matcher = setMatchers[j++]) ) {
  					matcher( unmatched, setMatched, context, xml );
  				}
  
  				if ( seed ) {
  					// Reintegrate element matches to eliminate the need for sorting
  					if ( matchedCount > 0 ) {
  						while ( i-- ) {
  							if ( !(unmatched[i] || setMatched[i]) ) {
  								setMatched[i] = pop.call( results );
  							}
  						}
  					}
  
  					// Discard index placeholder values to get only actual matches
  					setMatched = condense( setMatched );
  				}
  
  				// Add matches to results
  				push.apply( results, setMatched );
  
  				// Seedless set matches succeeding multiple successful matchers stipulate sorting
  				if ( outermost && !seed && setMatched.length > 0 &&
  					( matchedCount + setMatchers.length ) > 1 ) {
  
  					Sizzle.uniqueSort( results );
  				}
  			}
  
  			// Override manipulation of globals by nested matchers
  			if ( outermost ) {
  				dirruns = dirrunsUnique;
  				outermostContext = contextBackup;
  			}
  
  			return unmatched;
  		};
  
  	return bySet ?
  		markFunction( superMatcher ) :
  		superMatcher;
  }
  
  compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
  	var i,
  		setMatchers = [],
  		elementMatchers = [],
  		cached = compilerCache[ selector + " " ];
  
  	if ( !cached ) {
  		// Generate a function of recursive functions that can be used to check each element
  		if ( !match ) {
  			match = tokenize( selector );
  		}
  		i = match.length;
  		while ( i-- ) {
  			cached = matcherFromTokens( match[i] );
  			if ( cached[ expando ] ) {
  				setMatchers.push( cached );
  			} else {
  				elementMatchers.push( cached );
  			}
  		}
  
  		// Cache the compiled function
  		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
  
  		// Save selector and tokenization
  		cached.selector = selector;
  	}
  	return cached;
  };
  
  /**
   * A low-level selection function that works with Sizzle's compiled
   *  selector functions
   * @param {String|Function} selector A selector or a pre-compiled
   *  selector function built with Sizzle.compile
   * @param {Element} context
   * @param {Array} [results]
   * @param {Array} [seed] A set of elements to match against
   */
  select = Sizzle.select = function( selector, context, results, seed ) {
  	var i, tokens, token, type, find,
  		compiled = typeof selector === "function" && selector,
  		match = !seed && tokenize( (selector = compiled.selector || selector) );
  
  	results = results || [];
  
  	// Try to minimize operations if there is no seed and only one group
  	if ( match.length === 1 ) {
  
  		// Take a shortcut and set the context if the root selector is an ID
  		tokens = match[0] = match[0].slice( 0 );
  		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
  				support.getById && context.nodeType === 9 && documentIsHTML &&
  				Expr.relative[ tokens[1].type ] ) {
  
  			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
  			if ( !context ) {
  				return results;
  
  			// Precompiled matchers will still verify ancestry, so step up a level
  			} else if ( compiled ) {
  				context = context.parentNode;
  			}
  
  			selector = selector.slice( tokens.shift().value.length );
  		}
  
  		// Fetch a seed set for right-to-left matching
  		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
  		while ( i-- ) {
  			token = tokens[i];
  
  			// Abort if we hit a combinator
  			if ( Expr.relative[ (type = token.type) ] ) {
  				break;
  			}
  			if ( (find = Expr.find[ type ]) ) {
  				// Search, expanding context for leading sibling combinators
  				if ( (seed = find(
  					token.matches[0].replace( runescape, funescape ),
  					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
  				)) ) {
  
  					// If seed is empty or no tokens remain, we can return early
  					tokens.splice( i, 1 );
  					selector = seed.length && toSelector( tokens );
  					if ( !selector ) {
  						push.apply( results, seed );
  						return results;
  					}
  
  					break;
  				}
  			}
  		}
  	}
  
  	// Compile and execute a filtering function if one is not provided
  	// Provide `match` to avoid retokenization if we modified the selector above
  	( compiled || compile( selector, match ) )(
  		seed,
  		context,
  		!documentIsHTML,
  		results,
  		rsibling.test( selector ) && testContext( context.parentNode ) || context
  	);
  	return results;
  };
  
  // One-time assignments
  
  // Sort stability
  support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
  
  // Support: Chrome<14
  // Always assume duplicates if they aren't passed to the comparison function
  support.detectDuplicates = !!hasDuplicate;
  
  // Initialize against the default document
  setDocument();
  
  // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
  // Detached nodes confoundingly follow *each other*
  support.sortDetached = assert(function( div1 ) {
  	// Should return 1, but returns 4 (following)
  	return div1.compareDocumentPosition( document.createElement("div") ) & 1;
  });
  
  // Support: IE<8
  // Prevent attribute/property "interpolation"
  // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
  if ( !assert(function( div ) {
  	div.innerHTML = "<a href='#'></a>";
  	return div.firstChild.getAttribute("href") === "#" ;
  }) ) {
  	addHandle( "type|href|height|width", function( elem, name, isXML ) {
  		if ( !isXML ) {
  			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
  		}
  	});
  }
  
  // Support: IE<9
  // Use defaultValue in place of getAttribute("value")
  if ( !support.attributes || !assert(function( div ) {
  	div.innerHTML = "<input/>";
  	div.firstChild.setAttribute( "value", "" );
  	return div.firstChild.getAttribute( "value" ) === "";
  }) ) {
  	addHandle( "value", function( elem, name, isXML ) {
  		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
  			return elem.defaultValue;
  		}
  	});
  }
  
  // Support: IE<9
  // Use getAttributeNode to fetch booleans when getAttribute lies
  if ( !assert(function( div ) {
  	return div.getAttribute("disabled") == null;
  }) ) {
  	addHandle( booleans, function( elem, name, isXML ) {
  		var val;
  		if ( !isXML ) {
  			return elem[ name ] === true ? name.toLowerCase() :
  					(val = elem.getAttributeNode( name )) && val.specified ?
  					val.value :
  				null;
  		}
  	});
  }
  
  return Sizzle;
  
  })( window );
  
  
  
  jQuery.find = Sizzle;
  jQuery.expr = Sizzle.selectors;
  jQuery.expr[":"] = jQuery.expr.pseudos;
  jQuery.unique = Sizzle.uniqueSort;
  jQuery.text = Sizzle.getText;
  jQuery.isXMLDoc = Sizzle.isXML;
  jQuery.contains = Sizzle.contains;
  
  
  
  var rneedsContext = jQuery.expr.match.needsContext;
  
  var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
  
  
  
  var risSimple = /^.[^:#\[\.,]*$/;
  
  // Implement the identical functionality for filter and not
  function winnow( elements, qualifier, not ) {
  	if ( jQuery.isFunction( qualifier ) ) {
  		return jQuery.grep( elements, function( elem, i ) {
  			/* jshint -W018 */
  			return !!qualifier.call( elem, i, elem ) !== not;
  		});
  
  	}
  
  	if ( qualifier.nodeType ) {
  		return jQuery.grep( elements, function( elem ) {
  			return ( elem === qualifier ) !== not;
  		});
  
  	}
  
  	if ( typeof qualifier === "string" ) {
  		if ( risSimple.test( qualifier ) ) {
  			return jQuery.filter( qualifier, elements, not );
  		}
  
  		qualifier = jQuery.filter( qualifier, elements );
  	}
  
  	return jQuery.grep( elements, function( elem ) {
  		return ( jQuery.inArray( elem, qualifier ) >= 0 ) !== not;
  	});
  }
  
  jQuery.filter = function( expr, elems, not ) {
  	var elem = elems[ 0 ];
  
  	if ( not ) {
  		expr = ":not(" + expr + ")";
  	}
  
  	return elems.length === 1 && elem.nodeType === 1 ?
  		jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
  		jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
  			return elem.nodeType === 1;
  		}));
  };
  
  jQuery.fn.extend({
  	find: function( selector ) {
  		var i,
  			ret = [],
  			self = this,
  			len = self.length;
  
  		if ( typeof selector !== "string" ) {
  			return this.pushStack( jQuery( selector ).filter(function() {
  				for ( i = 0; i < len; i++ ) {
  					if ( jQuery.contains( self[ i ], this ) ) {
  						return true;
  					}
  				}
  			}) );
  		}
  
  		for ( i = 0; i < len; i++ ) {
  			jQuery.find( selector, self[ i ], ret );
  		}
  
  		// Needed because $( selector, context ) becomes $( context ).find( selector )
  		ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
  		ret.selector = this.selector ? this.selector + " " + selector : selector;
  		return ret;
  	},
  	filter: function( selector ) {
  		return this.pushStack( winnow(this, selector || [], false) );
  	},
  	not: function( selector ) {
  		return this.pushStack( winnow(this, selector || [], true) );
  	},
  	is: function( selector ) {
  		return !!winnow(
  			this,
  
  			// If this is a positional/relative selector, check membership in the returned set
  			// so $("p:first").is("p:last") won't return true for a doc with two "p".
  			typeof selector === "string" && rneedsContext.test( selector ) ?
  				jQuery( selector ) :
  				selector || [],
  			false
  		).length;
  	}
  });
  
  
  // Initialize a jQuery object
  
  
  // A central reference to the root jQuery(document)
  var rootjQuery,
  
  	// Use the correct document accordingly with window argument (sandbox)
  	document = window.document,
  
  	// A simple way to check for HTML strings
  	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
  	// Strict HTML recognition (#11290: must start with <)
  	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
  
  	init = jQuery.fn.init = function( selector, context ) {
  		var match, elem;
  
  		// HANDLE: $(""), $(null), $(undefined), $(false)
  		if ( !selector ) {
  			return this;
  		}
  
  		// Handle HTML strings
  		if ( typeof selector === "string" ) {
  			if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
  				// Assume that strings that start and end with <> are HTML and skip the regex check
  				match = [ null, selector, null ];
  
  			} else {
  				match = rquickExpr.exec( selector );
  			}
  
  			// Match html or make sure no context is specified for #id
  			if ( match && (match[1] || !context) ) {
  
  				// HANDLE: $(html) -> $(array)
  				if ( match[1] ) {
  					context = context instanceof jQuery ? context[0] : context;
  
  					// scripts is true for back-compat
  					// Intentionally let the error be thrown if parseHTML is not present
  					jQuery.merge( this, jQuery.parseHTML(
  						match[1],
  						context && context.nodeType ? context.ownerDocument || context : document,
  						true
  					) );
  
  					// HANDLE: $(html, props)
  					if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
  						for ( match in context ) {
  							// Properties of context are called as methods if possible
  							if ( jQuery.isFunction( this[ match ] ) ) {
  								this[ match ]( context[ match ] );
  
  							// ...and otherwise set as attributes
  							} else {
  								this.attr( match, context[ match ] );
  							}
  						}
  					}
  
  					return this;
  
  				// HANDLE: $(#id)
  				} else {
  					elem = document.getElementById( match[2] );
  
  					// Check parentNode to catch when Blackberry 4.6 returns
  					// nodes that are no longer in the document #6963
  					if ( elem && elem.parentNode ) {
  						// Handle the case where IE and Opera return items
  						// by name instead of ID
  						if ( elem.id !== match[2] ) {
  							return rootjQuery.find( selector );
  						}
  
  						// Otherwise, we inject the element directly into the jQuery object
  						this.length = 1;
  						this[0] = elem;
  					}
  
  					this.context = document;
  					this.selector = selector;
  					return this;
  				}
  
  			// HANDLE: $(expr, $(...))
  			} else if ( !context || context.jquery ) {
  				return ( context || rootjQuery ).find( selector );
  
  			// HANDLE: $(expr, context)
  			// (which is just equivalent to: $(context).find(expr)
  			} else {
  				return this.constructor( context ).find( selector );
  			}
  
  		// HANDLE: $(DOMElement)
  		} else if ( selector.nodeType ) {
  			this.context = this[0] = selector;
  			this.length = 1;
  			return this;
  
  		// HANDLE: $(function)
  		// Shortcut for document ready
  		} else if ( jQuery.isFunction( selector ) ) {
  			return typeof rootjQuery.ready !== "undefined" ?
  				rootjQuery.ready( selector ) :
  				// Execute immediately if ready is not present
  				selector( jQuery );
  		}
  
  		if ( selector.selector !== undefined ) {
  			this.selector = selector.selector;
  			this.context = selector.context;
  		}
  
  		return jQuery.makeArray( selector, this );
  	};
  
  // Give the init function the jQuery prototype for later instantiation
  init.prototype = jQuery.fn;
  
  // Initialize central reference
  rootjQuery = jQuery( document );
  
  
  var rparentsprev = /^(?:parents|prev(?:Until|All))/,
  	// methods guaranteed to produce a unique set when starting from a unique set
  	guaranteedUnique = {
  		children: true,
  		contents: true,
  		next: true,
  		prev: true
  	};
  
  jQuery.extend({
  	dir: function( elem, dir, until ) {
  		var matched = [],
  			cur = elem[ dir ];
  
  		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
  			if ( cur.nodeType === 1 ) {
  				matched.push( cur );
  			}
  			cur = cur[dir];
  		}
  		return matched;
  	},
  
  	sibling: function( n, elem ) {
  		var r = [];
  
  		for ( ; n; n = n.nextSibling ) {
  			if ( n.nodeType === 1 && n !== elem ) {
  				r.push( n );
  			}
  		}
  
  		return r;
  	}
  });
  
  jQuery.fn.extend({
  	has: function( target ) {
  		var i,
  			targets = jQuery( target, this ),
  			len = targets.length;
  
  		return this.filter(function() {
  			for ( i = 0; i < len; i++ ) {
  				if ( jQuery.contains( this, targets[i] ) ) {
  					return true;
  				}
  			}
  		});
  	},
  
  	closest: function( selectors, context ) {
  		var cur,
  			i = 0,
  			l = this.length,
  			matched = [],
  			pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
  				jQuery( selectors, context || this.context ) :
  				0;
  
  		for ( ; i < l; i++ ) {
  			for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
  				// Always skip document fragments
  				if ( cur.nodeType < 11 && (pos ?
  					pos.index(cur) > -1 :
  
  					// Don't pass non-elements to Sizzle
  					cur.nodeType === 1 &&
  						jQuery.find.matchesSelector(cur, selectors)) ) {
  
  					matched.push( cur );
  					break;
  				}
  			}
  		}
  
  		return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
  	},
  
  	// Determine the position of an element within
  	// the matched set of elements
  	index: function( elem ) {
  
  		// No argument, return index in parent
  		if ( !elem ) {
  			return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1;
  		}
  
  		// index in selector
  		if ( typeof elem === "string" ) {
  			return jQuery.inArray( this[0], jQuery( elem ) );
  		}
  
  		// Locate the position of the desired element
  		return jQuery.inArray(
  			// If it receives a jQuery object, the first element is used
  			elem.jquery ? elem[0] : elem, this );
  	},
  
  	add: function( selector, context ) {
  		return this.pushStack(
  			jQuery.unique(
  				jQuery.merge( this.get(), jQuery( selector, context ) )
  			)
  		);
  	},
  
  	addBack: function( selector ) {
  		return this.add( selector == null ?
  			this.prevObject : this.prevObject.filter(selector)
  		);
  	}
  });
  
  function sibling( cur, dir ) {
  	do {
  		cur = cur[ dir ];
  	} while ( cur && cur.nodeType !== 1 );
  
  	return cur;
  }
  
  jQuery.each({
  	parent: function( elem ) {
  		var parent = elem.parentNode;
  		return parent && parent.nodeType !== 11 ? parent : null;
  	},
  	parents: function( elem ) {
  		return jQuery.dir( elem, "parentNode" );
  	},
  	parentsUntil: function( elem, i, until ) {
  		return jQuery.dir( elem, "parentNode", until );
  	},
  	next: function( elem ) {
  		return sibling( elem, "nextSibling" );
  	},
  	prev: function( elem ) {
  		return sibling( elem, "previousSibling" );
  	},
  	nextAll: function( elem ) {
  		return jQuery.dir( elem, "nextSibling" );
  	},
  	prevAll: function( elem ) {
  		return jQuery.dir( elem, "previousSibling" );
  	},
  	nextUntil: function( elem, i, until ) {
  		return jQuery.dir( elem, "nextSibling", until );
  	},
  	prevUntil: function( elem, i, until ) {
  		return jQuery.dir( elem, "previousSibling", until );
  	},
  	siblings: function( elem ) {
  		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
  	},
  	children: function( elem ) {
  		return jQuery.sibling( elem.firstChild );
  	},
  	contents: function( elem ) {
  		return jQuery.nodeName( elem, "iframe" ) ?
  			elem.contentDocument || elem.contentWindow.document :
  			jQuery.merge( [], elem.childNodes );
  	}
  }, function( name, fn ) {
  	jQuery.fn[ name ] = function( until, selector ) {
  		var ret = jQuery.map( this, fn, until );
  
  		if ( name.slice( -5 ) !== "Until" ) {
  			selector = until;
  		}
  
  		if ( selector && typeof selector === "string" ) {
  			ret = jQuery.filter( selector, ret );
  		}
  
  		if ( this.length > 1 ) {
  			// Remove duplicates
  			if ( !guaranteedUnique[ name ] ) {
  				ret = jQuery.unique( ret );
  			}
  
  			// Reverse order for parents* and prev-derivatives
  			if ( rparentsprev.test( name ) ) {
  				ret = ret.reverse();
  			}
  		}
  
  		return this.pushStack( ret );
  	};
  });
  var rnotwhite = (/\S+/g);
  
  
  
  // String to Object options format cache
  var optionsCache = {};
  
  // Convert String-formatted options into Object-formatted ones and store in cache
  function createOptions( options ) {
  	var object = optionsCache[ options ] = {};
  	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
  		object[ flag ] = true;
  	});
  	return object;
  }
  
  /*
   * Create a callback list using the following parameters:
   *
   *	options: an optional list of space-separated options that will change how
   *			the callback list behaves or a more traditional option object
   *
   * By default a callback list will act like an event callback list and can be
   * "fired" multiple times.
   *
   * Possible options:
   *
   *	once:			will ensure the callback list can only be fired once (like a Deferred)
   *
   *	memory:			will keep track of previous values and will call any callback added
   *					after the list has been fired right away with the latest "memorized"
   *					values (like a Deferred)
   *
   *	unique:			will ensure a callback can only be added once (no duplicate in the list)
   *
   *	stopOnFalse:	interrupt callings when a callback returns false
   *
   */
  jQuery.Callbacks = function( options ) {
  
  	// Convert options from String-formatted to Object-formatted if needed
  	// (we check in cache first)
  	options = typeof options === "string" ?
  		( optionsCache[ options ] || createOptions( options ) ) :
  		jQuery.extend( {}, options );
  
  	var // Flag to know if list is currently firing
  		firing,
  		// Last fire value (for non-forgettable lists)
  		memory,
  		// Flag to know if list was already fired
  		fired,
  		// End of the loop when firing
  		firingLength,
  		// Index of currently firing callback (modified by remove if needed)
  		firingIndex,
  		// First callback to fire (used internally by add and fireWith)
  		firingStart,
  		// Actual callback list
  		list = [],
  		// Stack of fire calls for repeatable lists
  		stack = !options.once && [],
  		// Fire callbacks
  		fire = function( data ) {
  			memory = options.memory && data;
  			fired = true;
  			firingIndex = firingStart || 0;
  			firingStart = 0;
  			firingLength = list.length;
  			firing = true;
  			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
  				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
  					memory = false; // To prevent further calls using add
  					break;
  				}
  			}
  			firing = false;
  			if ( list ) {
  				if ( stack ) {
  					if ( stack.length ) {
  						fire( stack.shift() );
  					}
  				} else if ( memory ) {
  					list = [];
  				} else {
  					self.disable();
  				}
  			}
  		},
  		// Actual Callbacks object
  		self = {
  			// Add a callback or a collection of callbacks to the list
  			add: function() {
  				if ( list ) {
  					// First, we save the current length
  					var start = list.length;
  					(function add( args ) {
  						jQuery.each( args, function( _, arg ) {
  							var type = jQuery.type( arg );
  							if ( type === "function" ) {
  								if ( !options.unique || !self.has( arg ) ) {
  									list.push( arg );
  								}
  							} else if ( arg && arg.length && type !== "string" ) {
  								// Inspect recursively
  								add( arg );
  							}
  						});
  					})( arguments );
  					// Do we need to add the callbacks to the
  					// current firing batch?
  					if ( firing ) {
  						firingLength = list.length;
  					// With memory, if we're not firing then
  					// we should call right away
  					} else if ( memory ) {
  						firingStart = start;
  						fire( memory );
  					}
  				}
  				return this;
  			},
  			// Remove a callback from the list
  			remove: function() {
  				if ( list ) {
  					jQuery.each( arguments, function( _, arg ) {
  						var index;
  						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
  							list.splice( index, 1 );
  							// Handle firing indexes
  							if ( firing ) {
  								if ( index <= firingLength ) {
  									firingLength--;
  								}
  								if ( index <= firingIndex ) {
  									firingIndex--;
  								}
  							}
  						}
  					});
  				}
  				return this;
  			},
  			// Check if a given callback is in the list.
  			// If no argument is given, return whether or not list has callbacks attached.
  			has: function( fn ) {
  				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
  			},
  			// Remove all callbacks from the list
  			empty: function() {
  				list = [];
  				firingLength = 0;
  				return this;
  			},
  			// Have the list do nothing anymore
  			disable: function() {
  				list = stack = memory = undefined;
  				return this;
  			},
  			// Is it disabled?
  			disabled: function() {
  				return !list;
  			},
  			// Lock the list in its current state
  			lock: function() {
  				stack = undefined;
  				if ( !memory ) {
  					self.disable();
  				}
  				return this;
  			},
  			// Is it locked?
  			locked: function() {
  				return !stack;
  			},
  			// Call all callbacks with the given context and arguments
  			fireWith: function( context, args ) {
  				if ( list && ( !fired || stack ) ) {
  					args = args || [];
  					args = [ context, args.slice ? args.slice() : args ];
  					if ( firing ) {
  						stack.push( args );
  					} else {
  						fire( args );
  					}
  				}
  				return this;
  			},
  			// Call all the callbacks with the given arguments
  			fire: function() {
  				self.fireWith( this, arguments );
  				return this;
  			},
  			// To know if the callbacks have already been called at least once
  			fired: function() {
  				return !!fired;
  			}
  		};
  
  	return self;
  };
  
  
  jQuery.extend({
  
  	Deferred: function( func ) {
  		var tuples = [
  				// action, add listener, listener list, final state
  				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
  				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
  				[ "notify", "progress", jQuery.Callbacks("memory") ]
  			],
  			state = "pending",
  			promise = {
  				state: function() {
  					return state;
  				},
  				always: function() {
  					deferred.done( arguments ).fail( arguments );
  					return this;
  				},
  				then: function( /* fnDone, fnFail, fnProgress */ ) {
  					var fns = arguments;
  					return jQuery.Deferred(function( newDefer ) {
  						jQuery.each( tuples, function( i, tuple ) {
  							var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
  							// deferred[ done | fail | progress ] for forwarding actions to newDefer
  							deferred[ tuple[1] ](function() {
  								var returned = fn && fn.apply( this, arguments );
  								if ( returned && jQuery.isFunction( returned.promise ) ) {
  									returned.promise()
  										.done( newDefer.resolve )
  										.fail( newDefer.reject )
  										.progress( newDefer.notify );
  								} else {
  									newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
  								}
  							});
  						});
  						fns = null;
  					}).promise();
  				},
  				// Get a promise for this deferred
  				// If obj is provided, the promise aspect is added to the object
  				promise: function( obj ) {
  					return obj != null ? jQuery.extend( obj, promise ) : promise;
  				}
  			},
  			deferred = {};
  
  		// Keep pipe for back-compat
  		promise.pipe = promise.then;
  
  		// Add list-specific methods
  		jQuery.each( tuples, function( i, tuple ) {
  			var list = tuple[ 2 ],
  				stateString = tuple[ 3 ];
  
  			// promise[ done | fail | progress ] = list.add
  			promise[ tuple[1] ] = list.add;
  
  			// Handle state
  			if ( stateString ) {
  				list.add(function() {
  					// state = [ resolved | rejected ]
  					state = stateString;
  
  				// [ reject_list | resolve_list ].disable; progress_list.lock
  				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
  			}
  
  			// deferred[ resolve | reject | notify ]
  			deferred[ tuple[0] ] = function() {
  				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
  				return this;
  			};
  			deferred[ tuple[0] + "With" ] = list.fireWith;
  		});
  
  		// Make the deferred a promise
  		promise.promise( deferred );
  
  		// Call given func if any
  		if ( func ) {
  			func.call( deferred, deferred );
  		}
  
  		// All done!
  		return deferred;
  	},
  
  	// Deferred helper
  	when: function( subordinate /* , ..., subordinateN */ ) {
  		var i = 0,
  			resolveValues = slice.call( arguments ),
  			length = resolveValues.length,
  
  			// the count of uncompleted subordinates
  			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
  
  			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
  			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
  
  			// Update function for both resolve and progress values
  			updateFunc = function( i, contexts, values ) {
  				return function( value ) {
  					contexts[ i ] = this;
  					values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
  					if ( values === progressValues ) {
  						deferred.notifyWith( contexts, values );
  
  					} else if ( !(--remaining) ) {
  						deferred.resolveWith( contexts, values );
  					}
  				};
  			},
  
  			progressValues, progressContexts, resolveContexts;
  
  		// add listeners to Deferred subordinates; treat others as resolved
  		if ( length > 1 ) {
  			progressValues = new Array( length );
  			progressContexts = new Array( length );
  			resolveContexts = new Array( length );
  			for ( ; i < length; i++ ) {
  				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
  					resolveValues[ i ].promise()
  						.done( updateFunc( i, resolveContexts, resolveValues ) )
  						.fail( deferred.reject )
  						.progress( updateFunc( i, progressContexts, progressValues ) );
  				} else {
  					--remaining;
  				}
  			}
  		}
  
  		// if we're not waiting on anything, resolve the master
  		if ( !remaining ) {
  			deferred.resolveWith( resolveContexts, resolveValues );
  		}
  
  		return deferred.promise();
  	}
  });
  
  
  // The deferred used on DOM ready
  var readyList;
  
  jQuery.fn.ready = function( fn ) {
  	// Add the callback
  	jQuery.ready.promise().done( fn );
  
  	return this;
  };
  
  jQuery.extend({
  	// Is the DOM ready to be used? Set to true once it occurs.
  	isReady: false,
  
  	// A counter to track how many items to wait for before
  	// the ready event fires. See #6781
  	readyWait: 1,
  
  	// Hold (or release) the ready event
  	holdReady: function( hold ) {
  		if ( hold ) {
  			jQuery.readyWait++;
  		} else {
  			jQuery.ready( true );
  		}
  	},
  
  	// Handle when the DOM is ready
  	ready: function( wait ) {
  
  		// Abort if there are pending holds or we're already ready
  		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
  			return;
  		}
  
  		// Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
  		if ( !document.body ) {
  			return setTimeout( jQuery.ready );
  		}
  
  		// Remember that the DOM is ready
  		jQuery.isReady = true;
  
  		// If a normal DOM Ready event fired, decrement, and wait if need be
  		if ( wait !== true && --jQuery.readyWait > 0 ) {
  			return;
  		}
  
  		// If there are functions bound, to execute
  		readyList.resolveWith( document, [ jQuery ] );
  
  		// Trigger any bound ready events
  		if ( jQuery.fn.triggerHandler ) {
  			jQuery( document ).triggerHandler( "ready" );
  			jQuery( document ).off( "ready" );
  		}
  	}
  });
  
  /**
   * Clean-up method for dom ready events
   */
  function detach() {
  	if ( document.addEventListener ) {
  		document.removeEventListener( "DOMContentLoaded", completed, false );
  		window.removeEventListener( "load", completed, false );
  
  	} else {
  		document.detachEvent( "onreadystatechange", completed );
  		window.detachEvent( "onload", completed );
  	}
  }
  
  /**
   * The ready event handler and self cleanup method
   */
  function completed() {
  	// readyState === "complete" is good enough for us to call the dom ready in oldIE
  	if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) {
  		detach();
  		jQuery.ready();
  	}
  }
  
  jQuery.ready.promise = function( obj ) {
  	if ( !readyList ) {
  
  		readyList = jQuery.Deferred();
  
  		// Catch cases where $(document).ready() is called after the browser event has already occurred.
  		// we once tried to use readyState "interactive" here, but it caused issues like the one
  		// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
  		if ( document.readyState === "complete" ) {
  			// Handle it asynchronously to allow scripts the opportunity to delay ready
  			setTimeout( jQuery.ready );
  
  		// Standards-based browsers support DOMContentLoaded
  		} else if ( document.addEventListener ) {
  			// Use the handy event callback
  			document.addEventListener( "DOMContentLoaded", completed, false );
  
  			// A fallback to window.onload, that will always work
  			window.addEventListener( "load", completed, false );
  
  		// If IE event model is used
  		} else {
  			// Ensure firing before onload, maybe late but safe also for iframes
  			document.attachEvent( "onreadystatechange", completed );
  
  			// A fallback to window.onload, that will always work
  			window.attachEvent( "onload", completed );
  
  			// If IE and not a frame
  			// continually check to see if the document is ready
  			var top = false;
  
  			try {
  				top = window.frameElement == null && document.documentElement;
  			} catch(e) {}
  
  			if ( top && top.doScroll ) {
  				(function doScrollCheck() {
  					if ( !jQuery.isReady ) {
  
  						try {
  							// Use the trick by Diego Perini
  							// http://javascript.nwbox.com/IEContentLoaded/
  							top.doScroll("left");
  						} catch(e) {
  							return setTimeout( doScrollCheck, 50 );
  						}
  
  						// detach all dom ready events
  						detach();
  
  						// and execute any waiting functions
  						jQuery.ready();
  					}
  				})();
  			}
  		}
  	}
  	return readyList.promise( obj );
  };
  
  
  var strundefined = typeof undefined;
  
  
  
  // Support: IE<9
  // Iteration over object's inherited properties before its own
  var i;
  for ( i in jQuery( support ) ) {
  	break;
  }
  support.ownLast = i !== "0";
  
  // Note: most support tests are defined in their respective modules.
  // false until the test is run
  support.inlineBlockNeedsLayout = false;
  
  // Execute ASAP in case we need to set body.style.zoom
  jQuery(function() {
  	// Minified: var a,b,c,d
  	var val, div, body, container;
  
  	body = document.getElementsByTagName( "body" )[ 0 ];
  	if ( !body || !body.style ) {
  		// Return for frameset docs that don't have a body
  		return;
  	}
  
  	// Setup
  	div = document.createElement( "div" );
  	container = document.createElement( "div" );
  	container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
  	body.appendChild( container ).appendChild( div );
  
  	if ( typeof div.style.zoom !== strundefined ) {
  		// Support: IE<8
  		// Check if natively block-level elements act like inline-block
  		// elements when setting their display to 'inline' and giving
  		// them layout
  		div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1";
  
  		support.inlineBlockNeedsLayout = val = div.offsetWidth === 3;
  		if ( val ) {
  			// Prevent IE 6 from affecting layout for positioned elements #11048
  			// Prevent IE from shrinking the body in IE 7 mode #12869
  			// Support: IE<8
  			body.style.zoom = 1;
  		}
  	}
  
  	body.removeChild( container );
  });
  
  
  
  
  (function() {
  	var div = document.createElement( "div" );
  
  	// Execute the test only if not already executed in another module.
  	if (support.deleteExpando == null) {
  		// Support: IE<9
  		support.deleteExpando = true;
  		try {
  			delete div.test;
  		} catch( e ) {
  			support.deleteExpando = false;
  		}
  	}
  
  	// Null elements to avoid leaks in IE.
  	div = null;
  })();
  
  
  /**
   * Determines whether an object can have data
   */
  jQuery.acceptData = function( elem ) {
  	var noData = jQuery.noData[ (elem.nodeName + " ").toLowerCase() ],
  		nodeType = +elem.nodeType || 1;
  
  	// Do not set data on non-element DOM nodes because it will not be cleared (#8335).
  	return nodeType !== 1 && nodeType !== 9 ?
  		false :
  
  		// Nodes accept data unless otherwise specified; rejection can be conditional
  		!noData || noData !== true && elem.getAttribute("classid") === noData;
  };
  
  
  var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
  	rmultiDash = /([A-Z])/g;
  
  function dataAttr( elem, key, data ) {
  	// If nothing was found internally, try to fetch any
  	// data from the HTML5 data-* attribute
  	if ( data === undefined && elem.nodeType === 1 ) {
  
  		var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
  
  		data = elem.getAttribute( name );
  
  		if ( typeof data === "string" ) {
  			try {
  				data = data === "true" ? true :
  					data === "false" ? false :
  					data === "null" ? null :
  					// Only convert to a number if it doesn't change the string
  					+data + "" === data ? +data :
  					rbrace.test( data ) ? jQuery.parseJSON( data ) :
  					data;
  			} catch( e ) {}
  
  			// Make sure we set the data so it isn't changed later
  			jQuery.data( elem, key, data );
  
  		} else {
  			data = undefined;
  		}
  	}
  
  	return data;
  }
  
  // checks a cache object for emptiness
  function isEmptyDataObject( obj ) {
  	var name;
  	for ( name in obj ) {
  
  		// if the public data object is empty, the private is still empty
  		if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
  			continue;
  		}
  		if ( name !== "toJSON" ) {
  			return false;
  		}
  	}
  
  	return true;
  }
  
  function internalData( elem, name, data, pvt /* Internal Use Only */ ) {
  	if ( !jQuery.acceptData( elem ) ) {
  		return;
  	}
  
  	var ret, thisCache,
  		internalKey = jQuery.expando,
  
  		// We have to handle DOM nodes and JS objects differently because IE6-7
  		// can't GC object references properly across the DOM-JS boundary
  		isNode = elem.nodeType,
  
  		// Only DOM nodes need the global jQuery cache; JS object data is
  		// attached directly to the object so GC can occur automatically
  		cache = isNode ? jQuery.cache : elem,
  
  		// Only defining an ID for JS objects if its cache already exists allows
  		// the code to shortcut on the same path as a DOM node with no cache
  		id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey;
  
  	// Avoid doing any more work than we need to when trying to get data on an
  	// object that has no data at all
  	if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && data === undefined && typeof name === "string" ) {
  		return;
  	}
  
  	if ( !id ) {
  		// Only DOM nodes need a new unique ID for each element since their data
  		// ends up in the global cache
  		if ( isNode ) {
  			id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++;
  		} else {
  			id = internalKey;
  		}
  	}
  
  	if ( !cache[ id ] ) {
  		// Avoid exposing jQuery metadata on plain JS objects when the object
  		// is serialized using JSON.stringify
  		cache[ id ] = isNode ? {} : { toJSON: jQuery.noop };
  	}
  
  	// An object can be passed to jQuery.data instead of a key/value pair; this gets
  	// shallow copied over onto the existing cache
  	if ( typeof name === "object" || typeof name === "function" ) {
  		if ( pvt ) {
  			cache[ id ] = jQuery.extend( cache[ id ], name );
  		} else {
  			cache[ id ].data = jQuery.extend( cache[ id ].data, name );
  		}
  	}
  
  	thisCache = cache[ id ];
  
  	// jQuery data() is stored in a separate object inside the object's internal data
  	// cache in order to avoid key collisions between internal data and user-defined
  	// data.
  	if ( !pvt ) {
  		if ( !thisCache.data ) {
  			thisCache.data = {};
  		}
  
  		thisCache = thisCache.data;
  	}
  
  	if ( data !== undefined ) {
  		thisCache[ jQuery.camelCase( name ) ] = data;
  	}
  
  	// Check for both converted-to-camel and non-converted data property names
  	// If a data property was specified
  	if ( typeof name === "string" ) {
  
  		// First Try to find as-is property data
  		ret = thisCache[ name ];
  
  		// Test for null|undefined property data
  		if ( ret == null ) {
  
  			// Try to find the camelCased property
  			ret = thisCache[ jQuery.camelCase( name ) ];
  		}
  	} else {
  		ret = thisCache;
  	}
  
  	return ret;
  }
  
  function internalRemoveData( elem, name, pvt ) {
  	if ( !jQuery.acceptData( elem ) ) {
  		return;
  	}
  
  	var thisCache, i,
  		isNode = elem.nodeType,
  
  		// See jQuery.data for more information
  		cache = isNode ? jQuery.cache : elem,
  		id = isNode ? elem[ jQuery.expando ] : jQuery.expando;
  
  	// If there is already no cache entry for this object, there is no
  	// purpose in continuing
  	if ( !cache[ id ] ) {
  		return;
  	}
  
  	if ( name ) {
  
  		thisCache = pvt ? cache[ id ] : cache[ id ].data;
  
  		if ( thisCache ) {
  
  			// Support array or space separated string names for data keys
  			if ( !jQuery.isArray( name ) ) {
  
  				// try the string as a key before any manipulation
  				if ( name in thisCache ) {
  					name = [ name ];
  				} else {
  
  					// split the camel cased version by spaces unless a key with the spaces exists
  					name = jQuery.camelCase( name );
  					if ( name in thisCache ) {
  						name = [ name ];
  					} else {
  						name = name.split(" ");
  					}
  				}
  			} else {
  				// If "name" is an array of keys...
  				// When data is initially created, via ("key", "val") signature,
  				// keys will be converted to camelCase.
  				// Since there is no way to tell _how_ a key was added, remove
  				// both plain key and camelCase key. #12786
  				// This will only penalize the array argument path.
  				name = name.concat( jQuery.map( name, jQuery.camelCase ) );
  			}
  
  			i = name.length;
  			while ( i-- ) {
  				delete thisCache[ name[i] ];
  			}
  
  			// If there is no data left in the cache, we want to continue
  			// and let the cache object itself get destroyed
  			if ( pvt ? !isEmptyDataObject(thisCache) : !jQuery.isEmptyObject(thisCache) ) {
  				return;
  			}
  		}
  	}
  
  	// See jQuery.data for more information
  	if ( !pvt ) {
  		delete cache[ id ].data;
  
  		// Don't destroy the parent cache unless the internal data object
  		// had been the only thing left in it
  		if ( !isEmptyDataObject( cache[ id ] ) ) {
  			return;
  		}
  	}
  
  	// Destroy the cache
  	if ( isNode ) {
  		jQuery.cleanData( [ elem ], true );
  
  	// Use delete when supported for expandos or `cache` is not a window per isWindow (#10080)
  	/* jshint eqeqeq: false */
  	} else if ( support.deleteExpando || cache != cache.window ) {
  		/* jshint eqeqeq: true */
  		delete cache[ id ];
  
  	// When all else fails, null
  	} else {
  		cache[ id ] = null;
  	}
  }
  
  jQuery.extend({
  	cache: {},
  
  	// The following elements (space-suffixed to avoid Object.prototype collisions)
  	// throw uncatchable exceptions if you attempt to set expando properties
  	noData: {
  		"applet ": true,
  		"embed ": true,
  		// ...but Flash objects (which have this classid) *can* handle expandos
  		"object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
  	},
  
  	hasData: function( elem ) {
  		elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
  		return !!elem && !isEmptyDataObject( elem );
  	},
  
  	data: function( elem, name, data ) {
  		return internalData( elem, name, data );
  	},
  
  	removeData: function( elem, name ) {
  		return internalRemoveData( elem, name );
  	},
  
  	// For internal use only.
  	_data: function( elem, name, data ) {
  		return internalData( elem, name, data, true );
  	},
  
  	_removeData: function( elem, name ) {
  		return internalRemoveData( elem, name, true );
  	}
  });
  
  jQuery.fn.extend({
  	data: function( key, value ) {
  		var i, name, data,
  			elem = this[0],
  			attrs = elem && elem.attributes;
  
  		// Special expections of .data basically thwart jQuery.access,
  		// so implement the relevant behavior ourselves
  
  		// Gets all values
  		if ( key === undefined ) {
  			if ( this.length ) {
  				data = jQuery.data( elem );
  
  				if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
  					i = attrs.length;
  					while ( i-- ) {
  
  						// Support: IE11+
  						// The attrs elements can be null (#14894)
  						if ( attrs[ i ] ) {
  							name = attrs[ i ].name;
  							if ( name.indexOf( "data-" ) === 0 ) {
  								name = jQuery.camelCase( name.slice(5) );
  								dataAttr( elem, name, data[ name ] );
  							}
  						}
  					}
  					jQuery._data( elem, "parsedAttrs", true );
  				}
  			}
  
  			return data;
  		}
  
  		// Sets multiple values
  		if ( typeof key === "object" ) {
  			return this.each(function() {
  				jQuery.data( this, key );
  			});
  		}
  
  		return arguments.length > 1 ?
  
  			// Sets one value
  			this.each(function() {
  				jQuery.data( this, key, value );
  			}) :
  
  			// Gets one value
  			// Try to fetch any internally stored data first
  			elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined;
  	},
  
  	removeData: function( key ) {
  		return this.each(function() {
  			jQuery.removeData( this, key );
  		});
  	}
  });
  
  
  jQuery.extend({
  	queue: function( elem, type, data ) {
  		var queue;
  
  		if ( elem ) {
  			type = ( type || "fx" ) + "queue";
  			queue = jQuery._data( elem, type );
  
  			// Speed up dequeue by getting out quickly if this is just a lookup
  			if ( data ) {
  				if ( !queue || jQuery.isArray(data) ) {
  					queue = jQuery._data( elem, type, jQuery.makeArray(data) );
  				} else {
  					queue.push( data );
  				}
  			}
  			return queue || [];
  		}
  	},
  
  	dequeue: function( elem, type ) {
  		type = type || "fx";
  
  		var queue = jQuery.queue( elem, type ),
  			startLength = queue.length,
  			fn = queue.shift(),
  			hooks = jQuery._queueHooks( elem, type ),
  			next = function() {
  				jQuery.dequeue( elem, type );
  			};
  
  		// If the fx queue is dequeued, always remove the progress sentinel
  		if ( fn === "inprogress" ) {
  			fn = queue.shift();
  			startLength--;
  		}
  
  		if ( fn ) {
  
  			// Add a progress sentinel to prevent the fx queue from being
  			// automatically dequeued
  			if ( type === "fx" ) {
  				queue.unshift( "inprogress" );
  			}
  
  			// clear up the last queue stop function
  			delete hooks.stop;
  			fn.call( elem, next, hooks );
  		}
  
  		if ( !startLength && hooks ) {
  			hooks.empty.fire();
  		}
  	},
  
  	// not intended for public consumption - generates a queueHooks object, or returns the current one
  	_queueHooks: function( elem, type ) {
  		var key = type + "queueHooks";
  		return jQuery._data( elem, key ) || jQuery._data( elem, key, {
  			empty: jQuery.Callbacks("once memory").add(function() {
  				jQuery._removeData( elem, type + "queue" );
  				jQuery._removeData( elem, key );
  			})
  		});
  	}
  });
  
  jQuery.fn.extend({
  	queue: function( type, data ) {
  		var setter = 2;
  
  		if ( typeof type !== "string" ) {
  			data = type;
  			type = "fx";
  			setter--;
  		}
  
  		if ( arguments.length < setter ) {
  			return jQuery.queue( this[0], type );
  		}
  
  		return data === undefined ?
  			this :
  			this.each(function() {
  				var queue = jQuery.queue( this, type, data );
  
  				// ensure a hooks for this queue
  				jQuery._queueHooks( this, type );
  
  				if ( type === "fx" && queue[0] !== "inprogress" ) {
  					jQuery.dequeue( this, type );
  				}
  			});
  	},
  	dequeue: function( type ) {
  		return this.each(function() {
  			jQuery.dequeue( this, type );
  		});
  	},
  	clearQueue: function( type ) {
  		return this.queue( type || "fx", [] );
  	},
  	// Get a promise resolved when queues of a certain type
  	// are emptied (fx is the type by default)
  	promise: function( type, obj ) {
  		var tmp,
  			count = 1,
  			defer = jQuery.Deferred(),
  			elements = this,
  			i = this.length,
  			resolve = function() {
  				if ( !( --count ) ) {
  					defer.resolveWith( elements, [ elements ] );
  				}
  			};
  
  		if ( typeof type !== "string" ) {
  			obj = type;
  			type = undefined;
  		}
  		type = type || "fx";
  
  		while ( i-- ) {
  			tmp = jQuery._data( elements[ i ], type + "queueHooks" );
  			if ( tmp && tmp.empty ) {
  				count++;
  				tmp.empty.add( resolve );
  			}
  		}
  		resolve();
  		return defer.promise( obj );
  	}
  });
  var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
  
  var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
  
  var isHidden = function( elem, el ) {
  		// isHidden might be called from jQuery#filter function;
  		// in that case, element will be second argument
  		elem = el || elem;
  		return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
  	};
  
  
  
  // Multifunctional method to get and set values of a collection
  // The value/s can optionally be executed if it's a function
  var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
  	var i = 0,
  		length = elems.length,
  		bulk = key == null;
  
  	// Sets many values
  	if ( jQuery.type( key ) === "object" ) {
  		chainable = true;
  		for ( i in key ) {
  			jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
  		}
  
  	// Sets one value
  	} else if ( value !== undefined ) {
  		chainable = true;
  
  		if ( !jQuery.isFunction( value ) ) {
  			raw = true;
  		}
  
  		if ( bulk ) {
  			// Bulk operations run against the entire set
  			if ( raw ) {
  				fn.call( elems, value );
  				fn = null;
  
  			// ...except when executing function values
  			} else {
  				bulk = fn;
  				fn = function( elem, key, value ) {
  					return bulk.call( jQuery( elem ), value );
  				};
  			}
  		}
  
  		if ( fn ) {
  			for ( ; i < length; i++ ) {
  				fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
  			}
  		}
  	}
  
  	return chainable ?
  		elems :
  
  		// Gets
  		bulk ?
  			fn.call( elems ) :
  			length ? fn( elems[0], key ) : emptyGet;
  };
  var rcheckableType = (/^(?:checkbox|radio)$/i);
  
  
  
  (function() {
  	// Minified: var a,b,c
  	var input = document.createElement( "input" ),
  		div = document.createElement( "div" ),
  		fragment = document.createDocumentFragment();
  
  	// Setup
  	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
  
  	// IE strips leading whitespace when .innerHTML is used
  	support.leadingWhitespace = div.firstChild.nodeType === 3;
  
  	// Make sure that tbody elements aren't automatically inserted
  	// IE will insert them into empty tables
  	support.tbody = !div.getElementsByTagName( "tbody" ).length;
  
  	// Make sure that link elements get serialized correctly by innerHTML
  	// This requires a wrapper element in IE
  	support.htmlSerialize = !!div.getElementsByTagName( "link" ).length;
  
  	// Makes sure cloning an html5 element does not cause problems
  	// Where outerHTML is undefined, this still works
  	support.html5Clone =
  		document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav></:nav>";
  
  	// Check if a disconnected checkbox will retain its checked
  	// value of true after appended to the DOM (IE6/7)
  	input.type = "checkbox";
  	input.checked = true;
  	fragment.appendChild( input );
  	support.appendChecked = input.checked;
  
  	// Make sure textarea (and checkbox) defaultValue is properly cloned
  	// Support: IE6-IE11+
  	div.innerHTML = "<textarea>x</textarea>";
  	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
  
  	// #11217 - WebKit loses check when the name is after the checked attribute
  	fragment.appendChild( div );
  	div.innerHTML = "<input type='radio' checked='checked' name='t'/>";
  
  	// Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
  	// old WebKit doesn't clone checked state correctly in fragments
  	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
  
  	// Support: IE<9
  	// Opera does not clone events (and typeof div.attachEvent === undefined).
  	// IE9-10 clones events bound via attachEvent, but they don't trigger with .click()
  	support.noCloneEvent = true;
  	if ( div.attachEvent ) {
  		div.attachEvent( "onclick", function() {
  			support.noCloneEvent = false;
  		});
  
  		div.cloneNode( true ).click();
  	}
  
  	// Execute the test only if not already executed in another module.
  	if (support.deleteExpando == null) {
  		// Support: IE<9
  		support.deleteExpando = true;
  		try {
  			delete div.test;
  		} catch( e ) {
  			support.deleteExpando = false;
  		}
  	}
  })();
  
  
  (function() {
  	var i, eventName,
  		div = document.createElement( "div" );
  
  	// Support: IE<9 (lack submit/change bubble), Firefox 23+ (lack focusin event)
  	for ( i in { submit: true, change: true, focusin: true }) {
  		eventName = "on" + i;
  
  		if ( !(support[ i + "Bubbles" ] = eventName in window) ) {
  			// Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP)
  			div.setAttribute( eventName, "t" );
  			support[ i + "Bubbles" ] = div.attributes[ eventName ].expando === false;
  		}
  	}
  
  	// Null elements to avoid leaks in IE.
  	div = null;
  })();
  
  
  var rformElems = /^(?:input|select|textarea)$/i,
  	rkeyEvent = /^key/,
  	rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
  	rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
  	rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
  
  function returnTrue() {
  	return true;
  }
  
  function returnFalse() {
  	return false;
  }
  
  function safeActiveElement() {
  	try {
  		return document.activeElement;
  	} catch ( err ) { }
  }
  
  /*
   * Helper functions for managing events -- not part of the public interface.
   * Props to Dean Edwards' addEvent library for many of the ideas.
   */
  jQuery.event = {
  
  	global: {},
  
  	add: function( elem, types, handler, data, selector ) {
  		var tmp, events, t, handleObjIn,
  			special, eventHandle, handleObj,
  			handlers, type, namespaces, origType,
  			elemData = jQuery._data( elem );
  
  		// Don't attach events to noData or text/comment nodes (but allow plain objects)
  		if ( !elemData ) {
  			return;
  		}
  
  		// Caller can pass in an object of custom data in lieu of the handler
  		if ( handler.handler ) {
  			handleObjIn = handler;
  			handler = handleObjIn.handler;
  			selector = handleObjIn.selector;
  		}
  
  		// Make sure that the handler has a unique ID, used to find/remove it later
  		if ( !handler.guid ) {
  			handler.guid = jQuery.guid++;
  		}
  
  		// Init the element's event structure and main handler, if this is the first
  		if ( !(events = elemData.events) ) {
  			events = elemData.events = {};
  		}
  		if ( !(eventHandle = elemData.handle) ) {
  			eventHandle = elemData.handle = function( e ) {
  				// Discard the second event of a jQuery.event.trigger() and
  				// when an event is called after a page has unloaded
  				return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
  					jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
  					undefined;
  			};
  			// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
  			eventHandle.elem = elem;
  		}
  
  		// Handle multiple events separated by a space
  		types = ( types || "" ).match( rnotwhite ) || [ "" ];
  		t = types.length;
  		while ( t-- ) {
  			tmp = rtypenamespace.exec( types[t] ) || [];
  			type = origType = tmp[1];
  			namespaces = ( tmp[2] || "" ).split( "." ).sort();
  
  			// There *must* be a type, no attaching namespace-only handlers
  			if ( !type ) {
  				continue;
  			}
  
  			// If event changes its type, use the special event handlers for the changed type
  			special = jQuery.event.special[ type ] || {};
  
  			// If selector defined, determine special event api type, otherwise given type
  			type = ( selector ? special.delegateType : special.bindType ) || type;
  
  			// Update special based on newly reset type
  			special = jQuery.event.special[ type ] || {};
  
  			// handleObj is passed to all event handlers
  			handleObj = jQuery.extend({
  				type: type,
  				origType: origType,
  				data: data,
  				handler: handler,
  				guid: handler.guid,
  				selector: selector,
  				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
  				namespace: namespaces.join(".")
  			}, handleObjIn );
  
  			// Init the event handler queue if we're the first
  			if ( !(handlers = events[ type ]) ) {
  				handlers = events[ type ] = [];
  				handlers.delegateCount = 0;
  
  				// Only use addEventListener/attachEvent if the special events handler returns false
  				if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
  					// Bind the global event handler to the element
  					if ( elem.addEventListener ) {
  						elem.addEventListener( type, eventHandle, false );
  
  					} else if ( elem.attachEvent ) {
  						elem.attachEvent( "on" + type, eventHandle );
  					}
  				}
  			}
  
  			if ( special.add ) {
  				special.add.call( elem, handleObj );
  
  				if ( !handleObj.handler.guid ) {
  					handleObj.handler.guid = handler.guid;
  				}
  			}
  
  			// Add to the element's handler list, delegates in front
  			if ( selector ) {
  				handlers.splice( handlers.delegateCount++, 0, handleObj );
  			} else {
  				handlers.push( handleObj );
  			}
  
  			// Keep track of which events have ever been used, for event optimization
  			jQuery.event.global[ type ] = true;
  		}
  
  		// Nullify elem to prevent memory leaks in IE
  		elem = null;
  	},
  
  	// Detach an event or set of events from an element
  	remove: function( elem, types, handler, selector, mappedTypes ) {
  		var j, handleObj, tmp,
  			origCount, t, events,
  			special, handlers, type,
  			namespaces, origType,
  			elemData = jQuery.hasData( elem ) && jQuery._data( elem );
  
  		if ( !elemData || !(events = elemData.events) ) {
  			return;
  		}
  
  		// Once for each type.namespace in types; type may be omitted
  		types = ( types || "" ).match( rnotwhite ) || [ "" ];
  		t = types.length;
  		while ( t-- ) {
  			tmp = rtypenamespace.exec( types[t] ) || [];
  			type = origType = tmp[1];
  			namespaces = ( tmp[2] || "" ).split( "." ).sort();
  
  			// Unbind all events (on this namespace, if provided) for the element
  			if ( !type ) {
  				for ( type in events ) {
  					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
  				}
  				continue;
  			}
  
  			special = jQuery.event.special[ type ] || {};
  			type = ( selector ? special.delegateType : special.bindType ) || type;
  			handlers = events[ type ] || [];
  			tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
  
  			// Remove matching events
  			origCount = j = handlers.length;
  			while ( j-- ) {
  				handleObj = handlers[ j ];
  
  				if ( ( mappedTypes || origType === handleObj.origType ) &&
  					( !handler || handler.guid === handleObj.guid ) &&
  					( !tmp || tmp.test( handleObj.namespace ) ) &&
  					( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
  					handlers.splice( j, 1 );
  
  					if ( handleObj.selector ) {
  						handlers.delegateCount--;
  					}
  					if ( special.remove ) {
  						special.remove.call( elem, handleObj );
  					}
  				}
  			}
  
  			// Remove generic event handler if we removed something and no more handlers exist
  			// (avoids potential for endless recursion during removal of special event handlers)
  			if ( origCount && !handlers.length ) {
  				if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
  					jQuery.removeEvent( elem, type, elemData.handle );
  				}
  
  				delete events[ type ];
  			}
  		}
  
  		// Remove the expando if it's no longer used
  		if ( jQuery.isEmptyObject( events ) ) {
  			delete elemData.handle;
  
  			// removeData also checks for emptiness and clears the expando if empty
  			// so use it instead of delete
  			jQuery._removeData( elem, "events" );
  		}
  	},
  
  	trigger: function( event, data, elem, onlyHandlers ) {
  		var handle, ontype, cur,
  			bubbleType, special, tmp, i,
  			eventPath = [ elem || document ],
  			type = hasOwn.call( event, "type" ) ? event.type : event,
  			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
  
  		cur = tmp = elem = elem || document;
  
  		// Don't do events on text and comment nodes
  		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
  			return;
  		}
  
  		// focus/blur morphs to focusin/out; ensure we're not firing them right now
  		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
  			return;
  		}
  
  		if ( type.indexOf(".") >= 0 ) {
  			// Namespaced trigger; create a regexp to match event type in handle()
  			namespaces = type.split(".");
  			type = namespaces.shift();
  			namespaces.sort();
  		}
  		ontype = type.indexOf(":") < 0 && "on" + type;
  
  		// Caller can pass in a jQuery.Event object, Object, or just an event type string
  		event = event[ jQuery.expando ] ?
  			event :
  			new jQuery.Event( type, typeof event === "object" && event );
  
  		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
  		event.isTrigger = onlyHandlers ? 2 : 3;
  		event.namespace = namespaces.join(".");
  		event.namespace_re = event.namespace ?
  			new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
  			null;
  
  		// Clean up the event in case it is being reused
  		event.result = undefined;
  		if ( !event.target ) {
  			event.target = elem;
  		}
  
  		// Clone any incoming data and prepend the event, creating the handler arg list
  		data = data == null ?
  			[ event ] :
  			jQuery.makeArray( data, [ event ] );
  
  		// Allow special events to draw outside the lines
  		special = jQuery.event.special[ type ] || {};
  		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
  			return;
  		}
  
  		// Determine event propagation path in advance, per W3C events spec (#9951)
  		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
  		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
  
  			bubbleType = special.delegateType || type;
  			if ( !rfocusMorph.test( bubbleType + type ) ) {
  				cur = cur.parentNode;
  			}
  			for ( ; cur; cur = cur.parentNode ) {
  				eventPath.push( cur );
  				tmp = cur;
  			}
  
  			// Only add window if we got to document (e.g., not plain obj or detached DOM)
  			if ( tmp === (elem.ownerDocument || document) ) {
  				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
  			}
  		}
  
  		// Fire handlers on the event path
  		i = 0;
  		while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
  
  			event.type = i > 1 ?
  				bubbleType :
  				special.bindType || type;
  
  			// jQuery handler
  			handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
  			if ( handle ) {
  				handle.apply( cur, data );
  			}
  
  			// Native handler
  			handle = ontype && cur[ ontype ];
  			if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
  				event.result = handle.apply( cur, data );
  				if ( event.result === false ) {
  					event.preventDefault();
  				}
  			}
  		}
  		event.type = type;
  
  		// If nobody prevented the default action, do it now
  		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
  
  			if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
  				jQuery.acceptData( elem ) ) {
  
  				// Call a native DOM method on the target with the same name name as the event.
  				// Can't use an .isFunction() check here because IE6/7 fails that test.
  				// Don't do default actions on window, that's where global variables be (#6170)
  				if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) {
  
  					// Don't re-trigger an onFOO event when we call its FOO() method
  					tmp = elem[ ontype ];
  
  					if ( tmp ) {
  						elem[ ontype ] = null;
  					}
  
  					// Prevent re-triggering of the same event, since we already bubbled it above
  					jQuery.event.triggered = type;
  					try {
  						elem[ type ]();
  					} catch ( e ) {
  						// IE<9 dies on focus/blur to hidden element (#1486,#12518)
  						// only reproducible on winXP IE8 native, not IE9 in IE8 mode
  					}
  					jQuery.event.triggered = undefined;
  
  					if ( tmp ) {
  						elem[ ontype ] = tmp;
  					}
  				}
  			}
  		}
  
  		return event.result;
  	},
  
  	dispatch: function( event ) {
  
  		// Make a writable jQuery.Event from the native event object
  		event = jQuery.event.fix( event );
  
  		var i, ret, handleObj, matched, j,
  			handlerQueue = [],
  			args = slice.call( arguments ),
  			handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
  			special = jQuery.event.special[ event.type ] || {};
  
  		// Use the fix-ed jQuery.Event rather than the (read-only) native event
  		args[0] = event;
  		event.delegateTarget = this;
  
  		// Call the preDispatch hook for the mapped type, and let it bail if desired
  		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
  			return;
  		}
  
  		// Determine handlers
  		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
  
  		// Run delegates first; they may want to stop propagation beneath us
  		i = 0;
  		while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
  			event.currentTarget = matched.elem;
  
  			j = 0;
  			while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
  
  				// Triggered event must either 1) have no namespace, or
  				// 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
  				if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
  
  					event.handleObj = handleObj;
  					event.data = handleObj.data;
  
  					ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
  							.apply( matched.elem, args );
  
  					if ( ret !== undefined ) {
  						if ( (event.result = ret) === false ) {
  							event.preventDefault();
  							event.stopPropagation();
  						}
  					}
  				}
  			}
  		}
  
  		// Call the postDispatch hook for the mapped type
  		if ( special.postDispatch ) {
  			special.postDispatch.call( this, event );
  		}
  
  		return event.result;
  	},
  
  	handlers: function( event, handlers ) {
  		var sel, handleObj, matches, i,
  			handlerQueue = [],
  			delegateCount = handlers.delegateCount,
  			cur = event.target;
  
  		// Find delegate handlers
  		// Black-hole SVG <use> instance trees (#13180)
  		// Avoid non-left-click bubbling in Firefox (#3861)
  		if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
  
  			/* jshint eqeqeq: false */
  			for ( ; cur != this; cur = cur.parentNode || this ) {
  				/* jshint eqeqeq: true */
  
  				// Don't check non-elements (#13208)
  				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
  				if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) {
  					matches = [];
  					for ( i = 0; i < delegateCount; i++ ) {
  						handleObj = handlers[ i ];
  
  						// Don't conflict with Object.prototype properties (#13203)
  						sel = handleObj.selector + " ";
  
  						if ( matches[ sel ] === undefined ) {
  							matches[ sel ] = handleObj.needsContext ?
  								jQuery( sel, this ).index( cur ) >= 0 :
  								jQuery.find( sel, this, null, [ cur ] ).length;
  						}
  						if ( matches[ sel ] ) {
  							matches.push( handleObj );
  						}
  					}
  					if ( matches.length ) {
  						handlerQueue.push({ elem: cur, handlers: matches });
  					}
  				}
  			}
  		}
  
  		// Add the remaining (directly-bound) handlers
  		if ( delegateCount < handlers.length ) {
  			handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
  		}
  
  		return handlerQueue;
  	},
  
  	fix: function( event ) {
  		if ( event[ jQuery.expando ] ) {
  			return event;
  		}
  
  		// Create a writable copy of the event object and normalize some properties
  		var i, prop, copy,
  			type = event.type,
  			originalEvent = event,
  			fixHook = this.fixHooks[ type ];
  
  		if ( !fixHook ) {
  			this.fixHooks[ type ] = fixHook =
  				rmouseEvent.test( type ) ? this.mouseHooks :
  				rkeyEvent.test( type ) ? this.keyHooks :
  				{};
  		}
  		copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
  
  		event = new jQuery.Event( originalEvent );
  
  		i = copy.length;
  		while ( i-- ) {
  			prop = copy[ i ];
  			event[ prop ] = originalEvent[ prop ];
  		}
  
  		// Support: IE<9
  		// Fix target property (#1925)
  		if ( !event.target ) {
  			event.target = originalEvent.srcElement || document;
  		}
  
  		// Support: Chrome 23+, Safari?
  		// Target should not be a text node (#504, #13143)
  		if ( event.target.nodeType === 3 ) {
  			event.target = event.target.parentNode;
  		}
  
  		// Support: IE<9
  		// For mouse/key events, metaKey==false if it's undefined (#3368, #11328)
  		event.metaKey = !!event.metaKey;
  
  		return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
  	},
  
  	// Includes some event props shared by KeyEvent and MouseEvent
  	props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
  
  	fixHooks: {},
  
  	keyHooks: {
  		props: "char charCode key keyCode".split(" "),
  		filter: function( event, original ) {
  
  			// Add which for key events
  			if ( event.which == null ) {
  				event.which = original.charCode != null ? original.charCode : original.keyCode;
  			}
  
  			return event;
  		}
  	},
  
  	mouseHooks: {
  		props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
  		filter: function( event, original ) {
  			var body, eventDoc, doc,
  				button = original.button,
  				fromElement = original.fromElement;
  
  			// Calculate pageX/Y if missing and clientX/Y available
  			if ( event.pageX == null && original.clientX != null ) {
  				eventDoc = event.target.ownerDocument || document;
  				doc = eventDoc.documentElement;
  				body = eventDoc.body;
  
  				event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
  				event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
  			}
  
  			// Add relatedTarget, if necessary
  			if ( !event.relatedTarget && fromElement ) {
  				event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
  			}
  
  			// Add which for click: 1 === left; 2 === middle; 3 === right
  			// Note: button is not normalized, so don't use it
  			if ( !event.which && button !== undefined ) {
  				event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
  			}
  
  			return event;
  		}
  	},
  
  	special: {
  		load: {
  			// Prevent triggered image.load events from bubbling to window.load
  			noBubble: true
  		},
  		focus: {
  			// Fire native event if possible so blur/focus sequence is correct
  			trigger: function() {
  				if ( this !== safeActiveElement() && this.focus ) {
  					try {
  						this.focus();
  						return false;
  					} catch ( e ) {
  						// Support: IE<9
  						// If we error on focus to hidden element (#1486, #12518),
  						// let .trigger() run the handlers
  					}
  				}
  			},
  			delegateType: "focusin"
  		},
  		blur: {
  			trigger: function() {
  				if ( this === safeActiveElement() && this.blur ) {
  					this.blur();
  					return false;
  				}
  			},
  			delegateType: "focusout"
  		},
  		click: {
  			// For checkbox, fire native event so checked state will be right
  			trigger: function() {
  				if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) {
  					this.click();
  					return false;
  				}
  			},
  
  			// For cross-browser consistency, don't fire native .click() on links
  			_default: function( event ) {
  				return jQuery.nodeName( event.target, "a" );
  			}
  		},
  
  		beforeunload: {
  			postDispatch: function( event ) {
  
  				// Support: Firefox 20+
  				// Firefox doesn't alert if the returnValue field is not set.
  				if ( event.result !== undefined && event.originalEvent ) {
  					event.originalEvent.returnValue = event.result;
  				}
  			}
  		}
  	},
  
  	simulate: function( type, elem, event, bubble ) {
  		// Piggyback on a donor event to simulate a different one.
  		// Fake originalEvent to avoid donor's stopPropagation, but if the
  		// simulated event prevents default then we do the same on the donor.
  		var e = jQuery.extend(
  			new jQuery.Event(),
  			event,
  			{
  				type: type,
  				isSimulated: true,
  				originalEvent: {}
  			}
  		);
  		if ( bubble ) {
  			jQuery.event.trigger( e, null, elem );
  		} else {
  			jQuery.event.dispatch.call( elem, e );
  		}
  		if ( e.isDefaultPrevented() ) {
  			event.preventDefault();
  		}
  	}
  };
  
  jQuery.removeEvent = document.removeEventListener ?
  	function( elem, type, handle ) {
  		if ( elem.removeEventListener ) {
  			elem.removeEventListener( type, handle, false );
  		}
  	} :
  	function( elem, type, handle ) {
  		var name = "on" + type;
  
  		if ( elem.detachEvent ) {
  
  			// #8545, #7054, preventing memory leaks for custom events in IE6-8
  			// detachEvent needed property on element, by name of that event, to properly expose it to GC
  			if ( typeof elem[ name ] === strundefined ) {
  				elem[ name ] = null;
  			}
  
  			elem.detachEvent( name, handle );
  		}
  	};
  
  jQuery.Event = function( src, props ) {
  	// Allow instantiation without the 'new' keyword
  	if ( !(this instanceof jQuery.Event) ) {
  		return new jQuery.Event( src, props );
  	}
  
  	// Event object
  	if ( src && src.type ) {
  		this.originalEvent = src;
  		this.type = src.type;
  
  		// Events bubbling up the document may have been marked as prevented
  		// by a handler lower down the tree; reflect the correct value.
  		this.isDefaultPrevented = src.defaultPrevented ||
  				src.defaultPrevented === undefined &&
  				// Support: IE < 9, Android < 4.0
  				src.returnValue === false ?
  			returnTrue :
  			returnFalse;
  
  	// Event type
  	} else {
  		this.type = src;
  	}
  
  	// Put explicitly provided properties onto the event object
  	if ( props ) {
  		jQuery.extend( this, props );
  	}
  
  	// Create a timestamp if incoming event doesn't have one
  	this.timeStamp = src && src.timeStamp || jQuery.now();
  
  	// Mark it as fixed
  	this[ jQuery.expando ] = true;
  };
  
  // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
  // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
  jQuery.Event.prototype = {
  	isDefaultPrevented: returnFalse,
  	isPropagationStopped: returnFalse,
  	isImmediatePropagationStopped: returnFalse,
  
  	preventDefault: function() {
  		var e = this.originalEvent;
  
  		this.isDefaultPrevented = returnTrue;
  		if ( !e ) {
  			return;
  		}
  
  		// If preventDefault exists, run it on the original event
  		if ( e.preventDefault ) {
  			e.preventDefault();
  
  		// Support: IE
  		// Otherwise set the returnValue property of the original event to false
  		} else {
  			e.returnValue = false;
  		}
  	},
  	stopPropagation: function() {
  		var e = this.originalEvent;
  
  		this.isPropagationStopped = returnTrue;
  		if ( !e ) {
  			return;
  		}
  		// If stopPropagation exists, run it on the original event
  		if ( e.stopPropagation ) {
  			e.stopPropagation();
  		}
  
  		// Support: IE
  		// Set the cancelBubble property of the original event to true
  		e.cancelBubble = true;
  	},
  	stopImmediatePropagation: function() {
  		var e = this.originalEvent;
  
  		this.isImmediatePropagationStopped = returnTrue;
  
  		if ( e && e.stopImmediatePropagation ) {
  			e.stopImmediatePropagation();
  		}
  
  		this.stopPropagation();
  	}
  };
  
  // Create mouseenter/leave events using mouseover/out and event-time checks
  jQuery.each({
  	mouseenter: "mouseover",
  	mouseleave: "mouseout",
  	pointerenter: "pointerover",
  	pointerleave: "pointerout"
  }, function( orig, fix ) {
  	jQuery.event.special[ orig ] = {
  		delegateType: fix,
  		bindType: fix,
  
  		handle: function( event ) {
  			var ret,
  				target = this,
  				related = event.relatedTarget,
  				handleObj = event.handleObj;
  
  			// For mousenter/leave call the handler if related is outside the target.
  			// NB: No relatedTarget if the mouse left/entered the browser window
  			if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
  				event.type = handleObj.origType;
  				ret = handleObj.handler.apply( this, arguments );
  				event.type = fix;
  			}
  			return ret;
  		}
  	};
  });
  
  // IE submit delegation
  if ( !support.submitBubbles ) {
  
  	jQuery.event.special.submit = {
  		setup: function() {
  			// Only need this for delegated form submit events
  			if ( jQuery.nodeName( this, "form" ) ) {
  				return false;
  			}
  
  			// Lazy-add a submit handler when a descendant form may potentially be submitted
  			jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
  				// Node name check avoids a VML-related crash in IE (#9807)
  				var elem = e.target,
  					form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
  				if ( form && !jQuery._data( form, "submitBubbles" ) ) {
  					jQuery.event.add( form, "submit._submit", function( event ) {
  						event._submit_bubble = true;
  					});
  					jQuery._data( form, "submitBubbles", true );
  				}
  			});
  			// return undefined since we don't need an event listener
  		},
  
  		postDispatch: function( event ) {
  			// If form was submitted by the user, bubble the event up the tree
  			if ( event._submit_bubble ) {
  				delete event._submit_bubble;
  				if ( this.parentNode && !event.isTrigger ) {
  					jQuery.event.simulate( "submit", this.parentNode, event, true );
  				}
  			}
  		},
  
  		teardown: function() {
  			// Only need this for delegated form submit events
  			if ( jQuery.nodeName( this, "form" ) ) {
  				return false;
  			}
  
  			// Remove delegated handlers; cleanData eventually reaps submit handlers attached above
  			jQuery.event.remove( this, "._submit" );
  		}
  	};
  }
  
  // IE change delegation and checkbox/radio fix
  if ( !support.changeBubbles ) {
  
  	jQuery.event.special.change = {
  
  		setup: function() {
  
  			if ( rformElems.test( this.nodeName ) ) {
  				// IE doesn't fire change on a check/radio until blur; trigger it on click
  				// after a propertychange. Eat the blur-change in special.change.handle.
  				// This still fires onchange a second time for check/radio after blur.
  				if ( this.type === "checkbox" || this.type === "radio" ) {
  					jQuery.event.add( this, "propertychange._change", function( event ) {
  						if ( event.originalEvent.propertyName === "checked" ) {
  							this._just_changed = true;
  						}
  					});
  					jQuery.event.add( this, "click._change", function( event ) {
  						if ( this._just_changed && !event.isTrigger ) {
  							this._just_changed = false;
  						}
  						// Allow triggered, simulated change events (#11500)
  						jQuery.event.simulate( "change", this, event, true );
  					});
  				}
  				return false;
  			}
  			// Delegated event; lazy-add a change handler on descendant inputs
  			jQuery.event.add( this, "beforeactivate._change", function( e ) {
  				var elem = e.target;
  
  				if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) {
  					jQuery.event.add( elem, "change._change", function( event ) {
  						if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
  							jQuery.event.simulate( "change", this.parentNode, event, true );
  						}
  					});
  					jQuery._data( elem, "changeBubbles", true );
  				}
  			});
  		},
  
  		handle: function( event ) {
  			var elem = event.target;
  
  			// Swallow native change events from checkbox/radio, we already triggered them above
  			if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
  				return event.handleObj.handler.apply( this, arguments );
  			}
  		},
  
  		teardown: function() {
  			jQuery.event.remove( this, "._change" );
  
  			return !rformElems.test( this.nodeName );
  		}
  	};
  }
  
  // Create "bubbling" focus and blur events
  if ( !support.focusinBubbles ) {
  	jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
  
  		// Attach a single capturing handler on the document while someone wants focusin/focusout
  		var handler = function( event ) {
  				jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
  			};
  
  		jQuery.event.special[ fix ] = {
  			setup: function() {
  				var doc = this.ownerDocument || this,
  					attaches = jQuery._data( doc, fix );
  
  				if ( !attaches ) {
  					doc.addEventListener( orig, handler, true );
  				}
  				jQuery._data( doc, fix, ( attaches || 0 ) + 1 );
  			},
  			teardown: function() {
  				var doc = this.ownerDocument || this,
  					attaches = jQuery._data( doc, fix ) - 1;
  
  				if ( !attaches ) {
  					doc.removeEventListener( orig, handler, true );
  					jQuery._removeData( doc, fix );
  				} else {
  					jQuery._data( doc, fix, attaches );
  				}
  			}
  		};
  	});
  }
  
  jQuery.fn.extend({
  
  	on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
  		var type, origFn;
  
  		// Types can be a map of types/handlers
  		if ( typeof types === "object" ) {
  			// ( types-Object, selector, data )
  			if ( typeof selector !== "string" ) {
  				// ( types-Object, data )
  				data = data || selector;
  				selector = undefined;
  			}
  			for ( type in types ) {
  				this.on( type, selector, data, types[ type ], one );
  			}
  			return this;
  		}
  
  		if ( data == null && fn == null ) {
  			// ( types, fn )
  			fn = selector;
  			data = selector = undefined;
  		} else if ( fn == null ) {
  			if ( typeof selector === "string" ) {
  				// ( types, selector, fn )
  				fn = data;
  				data = undefined;
  			} else {
  				// ( types, data, fn )
  				fn = data;
  				data = selector;
  				selector = undefined;
  			}
  		}
  		if ( fn === false ) {
  			fn = returnFalse;
  		} else if ( !fn ) {
  			return this;
  		}
  
  		if ( one === 1 ) {
  			origFn = fn;
  			fn = function( event ) {
  				// Can use an empty set, since event contains the info
  				jQuery().off( event );
  				return origFn.apply( this, arguments );
  			};
  			// Use same guid so caller can remove using origFn
  			fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
  		}
  		return this.each( function() {
  			jQuery.event.add( this, types, fn, data, selector );
  		});
  	},
  	one: function( types, selector, data, fn ) {
  		return this.on( types, selector, data, fn, 1 );
  	},
  	off: function( types, selector, fn ) {
  		var handleObj, type;
  		if ( types && types.preventDefault && types.handleObj ) {
  			// ( event )  dispatched jQuery.Event
  			handleObj = types.handleObj;
  			jQuery( types.delegateTarget ).off(
  				handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
  				handleObj.selector,
  				handleObj.handler
  			);
  			return this;
  		}
  		if ( typeof types === "object" ) {
  			// ( types-object [, selector] )
  			for ( type in types ) {
  				this.off( type, selector, types[ type ] );
  			}
  			return this;
  		}
  		if ( selector === false || typeof selector === "function" ) {
  			// ( types [, fn] )
  			fn = selector;
  			selector = undefined;
  		}
  		if ( fn === false ) {
  			fn = returnFalse;
  		}
  		return this.each(function() {
  			jQuery.event.remove( this, types, fn, selector );
  		});
  	},
  
  	trigger: function( type, data ) {
  		return this.each(function() {
  			jQuery.event.trigger( type, data, this );
  		});
  	},
  	triggerHandler: function( type, data ) {
  		var elem = this[0];
  		if ( elem ) {
  			return jQuery.event.trigger( type, data, elem, true );
  		}
  	}
  });
  
  
  function createSafeFragment( document ) {
  	var list = nodeNames.split( "|" ),
  		safeFrag = document.createDocumentFragment();
  
  	if ( safeFrag.createElement ) {
  		while ( list.length ) {
  			safeFrag.createElement(
  				list.pop()
  			);
  		}
  	}
  	return safeFrag;
  }
  
  var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
  		"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
  	rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g,
  	rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
  	rleadingWhitespace = /^\s+/,
  	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
  	rtagName = /<([\w:]+)/,
  	rtbody = /<tbody/i,
  	rhtml = /<|&#?\w+;/,
  	// ##### BEGIN: MODIFIED BY SAP
  	// This fix solves performance issues of the IE regex engine
  	// rnoInnerhtml = /<(?:script|style|link)/i,
  	rnoInnerhtml = /(?:<script|<style|<link)/i,
  	// ##### END: MODIFIED BY SAP
  	// checked="checked" or checked
  	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
  	rscriptType = /^$|\/(?:java|ecma)script/i,
  	rscriptTypeMasked = /^true\/(.*)/,
  	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
  
  	// We have to close these tags to support XHTML (#13200)
  	wrapMap = {
  		option: [ 1, "<select multiple='multiple'>", "</select>" ],
  		legend: [ 1, "<fieldset>", "</fieldset>" ],
  		area: [ 1, "<map>", "</map>" ],
  		param: [ 1, "<object>", "</object>" ],
  		thead: [ 1, "<table>", "</table>" ],
  		tr: [ 2, "<table><tbody>", "</tbody></table>" ],
  		col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
  		td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
  
  		// IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags,
  		// unless wrapped in a div with non-breaking characters in front of it.
  		_default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>"  ]
  	},
  	safeFragment = createSafeFragment( document ),
  	fragmentDiv = safeFragment.appendChild( document.createElement("div") );
  
  wrapMap.optgroup = wrapMap.option;
  wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
  wrapMap.th = wrapMap.td;
  
  function getAll( context, tag ) {
  	var elems, elem,
  		i = 0,
  		found = typeof context.getElementsByTagName !== strundefined ? context.getElementsByTagName( tag || "*" ) :
  			typeof context.querySelectorAll !== strundefined ? context.querySelectorAll( tag || "*" ) :
  			undefined;
  
  	if ( !found ) {
  		for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) {
  			if ( !tag || jQuery.nodeName( elem, tag ) ) {
  				found.push( elem );
  			} else {
  				jQuery.merge( found, getAll( elem, tag ) );
  			}
  		}
  	}
  
  	return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
  		jQuery.merge( [ context ], found ) :
  		found;
  }
  
  // Used in buildFragment, fixes the defaultChecked property
  function fixDefaultChecked( elem ) {
  	if ( rcheckableType.test( elem.type ) ) {
  		elem.defaultChecked = elem.checked;
  	}
  }
  
  // Support: IE<8
  // Manipulating tables requires a tbody
  function manipulationTarget( elem, content ) {
  	return jQuery.nodeName( elem, "table" ) &&
  		jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
  
  		elem.getElementsByTagName("tbody")[0] ||
  			elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
  		elem;
  }
  
  // Replace/restore the type attribute of script elements for safe DOM manipulation
  function disableScript( elem ) {
  	elem.type = (jQuery.find.attr( elem, "type" ) !== null) + "/" + elem.type;
  	return elem;
  }
  function restoreScript( elem ) {
  	var match = rscriptTypeMasked.exec( elem.type );
  	if ( match ) {
  		elem.type = match[1];
  	} else {
  		elem.removeAttribute("type");
  	}
  	return elem;
  }
  
  // Mark scripts as having already been evaluated
  function setGlobalEval( elems, refElements ) {
  	var elem,
  		i = 0;
  	for ( ; (elem = elems[i]) != null; i++ ) {
  		jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) );
  	}
  }
  
  function cloneCopyEvent( src, dest ) {
  
  	if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
  		return;
  	}
  
  	var type, i, l,
  		oldData = jQuery._data( src ),
  		curData = jQuery._data( dest, oldData ),
  		events = oldData.events;
  
  	if ( events ) {
  		delete curData.handle;
  		curData.events = {};
  
  		for ( type in events ) {
  			for ( i = 0, l = events[ type ].length; i < l; i++ ) {
  				jQuery.event.add( dest, type, events[ type ][ i ] );
  			}
  		}
  	}
  
  	// make the cloned public data object a copy from the original
  	if ( curData.data ) {
  		curData.data = jQuery.extend( {}, curData.data );
  	}
  }
  
  function fixCloneNodeIssues( src, dest ) {
  	var nodeName, e, data;
  
  	// We do not need to do anything for non-Elements
  	if ( dest.nodeType !== 1 ) {
  		return;
  	}
  
  	nodeName = dest.nodeName.toLowerCase();
  
  	// IE6-8 copies events bound via attachEvent when using cloneNode.
  	if ( !support.noCloneEvent && dest[ jQuery.expando ] ) {
  		data = jQuery._data( dest );
  
  		for ( e in data.events ) {
  			jQuery.removeEvent( dest, e, data.handle );
  		}
  
  		// Event data gets referenced instead of copied if the expando gets copied too
  		dest.removeAttribute( jQuery.expando );
  	}
  
  	// IE blanks contents when cloning scripts, and tries to evaluate newly-set text
  	if ( nodeName === "script" && dest.text !== src.text ) {
  		disableScript( dest ).text = src.text;
  		restoreScript( dest );
  
  	// IE6-10 improperly clones children of object elements using classid.
  	// IE10 throws NoModificationAllowedError if parent is null, #12132.
  	} else if ( nodeName === "object" ) {
  		if ( dest.parentNode ) {
  			dest.outerHTML = src.outerHTML;
  		}
  
  		// This path appears unavoidable for IE9. When cloning an object
  		// element in IE9, the outerHTML strategy above is not sufficient.
  		// If the src has innerHTML and the destination does not,
  		// copy the src.innerHTML into the dest.innerHTML. #10324
  		if ( support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) {
  			dest.innerHTML = src.innerHTML;
  		}
  
  	} else if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
  		// IE6-8 fails to persist the checked state of a cloned checkbox
  		// or radio button. Worse, IE6-7 fail to give the cloned element
  		// a checked appearance if the defaultChecked value isn't also set
  
  		dest.defaultChecked = dest.checked = src.checked;
  
  		// IE6-7 get confused and end up setting the value of a cloned
  		// checkbox/radio button to an empty string instead of "on"
  		if ( dest.value !== src.value ) {
  			dest.value = src.value;
  		}
  
  	// IE6-8 fails to return the selected option to the default selected
  	// state when cloning options
  	} else if ( nodeName === "option" ) {
  		dest.defaultSelected = dest.selected = src.defaultSelected;
  
  	// IE6-8 fails to set the defaultValue to the correct value when
  	// cloning other types of input fields
  	} else if ( nodeName === "input" || nodeName === "textarea" ) {
  		dest.defaultValue = src.defaultValue;
  	}
  }
  
  jQuery.extend({
  	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
  		var destElements, node, clone, i, srcElements,
  			inPage = jQuery.contains( elem.ownerDocument, elem );
  
  		if ( support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) {
  			clone = elem.cloneNode( true );
  
  		// IE<=8 does not properly clone detached, unknown element nodes
  		} else {
  			fragmentDiv.innerHTML = elem.outerHTML;
  			fragmentDiv.removeChild( clone = fragmentDiv.firstChild );
  		}
  
  		if ( (!support.noCloneEvent || !support.noCloneChecked) &&
  				(elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
  
  			// We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
  			destElements = getAll( clone );
  			srcElements = getAll( elem );
  
  			// Fix all IE cloning issues
  			for ( i = 0; (node = srcElements[i]) != null; ++i ) {
  				// Ensure that the destination node is not null; Fixes #9587
  				if ( destElements[i] ) {
  					fixCloneNodeIssues( node, destElements[i] );
  				}
  			}
  		}
  
  		// Copy the events from the original to the clone
  		if ( dataAndEvents ) {
  			if ( deepDataAndEvents ) {
  				srcElements = srcElements || getAll( elem );
  				destElements = destElements || getAll( clone );
  
  				for ( i = 0; (node = srcElements[i]) != null; i++ ) {
  					cloneCopyEvent( node, destElements[i] );
  				}
  			} else {
  				cloneCopyEvent( elem, clone );
  			}
  		}
  
  		// Preserve script evaluation history
  		destElements = getAll( clone, "script" );
  		if ( destElements.length > 0 ) {
  			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
  		}
  
  		destElements = srcElements = node = null;
  
  		// Return the cloned set
  		return clone;
  	},
  
  	buildFragment: function( elems, context, scripts, selection ) {
  		var j, elem, contains,
  			tmp, tag, tbody, wrap,
  			l = elems.length,
  
  			// Ensure a safe fragment
  			safe = createSafeFragment( context ),
  
  			nodes = [],
  			i = 0;
  
  		for ( ; i < l; i++ ) {
  			elem = elems[ i ];
  
  			if ( elem || elem === 0 ) {
  
  				// Add nodes directly
  				if ( jQuery.type( elem ) === "object" ) {
  					jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
  
  				// Convert non-html into a text node
  				} else if ( !rhtml.test( elem ) ) {
  					nodes.push( context.createTextNode( elem ) );
  
  				// Convert html into DOM nodes
  				} else {
  					tmp = tmp || safe.appendChild( context.createElement("div") );
  
  					// Deserialize a standard representation
  					tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
  					wrap = wrapMap[ tag ] || wrapMap._default;
  
  					tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
  
  					// Descend through wrappers to the right content
  					j = wrap[0];
  					while ( j-- ) {
  						tmp = tmp.lastChild;
  					}
  
  					// Manually add leading whitespace removed by IE
  					if ( !support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
  						nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) );
  					}
  
  					// Remove IE's autoinserted <tbody> from table fragments
  					if ( !support.tbody ) {
  
  						// String was a <table>, *may* have spurious <tbody>
  						elem = tag === "table" && !rtbody.test( elem ) ?
  							tmp.firstChild :
  
  							// String was a bare <thead> or <tfoot>
  							wrap[1] === "<table>" && !rtbody.test( elem ) ?
  								tmp :
  								0;
  
  						j = elem && elem.childNodes.length;
  						while ( j-- ) {
  							if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) {
  								elem.removeChild( tbody );
  							}
  						}
  					}
  
  					jQuery.merge( nodes, tmp.childNodes );
  
  					// Fix #12392 for WebKit and IE > 9
  					tmp.textContent = "";
  
  					// Fix #12392 for oldIE
  					while ( tmp.firstChild ) {
  						tmp.removeChild( tmp.firstChild );
  					}
  
  					// Remember the top-level container for proper cleanup
  					tmp = safe.lastChild;
  				}
  			}
  		}
  
  		// Fix #11356: Clear elements from fragment
  		if ( tmp ) {
  			safe.removeChild( tmp );
  		}
  
  		// Reset defaultChecked for any radios and checkboxes
  		// about to be appended to the DOM in IE 6/7 (#8060)
  		if ( !support.appendChecked ) {
  			jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked );
  		}
  
  		i = 0;
  		while ( (elem = nodes[ i++ ]) ) {
  
  			// #4087 - If origin and destination elements are the same, and this is
  			// that element, do not do anything
  			if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
  				continue;
  			}
  
  			contains = jQuery.contains( elem.ownerDocument, elem );
  
  			// Append to fragment
  			tmp = getAll( safe.appendChild( elem ), "script" );
  
  			// Preserve script evaluation history
  			if ( contains ) {
  				setGlobalEval( tmp );
  			}
  
  			// Capture executables
  			if ( scripts ) {
  				j = 0;
  				while ( (elem = tmp[ j++ ]) ) {
  					if ( rscriptType.test( elem.type || "" ) ) {
  						scripts.push( elem );
  					}
  				}
  			}
  		}
  
  		tmp = null;
  
  		return safe;
  	},
  
  	cleanData: function( elems, /* internal */ acceptData ) {
  		var elem, type, id, data,
  			i = 0,
  			internalKey = jQuery.expando,
  			cache = jQuery.cache,
  			deleteExpando = support.deleteExpando,
  			special = jQuery.event.special;
  
  		for ( ; (elem = elems[i]) != null; i++ ) {
  			if ( acceptData || jQuery.acceptData( elem ) ) {
  
  				id = elem[ internalKey ];
  				data = id && cache[ id ];
  
  				if ( data ) {
  					if ( data.events ) {
  						for ( type in data.events ) {
  							if ( special[ type ] ) {
  								jQuery.event.remove( elem, type );
  
  							// This is a shortcut to avoid jQuery.event.remove's overhead
  							} else {
  								jQuery.removeEvent( elem, type, data.handle );
  							}
  						}
  					}
  
  					// Remove cache only if it was not already removed by jQuery.event.remove
  					if ( cache[ id ] ) {
  
  						delete cache[ id ];
  
  						// IE does not allow us to delete expando properties from nodes,
  						// nor does it have a removeAttribute function on Document nodes;
  						// we must handle all of these cases
  						if ( deleteExpando ) {
  							delete elem[ internalKey ];
  
  						} else if ( typeof elem.removeAttribute !== strundefined ) {
  							elem.removeAttribute( internalKey );
  
  						} else {
  							elem[ internalKey ] = null;
  						}
  
  						deletedIds.push( id );
  					}
  				}
  			}
  		}
  	}
  });
  
  jQuery.fn.extend({
  	text: function( value ) {
  		return access( this, function( value ) {
  			return value === undefined ?
  				jQuery.text( this ) :
  				this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
  		}, null, value, arguments.length );
  	},
  
  	append: function() {
  		return this.domManip( arguments, function( elem ) {
  			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  				var target = manipulationTarget( this, elem );
  				target.appendChild( elem );
  			}
  		});
  	},
  
  	prepend: function() {
  		return this.domManip( arguments, function( elem ) {
  			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
  				var target = manipulationTarget( this, elem );
  				target.insertBefore( elem, target.firstChild );
  			}
  		});
  	},
  
  	before: function() {
  		return this.domManip( arguments, function( elem ) {
  			if ( this.parentNode ) {
  				this.parentNode.insertBefore( elem, this );
  			}
  		});
  	},
  
  	after: function() {
  		return this.domManip( arguments, function( elem ) {
  			if ( this.parentNode ) {
  				this.parentNode.insertBefore( elem, this.nextSibling );
  			}
  		});
  	},
  
  	remove: function( selector, keepData /* Internal Use Only */ ) {
  		var elem,
  			elems = selector ? jQuery.filter( selector, this ) : this,
  			i = 0;
  
  		for ( ; (elem = elems[i]) != null; i++ ) {
  
  			if ( !keepData && elem.nodeType === 1 ) {
  				jQuery.cleanData( getAll( elem ) );
  			}
  
  			if ( elem.parentNode ) {
  				if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
  					setGlobalEval( getAll( elem, "script" ) );
  				}
  				elem.parentNode.removeChild( elem );
  			}
  		}
  
  		return this;
  	},
  
  	empty: function() {
  		var elem,
  			i = 0;
  
  		for ( ; (elem = this[i]) != null; i++ ) {
  			// Remove element nodes and prevent memory leaks
  			if ( elem.nodeType === 1 ) {
  				jQuery.cleanData( getAll( elem, false ) );
  			}
  
  			// Remove any remaining nodes
  			while ( elem.firstChild ) {
  				elem.removeChild( elem.firstChild );
  			}
  
  			// If this is a select, ensure that it displays empty (#12336)
  			// Support: IE<9
  			if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
  				elem.options.length = 0;
  			}
  		}
  
  		return this;
  	},
  
  	clone: function( dataAndEvents, deepDataAndEvents ) {
  		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
  		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
  
  		return this.map(function() {
  			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
  		});
  	},
  
  	html: function( value ) {
  		return access( this, function( value ) {
  			var elem = this[ 0 ] || {},
  				i = 0,
  				l = this.length;
  
  			if ( value === undefined ) {
  				return elem.nodeType === 1 ?
  					elem.innerHTML.replace( rinlinejQuery, "" ) :
  					undefined;
  			}
  
  			// See if we can take a shortcut and just use innerHTML
  			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
  				( support.htmlSerialize || !rnoshimcache.test( value )  ) &&
  				( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
  				!wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {
  
  				value = value.replace( rxhtmlTag, "<$1></$2>" );
  
  				try {
  					for (; i < l; i++ ) {
  						// Remove element nodes and prevent memory leaks
  						elem = this[i] || {};
  						if ( elem.nodeType === 1 ) {
  							jQuery.cleanData( getAll( elem, false ) );
  							elem.innerHTML = value;
  						}
  					}
  
  					elem = 0;
  
  				// If using innerHTML throws an exception, use the fallback method
  				} catch(e) {}
  			}
  
  			if ( elem ) {
  				this.empty().append( value );
  			}
  		}, null, value, arguments.length );
  	},
  
  	replaceWith: function() {
  		var arg = arguments[ 0 ];
  
  		// Make the changes, replacing each context element with the new content
  		this.domManip( arguments, function( elem ) {
  			arg = this.parentNode;
  
  			jQuery.cleanData( getAll( this ) );
  
  			if ( arg ) {
  				arg.replaceChild( elem, this );
  			}
  		});
  
  		// Force removal if there was no new content (e.g., from empty arguments)
  		return arg && (arg.length || arg.nodeType) ? this : this.remove();
  	},
  
  	detach: function( selector ) {
  		return this.remove( selector, true );
  	},
  
  	domManip: function( args, callback ) {
  
  		// Flatten any nested arrays
  		args = concat.apply( [], args );
  
  		var first, node, hasScripts,
  			scripts, doc, fragment,
  			i = 0,
  			l = this.length,
  			set = this,
  			iNoClone = l - 1,
  			value = args[0],
  			isFunction = jQuery.isFunction( value );
  
  		// We can't cloneNode fragments that contain checked, in WebKit
  		if ( isFunction ||
  				( l > 1 && typeof value === "string" &&
  					!support.checkClone && rchecked.test( value ) ) ) {
  			return this.each(function( index ) {
  				var self = set.eq( index );
  				if ( isFunction ) {
  					args[0] = value.call( this, index, self.html() );
  				}
  				self.domManip( args, callback );
  			});
  		}
  
  		if ( l ) {
  			fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
  			first = fragment.firstChild;
  
  			if ( fragment.childNodes.length === 1 ) {
  				fragment = first;
  			}
  
  			if ( first ) {
  				scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
  				hasScripts = scripts.length;
  
  				// Use the original fragment for the last item instead of the first because it can end up
  				// being emptied incorrectly in certain situations (#8070).
  				for ( ; i < l; i++ ) {
  					node = fragment;
  
  					if ( i !== iNoClone ) {
  						node = jQuery.clone( node, true, true );
  
  						// Keep references to cloned scripts for later restoration
  						if ( hasScripts ) {
  							jQuery.merge( scripts, getAll( node, "script" ) );
  						}
  					}
  
  					callback.call( this[i], node, i );
  				}
  
  				if ( hasScripts ) {
  					doc = scripts[ scripts.length - 1 ].ownerDocument;
  
  					// Reenable scripts
  					jQuery.map( scripts, restoreScript );
  
  					// Evaluate executable scripts on first document insertion
  					for ( i = 0; i < hasScripts; i++ ) {
  						node = scripts[ i ];
  						if ( rscriptType.test( node.type || "" ) &&
  							!jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
  
  							if ( node.src ) {
  								// Optional AJAX dependency, but won't run scripts if not present
  								if ( jQuery._evalUrl ) {
  									jQuery._evalUrl( node.src );
  								}
  							} else {
  								jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
  							}
  						}
  					}
  				}
  
  				// Fix #11809: Avoid leaking memory
  				fragment = first = null;
  			}
  		}
  
  		return this;
  	}
  });
  
  jQuery.each({
  	appendTo: "append",
  	prependTo: "prepend",
  	insertBefore: "before",
  	insertAfter: "after",
  	replaceAll: "replaceWith"
  }, function( name, original ) {
  	jQuery.fn[ name ] = function( selector ) {
  		var elems,
  			i = 0,
  			ret = [],
  			insert = jQuery( selector ),
  			last = insert.length - 1;
  
  		for ( ; i <= last; i++ ) {
  			elems = i === last ? this : this.clone(true);
  			jQuery( insert[i] )[ original ]( elems );
  
  			// Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get()
  			push.apply( ret, elems.get() );
  		}
  
  		return this.pushStack( ret );
  	};
  });
  
  
  var iframe,
  	elemdisplay = {};
  
  /**
   * Retrieve the actual display of a element
   * @param {String} name nodeName of the element
   * @param {Object} doc Document object
   */
  // Called only from within defaultDisplay
  function actualDisplay( name, doc ) {
  	var style,
  		elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
  
  		// getDefaultComputedStyle might be reliably used only on attached element
  		display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
  
  			// Use of this method is a temporary fix (more like optmization) until something better comes along,
  			// since it was removed from specification and supported only in FF
  			style.display : jQuery.css( elem[ 0 ], "display" );
  
  	// We don't have any data stored on the element,
  	// so use "detach" method as fast way to get rid of the element
  	elem.detach();
  
  	return display;
  }
  
  /**
   * Try to determine the default display value of an element
   * @param {String} nodeName
   */
  function defaultDisplay( nodeName ) {
  	var doc = document,
  		display = elemdisplay[ nodeName ];
  
  	if ( !display ) {
  		display = actualDisplay( nodeName, doc );
  
  		// If the simple way fails, read from inside an iframe
  		if ( display === "none" || !display ) {
  
  			// Use the already-created iframe if possible
  			iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
  
  			// Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
  			doc = ( iframe[ 0 ].contentWindow || iframe[ 0 ].contentDocument ).document;
  
  			// Support: IE
  			doc.write();
  			doc.close();
  
  			display = actualDisplay( nodeName, doc );
  			iframe.detach();
  		}
  
  		// Store the correct default display
  		elemdisplay[ nodeName ] = display;
  	}
  
  	return display;
  }
  
  
  (function() {
  	var shrinkWrapBlocksVal;
  
  	support.shrinkWrapBlocks = function() {
  		if ( shrinkWrapBlocksVal != null ) {
  			return shrinkWrapBlocksVal;
  		}
  
  		// Will be changed later if needed.
  		shrinkWrapBlocksVal = false;
  
  		// Minified: var b,c,d
  		var div, body, container;
  
  		body = document.getElementsByTagName( "body" )[ 0 ];
  		if ( !body || !body.style ) {
  			// Test fired too early or in an unsupported environment, exit.
  			return;
  		}
  
  		// Setup
  		div = document.createElement( "div" );
  		container = document.createElement( "div" );
  		container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
  		body.appendChild( container ).appendChild( div );
  
  		// Support: IE6
  		// Check if elements with layout shrink-wrap their children
  		if ( typeof div.style.zoom !== strundefined ) {
  			// Reset CSS: box-sizing; display; margin; border
  			div.style.cssText =
  				// Support: Firefox<29, Android 2.3
  				// Vendor-prefix box-sizing
  				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
  				"box-sizing:content-box;display:block;margin:0;border:0;" +
  				"padding:1px;width:1px;zoom:1";
  			div.appendChild( document.createElement( "div" ) ).style.width = "5px";
  			shrinkWrapBlocksVal = div.offsetWidth !== 3;
  		}
  
  		body.removeChild( container );
  
  		return shrinkWrapBlocksVal;
  	};
  
  })();
  var rmargin = (/^margin/);
  
  var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
  
  
  
  var getStyles, curCSS,
  	rposition = /^(top|right|bottom|left)$/;
  
  if ( window.getComputedStyle ) {
  	getStyles = function( elem ) {
  		return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
  	};
  
  	curCSS = function( elem, name, computed ) {
  		var width, minWidth, maxWidth, ret,
  			style = elem.style;
  
  		computed = computed || getStyles( elem );
  
  		// getPropertyValue is only needed for .css('filter') in IE9, see #12537
  		ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined;
  
  		if ( computed ) {
  
  			if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
  				ret = jQuery.style( elem, name );
  			}
  
  			// A tribute to the "awesome hack by Dean Edwards"
  			// Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right
  			// Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
  			// this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
  			if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
  
  				// Remember the original values
  				width = style.width;
  				minWidth = style.minWidth;
  				maxWidth = style.maxWidth;
  
  				// Put in the new values to get a computed value out
  				style.minWidth = style.maxWidth = style.width = ret;
  				ret = computed.width;
  
  				// Revert the changed values
  				style.width = width;
  				style.minWidth = minWidth;
  				style.maxWidth = maxWidth;
  			}
  		}
  
  		// Support: IE
  		// IE returns zIndex value as an integer.
  		return ret === undefined ?
  			ret :
  			ret + "";
  	};
  } else if ( document.documentElement.currentStyle ) {
  	getStyles = function( elem ) {
  		return elem.currentStyle;
  	};
  
  	curCSS = function( elem, name, computed ) {
  		var left, rs, rsLeft, ret,
  			style = elem.style;
  
  		computed = computed || getStyles( elem );
  		ret = computed ? computed[ name ] : undefined;
  
  		// Avoid setting ret to empty string here
  		// so we don't default to auto
  		if ( ret == null && style && style[ name ] ) {
  			ret = style[ name ];
  		}
  
  		// From the awesome hack by Dean Edwards
  		// http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
  
  		// If we're not dealing with a regular pixel number
  		// but a number that has a weird ending, we need to convert it to pixels
  		// but not position css attributes, as those are proportional to the parent element instead
  		// and we can't measure the parent instead because it might trigger a "stacking dolls" problem
  		if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) {
  
  			// Remember the original values
  			left = style.left;
  			rs = elem.runtimeStyle;
  			rsLeft = rs && rs.left;
  
  			// Put in the new values to get a computed value out
  			if ( rsLeft ) {
  				rs.left = elem.currentStyle.left;
  			}
  			style.left = name === "fontSize" ? "1em" : ret;
  			ret = style.pixelLeft + "px";
  
  			// Revert the changed values
  			style.left = left;
  			if ( rsLeft ) {
  				rs.left = rsLeft;
  			}
  		}
  
  		// Support: IE
  		// IE returns zIndex value as an integer.
  		return ret === undefined ?
  			ret :
  			ret + "" || "auto";
  	};
  }
  
  
  
  
  function addGetHookIf( conditionFn, hookFn ) {
  	// Define the hook, we'll check on the first run if it's really needed.
  	return {
  		get: function() {
  			var condition = conditionFn();
  
  			if ( condition == null ) {
  				// The test was not ready at this point; screw the hook this time
  				// but check again when needed next time.
  				return;
  			}
  
  			if ( condition ) {
  				// Hook not needed (or it's not possible to use it due to missing dependency),
  				// remove it.
  				// Since there are no other hooks for marginRight, remove the whole object.
  				delete this.get;
  				return;
  			}
  
  			// Hook needed; redefine it so that the support test is not executed again.
  
  			return (this.get = hookFn).apply( this, arguments );
  		}
  	};
  }
  
  
  (function() {
  	// Minified: var b,c,d,e,f,g, h,i
  	var div, style, a, pixelPositionVal, boxSizingReliableVal,
  		reliableHiddenOffsetsVal, reliableMarginRightVal;
  
  	// Setup
  	div = document.createElement( "div" );
  	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
  	a = div.getElementsByTagName( "a" )[ 0 ];
  	style = a && a.style;
  
  	// Finish early in limited (non-browser) environments
  	if ( !style ) {
  		return;
  	}
  
  	style.cssText = "float:left;opacity:.5";
  
  	// Support: IE<9
  	// Make sure that element opacity exists (as opposed to filter)
  	support.opacity = style.opacity === "0.5";
  
  	// Verify style float existence
  	// (IE uses styleFloat instead of cssFloat)
  	support.cssFloat = !!style.cssFloat;
  
  	div.style.backgroundClip = "content-box";
  	div.cloneNode( true ).style.backgroundClip = "";
  	support.clearCloneStyle = div.style.backgroundClip === "content-box";
  
  	// Support: Firefox<29, Android 2.3
  	// Vendor-prefix box-sizing
  	support.boxSizing = style.boxSizing === "" || style.MozBoxSizing === "" ||
  		style.WebkitBoxSizing === "";
  
  	jQuery.extend(support, {
  		reliableHiddenOffsets: function() {
  			if ( reliableHiddenOffsetsVal == null ) {
  				computeStyleTests();
  			}
  			return reliableHiddenOffsetsVal;
  		},
  
  		boxSizingReliable: function() {
  			if ( boxSizingReliableVal == null ) {
  				computeStyleTests();
  			}
  			return boxSizingReliableVal;
  		},
  
  		pixelPosition: function() {
  			if ( pixelPositionVal == null ) {
  				computeStyleTests();
  			}
  			return pixelPositionVal;
  		},
  
  		// Support: Android 2.3
  		reliableMarginRight: function() {
  			if ( reliableMarginRightVal == null ) {
  				computeStyleTests();
  			}
  			return reliableMarginRightVal;
  		}
  	});
  
  	function computeStyleTests() {
  		// Minified: var b,c,d,j
  		var div, body, container, contents;
  
  		body = document.getElementsByTagName( "body" )[ 0 ];
  		if ( !body || !body.style ) {
  			// Test fired too early or in an unsupported environment, exit.
  			return;
  		}
  
  		// Setup
  		div = document.createElement( "div" );
  		container = document.createElement( "div" );
  		container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px";
  		body.appendChild( container ).appendChild( div );
  
  		div.style.cssText =
  			// Support: Firefox<29, Android 2.3
  			// Vendor-prefix box-sizing
  			"-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
  			"box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
  			"border:1px;padding:1px;width:4px;position:absolute";
  
  		// Support: IE<9
  		// Assume reasonable values in the absence of getComputedStyle
  		pixelPositionVal = boxSizingReliableVal = false;
  		reliableMarginRightVal = true;
  
  		// Check for getComputedStyle so that this code is not run in IE<9.
  		if ( window.getComputedStyle ) {
  			pixelPositionVal = ( window.getComputedStyle( div, null ) || {} ).top !== "1%";
  			boxSizingReliableVal =
  				( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px";
  
  			// Support: Android 2.3
  			// Div with explicit width and no margin-right incorrectly
  			// gets computed margin-right based on width of container (#3333)
  			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  			contents = div.appendChild( document.createElement( "div" ) );
  
  			// Reset CSS: box-sizing; display; margin; border; padding
  			contents.style.cssText = div.style.cssText =
  				// Support: Firefox<29, Android 2.3
  				// Vendor-prefix box-sizing
  				"-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
  				"box-sizing:content-box;display:block;margin:0;border:0;padding:0";
  			contents.style.marginRight = contents.style.width = "0";
  			div.style.width = "1px";
  
  			reliableMarginRightVal =
  				!parseFloat( ( window.getComputedStyle( contents, null ) || {} ).marginRight );
  		}
  
  		// Support: IE8
  		// Check if table cells still have offsetWidth/Height when they are set
  		// to display:none and there are still other visible table cells in a
  		// table row; if so, offsetWidth/Height are not reliable for use when
  		// determining if an element has been hidden directly using
  		// display:none (it is still safe to use offsets if a parent element is
  		// hidden; don safety goggles and see bug #4512 for more information).
  		div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>";
  		contents = div.getElementsByTagName( "td" );
  		contents[ 0 ].style.cssText = "margin:0;border:0;padding:0;display:none";
  		reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
  		if ( reliableHiddenOffsetsVal ) {
  			contents[ 0 ].style.display = "";
  			contents[ 1 ].style.display = "none";
  			reliableHiddenOffsetsVal = contents[ 0 ].offsetHeight === 0;
  		}
  
  		body.removeChild( container );
  	}
  
  })();
  
  
  // A method for quickly swapping in/out CSS properties to get correct calculations.
  jQuery.swap = function( elem, options, callback, args ) {
  	var ret, name,
  		old = {};
  
  	// Remember the old values, and insert the new ones
  	for ( name in options ) {
  		old[ name ] = elem.style[ name ];
  		elem.style[ name ] = options[ name ];
  	}
  
  	ret = callback.apply( elem, args || [] );
  
  	// Revert the old values
  	for ( name in options ) {
  		elem.style[ name ] = old[ name ];
  	}
  
  	return ret;
  };
  
  
  var
  		ralpha = /alpha\([^)]*\)/i,
  	ropacity = /opacity\s*=\s*([^)]*)/,
  
  	// swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
  	// see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
  	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
  	rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
  	rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
  
  	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
  	cssNormalTransform = {
  		letterSpacing: "0",
  		fontWeight: "400"
  	},
  
  	cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
  
  
  // return a css property mapped to a potentially vendor prefixed property
  function vendorPropName( style, name ) {
  
  	// shortcut for names that are not vendor prefixed
  	if ( name in style ) {
  		return name;
  	}
  
  	// check for vendor prefixed names
  	var capName = name.charAt(0).toUpperCase() + name.slice(1),
  		origName = name,
  		i = cssPrefixes.length;
  
  	while ( i-- ) {
  		name = cssPrefixes[ i ] + capName;
  		if ( name in style ) {
  			return name;
  		}
  	}
  
  	return origName;
  }
  
  function showHide( elements, show ) {
  	var display, elem, hidden,
  		values = [],
  		index = 0,
  		length = elements.length;
  
  	for ( ; index < length; index++ ) {
  		elem = elements[ index ];
  		if ( !elem.style ) {
  			continue;
  		}
  
  		values[ index ] = jQuery._data( elem, "olddisplay" );
  		display = elem.style.display;
  		if ( show ) {
  			// Reset the inline display of this element to learn if it is
  			// being hidden by cascaded rules or not
  			if ( !values[ index ] && display === "none" ) {
  				elem.style.display = "";
  			}
  
  			// Set elements which have been overridden with display: none
  			// in a stylesheet to whatever the default browser style is
  			// for such an element
  			if ( elem.style.display === "" && isHidden( elem ) ) {
  				values[ index ] = jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
  			}
  		} else {
  			hidden = isHidden( elem );
  
  			if ( display && display !== "none" || !hidden ) {
  				jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
  			}
  		}
  	}
  
  	// Set the display of most of the elements in a second loop
  	// to avoid the constant reflow
  	for ( index = 0; index < length; index++ ) {
  		elem = elements[ index ];
  		if ( !elem.style ) {
  			continue;
  		}
  		if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
  			elem.style.display = show ? values[ index ] || "" : "none";
  		}
  	}
  
  	return elements;
  }
  
  function setPositiveNumber( elem, value, subtract ) {
  	var matches = rnumsplit.exec( value );
  	return matches ?
  		// Guard against undefined "subtract", e.g., when used as in cssHooks
  		Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
  		value;
  }
  
  function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
  	var i = extra === ( isBorderBox ? "border" : "content" ) ?
  		// If we already have the right measurement, avoid augmentation
  		4 :
  		// Otherwise initialize for horizontal or vertical properties
  		name === "width" ? 1 : 0,
  
  		val = 0;
  
  	for ( ; i < 4; i += 2 ) {
  		// both box models exclude margin, so add it if we want it
  		if ( extra === "margin" ) {
  			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
  		}
  
  		if ( isBorderBox ) {
  			// border-box includes padding, so remove it if we want content
  			if ( extra === "content" ) {
  				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  			}
  
  			// at this point, extra isn't border nor margin, so remove border
  			if ( extra !== "margin" ) {
  				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  			}
  		} else {
  			// at this point, extra isn't content, so add padding
  			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
  
  			// at this point, extra isn't content nor padding, so add border
  			if ( extra !== "padding" ) {
  				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
  			}
  		}
  	}
  
  	return val;
  }
  
  function getWidthOrHeight( elem, name, extra ) {
  
  	// Start with offset property, which is equivalent to the border-box value
  	var valueIsBorderBox = true,
  		val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
  		styles = getStyles( elem ),
  		isBorderBox = support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
  
  	// some non-html elements return undefined for offsetWidth, so check for null/undefined
  	// svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
  	// MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
  	if ( val <= 0 || val == null ) {
  		// Fall back to computed then uncomputed css if necessary
  		val = curCSS( elem, name, styles );
  		if ( val < 0 || val == null ) {
  			val = elem.style[ name ];
  		}
  
  		// Computed unit is not pixels. Stop here and return.
  		if ( rnumnonpx.test(val) ) {
  			return val;
  		}
  
  		// we need the check for style in case a browser which returns unreliable values
  		// for getComputedStyle silently falls back to the reliable elem.style
  		valueIsBorderBox = isBorderBox && ( support.boxSizingReliable() || val === elem.style[ name ] );
  
  		// Normalize "", auto, and prepare for extra
  		val = parseFloat( val ) || 0;
  	}
  
  	// use the active box-sizing model to add/subtract irrelevant styles
  	return ( val +
  		augmentWidthOrHeight(
  			elem,
  			name,
  			extra || ( isBorderBox ? "border" : "content" ),
  			valueIsBorderBox,
  			styles
  		)
  	) + "px";
  }
  
  jQuery.extend({
  	// Add in style property hooks for overriding the default
  	// behavior of getting and setting a style property
  	cssHooks: {
  		opacity: {
  			get: function( elem, computed ) {
  				if ( computed ) {
  					// We should always get a number back from opacity
  					var ret = curCSS( elem, "opacity" );
  					return ret === "" ? "1" : ret;
  				}
  			}
  		}
  	},
  
  	// Don't automatically add "px" to these possibly-unitless properties
  	cssNumber: {
  		"columnCount": true,
  		"fillOpacity": true,
  		"flexGrow": true,
  		"flexShrink": true,
  		"fontWeight": true,
  		"lineHeight": true,
  		"opacity": true,
  		"order": true,
  		"orphans": true,
  		"widows": true,
  		"zIndex": true,
  		"zoom": true
  	},
  
  	// Add in properties whose names you wish to fix before
  	// setting or getting the value
  	cssProps: {
  		// normalize float css property
  		"float": support.cssFloat ? "cssFloat" : "styleFloat"
  	},
  
  	// Get and set the style property on a DOM Node
  	style: function( elem, name, value, extra ) {
  		// Don't set styles on text and comment nodes
  		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
  			return;
  		}
  
  		// Make sure that we're working with the right name
  		var ret, type, hooks,
  			origName = jQuery.camelCase( name ),
  			style = elem.style;
  
  		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
  
  		// gets hook for the prefixed version
  		// followed by the unprefixed version
  		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  
  		// Check if we're setting a value
  		if ( value !== undefined ) {
  			type = typeof value;
  
  			// convert relative number strings (+= or -=) to relative numbers. #7345
  			if ( type === "string" && (ret = rrelNum.exec( value )) ) {
  				value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
  				// Fixes bug #9237
  				type = "number";
  			}
  
  			// Make sure that null and NaN values aren't set. See: #7116
  			if ( value == null || value !== value ) {
  				return;
  			}
  
  			// If a number was passed in, add 'px' to the (except for certain CSS properties)
  			if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
  				value += "px";
  			}
  
  			// Fixes #8908, it can be done more correctly by specifing setters in cssHooks,
  			// but it would mean to define eight (for every problematic property) identical functions
  			if ( !support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) {
  				style[ name ] = "inherit";
  			}
  
  			// If a hook was provided, use that value, otherwise just set the specified value
  			if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
  
  				// Support: IE
  				// Swallow errors from 'invalid' CSS values (#5509)
  				try {
  					style[ name ] = value;
  				} catch(e) {}
  			}
  
  		} else {
  			// If a hook was provided get the non-computed value from there
  			if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
  				return ret;
  			}
  
  			// Otherwise just get the value from the style object
  			return style[ name ];
  		}
  	},
  
  	css: function( elem, name, extra, styles ) {
  		var num, val, hooks,
  			origName = jQuery.camelCase( name );
  
  		// Make sure that we're working with the right name
  		name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
  
  		// gets hook for the prefixed version
  		// followed by the unprefixed version
  		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
  
  		// If a hook was provided get the computed value from there
  		if ( hooks && "get" in hooks ) {
  			val = hooks.get( elem, true, extra );
  		}
  
  		// Otherwise, if a way to get the computed value exists, use that
  		if ( val === undefined ) {
  			val = curCSS( elem, name, styles );
  		}
  
  		//convert "normal" to computed value
  		if ( val === "normal" && name in cssNormalTransform ) {
  			val = cssNormalTransform[ name ];
  		}
  
  		// Return, converting to number if forced or a qualifier was provided and val looks numeric
  		if ( extra === "" || extra ) {
  			num = parseFloat( val );
  			return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
  		}
  		return val;
  	}
  });
  
  jQuery.each([ "height", "width" ], function( i, name ) {
  	jQuery.cssHooks[ name ] = {
  		get: function( elem, computed, extra ) {
  			if ( computed ) {
  				// certain elements can have dimension info if we invisibly show them
  				// however, it must have a current display style that would benefit from this
  				return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
  					jQuery.swap( elem, cssShow, function() {
  						return getWidthOrHeight( elem, name, extra );
  					}) :
  					getWidthOrHeight( elem, name, extra );
  			}
  		},
  
  		set: function( elem, value, extra ) {
  			var styles = extra && getStyles( elem );
  			return setPositiveNumber( elem, value, extra ?
  				augmentWidthOrHeight(
  					elem,
  					name,
  					extra,
  					support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
  					styles
  				) : 0
  			);
  		}
  	};
  });
  
  if ( !support.opacity ) {
  	jQuery.cssHooks.opacity = {
  		get: function( elem, computed ) {
  			// IE uses filters for opacity
  			return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
  				( 0.01 * parseFloat( RegExp.$1 ) ) + "" :
  				computed ? "1" : "";
  		},
  
  		set: function( elem, value ) {
  			var style = elem.style,
  				currentStyle = elem.currentStyle,
  				opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
  				filter = currentStyle && currentStyle.filter || style.filter || "";
  
  			// IE has trouble with opacity if it does not have layout
  			// Force it by setting the zoom level
  			style.zoom = 1;
  
  			// if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
  			// if value === "", then remove inline opacity #12685
  			if ( ( value >= 1 || value === "" ) &&
  					jQuery.trim( filter.replace( ralpha, "" ) ) === "" &&
  					style.removeAttribute ) {
  
  				// Setting style.filter to null, "" & " " still leave "filter:" in the cssText
  				// if "filter:" is present at all, clearType is disabled, we want to avoid this
  				// style.removeAttribute is IE Only, but so apparently is this code path...
  				style.removeAttribute( "filter" );
  
  				// if there is no filter style applied in a css rule or unset inline opacity, we are done
  				if ( value === "" || currentStyle && !currentStyle.filter ) {
  					return;
  				}
  			}
  
  			// otherwise, set new filter values
  			style.filter = ralpha.test( filter ) ?
  				filter.replace( ralpha, opacity ) :
  				filter + " " + opacity;
  		}
  	};
  }
  
  jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
  	function( elem, computed ) {
  		if ( computed ) {
  			// WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
  			// Work around by temporarily setting element display to inline-block
  			return jQuery.swap( elem, { "display": "inline-block" },
  				curCSS, [ elem, "marginRight" ] );
  		}
  	}
  );
  
  // These hooks are used by animate to expand properties
  jQuery.each({
  	margin: "",
  	padding: "",
  	border: "Width"
  }, function( prefix, suffix ) {
  	jQuery.cssHooks[ prefix + suffix ] = {
  		expand: function( value ) {
  			var i = 0,
  				expanded = {},
  
  				// assumes a single number if not a string
  				parts = typeof value === "string" ? value.split(" ") : [ value ];
  
  			for ( ; i < 4; i++ ) {
  				expanded[ prefix + cssExpand[ i ] + suffix ] =
  					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
  			}
  
  			return expanded;
  		}
  	};
  
  	if ( !rmargin.test( prefix ) ) {
  		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
  	}
  });
  
  jQuery.fn.extend({
  	css: function( name, value ) {
  		return access( this, function( elem, name, value ) {
  			var styles, len,
  				map = {},
  				i = 0;
  
  			if ( jQuery.isArray( name ) ) {
  				styles = getStyles( elem );
  				len = name.length;
  
  				for ( ; i < len; i++ ) {
  					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
  				}
  
  				return map;
  			}
  
  			return value !== undefined ?
  				jQuery.style( elem, name, value ) :
  				jQuery.css( elem, name );
  		}, name, value, arguments.length > 1 );
  	},
  	show: function() {
  		return showHide( this, true );
  	},
  	hide: function() {
  		return showHide( this );
  	},
  	toggle: function( state ) {
  		if ( typeof state === "boolean" ) {
  			return state ? this.show() : this.hide();
  		}
  
  		return this.each(function() {
  			if ( isHidden( this ) ) {
  				jQuery( this ).show();
  			} else {
  				jQuery( this ).hide();
  			}
  		});
  	}
  });
  
  
  function Tween( elem, options, prop, end, easing ) {
  	return new Tween.prototype.init( elem, options, prop, end, easing );
  }
  jQuery.Tween = Tween;
  
  Tween.prototype = {
  	constructor: Tween,
  	init: function( elem, options, prop, end, easing, unit ) {
  		this.elem = elem;
  		this.prop = prop;
  		this.easing = easing || "swing";
  		this.options = options;
  		this.start = this.now = this.cur();
  		this.end = end;
  		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
  	},
  	cur: function() {
  		var hooks = Tween.propHooks[ this.prop ];
  
  		return hooks && hooks.get ?
  			hooks.get( this ) :
  			Tween.propHooks._default.get( this );
  	},
  	run: function( percent ) {
  		var eased,
  			hooks = Tween.propHooks[ this.prop ];
  
  		if ( this.options.duration ) {
  			this.pos = eased = jQuery.easing[ this.easing ](
  				percent, this.options.duration * percent, 0, 1, this.options.duration
  			);
  		} else {
  			this.pos = eased = percent;
  		}
  		this.now = ( this.end - this.start ) * eased + this.start;
  
  		if ( this.options.step ) {
  			this.options.step.call( this.elem, this.now, this );
  		}
  
  		if ( hooks && hooks.set ) {
  			hooks.set( this );
  		} else {
  			Tween.propHooks._default.set( this );
  		}
  		return this;
  	}
  };
  
  Tween.prototype.init.prototype = Tween.prototype;
  
  Tween.propHooks = {
  	_default: {
  		get: function( tween ) {
  			var result;
  
  			if ( tween.elem[ tween.prop ] != null &&
  				(!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
  				return tween.elem[ tween.prop ];
  			}
  
  			// passing an empty string as a 3rd parameter to .css will automatically
  			// attempt a parseFloat and fallback to a string if the parse fails
  			// so, simple values such as "10px" are parsed to Float.
  			// complex values such as "rotate(1rad)" are returned as is.
  			result = jQuery.css( tween.elem, tween.prop, "" );
  			// Empty strings, null, undefined and "auto" are converted to 0.
  			return !result || result === "auto" ? 0 : result;
  		},
  		set: function( tween ) {
  			// use step hook for back compat - use cssHook if its there - use .style if its
  			// available and use plain properties where available
  			if ( jQuery.fx.step[ tween.prop ] ) {
  				jQuery.fx.step[ tween.prop ]( tween );
  			} else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
  				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
  			} else {
  				tween.elem[ tween.prop ] = tween.now;
  			}
  		}
  	}
  };
  
  // Support: IE <=9
  // Panic based approach to setting things on disconnected nodes
  
  Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
  	set: function( tween ) {
  		if ( tween.elem.nodeType && tween.elem.parentNode ) {
  			tween.elem[ tween.prop ] = tween.now;
  		}
  	}
  };
  
  jQuery.easing = {
  	linear: function( p ) {
  		return p;
  	},
  	swing: function( p ) {
  		return 0.5 - Math.cos( p * Math.PI ) / 2;
  	}
  };
  
  jQuery.fx = Tween.prototype.init;
  
  // Back Compat <1.8 extension point
  jQuery.fx.step = {};
  
  
  
  
  var
  	fxNow, timerId,
  	rfxtypes = /^(?:toggle|show|hide)$/,
  	rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
  	rrun = /queueHooks$/,
  	animationPrefilters = [ defaultPrefilter ],
  	tweeners = {
  		"*": [ function( prop, value ) {
  			var tween = this.createTween( prop, value ),
  				target = tween.cur(),
  				parts = rfxnum.exec( value ),
  				unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
  
  				// Starting value computation is required for potential unit mismatches
  				start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
  					rfxnum.exec( jQuery.css( tween.elem, prop ) ),
  				scale = 1,
  				maxIterations = 20;
  
  			if ( start && start[ 3 ] !== unit ) {
  				// Trust units reported by jQuery.css
  				unit = unit || start[ 3 ];
  
  				// Make sure we update the tween properties later on
  				parts = parts || [];
  
  				// Iteratively approximate from a nonzero starting point
  				start = +target || 1;
  
  				do {
  					// If previous iteration zeroed out, double until we get *something*
  					// Use a string for doubling factor so we don't accidentally see scale as unchanged below
  					scale = scale || ".5";
  
  					// Adjust and apply
  					start = start / scale;
  					jQuery.style( tween.elem, prop, start + unit );
  
  				// Update scale, tolerating zero or NaN from tween.cur()
  				// And breaking the loop if scale is unchanged or perfect, or if we've just had enough
  				} while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
  			}
  
  			// Update tween properties
  			if ( parts ) {
  				start = tween.start = +start || +target || 0;
  				tween.unit = unit;
  				// If a +=/-= token was provided, we're doing a relative animation
  				tween.end = parts[ 1 ] ?
  					start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
  					+parts[ 2 ];
  			}
  
  			return tween;
  		} ]
  	};
  
  // Animations created synchronously will run synchronously
  function createFxNow() {
  	setTimeout(function() {
  		fxNow = undefined;
  	});
  	return ( fxNow = jQuery.now() );
  }
  
  // Generate parameters to create a standard animation
  function genFx( type, includeWidth ) {
  	var which,
  		attrs = { height: type },
  		i = 0;
  
  	// if we include width, step value is 1 to do all cssExpand values,
  	// if we don't include width, step value is 2 to skip over Left and Right
  	includeWidth = includeWidth ? 1 : 0;
  	for ( ; i < 4 ; i += 2 - includeWidth ) {
  		which = cssExpand[ i ];
  		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
  	}
  
  	if ( includeWidth ) {
  		attrs.opacity = attrs.width = type;
  	}
  
  	return attrs;
  }
  
  function createTween( value, prop, animation ) {
  	var tween,
  		collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
  		index = 0,
  		length = collection.length;
  	for ( ; index < length; index++ ) {
  		if ( (tween = collection[ index ].call( animation, prop, value )) ) {
  
  			// we're done with this property
  			return tween;
  		}
  	}
  }
  
  function defaultPrefilter( elem, props, opts ) {
  	/* jshint validthis: true */
  	var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
  		anim = this,
  		orig = {},
  		style = elem.style,
  		hidden = elem.nodeType && isHidden( elem ),
  		dataShow = jQuery._data( elem, "fxshow" );
  
  	// handle queue: false promises
  	if ( !opts.queue ) {
  		hooks = jQuery._queueHooks( elem, "fx" );
  		if ( hooks.unqueued == null ) {
  			hooks.unqueued = 0;
  			oldfire = hooks.empty.fire;
  			hooks.empty.fire = function() {
  				if ( !hooks.unqueued ) {
  					oldfire();
  				}
  			};
  		}
  		hooks.unqueued++;
  
  		anim.always(function() {
  			// doing this makes sure that the complete handler will be called
  			// before this completes
  			anim.always(function() {
  				hooks.unqueued--;
  				if ( !jQuery.queue( elem, "fx" ).length ) {
  					hooks.empty.fire();
  				}
  			});
  		});
  	}
  
  	// height/width overflow pass
  	if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
  		// Make sure that nothing sneaks out
  		// Record all 3 overflow attributes because IE does not
  		// change the overflow attribute when overflowX and
  		// overflowY are set to the same value
  		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
  
  		// Set display property to inline-block for height/width
  		// animations on inline elements that are having width/height animated
  		display = jQuery.css( elem, "display" );
  
  		// Test default display if display is currently "none"
  		checkDisplay = display === "none" ?
  			jQuery._data( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
  
  		if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
  
  			// inline-level elements accept inline-block;
  			// block-level elements need to be inline with layout
  			if ( !support.inlineBlockNeedsLayout || defaultDisplay( elem.nodeName ) === "inline" ) {
  				style.display = "inline-block";
  			} else {
  				style.zoom = 1;
  			}
  		}
  	}
  
  	if ( opts.overflow ) {
  		style.overflow = "hidden";
  		if ( !support.shrinkWrapBlocks() ) {
  			anim.always(function() {
  				style.overflow = opts.overflow[ 0 ];
  				style.overflowX = opts.overflow[ 1 ];
  				style.overflowY = opts.overflow[ 2 ];
  			});
  		}
  	}
  
  	// show/hide pass
  	for ( prop in props ) {
  		value = props[ prop ];
  		if ( rfxtypes.exec( value ) ) {
  			delete props[ prop ];
  			toggle = toggle || value === "toggle";
  			if ( value === ( hidden ? "hide" : "show" ) ) {
  
  				// If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
  				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
  					hidden = true;
  				} else {
  					continue;
  				}
  			}
  			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
  
  		// Any non-fx value stops us from restoring the original display value
  		} else {
  			display = undefined;
  		}
  	}
  
  	if ( !jQuery.isEmptyObject( orig ) ) {
  		if ( dataShow ) {
  			if ( "hidden" in dataShow ) {
  				hidden = dataShow.hidden;
  			}
  		} else {
  			dataShow = jQuery._data( elem, "fxshow", {} );
  		}
  
  		// store state if its toggle - enables .stop().toggle() to "reverse"
  		if ( toggle ) {
  			dataShow.hidden = !hidden;
  		}
  		if ( hidden ) {
  			jQuery( elem ).show();
  		} else {
  			anim.done(function() {
  				jQuery( elem ).hide();
  			});
  		}
  		anim.done(function() {
  			var prop;
  			jQuery._removeData( elem, "fxshow" );
  			for ( prop in orig ) {
  				jQuery.style( elem, prop, orig[ prop ] );
  			}
  		});
  		for ( prop in orig ) {
  			tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
  
  			if ( !( prop in dataShow ) ) {
  				dataShow[ prop ] = tween.start;
  				if ( hidden ) {
  					tween.end = tween.start;
  					tween.start = prop === "width" || prop === "height" ? 1 : 0;
  				}
  			}
  		}
  
  	// If this is a noop like .hide().hide(), restore an overwritten display value
  	} else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
  		style.display = display;
  	}
  }
  
  function propFilter( props, specialEasing ) {
  	var index, name, easing, value, hooks;
  
  	// camelCase, specialEasing and expand cssHook pass
  	for ( index in props ) {
  		name = jQuery.camelCase( index );
  		easing = specialEasing[ name ];
  		value = props[ index ];
  		if ( jQuery.isArray( value ) ) {
  			easing = value[ 1 ];
  			value = props[ index ] = value[ 0 ];
  		}
  
  		if ( index !== name ) {
  			props[ name ] = value;
  			delete props[ index ];
  		}
  
  		hooks = jQuery.cssHooks[ name ];
  		if ( hooks && "expand" in hooks ) {
  			value = hooks.expand( value );
  			delete props[ name ];
  
  			// not quite $.extend, this wont overwrite keys already present.
  			// also - reusing 'index' from above because we have the correct "name"
  			for ( index in value ) {
  				if ( !( index in props ) ) {
  					props[ index ] = value[ index ];
  					specialEasing[ index ] = easing;
  				}
  			}
  		} else {
  			specialEasing[ name ] = easing;
  		}
  	}
  }
  
  function Animation( elem, properties, options ) {
  	var result,
  		stopped,
  		index = 0,
  		length = animationPrefilters.length,
  		deferred = jQuery.Deferred().always( function() {
  			// don't match elem in the :animated selector
  			delete tick.elem;
  		}),
  		tick = function() {
  			if ( stopped ) {
  				return false;
  			}
  			var currentTime = fxNow || createFxNow(),
  				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
  				// archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
  				temp = remaining / animation.duration || 0,
  				percent = 1 - temp,
  				index = 0,
  				length = animation.tweens.length;
  
  			for ( ; index < length ; index++ ) {
  				animation.tweens[ index ].run( percent );
  			}
  
  			deferred.notifyWith( elem, [ animation, percent, remaining ]);
  
  			if ( percent < 1 && length ) {
  				return remaining;
  			} else {
  				deferred.resolveWith( elem, [ animation ] );
  				return false;
  			}
  		},
  		animation = deferred.promise({
  			elem: elem,
  			props: jQuery.extend( {}, properties ),
  			opts: jQuery.extend( true, { specialEasing: {} }, options ),
  			originalProperties: properties,
  			originalOptions: options,
  			startTime: fxNow || createFxNow(),
  			duration: options.duration,
  			tweens: [],
  			createTween: function( prop, end ) {
  				var tween = jQuery.Tween( elem, animation.opts, prop, end,
  						animation.opts.specialEasing[ prop ] || animation.opts.easing );
  				animation.tweens.push( tween );
  				return tween;
  			},
  			stop: function( gotoEnd ) {
  				var index = 0,
  					// if we are going to the end, we want to run all the tweens
  					// otherwise we skip this part
  					length = gotoEnd ? animation.tweens.length : 0;
  				if ( stopped ) {
  					return this;
  				}
  				stopped = true;
  				for ( ; index < length ; index++ ) {
  					animation.tweens[ index ].run( 1 );
  				}
  
  				// resolve when we played the last frame
  				// otherwise, reject
  				if ( gotoEnd ) {
  					deferred.resolveWith( elem, [ animation, gotoEnd ] );
  				} else {
  					deferred.rejectWith( elem, [ animation, gotoEnd ] );
  				}
  				return this;
  			}
  		}),
  		props = animation.props;
  
  	propFilter( props, animation.opts.specialEasing );
  
  	for ( ; index < length ; index++ ) {
  		result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
  		if ( result ) {
  			return result;
  		}
  	}
  
  	jQuery.map( props, createTween, animation );
  
  	if ( jQuery.isFunction( animation.opts.start ) ) {
  		animation.opts.start.call( elem, animation );
  	}
  
  	jQuery.fx.timer(
  		jQuery.extend( tick, {
  			elem: elem,
  			anim: animation,
  			queue: animation.opts.queue
  		})
  	);
  
  	// attach callbacks from options
  	return animation.progress( animation.opts.progress )
  		.done( animation.opts.done, animation.opts.complete )
  		.fail( animation.opts.fail )
  		.always( animation.opts.always );
  }
  
  jQuery.Animation = jQuery.extend( Animation, {
  	tweener: function( props, callback ) {
  		if ( jQuery.isFunction( props ) ) {
  			callback = props;
  			props = [ "*" ];
  		} else {
  			props = props.split(" ");
  		}
  
  		var prop,
  			index = 0,
  			length = props.length;
  
  		for ( ; index < length ; index++ ) {
  			prop = props[ index ];
  			tweeners[ prop ] = tweeners[ prop ] || [];
  			tweeners[ prop ].unshift( callback );
  		}
  	},
  
  	prefilter: function( callback, prepend ) {
  		if ( prepend ) {
  			animationPrefilters.unshift( callback );
  		} else {
  			animationPrefilters.push( callback );
  		}
  	}
  });
  
  jQuery.speed = function( speed, easing, fn ) {
  	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
  		complete: fn || !fn && easing ||
  			jQuery.isFunction( speed ) && speed,
  		duration: speed,
  		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
  	};
  
  	opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
  		opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
  
  	// normalize opt.queue - true/undefined/null -> "fx"
  	if ( opt.queue == null || opt.queue === true ) {
  		opt.queue = "fx";
  	}
  
  	// Queueing
  	opt.old = opt.complete;
  
  	opt.complete = function() {
  		if ( jQuery.isFunction( opt.old ) ) {
  			opt.old.call( this );
  		}
  
  		if ( opt.queue ) {
  			jQuery.dequeue( this, opt.queue );
  		}
  	};
  
  	return opt;
  };
  
  jQuery.fn.extend({
  	fadeTo: function( speed, to, easing, callback ) {
  
  		// show any hidden elements after setting opacity to 0
  		return this.filter( isHidden ).css( "opacity", 0 ).show()
  
  			// animate to the value specified
  			.end().animate({ opacity: to }, speed, easing, callback );
  	},
  	animate: function( prop, speed, easing, callback ) {
  		var empty = jQuery.isEmptyObject( prop ),
  			optall = jQuery.speed( speed, easing, callback ),
  			doAnimation = function() {
  				// Operate on a copy of prop so per-property easing won't be lost
  				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
  
  				// Empty animations, or finishing resolves immediately
  				if ( empty || jQuery._data( this, "finish" ) ) {
  					anim.stop( true );
  				}
  			};
  			doAnimation.finish = doAnimation;
  
  		return empty || optall.queue === false ?
  			this.each( doAnimation ) :
  			this.queue( optall.queue, doAnimation );
  	},
  	stop: function( type, clearQueue, gotoEnd ) {
  		var stopQueue = function( hooks ) {
  			var stop = hooks.stop;
  			delete hooks.stop;
  			stop( gotoEnd );
  		};
  
  		if ( typeof type !== "string" ) {
  			gotoEnd = clearQueue;
  			clearQueue = type;
  			type = undefined;
  		}
  		if ( clearQueue && type !== false ) {
  			this.queue( type || "fx", [] );
  		}
  
  		return this.each(function() {
  			var dequeue = true,
  				index = type != null && type + "queueHooks",
  				timers = jQuery.timers,
  				data = jQuery._data( this );
  
  			if ( index ) {
  				if ( data[ index ] && data[ index ].stop ) {
  					stopQueue( data[ index ] );
  				}
  			} else {
  				for ( index in data ) {
  					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
  						stopQueue( data[ index ] );
  					}
  				}
  			}
  
  			for ( index = timers.length; index--; ) {
  				if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
  					timers[ index ].anim.stop( gotoEnd );
  					dequeue = false;
  					timers.splice( index, 1 );
  				}
  			}
  
  			// start the next in the queue if the last step wasn't forced
  			// timers currently will call their complete callbacks, which will dequeue
  			// but only if they were gotoEnd
  			if ( dequeue || !gotoEnd ) {
  				jQuery.dequeue( this, type );
  			}
  		});
  	},
  	finish: function( type ) {
  		if ( type !== false ) {
  			type = type || "fx";
  		}
  		return this.each(function() {
  			var index,
  				data = jQuery._data( this ),
  				queue = data[ type + "queue" ],
  				hooks = data[ type + "queueHooks" ],
  				timers = jQuery.timers,
  				length = queue ? queue.length : 0;
  
  			// enable finishing flag on private data
  			data.finish = true;
  
  			// empty the queue first
  			jQuery.queue( this, type, [] );
  
  			if ( hooks && hooks.stop ) {
  				hooks.stop.call( this, true );
  			}
  
  			// look for any active animations, and finish them
  			for ( index = timers.length; index--; ) {
  				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
  					timers[ index ].anim.stop( true );
  					timers.splice( index, 1 );
  				}
  			}
  
  			// look for any animations in the old queue and finish them
  			for ( index = 0; index < length; index++ ) {
  				if ( queue[ index ] && queue[ index ].finish ) {
  					queue[ index ].finish.call( this );
  				}
  			}
  
  			// turn off finishing flag
  			delete data.finish;
  		});
  	}
  });
  
  jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
  	var cssFn = jQuery.fn[ name ];
  	jQuery.fn[ name ] = function( speed, easing, callback ) {
  		return speed == null || typeof speed === "boolean" ?
  			cssFn.apply( this, arguments ) :
  			this.animate( genFx( name, true ), speed, easing, callback );
  	};
  });
  
  // Generate shortcuts for custom animations
  jQuery.each({
  	slideDown: genFx("show"),
  	slideUp: genFx("hide"),
  	slideToggle: genFx("toggle"),
  	fadeIn: { opacity: "show" },
  	fadeOut: { opacity: "hide" },
  	fadeToggle: { opacity: "toggle" }
  }, function( name, props ) {
  	jQuery.fn[ name ] = function( speed, easing, callback ) {
  		return this.animate( props, speed, easing, callback );
  	};
  });
  
  jQuery.timers = [];
  jQuery.fx.tick = function() {
  	var timer,
  		timers = jQuery.timers,
  		i = 0;
  
  	fxNow = jQuery.now();
  
  	for ( ; i < timers.length; i++ ) {
  		timer = timers[ i ];
  		// Checks the timer has not already been removed
  		if ( !timer() && timers[ i ] === timer ) {
  			timers.splice( i--, 1 );
  		}
  	}
  
  	if ( !timers.length ) {
  		jQuery.fx.stop();
  	}
  	fxNow = undefined;
  };
  
  jQuery.fx.timer = function( timer ) {
  	jQuery.timers.push( timer );
  	if ( timer() ) {
  		jQuery.fx.start();
  	} else {
  		jQuery.timers.pop();
  	}
  };
  
  jQuery.fx.interval = 13;
  
  jQuery.fx.start = function() {
  	if ( !timerId ) {
  		timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
  	}
  };
  
  jQuery.fx.stop = function() {
  	clearInterval( timerId );
  	timerId = null;
  };
  
  jQuery.fx.speeds = {
  	slow: 600,
  	fast: 200,
  	// Default speed
  	_default: 400
  };
  
  
  // Based off of the plugin by Clint Helfers, with permission.
  // http://blindsignals.com/index.php/2009/07/jquery-delay/
  jQuery.fn.delay = function( time, type ) {
  	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
  	type = type || "fx";
  
  	return this.queue( type, function( next, hooks ) {
  		var timeout = setTimeout( next, time );
  		hooks.stop = function() {
  			clearTimeout( timeout );
  		};
  	});
  };
  
  
  (function() {
  	// Minified: var a,b,c,d,e
  	var input, div, select, a, opt;
  
  	// Setup
  	div = document.createElement( "div" );
  	div.setAttribute( "className", "t" );
  	div.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>";
  	a = div.getElementsByTagName("a")[ 0 ];
  
  	// First batch of tests.
  	select = document.createElement("select");
  	opt = select.appendChild( document.createElement("option") );
  	input = div.getElementsByTagName("input")[ 0 ];
  
  	a.style.cssText = "top:1px";
  
  	// Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
  	support.getSetAttribute = div.className !== "t";
  
  	// Get the style information from getAttribute
  	// (IE uses .cssText instead)
  	support.style = /top/.test( a.getAttribute("style") );
  
  	// Make sure that URLs aren't manipulated
  	// (IE normalizes it by default)
  	support.hrefNormalized = a.getAttribute("href") === "/a";
  
  	// Check the default checkbox/radio value ("" on WebKit; "on" elsewhere)
  	support.checkOn = !!input.value;
  
  	// Make sure that a selected-by-default option has a working selected property.
  	// (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
  	support.optSelected = opt.selected;
  
  	// Tests for enctype support on a form (#6743)
  	support.enctype = !!document.createElement("form").enctype;
  
  	// Make sure that the options inside disabled selects aren't marked as disabled
  	// (WebKit marks them as disabled)
  	select.disabled = true;
  	support.optDisabled = !opt.disabled;
  
  	// Support: IE8 only
  	// Check if we can trust getAttribute("value")
  	input = document.createElement( "input" );
  	input.setAttribute( "value", "" );
  	support.input = input.getAttribute( "value" ) === "";
  
  	// Check if an input maintains its value after becoming a radio
  	input.value = "t";
  	input.setAttribute( "type", "radio" );
  	support.radioValue = input.value === "t";
  })();
  
  
  var rreturn = /\r/g;
  
  jQuery.fn.extend({
  	val: function( value ) {
  		var hooks, ret, isFunction,
  			elem = this[0];
  
  		if ( !arguments.length ) {
  			if ( elem ) {
  				hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
  
  				if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
  					return ret;
  				}
  
  				ret = elem.value;
  
  				return typeof ret === "string" ?
  					// handle most common string cases
  					ret.replace(rreturn, "") :
  					// handle cases where value is null/undef or number
  					ret == null ? "" : ret;
  			}
  
  			return;
  		}
  
  		isFunction = jQuery.isFunction( value );
  
  		return this.each(function( i ) {
  			var val;
  
  			if ( this.nodeType !== 1 ) {
  				return;
  			}
  
  			if ( isFunction ) {
  				val = value.call( this, i, jQuery( this ).val() );
  			} else {
  				val = value;
  			}
  
  			// Treat null/undefined as ""; convert numbers to string
  			if ( val == null ) {
  				val = "";
  			} else if ( typeof val === "number" ) {
  				val += "";
  			} else if ( jQuery.isArray( val ) ) {
  				val = jQuery.map( val, function( value ) {
  					return value == null ? "" : value + "";
  				});
  			}
  
  			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
  
  			// If set returns undefined, fall back to normal setting
  			if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
  				this.value = val;
  			}
  		});
  	}
  });
  
  jQuery.extend({
  	valHooks: {
  		option: {
  			get: function( elem ) {
  				var val = jQuery.find.attr( elem, "value" );
  				return val != null ?
  					val :
  					// Support: IE10-11+
  					// option.text throws exceptions (#14686, #14858)
  					jQuery.trim( jQuery.text( elem ) );
  			}
  		},
  		select: {
  			get: function( elem ) {
  				var value, option,
  					options = elem.options,
  					index = elem.selectedIndex,
  					one = elem.type === "select-one" || index < 0,
  					values = one ? null : [],
  					max = one ? index + 1 : options.length,
  					i = index < 0 ?
  						max :
  						one ? index : 0;
  
  				// Loop through all the selected options
  				for ( ; i < max; i++ ) {
  					option = options[ i ];
  
  					// oldIE doesn't update selected after form reset (#2551)
  					if ( ( option.selected || i === index ) &&
  							// Don't return options that are disabled or in a disabled optgroup
  							( support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) &&
  							( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
  
  						// Get the specific value for the option
  						value = jQuery( option ).val();
  
  						// We don't need an array for one selects
  						if ( one ) {
  							return value;
  						}
  
  						// Multi-Selects return an array
  						values.push( value );
  					}
  				}
  
  				return values;
  			},
  
  			set: function( elem, value ) {
  				var optionSet, option,
  					options = elem.options,
  					values = jQuery.makeArray( value ),
  					i = options.length;
  
  				while ( i-- ) {
  					option = options[ i ];
  
  					if ( jQuery.inArray( jQuery.valHooks.option.get( option ), values ) >= 0 ) {
  
  						// Support: IE6
  						// When new option element is added to select box we need to
  						// force reflow of newly added node in order to workaround delay
  						// of initialization properties
  						try {
  							option.selected = optionSet = true;
  
  						} catch ( _ ) {
  
  							// Will be executed only in IE6
  							option.scrollHeight;
  						}
  
  					} else {
  						option.selected = false;
  					}
  				}
  
  				// Force browsers to behave consistently when non-matching value is set
  				if ( !optionSet ) {
  					elem.selectedIndex = -1;
  				}
  
  				return options;
  			}
  		}
  	}
  });
  
  // Radios and checkboxes getter/setter
  jQuery.each([ "radio", "checkbox" ], function() {
  	jQuery.valHooks[ this ] = {
  		set: function( elem, value ) {
  			if ( jQuery.isArray( value ) ) {
  				return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
  			}
  		}
  	};
  	if ( !support.checkOn ) {
  		jQuery.valHooks[ this ].get = function( elem ) {
  			// Support: Webkit
  			// "" is returned instead of "on" if a value isn't specified
  			return elem.getAttribute("value") === null ? "on" : elem.value;
  		};
  	}
  });
  
  
  
  
  var nodeHook, boolHook,
  	attrHandle = jQuery.expr.attrHandle,
  	ruseDefault = /^(?:checked|selected)$/i,
  	getSetAttribute = support.getSetAttribute,
  	getSetInput = support.input;
  
  jQuery.fn.extend({
  	attr: function( name, value ) {
  		return access( this, jQuery.attr, name, value, arguments.length > 1 );
  	},
  
  	removeAttr: function( name ) {
  		return this.each(function() {
  			jQuery.removeAttr( this, name );
  		});
  	}
  });
  
  jQuery.extend({
  	attr: function( elem, name, value ) {
  		var hooks, ret,
  			nType = elem.nodeType;
  
  		// don't get/set attributes on text, comment and attribute nodes
  		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  			return;
  		}
  
  		// Fallback to prop when attributes are not supported
  		if ( typeof elem.getAttribute === strundefined ) {
  			return jQuery.prop( elem, name, value );
  		}
  
  		// All attributes are lowercase
  		// Grab necessary hook if one is defined
  		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
  			name = name.toLowerCase();
  			hooks = jQuery.attrHooks[ name ] ||
  				( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
  		}
  
  		if ( value !== undefined ) {
  
  			if ( value === null ) {
  				jQuery.removeAttr( elem, name );
  
  			} else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
  				return ret;
  
  			} else {
  				elem.setAttribute( name, value + "" );
  				return value;
  			}
  
  		} else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
  			return ret;
  
  		} else {
  			ret = jQuery.find.attr( elem, name );
  
  			// Non-existent attributes return null, we normalize to undefined
  			return ret == null ?
  				undefined :
  				ret;
  		}
  	},
  
  	removeAttr: function( elem, value ) {
  		var name, propName,
  			i = 0,
  			attrNames = value && value.match( rnotwhite );
  
  		if ( attrNames && elem.nodeType === 1 ) {
  			while ( (name = attrNames[i++]) ) {
  				propName = jQuery.propFix[ name ] || name;
  
  				// Boolean attributes get special treatment (#10870)
  				if ( jQuery.expr.match.bool.test( name ) ) {
  					// Set corresponding property to false
  					if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
  						elem[ propName ] = false;
  					// Support: IE<9
  					// Also clear defaultChecked/defaultSelected (if appropriate)
  					} else {
  						elem[ jQuery.camelCase( "default-" + name ) ] =
  							elem[ propName ] = false;
  					}
  
  				// See #9699 for explanation of this approach (setting first, then removal)
  				} else {
  					jQuery.attr( elem, name, "" );
  				}
  
  				elem.removeAttribute( getSetAttribute ? name : propName );
  			}
  		}
  	},
  
  	attrHooks: {
  		type: {
  			set: function( elem, value ) {
  				if ( !support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
  					// Setting the type on a radio button after the value resets the value in IE6-9
  					// Reset value to default in case type is set after value during creation
  					var val = elem.value;
  					elem.setAttribute( "type", value );
  					if ( val ) {
  						elem.value = val;
  					}
  					return value;
  				}
  			}
  		}
  	}
  });
  
  // Hook for boolean attributes
  boolHook = {
  	set: function( elem, value, name ) {
  		if ( value === false ) {
  			// Remove boolean attributes when set to false
  			jQuery.removeAttr( elem, name );
  		} else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) {
  			// IE<8 needs the *property* name
  			elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name );
  
  		// Use defaultChecked and defaultSelected for oldIE
  		} else {
  			elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true;
  		}
  
  		return name;
  	}
  };
  
  // Retrieve booleans specially
  jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
  
  	var getter = attrHandle[ name ] || jQuery.find.attr;
  
  	attrHandle[ name ] = getSetInput && getSetAttribute || !ruseDefault.test( name ) ?
  		function( elem, name, isXML ) {
  			var ret, handle;
  			if ( !isXML ) {
  				// Avoid an infinite loop by temporarily removing this function from the getter
  				handle = attrHandle[ name ];
  				attrHandle[ name ] = ret;
  				ret = getter( elem, name, isXML ) != null ?
  					name.toLowerCase() :
  					null;
  				attrHandle[ name ] = handle;
  			}
  			return ret;
  		} :
  		function( elem, name, isXML ) {
  			if ( !isXML ) {
  				return elem[ jQuery.camelCase( "default-" + name ) ] ?
  					name.toLowerCase() :
  					null;
  			}
  		};
  });
  
  // fix oldIE attroperties
  if ( !getSetInput || !getSetAttribute ) {
  	jQuery.attrHooks.value = {
  		set: function( elem, value, name ) {
  			if ( jQuery.nodeName( elem, "input" ) ) {
  				// Does not return so that setAttribute is also used
  				elem.defaultValue = value;
  			} else {
  				// Use nodeHook if defined (#1954); otherwise setAttribute is fine
  				return nodeHook && nodeHook.set( elem, value, name );
  			}
  		}
  	};
  }
  
  // IE6/7 do not support getting/setting some attributes with get/setAttribute
  if ( !getSetAttribute ) {
  
  	// Use this for any attribute in IE6/7
  	// This fixes almost every IE6/7 issue
  	nodeHook = {
  		set: function( elem, value, name ) {
  			// Set the existing or create a new attribute node
  			var ret = elem.getAttributeNode( name );
  			if ( !ret ) {
  				elem.setAttributeNode(
  					(ret = elem.ownerDocument.createAttribute( name ))
  				);
  			}
  
  			ret.value = value += "";
  
  			// Break association with cloned elements by also using setAttribute (#9646)
  			if ( name === "value" || value === elem.getAttribute( name ) ) {
  				return value;
  			}
  		}
  	};
  
  	// Some attributes are constructed with empty-string values when not defined
  	attrHandle.id = attrHandle.name = attrHandle.coords =
  		function( elem, name, isXML ) {
  			var ret;
  			if ( !isXML ) {
  				return (ret = elem.getAttributeNode( name )) && ret.value !== "" ?
  					ret.value :
  					null;
  			}
  		};
  
  	// Fixing value retrieval on a button requires this module
  	jQuery.valHooks.button = {
  		get: function( elem, name ) {
  			var ret = elem.getAttributeNode( name );
  			if ( ret && ret.specified ) {
  				return ret.value;
  			}
  		},
  		set: nodeHook.set
  	};
  
  	// Set contenteditable to false on removals(#10429)
  	// Setting to empty string throws an error as an invalid value
  	jQuery.attrHooks.contenteditable = {
  		set: function( elem, value, name ) {
  			nodeHook.set( elem, value === "" ? false : value, name );
  		}
  	};
  
  	// Set width and height to auto instead of 0 on empty string( Bug #8150 )
  	// This is for removals
  	jQuery.each([ "width", "height" ], function( i, name ) {
  		jQuery.attrHooks[ name ] = {
  			set: function( elem, value ) {
  				if ( value === "" ) {
  					elem.setAttribute( name, "auto" );
  					return value;
  				}
  			}
  		};
  	});
  }
  
  if ( !support.style ) {
  	jQuery.attrHooks.style = {
  		get: function( elem ) {
  			// Return undefined in the case of empty string
  			// Note: IE uppercases css property names, but if we were to .toLowerCase()
  			// .cssText, that would destroy case senstitivity in URL's, like in "background"
  			return elem.style.cssText || undefined;
  		},
  		set: function( elem, value ) {
  			return ( elem.style.cssText = value + "" );
  		}
  	};
  }
  
  
  
  
  var rfocusable = /^(?:input|select|textarea|button|object)$/i,
  	rclickable = /^(?:a|area)$/i;
  
  jQuery.fn.extend({
  	prop: function( name, value ) {
  		return access( this, jQuery.prop, name, value, arguments.length > 1 );
  	},
  
  	removeProp: function( name ) {
  		name = jQuery.propFix[ name ] || name;
  		return this.each(function() {
  			// try/catch handles cases where IE balks (such as removing a property on window)
  			try {
  				this[ name ] = undefined;
  				delete this[ name ];
  			} catch( e ) {}
  		});
  	}
  });
  
  jQuery.extend({
  	propFix: {
  		"for": "htmlFor",
  		"class": "className"
  	},
  
  	prop: function( elem, name, value ) {
  		var ret, hooks, notxml,
  			nType = elem.nodeType;
  
  		// don't get/set properties on text, comment and attribute nodes
  		if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
  			return;
  		}
  
  		notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
  
  		if ( notxml ) {
  			// Fix name and attach hooks
  			name = jQuery.propFix[ name ] || name;
  			hooks = jQuery.propHooks[ name ];
  		}
  
  		if ( value !== undefined ) {
  			return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
  				ret :
  				( elem[ name ] = value );
  
  		} else {
  			return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
  				ret :
  				elem[ name ];
  		}
  	},
  
  	propHooks: {
  		tabIndex: {
  			get: function( elem ) {
  				// elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
  				// http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
  				// Use proper attribute retrieval(#12072)
  				var tabindex = jQuery.find.attr( elem, "tabindex" );
  
  				return tabindex ?
  					parseInt( tabindex, 10 ) :
  					rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
  						0 :
  						-1;
  			}
  		}
  	}
  });
  
  // Some attributes require a special call on IE
  // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
  if ( !support.hrefNormalized ) {
  	// href/src property should get the full normalized URL (#10299/#12915)
  	jQuery.each([ "href", "src" ], function( i, name ) {
  		jQuery.propHooks[ name ] = {
  			get: function( elem ) {
  				return elem.getAttribute( name, 4 );
  			}
  		};
  	});
  }
  
  // Support: Safari, IE9+
  // mis-reports the default selected property of an option
  // Accessing the parent's selectedIndex property fixes it
  if ( !support.optSelected ) {
  	jQuery.propHooks.selected = {
  		get: function( elem ) {
  			var parent = elem.parentNode;
  
  			if ( parent ) {
  				parent.selectedIndex;
  
  				// Make sure that it also works with optgroups, see #5701
  				if ( parent.parentNode ) {
  					parent.parentNode.selectedIndex;
  				}
  			}
  			return null;
  		}
  	};
  }
  
  jQuery.each([
  	"tabIndex",
  	"readOnly",
  	"maxLength",
  	"cellSpacing",
  	"cellPadding",
  	"rowSpan",
  	"colSpan",
  	"useMap",
  	"frameBorder",
  	"contentEditable"
  ], function() {
  	jQuery.propFix[ this.toLowerCase() ] = this;
  });
  
  // IE6/7 call enctype encoding
  if ( !support.enctype ) {
  	jQuery.propFix.enctype = "encoding";
  }
  
  
  
  
  var rclass = /[\t\r\n\f]/g;
  
  jQuery.fn.extend({
  	addClass: function( value ) {
  		var classes, elem, cur, clazz, j, finalValue,
  			i = 0,
  			len = this.length,
  			proceed = typeof value === "string" && value;
  
  		if ( jQuery.isFunction( value ) ) {
  			return this.each(function( j ) {
  				jQuery( this ).addClass( value.call( this, j, this.className ) );
  			});
  		}
  
  		if ( proceed ) {
  			// The disjunction here is for better compressibility (see removeClass)
  			classes = ( value || "" ).match( rnotwhite ) || [];
  
  			for ( ; i < len; i++ ) {
  				elem = this[ i ];
  				cur = elem.nodeType === 1 && ( elem.className ?
  					( " " + elem.className + " " ).replace( rclass, " " ) :
  					" "
  				);
  
  				if ( cur ) {
  					j = 0;
  					while ( (clazz = classes[j++]) ) {
  						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
  							cur += clazz + " ";
  						}
  					}
  
  					// only assign if different to avoid unneeded rendering.
  					finalValue = jQuery.trim( cur );
  					if ( elem.className !== finalValue ) {
  						elem.className = finalValue;
  					}
  				}
  			}
  		}
  
  		return this;
  	},
  
  	removeClass: function( value ) {
  		var classes, elem, cur, clazz, j, finalValue,
  			i = 0,
  			len = this.length,
  			proceed = arguments.length === 0 || typeof value === "string" && value;
  
  		if ( jQuery.isFunction( value ) ) {
  			return this.each(function( j ) {
  				jQuery( this ).removeClass( value.call( this, j, this.className ) );
  			});
  		}
  		if ( proceed ) {
  			classes = ( value || "" ).match( rnotwhite ) || [];
  
  			for ( ; i < len; i++ ) {
  				elem = this[ i ];
  				// This expression is here for better compressibility (see addClass)
  				cur = elem.nodeType === 1 && ( elem.className ?
  					( " " + elem.className + " " ).replace( rclass, " " ) :
  					""
  				);
  
  				if ( cur ) {
  					j = 0;
  					while ( (clazz = classes[j++]) ) {
  						// Remove *all* instances
  						while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
  							cur = cur.replace( " " + clazz + " ", " " );
  						}
  					}
  
  					// only assign if different to avoid unneeded rendering.
  					finalValue = value ? jQuery.trim( cur ) : "";
  					if ( elem.className !== finalValue ) {
  						elem.className = finalValue;
  					}
  				}
  			}
  		}
  
  		return this;
  	},
  
  	toggleClass: function( value, stateVal ) {
  		var type = typeof value;
  
  		if ( typeof stateVal === "boolean" && type === "string" ) {
  			return stateVal ? this.addClass( value ) : this.removeClass( value );
  		}
  
  		if ( jQuery.isFunction( value ) ) {
  			return this.each(function( i ) {
  				jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
  			});
  		}
  
  		return this.each(function() {
  			if ( type === "string" ) {
  				// toggle individual class names
  				var className,
  					i = 0,
  					self = jQuery( this ),
  					classNames = value.match( rnotwhite ) || [];
  
  				while ( (className = classNames[ i++ ]) ) {
  					// check each className given, space separated list
  					if ( self.hasClass( className ) ) {
  						self.removeClass( className );
  					} else {
  						self.addClass( className );
  					}
  				}
  
  			// Toggle whole class name
  			} else if ( type === strundefined || type === "boolean" ) {
  				if ( this.className ) {
  					// store className if set
  					jQuery._data( this, "__className__", this.className );
  				}
  
  				// If the element has a class name or if we're passed "false",
  				// then remove the whole classname (if there was one, the above saved it).
  				// Otherwise bring back whatever was previously saved (if anything),
  				// falling back to the empty string if nothing was stored.
  				this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
  			}
  		});
  	},
  
  	hasClass: function( selector ) {
  		var className = " " + selector + " ",
  			i = 0,
  			l = this.length;
  		for ( ; i < l; i++ ) {
  			if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
  				return true;
  			}
  		}
  
  		return false;
  	}
  });
  
  
  
  
  // Return jQuery for attributes-only inclusion
  
  
  jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
  	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
  	"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
  
  	// Handle event binding
  	jQuery.fn[ name ] = function( data, fn ) {
  		return arguments.length > 0 ?
  			this.on( name, null, data, fn ) :
  			this.trigger( name );
  	};
  });
  
  jQuery.fn.extend({
  	hover: function( fnOver, fnOut ) {
  		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
  	},
  
  	bind: function( types, data, fn ) {
  		return this.on( types, null, data, fn );
  	},
  	unbind: function( types, fn ) {
  		return this.off( types, null, fn );
  	},
  
  	delegate: function( selector, types, data, fn ) {
  		return this.on( types, selector, data, fn );
  	},
  	undelegate: function( selector, types, fn ) {
  		// ( namespace ) or ( selector, types [, fn] )
  		return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
  	}
  });
  
  
  var nonce = jQuery.now();
  
  var rquery = (/\?/);
  
  
  
  var rvalidtokens = /(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;
  
  jQuery.parseJSON = function( data ) {
  	// Attempt to parse using the native JSON parser first
  	if ( window.JSON && window.JSON.parse ) {
  		// Support: Android 2.3
  		// Workaround failure to string-cast null input
  		return window.JSON.parse( data + "" );
  	}
  
  	var requireNonComma,
  		depth = null,
  		str = jQuery.trim( data + "" );
  
  	// Guard against invalid (and possibly dangerous) input by ensuring that nothing remains
  	// after removing valid tokens
  	return str && !jQuery.trim( str.replace( rvalidtokens, function( token, comma, open, close ) {
  
  		// Force termination if we see a misplaced comma
  		if ( requireNonComma && comma ) {
  			depth = 0;
  		}
  
  		// Perform no more replacements after returning to outermost depth
  		if ( depth === 0 ) {
  			return token;
  		}
  
  		// Commas must not follow "[", "{", or ","
  		requireNonComma = open || comma;
  
  		// Determine new depth
  		// array/object open ("[" or "{"): depth += true - false (increment)
  		// array/object close ("]" or "}"): depth += false - true (decrement)
  		// other cases ("," or primitive): depth += true - true (numeric cast)
  		depth += !close - !open;
  
  		// Remove this token
  		return "";
  	}) ) ?
  		( Function( "return " + str ) )() :
  		jQuery.error( "Invalid JSON: " + data );
  };
  
  
  // Cross-browser xml parsing
  jQuery.parseXML = function( data ) {
  	var xml, tmp;
  	if ( !data || typeof data !== "string" ) {
  		return null;
  	}
  	try {
  		if ( window.DOMParser ) { // Standard
  			tmp = new DOMParser();
  			xml = tmp.parseFromString( data, "text/xml" );
  		} else { // IE
  			xml = new ActiveXObject( "Microsoft.XMLDOM" );
  			xml.async = "false";
  			xml.loadXML( data );
  		}
  	} catch( e ) {
  		xml = undefined;
  	}
  	if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
  		jQuery.error( "Invalid XML: " + data );
  	}
  	return xml;
  };
  
  
  var
  	// Document location
  	ajaxLocParts,
  	ajaxLocation,
  
  	rhash = /#.*$/,
  	rts = /([?&])_=[^&]*/,
  	rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
  	// #7653, #8125, #8152: local protocol detection
  	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
  	rnoContent = /^(?:GET|HEAD)$/,
  	rprotocol = /^\/\//,
  	rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
  
  	/* Prefilters
  	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
  	 * 2) These are called:
  	 *    - BEFORE asking for a transport
  	 *    - AFTER param serialization (s.data is a string if s.processData is true)
  	 * 3) key is the dataType
  	 * 4) the catchall symbol "*" can be used
  	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
  	 */
  	prefilters = {},
  
  	/* Transports bindings
  	 * 1) key is the dataType
  	 * 2) the catchall symbol "*" can be used
  	 * 3) selection will start with transport dataType and THEN go to "*" if needed
  	 */
  	transports = {},
  
  	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
  	allTypes = "*/".concat("*");
  
  // #8138, IE may throw an exception when accessing
  // a field from window.location if document.domain has been set
  try {
  	ajaxLocation = location.href;
  } catch( e ) {
  	// Use the href attribute of an A element
  	// since IE will modify it given document.location
  	ajaxLocation = document.createElement( "a" );
  	ajaxLocation.href = "";
  	ajaxLocation = ajaxLocation.href;
  }
  
  // Segment location into parts
  ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
  
  // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
  function addToPrefiltersOrTransports( structure ) {
  
  	// dataTypeExpression is optional and defaults to "*"
  	return function( dataTypeExpression, func ) {
  
  		if ( typeof dataTypeExpression !== "string" ) {
  			func = dataTypeExpression;
  			dataTypeExpression = "*";
  		}
  
  		var dataType,
  			i = 0,
  			dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
  
  		if ( jQuery.isFunction( func ) ) {
  			// For each dataType in the dataTypeExpression
  			while ( (dataType = dataTypes[i++]) ) {
  				// Prepend if requested
  				if ( dataType.charAt( 0 ) === "+" ) {
  					dataType = dataType.slice( 1 ) || "*";
  					(structure[ dataType ] = structure[ dataType ] || []).unshift( func );
  
  				// Otherwise append
  				} else {
  					(structure[ dataType ] = structure[ dataType ] || []).push( func );
  				}
  			}
  		}
  	};
  }
  
  // Base inspection function for prefilters and transports
  function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
  
  	var inspected = {},
  		seekingTransport = ( structure === transports );
  
  	function inspect( dataType ) {
  		var selected;
  		inspected[ dataType ] = true;
  		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
  			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
  			if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
  				options.dataTypes.unshift( dataTypeOrTransport );
  				inspect( dataTypeOrTransport );
  				return false;
  			} else if ( seekingTransport ) {
  				return !( selected = dataTypeOrTransport );
  			}
  		});
  		return selected;
  	}
  
  	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
  }
  
  // A special extend for ajax options
  // that takes "flat" options (not to be deep extended)
  // Fixes #9887
  function ajaxExtend( target, src ) {
  	var deep, key,
  		flatOptions = jQuery.ajaxSettings.flatOptions || {};
  
  	for ( key in src ) {
  		if ( src[ key ] !== undefined ) {
  			( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
  		}
  	}
  	if ( deep ) {
  		jQuery.extend( true, target, deep );
  	}
  
  	return target;
  }
  
  /* Handles responses to an ajax request:
   * - finds the right dataType (mediates between content-type and expected dataType)
   * - returns the corresponding response
   */
  function ajaxHandleResponses( s, jqXHR, responses ) {
  	var firstDataType, ct, finalDataType, type,
  		contents = s.contents,
  		dataTypes = s.dataTypes;
  
  	// Remove auto dataType and get content-type in the process
  	while ( dataTypes[ 0 ] === "*" ) {
  		dataTypes.shift();
  		if ( ct === undefined ) {
  			ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
  		}
  	}
  
  	// Check if we're dealing with a known content-type
  	if ( ct ) {
  		for ( type in contents ) {
  			if ( contents[ type ] && contents[ type ].test( ct ) ) {
  				dataTypes.unshift( type );
  				break;
  			}
  		}
  	}
  
  	// Check to see if we have a response for the expected dataType
  	if ( dataTypes[ 0 ] in responses ) {
  		finalDataType = dataTypes[ 0 ];
  	} else {
  		// Try convertible dataTypes
  		for ( type in responses ) {
  			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
  				finalDataType = type;
  				break;
  			}
  			if ( !firstDataType ) {
  				firstDataType = type;
  			}
  		}
  		// Or just use first one
  		finalDataType = finalDataType || firstDataType;
  	}
  
  	// If we found a dataType
  	// We add the dataType to the list if needed
  	// and return the corresponding response
  	if ( finalDataType ) {
  		if ( finalDataType !== dataTypes[ 0 ] ) {
  			dataTypes.unshift( finalDataType );
  		}
  		return responses[ finalDataType ];
  	}
  }
  
  /* Chain conversions given the request and the original response
   * Also sets the responseXXX fields on the jqXHR instance
   */
  function ajaxConvert( s, response, jqXHR, isSuccess ) {
  	var conv2, current, conv, tmp, prev,
  		converters = {},
  		// Work with a copy of dataTypes in case we need to modify it for conversion
  		dataTypes = s.dataTypes.slice();
  
  	// Create converters map with lowercased keys
  	if ( dataTypes[ 1 ] ) {
  		for ( conv in s.converters ) {
  			converters[ conv.toLowerCase() ] = s.converters[ conv ];
  		}
  	}
  
  	current = dataTypes.shift();
  
  	// Convert to each sequential dataType
  	while ( current ) {
  
  		if ( s.responseFields[ current ] ) {
  			jqXHR[ s.responseFields[ current ] ] = response;
  		}
  
  		// Apply the dataFilter if provided
  		if ( !prev && isSuccess && s.dataFilter ) {
  			response = s.dataFilter( response, s.dataType );
  		}
  
  		prev = current;
  		current = dataTypes.shift();
  
  		if ( current ) {
  
  			// There's only work to do if current dataType is non-auto
  			if ( current === "*" ) {
  
  				current = prev;
  
  			// Convert response if prev dataType is non-auto and differs from current
  			} else if ( prev !== "*" && prev !== current ) {
  
  				// Seek a direct converter
  				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
  
  				// If none found, seek a pair
  				if ( !conv ) {
  					for ( conv2 in converters ) {
  
  						// If conv2 outputs current
  						tmp = conv2.split( " " );
  						if ( tmp[ 1 ] === current ) {
  
  							// If prev can be converted to accepted input
  							conv = converters[ prev + " " + tmp[ 0 ] ] ||
  								converters[ "* " + tmp[ 0 ] ];
  							if ( conv ) {
  								// Condense equivalence converters
  								if ( conv === true ) {
  									conv = converters[ conv2 ];
  
  								// Otherwise, insert the intermediate dataType
  								} else if ( converters[ conv2 ] !== true ) {
  									current = tmp[ 0 ];
  									dataTypes.unshift( tmp[ 1 ] );
  								}
  								break;
  							}
  						}
  					}
  				}
  
  				// Apply converter (if not an equivalence)
  				if ( conv !== true ) {
  
  					// Unless errors are allowed to bubble, catch and return them
  					if ( conv && s[ "throws" ] ) {
  						response = conv( response );
  					} else {
  						try {
  							response = conv( response );
  						} catch ( e ) {
  							return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
  						}
  					}
  				}
  			}
  		}
  	}
  
  	return { state: "success", data: response };
  }
  
  jQuery.extend({
  
  	// Counter for holding the number of active queries
  	active: 0,
  
  	// Last-Modified header cache for next request
  	lastModified: {},
  	etag: {},
  
  	ajaxSettings: {
  		url: ajaxLocation,
  		type: "GET",
  		isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
  		global: true,
  		processData: true,
  		async: true,
  		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
  		/*
  		timeout: 0,
  		data: null,
  		dataType: null,
  		username: null,
  		password: null,
  		cache: null,
  		throws: false,
  		traditional: false,
  		headers: {},
  		*/
  
  		accepts: {
  			"*": allTypes,
  			text: "text/plain",
  			html: "text/html",
  			xml: "application/xml, text/xml",
  			json: "application/json, text/javascript"
  		},
  
  		contents: {
  			xml: /xml/,
  			html: /html/,
  			json: /json/
  		},
  
  		responseFields: {
  			xml: "responseXML",
  			text: "responseText",
  			json: "responseJSON"
  		},
  
  		// Data converters
  		// Keys separate source (or catchall "*") and destination types with a single space
  		converters: {
  
  			// Convert anything to text
  			"* text": String,
  
  			// Text to html (true = no transformation)
  			"text html": true,
  
  			// Evaluate text as a json expression
  			"text json": jQuery.parseJSON,
  
  			// Parse text as xml
  			"text xml": jQuery.parseXML
  		},
  
  		// For options that shouldn't be deep extended:
  		// you can add your own custom options here if
  		// and when you create one that shouldn't be
  		// deep extended (see ajaxExtend)
  		flatOptions: {
  			url: true,
  			context: true
  		}
  	},
  
  	// Creates a full fledged settings object into target
  	// with both ajaxSettings and settings fields.
  	// If target is omitted, writes into ajaxSettings.
  	ajaxSetup: function( target, settings ) {
  		return settings ?
  
  			// Building a settings object
  			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
  
  			// Extending ajaxSettings
  			ajaxExtend( jQuery.ajaxSettings, target );
  	},
  
  	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
  	ajaxTransport: addToPrefiltersOrTransports( transports ),
  
  	// Main method
  	ajax: function( url, options ) {
  
  		// If url is an object, simulate pre-1.5 signature
  		if ( typeof url === "object" ) {
  			options = url;
  			url = undefined;
  		}
  
  		// Force options to be an object
  		options = options || {};
  
  		var // Cross-domain detection vars
  			parts,
  			// Loop variable
  			i,
  			// URL without anti-cache param
  			cacheURL,
  			// Response headers as string
  			responseHeadersString,
  			// timeout handle
  			timeoutTimer,
  
  			// To know if global events are to be dispatched
  			fireGlobals,
  
  			transport,
  			// Response headers
  			responseHeaders,
  			// Create the final options object
  			s = jQuery.ajaxSetup( {}, options ),
  			// Callbacks context
  			callbackContext = s.context || s,
  			// Context for global events is callbackContext if it is a DOM node or jQuery collection
  			globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
  				jQuery( callbackContext ) :
  				jQuery.event,
  			// Deferreds
  			deferred = jQuery.Deferred(),
  			completeDeferred = jQuery.Callbacks("once memory"),
  			// Status-dependent callbacks
  			statusCode = s.statusCode || {},
  			// Headers (they are sent all at once)
  			requestHeaders = {},
  			requestHeadersNames = {},
  			// The jqXHR state
  			state = 0,
  			// Default abort message
  			strAbort = "canceled",
  			// Fake xhr
  			jqXHR = {
  				readyState: 0,
  
  				// Builds headers hashtable if needed
  				getResponseHeader: function( key ) {
  					var match;
  					if ( state === 2 ) {
  						if ( !responseHeaders ) {
  							responseHeaders = {};
  							while ( (match = rheaders.exec( responseHeadersString )) ) {
  								responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
  							}
  						}
  						match = responseHeaders[ key.toLowerCase() ];
  					}
  					return match == null ? null : match;
  				},
  
  				// Raw string
  				getAllResponseHeaders: function() {
  					return state === 2 ? responseHeadersString : null;
  				},
  
  				// Caches the header
  				setRequestHeader: function( name, value ) {
  					var lname = name.toLowerCase();
  					if ( !state ) {
  						name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
  						requestHeaders[ name ] = value;
  					}
  					return this;
  				},
  
  				// Overrides response content-type header
  				overrideMimeType: function( type ) {
  					if ( !state ) {
  						s.mimeType = type;
  					}
  					return this;
  				},
  
  				// Status-dependent callbacks
  				statusCode: function( map ) {
  					var code;
  					if ( map ) {
  						if ( state < 2 ) {
  							for ( code in map ) {
  								// Lazy-add the new callback in a way that preserves old ones
  								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
  							}
  						} else {
  							// Execute the appropriate callbacks
  							jqXHR.always( map[ jqXHR.status ] );
  						}
  					}
  					return this;
  				},
  
  				// Cancel the request
  				abort: function( statusText ) {
  					var finalText = statusText || strAbort;
  					if ( transport ) {
  						transport.abort( finalText );
  					}
  					done( 0, finalText );
  					return this;
  				}
  			};
  
  		// Attach deferreds
  		deferred.promise( jqXHR ).complete = completeDeferred.add;
  		jqXHR.success = jqXHR.done;
  		jqXHR.error = jqXHR.fail;
  
  		// Remove hash character (#7531: and string promotion)
  		// Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
  		// Handle falsy url in the settings object (#10093: consistency with old signature)
  		// We also use the url parameter if available
  		s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
  
  		// Alias method option to type as per ticket #12004
  		s.type = options.method || options.type || s.method || s.type;
  
  		// Extract dataTypes list
  		s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
  
  		// A cross-domain request is in order when we have a protocol:host:port mismatch
  		if ( s.crossDomain == null ) {
  			parts = rurl.exec( s.url.toLowerCase() );
  			s.crossDomain = !!( parts &&
  				( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
  					( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
  						( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
  			);
  		}
  
  		// Convert data if not already a string
  		if ( s.data && s.processData && typeof s.data !== "string" ) {
  			s.data = jQuery.param( s.data, s.traditional );
  		}
  
  		// Apply prefilters
  		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
  
  		// If request was aborted inside a prefilter, stop there
  		if ( state === 2 ) {
  			return jqXHR;
  		}
  
  		// We can fire global events as of now if asked to
  		fireGlobals = s.global;
  
  		// Watch for a new set of requests
  		if ( fireGlobals && jQuery.active++ === 0 ) {
  			jQuery.event.trigger("ajaxStart");
  		}
  
  		// Uppercase the type
  		s.type = s.type.toUpperCase();
  
  		// Determine if request has content
  		s.hasContent = !rnoContent.test( s.type );
  
  		// Save the URL in case we're toying with the If-Modified-Since
  		// and/or If-None-Match header later on
  		cacheURL = s.url;
  
  		// More options handling for requests with no content
  		if ( !s.hasContent ) {
  
  			// If data is available, append data to url
  			if ( s.data ) {
  				cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
  				// #9682: remove data so that it's not used in an eventual retry
  				delete s.data;
  			}
  
  			// Add anti-cache in url if needed
  			if ( s.cache === false ) {
  				s.url = rts.test( cacheURL ) ?
  
  					// If there is already a '_' parameter, set its value
  					cacheURL.replace( rts, "$1_=" + nonce++ ) :
  
  					// Otherwise add one to the end
  					cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
  			}
  		}
  
  		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  		if ( s.ifModified ) {
  			if ( jQuery.lastModified[ cacheURL ] ) {
  				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
  			}
  			if ( jQuery.etag[ cacheURL ] ) {
  				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
  			}
  		}
  
  		// Set the correct header, if data is being sent
  		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
  			jqXHR.setRequestHeader( "Content-Type", s.contentType );
  		}
  
  		// Set the Accepts header for the server, depending on the dataType
  		jqXHR.setRequestHeader(
  			"Accept",
  			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
  				s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
  				s.accepts[ "*" ]
  		);
  
  		// Check for headers option
  		for ( i in s.headers ) {
  			jqXHR.setRequestHeader( i, s.headers[ i ] );
  		}
  
  		// Allow custom headers/mimetypes and early abort
  		if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
  			// Abort if not done already and return
  			return jqXHR.abort();
  		}
  
  		// aborting is no longer a cancellation
  		strAbort = "abort";
  
  		// Install callbacks on deferreds
  		for ( i in { success: 1, error: 1, complete: 1 } ) {
  			jqXHR[ i ]( s[ i ] );
  		}
  
  		// Get transport
  		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
  
  		// If no transport, we auto-abort
  		if ( !transport ) {
  			done( -1, "No Transport" );
  		} else {
  			jqXHR.readyState = 1;
  
  			// Send global event
  			if ( fireGlobals ) {
  				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
  			}
  			// Timeout
  			if ( s.async && s.timeout > 0 ) {
  				timeoutTimer = setTimeout(function() {
  					jqXHR.abort("timeout");
  				}, s.timeout );
  			}
  
  			try {
  				state = 1;
  				transport.send( requestHeaders, done );
  			} catch ( e ) {
  				// Propagate exception as error if not done
  				if ( state < 2 ) {
  					done( -1, e );
  				// Simply rethrow otherwise
  				} else {
  					throw e;
  				}
  			}
  		}
  
  		// Callback for when everything is done
  		function done( status, nativeStatusText, responses, headers ) {
  			var isSuccess, success, error, response, modified,
  				statusText = nativeStatusText;
  
  			// Called once
  			if ( state === 2 ) {
  				return;
  			}
  
  			// State is "done" now
  			state = 2;
  
  			// Clear timeout if it exists
  			if ( timeoutTimer ) {
  				clearTimeout( timeoutTimer );
  			}
  
  			// Dereference transport for early garbage collection
  			// (no matter how long the jqXHR object will be used)
  			transport = undefined;
  
  			// Cache response headers
  			responseHeadersString = headers || "";
  
  			// Set readyState
  			jqXHR.readyState = status > 0 ? 4 : 0;
  
  			// Determine if successful
  			isSuccess = status >= 200 && status < 300 || status === 304;
  
  			// Get response data
  			if ( responses ) {
  				response = ajaxHandleResponses( s, jqXHR, responses );
  			}
  
  			// Convert no matter what (that way responseXXX fields are always set)
  			response = ajaxConvert( s, response, jqXHR, isSuccess );
  
  			// If successful, handle type chaining
  			if ( isSuccess ) {
  
  				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
  				if ( s.ifModified ) {
  					modified = jqXHR.getResponseHeader("Last-Modified");
  					if ( modified ) {
  						jQuery.lastModified[ cacheURL ] = modified;
  					}
  					modified = jqXHR.getResponseHeader("etag");
  					if ( modified ) {
  						jQuery.etag[ cacheURL ] = modified;
  					}
  				}
  
  				// if no content
  				if ( status === 204 || s.type === "HEAD" ) {
  					statusText = "nocontent";
  
  				// if not modified
  				} else if ( status === 304 ) {
  					statusText = "notmodified";
  
  				// If we have data, let's convert it
  				} else {
  					statusText = response.state;
  					success = response.data;
  					error = response.error;
  					isSuccess = !error;
  				}
  			} else {
  				// We extract error from statusText
  				// then normalize statusText and status for non-aborts
  				error = statusText;
  				if ( status || !statusText ) {
  					statusText = "error";
  					if ( status < 0 ) {
  						status = 0;
  					}
  				}
  			}
  
  			// Set data for the fake xhr object
  			jqXHR.status = status;
  			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
  
  			// Success/Error
  			if ( isSuccess ) {
  				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
  			} else {
  				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
  			}
  
  			// Status-dependent callbacks
  			jqXHR.statusCode( statusCode );
  			statusCode = undefined;
  
  			if ( fireGlobals ) {
  				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
  					[ jqXHR, s, isSuccess ? success : error ] );
  			}
  
  			// Complete
  			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
  
  			if ( fireGlobals ) {
  				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
  				// Handle the global AJAX counter
  				if ( !( --jQuery.active ) ) {
  					jQuery.event.trigger("ajaxStop");
  				}
  			}
  		}
  
  		return jqXHR;
  	},
  
  	getJSON: function( url, data, callback ) {
  		return jQuery.get( url, data, callback, "json" );
  	},
  
  	getScript: function( url, callback ) {
  		return jQuery.get( url, undefined, callback, "script" );
  	}
  });
  
  jQuery.each( [ "get", "post" ], function( i, method ) {
  	jQuery[ method ] = function( url, data, callback, type ) {
  		// shift arguments if data argument was omitted
  		if ( jQuery.isFunction( data ) ) {
  			type = type || callback;
  			callback = data;
  			data = undefined;
  		}
  
  		return jQuery.ajax({
  			url: url,
  			type: method,
  			dataType: type,
  			data: data,
  			success: callback
  		});
  	};
  });
  
  // Attach a bunch of functions for handling common AJAX events
  jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
  	jQuery.fn[ type ] = function( fn ) {
  		return this.on( type, fn );
  	};
  });
  
  
  jQuery._evalUrl = function( url ) {
  	return jQuery.ajax({
  		url: url,
  		type: "GET",
  		dataType: "script",
  		async: false,
  		global: false,
  		"throws": true
  	});
  };
  
  
  jQuery.fn.extend({
  	wrapAll: function( html ) {
  		if ( jQuery.isFunction( html ) ) {
  			return this.each(function(i) {
  				jQuery(this).wrapAll( html.call(this, i) );
  			});
  		}
  
  		if ( this[0] ) {
  			// The elements to wrap the target around
  			var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
  
  			if ( this[0].parentNode ) {
  				wrap.insertBefore( this[0] );
  			}
  
  			wrap.map(function() {
  				var elem = this;
  
  				while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
  					elem = elem.firstChild;
  				}
  
  				return elem;
  			}).append( this );
  		}
  
  		return this;
  	},
  
  	wrapInner: function( html ) {
  		if ( jQuery.isFunction( html ) ) {
  			return this.each(function(i) {
  				jQuery(this).wrapInner( html.call(this, i) );
  			});
  		}
  
  		return this.each(function() {
  			var self = jQuery( this ),
  				contents = self.contents();
  
  			if ( contents.length ) {
  				contents.wrapAll( html );
  
  			} else {
  				self.append( html );
  			}
  		});
  	},
  
  	wrap: function( html ) {
  		var isFunction = jQuery.isFunction( html );
  
  		return this.each(function(i) {
  			jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
  		});
  	},
  
  	unwrap: function() {
  		return this.parent().each(function() {
  			if ( !jQuery.nodeName( this, "body" ) ) {
  				jQuery( this ).replaceWith( this.childNodes );
  			}
  		}).end();
  	}
  });
  
  
  jQuery.expr.filters.hidden = function( elem ) {
  	// Support: Opera <= 12.12
  	// Opera reports offsetWidths and offsetHeights less than zero on some elements
  	return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 ||
  		(!support.reliableHiddenOffsets() &&
  			((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
  };
  
  jQuery.expr.filters.visible = function( elem ) {
  	return !jQuery.expr.filters.hidden( elem );
  };
  
  
  
  
  var r20 = /%20/g,
  	rbracket = /\[\]$/,
  	rCRLF = /\r?\n/g,
  	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
  	rsubmittable = /^(?:input|select|textarea|keygen)/i;
  
  function buildParams( prefix, obj, traditional, add ) {
  	var name;
  
  	if ( jQuery.isArray( obj ) ) {
  		// Serialize array item.
  		jQuery.each( obj, function( i, v ) {
  			if ( traditional || rbracket.test( prefix ) ) {
  				// Treat each array item as a scalar.
  				add( prefix, v );
  
  			} else {
  				// Item is non-scalar (array or object), encode its numeric index.
  				buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
  			}
  		});
  
  	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
  		// Serialize object item.
  		for ( name in obj ) {
  			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
  		}
  
  	} else {
  		// Serialize scalar item.
  		add( prefix, obj );
  	}
  }
  
  // Serialize an array of form elements or a set of
  // key/values into a query string
  jQuery.param = function( a, traditional ) {
  	var prefix,
  		s = [],
  		add = function( key, value ) {
  			// If value is a function, invoke it and return its value
  			value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
  			s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
  		};
  
  	// Set traditional to true for jQuery <= 1.3.2 behavior.
  	if ( traditional === undefined ) {
  		traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
  	}
  
  	// If an array was passed in, assume that it is an array of form elements.
  	if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
  		// Serialize the form elements
  		jQuery.each( a, function() {
  			add( this.name, this.value );
  		});
  
  	} else {
  		// If traditional, encode the "old" way (the way 1.3.2 or older
  		// did it), otherwise encode params recursively.
  		for ( prefix in a ) {
  			buildParams( prefix, a[ prefix ], traditional, add );
  		}
  	}
  
  	// Return the resulting serialization
  	return s.join( "&" ).replace( r20, "+" );
  };
  
  jQuery.fn.extend({
  	serialize: function() {
  		return jQuery.param( this.serializeArray() );
  	},
  	serializeArray: function() {
  		return this.map(function() {
  			// Can add propHook for "elements" to filter or add form elements
  			var elements = jQuery.prop( this, "elements" );
  			return elements ? jQuery.makeArray( elements ) : this;
  		})
  		.filter(function() {
  			var type = this.type;
  			// Use .is(":disabled") so that fieldset[disabled] works
  			return this.name && !jQuery( this ).is( ":disabled" ) &&
  				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
  				( this.checked || !rcheckableType.test( type ) );
  		})
  		.map(function( i, elem ) {
  			var val = jQuery( this ).val();
  
  			return val == null ?
  				null :
  				jQuery.isArray( val ) ?
  					jQuery.map( val, function( val ) {
  						return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  					}) :
  					{ name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
  		}).get();
  	}
  });
  
  
  // Create the request object
  // (This is still attached to ajaxSettings for backward compatibility)
  jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?
  	// Support: IE6+
  	function() {
  
  		// XHR cannot access local files, always use ActiveX for that case
  		return !this.isLocal &&
  
  			// Support: IE7-8
  			// oldIE XHR does not support non-RFC2616 methods (#13240)
  			// See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
  			// and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
  			// Although this check for six methods instead of eight
  			// since IE also does not support "trace" and "connect"
  			/^(get|post|head|put|delete|options)$/i.test( this.type ) &&
  
  			createStandardXHR() || createActiveXHR();
  	} :
  	// For all other browsers, use the standard XMLHttpRequest object
  	createStandardXHR;
  
  var xhrId = 0,
  	xhrCallbacks = {},
  	xhrSupported = jQuery.ajaxSettings.xhr();
  
  // Support: IE<10
  // Open requests must be manually aborted on unload (#5280)
  if ( window.ActiveXObject ) {
  	jQuery( window ).on( "unload", function() {
  		for ( var key in xhrCallbacks ) {
  			xhrCallbacks[ key ]( undefined, true );
  		}
  	});
  }
  
  // Determine support properties
  support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
  xhrSupported = support.ajax = !!xhrSupported;
  
  // Create transport if the browser can provide an xhr
  if ( xhrSupported ) {
  
  	jQuery.ajaxTransport(function( options ) {
  		// Cross domain only allowed if supported through XMLHttpRequest
  		if ( !options.crossDomain || support.cors ) {
  
  			var callback;
  
  			return {
  				send: function( headers, complete ) {
  					var i,
  						xhr = options.xhr(),
  						id = ++xhrId;
  
  					// Open the socket
  					xhr.open( options.type, options.url, options.async, options.username, options.password );
  
  					// Apply custom fields if provided
  					if ( options.xhrFields ) {
  						for ( i in options.xhrFields ) {
  							xhr[ i ] = options.xhrFields[ i ];
  						}
  					}
  
  					// Override mime type if needed
  					if ( options.mimeType && xhr.overrideMimeType ) {
  						xhr.overrideMimeType( options.mimeType );
  					}
  
  					// X-Requested-With header
  					// For cross-domain requests, seeing as conditions for a preflight are
  					// akin to a jigsaw puzzle, we simply never set it to be sure.
  					// (it can always be set on a per-request basis or even using ajaxSetup)
  					// For same-domain requests, won't change header if already provided.
  					if ( !options.crossDomain && !headers["X-Requested-With"] ) {
  						headers["X-Requested-With"] = "XMLHttpRequest";
  					}
  
  					// Set headers
  					for ( i in headers ) {
  						// Support: IE<9
  						// IE's ActiveXObject throws a 'Type Mismatch' exception when setting
  						// request header to a null-value.
  						//
  						// To keep consistent with other XHR implementations, cast the value
  						// to string and ignore `undefined`.
  						if ( headers[ i ] !== undefined ) {
  							xhr.setRequestHeader( i, headers[ i ] + "" );
  						}
  					}
  
  					// Do send the request
  					// This may raise an exception which is actually
  					// handled in jQuery.ajax (so no try/catch here)
  					xhr.send( ( options.hasContent && options.data ) || null );
  
  					// Listener
  					callback = function( _, isAbort ) {
  						var status, statusText, responses;
  
  						// Was never called and is aborted or complete
  						if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
  							// Clean up
  							delete xhrCallbacks[ id ];
  							callback = undefined;
  							xhr.onreadystatechange = jQuery.noop;
  
  							// Abort manually if needed
  							if ( isAbort ) {
  								if ( xhr.readyState !== 4 ) {
  									xhr.abort();
  								}
  							} else {
  								responses = {};
  								status = xhr.status;
  
  								// Support: IE<10
  								// Accessing binary-data responseText throws an exception
  								// (#11426)
  								if ( typeof xhr.responseText === "string" ) {
  									responses.text = xhr.responseText;
  								}
  
  								// Firefox throws an exception when accessing
  								// statusText for faulty cross-domain requests
  								try {
  									statusText = xhr.statusText;
  								} catch( e ) {
  									// We normalize with Webkit giving an empty statusText
  									statusText = "";
  								}
  
  								// Filter status for non standard behaviors
  
  								// If the request is local and we have data: assume a success
  								// (success with no data won't get notified, that's the best we
  								// can do given current implementations)
  								if ( !status && options.isLocal && !options.crossDomain ) {
  									status = responses.text ? 200 : 404;
  								// IE - #1450: sometimes returns 1223 when it should be 204
  								} else if ( status === 1223 ) {
  									status = 204;
  								}
  							}
  						}
  
  						// Call complete if needed
  						if ( responses ) {
  							complete( status, statusText, responses, xhr.getAllResponseHeaders() );
  						}
  					};
  
  					if ( !options.async ) {
  						// if we're in sync mode we fire the callback
  						callback();
  					} else if ( xhr.readyState === 4 ) {
  						// (IE6 & IE7) if it's in cache and has been
  						// retrieved directly we need to fire the callback
  						setTimeout( callback );
  					} else {
  						// Add to the list of active xhr callbacks
  						xhr.onreadystatechange = xhrCallbacks[ id ] = callback;
  					}
  				},
  
  				abort: function() {
  					if ( callback ) {
  						callback( undefined, true );
  					}
  				}
  			};
  		}
  	});
  }
  
  // Functions to create xhrs
  function createStandardXHR() {
  	try {
  		return new window.XMLHttpRequest();
  	} catch( e ) {}
  }
  
  function createActiveXHR() {
  	try {
  		return new window.ActiveXObject( "Microsoft.XMLHTTP" );
  	} catch( e ) {}
  }
  
  
  
  
  // Install script dataType
  jQuery.ajaxSetup({
  	accepts: {
  		script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
  	},
  	contents: {
  		script: /(?:java|ecma)script/
  	},
  	converters: {
  		"text script": function( text ) {
  			jQuery.globalEval( text );
  			return text;
  		}
  	}
  });
  
  // Handle cache's special case and global
  jQuery.ajaxPrefilter( "script", function( s ) {
  	if ( s.cache === undefined ) {
  		s.cache = false;
  	}
  	if ( s.crossDomain ) {
  		s.type = "GET";
  		s.global = false;
  	}
  });
  
  // Bind script tag hack transport
  jQuery.ajaxTransport( "script", function(s) {
  
  	// This transport only deals with cross domain requests
  	if ( s.crossDomain ) {
  
  		var script,
  			head = document.head || jQuery("head")[0] || document.documentElement;
  
  		return {
  
  			send: function( _, callback ) {
  
  				script = document.createElement("script");
  
  				script.async = true;
  
  				if ( s.scriptCharset ) {
  					script.charset = s.scriptCharset;
  				}
  
  				script.src = s.url;
  
  				// Attach handlers for all browsers
  				script.onload = script.onreadystatechange = function( _, isAbort ) {
  
  					if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
  
  						// Handle memory leak in IE
  						script.onload = script.onreadystatechange = null;
  
  						// Remove the script
  						if ( script.parentNode ) {
  							script.parentNode.removeChild( script );
  						}
  
  						// Dereference the script
  						script = null;
  
  						// Callback if not abort
  						if ( !isAbort ) {
  							callback( 200, "success" );
  						}
  					}
  				};
  
  				// Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending
  				// Use native DOM manipulation to avoid our domManip AJAX trickery
  				head.insertBefore( script, head.firstChild );
  			},
  
  			abort: function() {
  				if ( script ) {
  					script.onload( undefined, true );
  				}
  			}
  		};
  	}
  });
  
  
  
  
  var oldCallbacks = [],
  	rjsonp = /(=)\?(?=&|$)|\?\?/;
  
  // Default jsonp settings
  jQuery.ajaxSetup({
  	jsonp: "callback",
  	jsonpCallback: function() {
  		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
  		this[ callback ] = true;
  		return callback;
  	}
  });
  
  // Detect, normalize options and install callbacks for jsonp requests
  jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
  
  	var callbackName, overwritten, responseContainer,
  		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
  			"url" :
  			typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
  		);
  
  	// Handle iff the expected data type is "jsonp" or we have a parameter to set
  	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
  
  		// Get callback name, remembering preexisting value associated with it
  		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
  			s.jsonpCallback() :
  			s.jsonpCallback;
  
  		// Insert callback into url or form data
  		if ( jsonProp ) {
  			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
  		} else if ( s.jsonp !== false ) {
  			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
  		}
  
  		// Use data converter to retrieve json after script execution
  		s.converters["script json"] = function() {
  			if ( !responseContainer ) {
  				jQuery.error( callbackName + " was not called" );
  			}
  			return responseContainer[ 0 ];
  		};
  
  		// force json dataType
  		s.dataTypes[ 0 ] = "json";
  
  		// Install callback
  		overwritten = window[ callbackName ];
  		window[ callbackName ] = function() {
  			responseContainer = arguments;
  		};
  
  		// Clean-up function (fires after converters)
  		jqXHR.always(function() {
  			// Restore preexisting value
  			window[ callbackName ] = overwritten;
  
  			// Save back as free
  			if ( s[ callbackName ] ) {
  				// make sure that re-using the options doesn't screw things around
  				s.jsonpCallback = originalSettings.jsonpCallback;
  
  				// save the callback name for future use
  				oldCallbacks.push( callbackName );
  			}
  
  			// Call if it was a function and we have a response
  			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
  				overwritten( responseContainer[ 0 ] );
  			}
  
  			responseContainer = overwritten = undefined;
  		});
  
  		// Delegate to script
  		return "script";
  	}
  });
  
  
  
  
  // data: string of html
  // context (optional): If specified, the fragment will be created in this context, defaults to document
  // keepScripts (optional): If true, will include scripts passed in the html string
  jQuery.parseHTML = function( data, context, keepScripts ) {
  	if ( !data || typeof data !== "string" ) {
  		return null;
  	}
  	if ( typeof context === "boolean" ) {
  		keepScripts = context;
  		context = false;
  	}
  	context = context || document;
  
  	var parsed = rsingleTag.exec( data ),
  		scripts = !keepScripts && [];
  
  	// Single tag
  	if ( parsed ) {
  		return [ context.createElement( parsed[1] ) ];
  	}
  
  	parsed = jQuery.buildFragment( [ data ], context, scripts );
  
  	if ( scripts && scripts.length ) {
  		jQuery( scripts ).remove();
  	}
  
  	return jQuery.merge( [], parsed.childNodes );
  };
  
  
  // Keep a copy of the old load method
  var _load = jQuery.fn.load;
  
  /**
   * Load a url into a page
   */
  jQuery.fn.load = function( url, params, callback ) {
  	if ( typeof url !== "string" && _load ) {
  		return _load.apply( this, arguments );
  	}
  
  	var selector, response, type,
  		self = this,
  		off = url.indexOf(" ");
  
  	if ( off >= 0 ) {
  		selector = jQuery.trim( url.slice( off, url.length ) );
  		url = url.slice( 0, off );
  	}
  
  	// If it's a function
  	if ( jQuery.isFunction( params ) ) {
  
  		// We assume that it's the callback
  		callback = params;
  		params = undefined;
  
  	// Otherwise, build a param string
  	} else if ( params && typeof params === "object" ) {
  		type = "POST";
  	}
  
  	// If we have elements to modify, make the request
  	if ( self.length > 0 ) {
  		jQuery.ajax({
  			url: url,
  
  			// if "type" variable is undefined, then "GET" method will be used
  			type: type,
  			dataType: "html",
  			data: params
  		}).done(function( responseText ) {
  
  			// Save response for use in complete callback
  			response = arguments;
  
  			self.html( selector ?
  
  				// If a selector was specified, locate the right elements in a dummy div
  				// Exclude scripts to avoid IE 'Permission Denied' errors
  				jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
  
  				// Otherwise use the full result
  				responseText );
  
  		}).complete( callback && function( jqXHR, status ) {
  			self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
  		});
  	}
  
  	return this;
  };
  
  
  
  
  jQuery.expr.filters.animated = function( elem ) {
  	return jQuery.grep(jQuery.timers, function( fn ) {
  		return elem === fn.elem;
  	}).length;
  };
  
  
  
  
  
  var docElem = window.document.documentElement;
  
  /**
   * Gets a window from an element
   */
  function getWindow( elem ) {
  	return jQuery.isWindow( elem ) ?
  		elem :
  		elem.nodeType === 9 ?
  			elem.defaultView || elem.parentWindow :
  			false;
  }
  
  jQuery.offset = {
  	setOffset: function( elem, options, i ) {
  		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
  			position = jQuery.css( elem, "position" ),
  			curElem = jQuery( elem ),
  			props = {};
  
  		// set position first, in-case top/left are set even on static elem
  		if ( position === "static" ) {
  			elem.style.position = "relative";
  		}
  
  		curOffset = curElem.offset();
  		curCSSTop = jQuery.css( elem, "top" );
  		curCSSLeft = jQuery.css( elem, "left" );
  		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
  			jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
  
  		// need to be able to calculate position if either top or left is auto and position is either absolute or fixed
  		if ( calculatePosition ) {
  			curPosition = curElem.position();
  			curTop = curPosition.top;
  			curLeft = curPosition.left;
  		} else {
  			curTop = parseFloat( curCSSTop ) || 0;
  			curLeft = parseFloat( curCSSLeft ) || 0;
  		}
  
  		if ( jQuery.isFunction( options ) ) {
  			options = options.call( elem, i, curOffset );
  		}
  
  		if ( options.top != null ) {
  			props.top = ( options.top - curOffset.top ) + curTop;
  		}
  		if ( options.left != null ) {
  			props.left = ( options.left - curOffset.left ) + curLeft;
  		}
  
  		if ( "using" in options ) {
  			options.using.call( elem, props );
  		} else {
  			curElem.css( props );
  		}
  	}
  };
  
  jQuery.fn.extend({
  	offset: function( options ) {
  		if ( arguments.length ) {
  			return options === undefined ?
  				this :
  				this.each(function( i ) {
  					jQuery.offset.setOffset( this, options, i );
  				});
  		}
  
  		var docElem, win,
  			box = { top: 0, left: 0 },
  			elem = this[ 0 ],
  			doc = elem && elem.ownerDocument;
  
  		if ( !doc ) {
  			return;
  		}
  
  		docElem = doc.documentElement;
  
  		// Make sure it's not a disconnected DOM node
  		if ( !jQuery.contains( docElem, elem ) ) {
  			return box;
  		}
  
  		// If we don't have gBCR, just use 0,0 rather than error
  		// BlackBerry 5, iOS 3 (original iPhone)
  		if ( typeof elem.getBoundingClientRect !== strundefined ) {
  			box = elem.getBoundingClientRect();
  		}
  		win = getWindow( doc );
  		return {
  			top: box.top  + ( win.pageYOffset || docElem.scrollTop )  - ( docElem.clientTop  || 0 ),
  			left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
  		};
  	},
  
  	position: function() {
  		if ( !this[ 0 ] ) {
  			return;
  		}
  
  		var offsetParent, offset,
  			parentOffset = { top: 0, left: 0 },
  			elem = this[ 0 ];
  
  		// fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
  		if ( jQuery.css( elem, "position" ) === "fixed" ) {
  			// we assume that getBoundingClientRect is available when computed position is fixed
  			offset = elem.getBoundingClientRect();
  		} else {
  			// Get *real* offsetParent
  			offsetParent = this.offsetParent();
  
  			// Get correct offsets
  			offset = this.offset();
  			if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
  				parentOffset = offsetParent.offset();
  			}
  
  			// Add offsetParent borders
  			parentOffset.top  += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
  			parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
  		}
  
  		// Subtract parent offsets and element margins
  		// note: when an element has margin: auto the offsetLeft and marginLeft
  		// are the same in Safari causing offset.left to incorrectly be 0
  		return {
  			top:  offset.top  - parentOffset.top - jQuery.css( elem, "marginTop", true ),
  			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
  		};
  	},
  
  	offsetParent: function() {
  		return this.map(function() {
  			var offsetParent = this.offsetParent || docElem;
  
  			while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
  				offsetParent = offsetParent.offsetParent;
  			}
  			return offsetParent || docElem;
  		});
  	}
  });
  
  // Create scrollLeft and scrollTop methods
  jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
  	var top = /Y/.test( prop );
  
  	jQuery.fn[ method ] = function( val ) {
  		return access( this, function( elem, method, val ) {
  			var win = getWindow( elem );
  
  			if ( val === undefined ) {
  				return win ? (prop in win) ? win[ prop ] :
  					win.document.documentElement[ method ] :
  					elem[ method ];
  			}
  
  			if ( win ) {
  				win.scrollTo(
  					!top ? val : jQuery( win ).scrollLeft(),
  					top ? val : jQuery( win ).scrollTop()
  				);
  
  			} else {
  				elem[ method ] = val;
  			}
  		}, method, val, arguments.length, null );
  	};
  });
  
  // Add the top/left cssHooks using jQuery.fn.position
  // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
  // getComputedStyle returns percent when specified for top/left/bottom/right
  // rather than make the css module depend on the offset module, we just check for it here
  jQuery.each( [ "top", "left" ], function( i, prop ) {
  	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
  		function( elem, computed ) {
  			if ( computed ) {
  				computed = curCSS( elem, prop );
  				// if curCSS returns percentage, fallback to offset
  				return rnumnonpx.test( computed ) ?
  					jQuery( elem ).position()[ prop ] + "px" :
  					computed;
  			}
  		}
  	);
  });
  
  
  // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
  jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
  	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
  		// margin is only for outerHeight, outerWidth
  		jQuery.fn[ funcName ] = function( margin, value ) {
  			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
  				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
  
  			return access( this, function( elem, type, value ) {
  				var doc;
  
  				if ( jQuery.isWindow( elem ) ) {
  					// As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
  					// isn't a whole lot we can do. See pull request at this URL for discussion:
  					// https://github.com/jquery/jquery/pull/764
  					return elem.document.documentElement[ "client" + name ];
  				}
  
  				// Get document width or height
  				if ( elem.nodeType === 9 ) {
  					doc = elem.documentElement;
  
  					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
  					// unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
  					return Math.max(
  						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
  						elem.body[ "offset" + name ], doc[ "offset" + name ],
  						doc[ "client" + name ]
  					);
  				}
  
  				return value === undefined ?
  					// Get width or height on the element, requesting but not forcing parseFloat
  					jQuery.css( elem, type, extra ) :
  
  					// Set width or height on the element
  					jQuery.style( elem, type, value, extra );
  			}, type, chainable ? margin : undefined, chainable, null );
  		};
  	});
  });
  
  
  // The number of elements contained in the matched element set
  jQuery.fn.size = function() {
  	return this.length;
  };
  
  jQuery.fn.andSelf = jQuery.fn.addBack;
  
  
  
  
  // Register as a named AMD module, since jQuery can be concatenated with other
  // files that may use define, but not via a proper concatenation script that
  // understands anonymous AMD modules. A named AMD is safest and most robust
  // way to register. Lowercase jquery is used because AMD module names are
  // derived from file names, and jQuery is normally delivered in a lowercase
  // file name. Do this after creating the global so that if an AMD module wants
  // to call noConflict to hide this version of jQuery, it will work.
  
  // Note that for maximum portability, libraries that are not jQuery should
  // declare themselves as anonymous modules, and avoid setting a global if an
  // AMD loader is present. jQuery is a special case. For more information, see
  // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
  
  if ( typeof define === "function" && define.amd ) {
  	define( "jquery", [], function() {
  		return jQuery;
  	});
  }
  
  
  
  
  var
  	// Map over jQuery in case of overwrite
  	_jQuery = window.jQuery,
  
  	// Map over the $ in case of overwrite
  	_$ = window.$;
  
  jQuery.noConflict = function( deep ) {
  	if ( window.$ === jQuery ) {
  		window.$ = _$;
  	}
  
  	if ( deep && window.jQuery === jQuery ) {
  		window.jQuery = _jQuery;
  	}
  
  	return jQuery;
  };
  
  // Expose jQuery and $ identifiers, even in
  // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
  // and CommonJS for browser emulators (#13566)
  if ( typeof noGlobal === strundefined ) {
  	window.jQuery = window.$ = jQuery;
  }
  
  
  
  
  return jQuery;
  
  }));
  /*!
   * SAP UI development toolkit for HTML5 (SAPUI5/OpenUI5)
   * (c) Copyright 2009-2015 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  /** 
   * Device and Feature Detection API of the SAP UI5 Library.
   *
   * @version 1.28.5
   * @namespace
   * @name sap.ui.Device
   * @public
   */
  
  /*global console */
  
  //Declare Module if API is available
  if (window.jQuery && window.jQuery.sap && window.jQuery.sap.declare) {
  	window.jQuery.sap.declare("sap.ui.Device", false);
  }
  
  //Introduce namespace if it does not yet exist
  if (typeof window.sap !== "object" && typeof window.sap !== "function" ) {
  	  window.sap = {};
  }
  if (typeof window.sap.ui !== "object") {
  	window.sap.ui = {};
  }
  
  (function() {
  
  	//Skip initialization if API is already available
  	if (typeof window.sap.ui.Device === "object" || typeof window.sap.ui.Device === "function" ) {
  		var apiVersion = "1.28.5";
  		window.sap.ui.Device._checkAPIVersion(apiVersion);
  		return;
  	}
  	
  	var device = {};
  
  ////-------------------------- Logging -------------------------------------
  	/* since we cannot use the logging from jquery.sap.global.js, we need to come up with a seperate
  	 * solution for the device API
  	 */
  	// helper function for date formatting
  	function pad0(i,w) {
  		return ("000" + String(i)).slice(-w);
  	}
  
  	var FATAL = 0, ERROR = 1, WARNING = 2, INFO = 3, DEBUG = 4, TRACE = 5;
  
  	var deviceLogger = function() {
  		this.defaultComponent = 'DEVICE';
  		this.sWindowName = (window.top == window) ? "" : "[" + window.location.pathname.split('/').slice(-1)[0] + "] ";
  	// Creates a new log entry depending on its level and component.
  		this.log = function (iLevel, sMessage, sComponent) {
  			sComponent = sComponent || this.defaultComponent  || '';
  				var oNow = new Date(),
  					oLogEntry = {
  						time     : pad0(oNow.getHours(),2) + ":" + pad0(oNow.getMinutes(),2) + ":" + pad0(oNow.getSeconds(),2),
  						date     : pad0(oNow.getFullYear(),4) + "-" + pad0(oNow.getMonth() + 1,2) + "-" + pad0(oNow.getDate(),2),
  						timestamp: oNow.getTime(),
  						level    : iLevel,
  						message  : sMessage || "",
  						component: sComponent || ""
  					};
  				/*eslint-disable no-console */
  				if (window.console) { // in IE and FF, console might not exist; in FF it might even disappear
  					var logText = oLogEntry.date + " " + oLogEntry.time + " " + this.sWindowName + oLogEntry.message + " - " + oLogEntry.component;
  					switch (iLevel) {
  					case FATAL:
  					case ERROR: console.error(logText); break;
  					case WARNING: console.warn(logText); break;
  					case INFO: console.info ? console.info(logText) : console.log(logText); break;    // info not available in iOS simulator
  					case DEBUG: console.debug ? console.debug(logText) : console.log(logText); break; // debug not available in IE, fallback to log
  					case TRACE: console.trace ? console.trace(logText) : console.log(logText); break; // trace not available in IE, fallback to log (no trace)
  					}
  				}
  				/*eslint-enable no-console */
  				return oLogEntry;
  		};
  	};
  // instantiate new logger		
  	var logger = new deviceLogger();
  	logger.log(INFO, "Device API logging initialized");
  	
  	
  //******** Version Check ********
  	
  	//Only used internal to make clear when Device API is loaded in wrong version
  	device._checkAPIVersion = function(sVersion){
  		var v = "1.28.5";
  		if (v != sVersion) {
  			logger.log(WARNING, "Device API version differs: " + v + " <-> " + sVersion);
  		}
  	};
  
  
  //******** Event Management ******** (see Event Provider)
  
  	var mEventRegistry = {};
  
  	function attachEvent(sEventId, fnFunction, oListener) {
  		if (!mEventRegistry[sEventId]) {
  			mEventRegistry[sEventId] = [];
  		}
  		mEventRegistry[sEventId].push({oListener: oListener, fFunction:fnFunction});
  	}
  
  	function detachEvent(sEventId, fnFunction, oListener) {
  		var aEventListeners = mEventRegistry[sEventId];
  		
  		if (!aEventListeners) {
  			return this;
  		}
  
  		for (var i = 0, iL = aEventListeners.length; i < iL; i++) {
  			if (aEventListeners[i].fFunction === fnFunction && aEventListeners[i].oListener === oListener) {
  				aEventListeners.splice(i,1);
  				break;
  			}
  		}
  		if (aEventListeners.length == 0) {
  			delete mEventRegistry[sEventId];
  		}
  	}
  
  	function fireEvent(sEventId, mParameters) {
  		var aEventListeners = mEventRegistry[sEventId], oInfo;
  		if (aEventListeners) {
  			aEventListeners = aEventListeners.slice();
  			for (var i = 0, iL = aEventListeners.length; i < iL; i++) {
  				oInfo = aEventListeners[i];
  				oInfo.fFunction.call(oInfo.oListener || window, mParameters);
  			}
  		}
  	}
  
  //******** OS Detection ********
  
  	/** 
  	 * Contains information about the operating system of the device.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.os
  	 * @public
  	 */
  	/**
  	 * Enumeration containing the names of known operating systems.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.os.OS
  	 * @public
  	 */
  	/**
  	 * The name of the operating system.
  	 * 
  	 * @see sap.ui.Device.os#OS
  	 * @name sap.ui.Device.os#name
  	 * @type String
  	 * @public
  	 */
  	/**
  	 * The version as string. Might be empty if no version can be determined.
  	 * 
  	 * @name sap.ui.Device.os#versionStr
  	 * @type String
  	 * @public
  	 */
  	/**
  	 * The version as float. Might be -1 if no version can be determined.
  	 * 
  	 * @name sap.ui.Device.os#version
  	 * @type float
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Windows operating system.
  	 * 
  	 * @name sap.ui.Device.os#windows
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Linux operating system.
  	 * 
  	 * @name sap.ui.Device.os#linux
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the MAC operating system.
  	 * 
  	 * @name sap.ui.Device.os#macintosh
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the iOS operating system.
  	 * 
  	 * @name sap.ui.Device.os#ios
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Android operating system.
  	 * 
  	 * @name sap.ui.Device.os#android
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Blackberry operating system.
  	 * 
  	 * @name sap.ui.Device.os#blackberry
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Windows Phone operating system.
  	 * 
  	 * @name sap.ui.Device.os#windows_phone
  	 * @type boolean
  	 * @public
  	 */
  	
  	/**
  	 * Windows operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#WINDOWS
  	 * @public
  	 */
  	/**
  	 * MAC operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#MACINTOSH
  	 * @public
  	 */
  	/**
  	 * Linux operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#LINUX
  	 * @public
  	 */
  	/**
  	 * iOS operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#IOS
  	 * @public
  	 */
  	/**
  	 * Android operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#ANDROID
  	 * @public
  	 */
  	/**
  	 * Blackberry operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @name sap.ui.Device.os.OS#BLACKBERRY
  	 * @public
  	 */
  	/**
  	 * Windows Phone operating system name.
  	 * 
  	 * @see sap.ui.Device.os#name
  	 * @alias sap.ui.Device.os.OS#WINDOWS_PHONE
  	 * @public
  	 */
  	
  	var OS = {
  		"WINDOWS": "win",
  		"MACINTOSH": "mac",
  		"LINUX": "linux",
  		"IOS": "iOS",
  		"ANDROID": "Android",
  		"BLACKBERRY": "bb",
  		"WINDOWS_PHONE": "winphone"
  	};
  
  	function getOS(userAgent){ // may return null!!
  
  		userAgent = userAgent || navigator.userAgent;
  
  		var platform, // regular expression for platform
  			result;
  
  		function getDesktopOS(){
  			var pf = navigator.platform;
  			if (pf.indexOf("Win") != -1 ) {
  				// userAgent in windows 7 contains: windows NT 6.1
  				// userAgent in windows 8 contains: windows NT 6.2 or higher
  				// TODO: update this after windows 9 is released
  				var rVersion = /windows NT 6.(\d)/i;
  				var uaResult = userAgent.match(rVersion);
  				var sVersionStr = "";
  				if (uaResult) {
  					if (uaResult[1] == 1) {
  						sVersionStr = "7";
  					} else if (uaResult[1] > 1) {
  						sVersionStr = "8";
  					}
  				}
  				return {"name": OS.WINDOWS, "versionStr": sVersionStr};
  			} else if (pf.indexOf("Mac") != -1) {
  				return {"name": OS.MACINTOSH, "versionStr": ""};
  			} else if (pf.indexOf("Linux") != -1) {
  				return {"name": OS.LINUX, "versionStr": ""};
  			}
  			logger.log(INFO, "OS detection returned no result");
  			return null;
  		}
  
  		// Windows Phone. User agent includes other platforms and therefore must be checked first:
  		platform = /Windows Phone (?:OS )?([\d.]*)/;
  		result = userAgent.match(platform);
  		if (result) {
  			return ({"name": OS.WINDOWS_PHONE, "versionStr": result[1]});
  		}
  
  		// BlackBerry 10:
  		if (userAgent.indexOf("(BB10;") > 0) {
  			platform = /\sVersion\/([\d.]+)\s/;
  			result = userAgent.match(platform);
  			if (result) {
  				return {"name": OS.BLACKBERRY, "versionStr": result[1]};
  			} else {
  				return {"name": OS.BLACKBERRY, "versionStr": '10'};
  			}
  		}
  
  		// iOS, Android, BlackBerry 6.0+:
  		platform = /\(([a-zA-Z ]+);\s(?:[U]?[;]?)([\D]+)((?:[\d._]*))(?:.*[\)][^\d]*)([\d.]*)\s/;
  		result = userAgent.match(platform);
  		if (result) {
  			var appleDevices = /iPhone|iPad|iPod/;
  			var bbDevices = /PlayBook|BlackBerry/;
  			if (result[0].match(appleDevices)) {
  				result[3] = result[3].replace(/_/g, ".");
  				//result[1] contains info of devices
  				return ({"name": OS.IOS, "versionStr": result[3]});
  			} else if (result[2].match(/Android/)) {
  				result[2] = result[2].replace(/\s/g, "");
  				return ({"name": OS.ANDROID, "versionStr": result[3]});
  			} else if (result[0].match(bbDevices)) {
  				return ({"name": OS.BLACKBERRY, "versionStr": result[4]});
  			}
  		}
  
  		// Desktop
  		return getDesktopOS();
  	}
  	
  	function setOS() {
  		device.os = getOS() || {};
  		device.os.OS = OS;
  		device.os.version = device.os.versionStr ? parseFloat(device.os.versionStr) : -1;
  
  		if (device.os.name) {
  			for (var b in OS) {
  				if (OS[b] === device.os.name) {
  					device.os[b.toLowerCase()] = true;
  				}
  			}
  		}
  	}
  	setOS();
  
  
  
  //******** Browser Detection ********
  	
  	/** 
  	 * Contains information about the used browser.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.browser
  	 * @public
  	 */
  	
  	/**
  	 * Enumeration containing the names of known browsers.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.browser.BROWSER
  	 * @public
  	 */
  	
  	/**
  	 * The name of the browser.
  	 * 
  	 * @see sap.ui.Device.browser#BROWSER
  	 * @name sap.ui.Device.browser#name
  	 * @type String
  	 * @public
  	 */
  	/**
  	 * The version as string. Might be empty if no version can be determined.
  	 * 
  	 * @name sap.ui.Device.browser#versionStr
  	 * @type String
  	 * @public
  	 */
  	/**
  	 * The version as float. Might be -1 if no version can be determined.
  	 * 
  	 * @name sap.ui.Device.browser#version
  	 * @type float
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether the mobile variant of the browser is used.
  	 * 
  	 * @name sap.ui.Device.browser#mobile
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Internet Explorer browser.
  	 * 
  	 * @name sap.ui.Device.browser#internet_explorer
  	 * @type boolean
  	 * @deprecated since 1.20: use sap.ui.Device.browser.msie
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Internet Explorer browser.
  	 * 
  	 * @name sap.ui.Device.browser#msie
  	 * @type boolean
  	 * @since 1.20.0
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Firefox browser.
  	 * 
  	 * @name sap.ui.Device.browser#firefox
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Chrome browser.
  	 * 
  	 * @name sap.ui.Device.browser#chrome
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating the Safari browser.
  	 * 
  	 * @name sap.ui.Device.browser#safari
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating a Webkit browser.
  	 * 
  	 * @name sap.ui.Device.browser#webkit
  	 * @type boolean
  	 * @since 1.20.0
  	 * @public
  	 */
  	/**
  	 * Flag indicating a Mozilla browser.
  	 * 
  	 * @name sap.ui.Device.browser#mozilla
  	 * @type boolean
  	 * @since 1.20.0
  	 * @public
  	 */
  	/**
  	 * Internet Explorer browser name.
  	 * 
  	 * @see sap.ui.Device.browser#name
  	 * @name sap.ui.Device.browser.BROWSER#INTERNET_EXPLORER
  	 * @public
  	 */
  	/**
  	 * Firefox browser name.
  	 * 
  	 * @see sap.ui.Device.browser#name
  	 * @name sap.ui.Device.browser.BROWSER#FIREFOX
  	 * @public
  	 */
  	/**
  	 * Chrome browser name.
  	 * 
  	 * @see sap.ui.Device.browser#name
  	 * @name sap.ui.Device.browser.BROWSER#CHROME
  	 * @public
  	 */
  	/**
  	 * Safari browser name.
  	 * 
  	 * @see sap.ui.Device.browser#name
  	 * @name sap.ui.Device.browser.BROWSER#SAFARI
  	 * @public
  	 */
  	/**
  	 * Android stock browser name.
  	 * 
  	 * @see sap.ui.Device.browser#name
  	 * @alias sap.ui.Device.browser.BROWSER#ANDROID
  	 * @public
  	 */
  	
  	var BROWSER = {
  		"INTERNET_EXPLORER": "ie",
  		"FIREFOX": "ff",
  		"CHROME": "cr",
  		"SAFARI": "sf",
  		"ANDROID": "an"
  	};
  
  	var ua = navigator.userAgent;
  
  	/*!
  	 * Taken from jQuery JavaScript Library v1.7.1
  	 * http://jquery.com/
  	 *
  	 * Copyright 2011, John Resig
  	 * Dual licensed under the MIT or GPL Version 2 licenses.
  	 * http://jquery.org/license
  	 *
  	 * Includes Sizzle.js
  	 * http://sizzlejs.com/
  	 * Copyright 2011, The Dojo Foundation
  	 * Released under the MIT, BSD, and GPL Licenses.
  	 *
  	 * Date: Mon Nov 21 21:11:03 2011 -0500
  	 */
  	function calcBrowser(customUa){
  		var _ua = (customUa || ua).toLowerCase(); // use custom user-agent if given
  
  		var rwebkit = /(webkit)[ \/]([\w.]+)/;
  		var ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/;
  		var rmsie = /(msie) ([\w.]+)/;
  		//TODO this might needs to be adjusted in future IE version > 11
  		var rmsienew = /(trident)\/[\w.]+;.*rv:([\w.]+)/;
  		var rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/;
  
  		// WinPhone IE11 userAgent contains "WebKit" and "Mozilla" and therefore must be checked first
  		var browserMatch = rmsienew.exec( _ua ) ||
  					rwebkit.exec( _ua ) ||
  					ropera.exec( _ua ) ||
  					rmsie.exec( _ua ) ||
  					_ua.indexOf("compatible") < 0 && rmozilla.exec( _ua ) ||
  					[];
  
  		var res = { browser: browserMatch[1] || "", version: browserMatch[2] || "0" };
  		res[res.browser] = true;
  		return res;
  	}
  
  	function getBrowser(customUa) {
  		var b = calcBrowser(customUa);
  		var _ua = customUa || ua;
  
  		// jQuery checks for user agent strings. We differentiate between browsers
  		var oExpMobile;
  		if ( b.mozilla ) {
  			oExpMobile = /Mobile/;
  			if ( _ua.match(/Firefox\/(\d+\.\d+)/) ) {
  				var version = parseFloat(RegExp.$1);
  				return {
  					name: BROWSER.FIREFOX,
  					versionStr: "" + version,
  					version: version,
  					mozilla: true,
  					mobile: oExpMobile.test(_ua)
  				};
  			} else {
  				// unknown mozilla browser
  				return {
  					mobile: oExpMobile.test(_ua),
  					mozilla: true
  				};
  			}
  		} else if ( b.webkit ) {
  			// webkit version is needed for calculation if the mobile android device is a tablet (calculation of other mobile devices work without)
  			var regExpWebkitVersion = _ua.toLowerCase().match(/webkit[\/]([\d.]+)/);
  			var webkitVersion;
  			if (regExpWebkitVersion) {
  				webkitVersion = regExpWebkitVersion[1];
  			}
  			oExpMobile = /Mobile/;
  			if ( _ua.match(/(Chrome|CriOS)\/(\d+\.\d+).\d+/)) {
  				var version = parseFloat(RegExp.$2);
  				return {
  					name: BROWSER.CHROME,
  					versionStr: "" + version,
  					version: version,
  					mobile: oExpMobile.test(_ua),
  					webkit: true,
  					webkitVersion: webkitVersion
  				};
  			} else if ( _ua.match(/Android .+ Version\/(\d+\.\d+)/) ) {
  				var version = parseFloat(RegExp.$1);
  				return {
  					name: BROWSER.ANDROID,
  					versionStr: "" + version,
  					version: version,
  					mobile: oExpMobile.test(_ua),
  					webkit: true,
  					webkitVersion: webkitVersion
  				};
  			} else { // Safari might have an issue with _ua.match(...); thus changing
  				var oExp = /(Version|PhantomJS)\/(\d+\.\d+).*Safari/;
  				if (oExp.test(_ua)) {
  					var aParts = oExp.exec(_ua);
  					var version = parseFloat(aParts[2]);
  					return {
  						name: BROWSER.SAFARI,
  						versionStr: "" + version,
  						version: version,
  						mobile: oExpMobile.test(_ua),
  						webkit: true,
  						webkitVersion: webkitVersion,
  						phantomJS: aParts[1] === "PhantomJS"
  					};
  				} else {
  					// unknown webkit browser
  					return {
  						mobile: oExpMobile.test(_ua),
  						webkit: true,
  						webkitVersion: webkitVersion
  					};
  				}
  			}
  		} else if ( b.msie || b.trident ) {
  			var version;
  			// recognize IE8 when running in compat mode (only then the documentMode property is there)
  			if (document.documentMode && !customUa) { // only use the actual documentMode when no custom user-agent was given
  				if (document.documentMode === 7) { // OK, obviously we are IE and seem to be 7... but as documentMode is there this cannot be IE7!
  					version = 8.0;
  				} else {
  					version = parseFloat(document.documentMode);
  				}
  			} else {
  				version = parseFloat(b.version);
  			}
  			return {
  				name: BROWSER.INTERNET_EXPLORER,
  				versionStr: "" + version,
  				version: version,
  				msie: true,
  				mobile: false // TODO: really?
  			};
  		}
  		return {
  			name: "",
  			versionStr: "",
  			version: -1,
  			mobile: false
  		};
  	}
  	device._testUserAgent = getBrowser; // expose the user-agent parsing (mainly for testing), but don't let it be overwritten
  	
  	function setBrowser() {
  		device.browser = getBrowser();
  		device.browser.BROWSER = BROWSER;
  		
  		if (device.browser.name) {
  			for (var b in BROWSER) {
  				if (BROWSER[b] === device.browser.name) {
  					device.browser[b.toLowerCase()] = true;
  				}
  			}
  		}
  	}
  	setBrowser();
  
  
  	
  
  //******** Support Detection ********
  	
  	/** 
  	 * Contains information about detected capabilities of the used browser or device.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.support
  	 * @public
  	 */
  	
  	/**
  	 * Flag indicating whether touch events are supported.
  	 * 
  	 * @name sap.ui.Device.support#touch
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether pointer events are supported.
  	 * 
  	 * @name sap.ui.Device.support#pointer
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether media queries via JavaScript are supported.
  	 * 
  	 * @name sap.ui.Device.support#matchmedia
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether events on JavaScript media queries are supported.
  	 * 
  	 * @name sap.ui.Device.support#matchmedialistener
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether the native orientationchange event is supported.
  	 * 
  	 * @name sap.ui.Device.support#orientation
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether the device has a Retina display.
  	 * 
  	 * @name sap.ui.Device.support#retina
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether WebSockets are supported.
  	 * 
  	 * @name sap.ui.Device.support#websocket
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating whether placeholder on input tags are supported.
  	 * 
  	 * @name sap.ui.Device.support#input.placeholder
  	 * @type boolean
  	 * @public
  	 */
  
  	device.support = {};
  
  	//Maybe better to but this on device.browser because there are cases that a browser can touch but a device can't!
  	device.support.touch = !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch);
  
  	// FIXME: PhantomJS doesn't support touch events but exposes itself as touch
  	//        enabled browser. Therfore we manually override that in jQuery.support!
  	//        This has been tested with PhantomJS 1.9.7 and 2.0.0!
  	if (device.browser.phantomJS) {
  		device.support.touch = false;
  	}
  
  	device.support.pointer = !!window.PointerEvent;
  
  	device.support.matchmedia = !!window.matchMedia;
  	var m = device.support.matchmedia ? window.matchMedia("screen and (max-width:0px)") : null; //IE10 doesn't like empty string as argument for matchMedia, FF returns null when running within an iframe with display:none
  	device.support.matchmedialistener = !!(m && m.addListener);
  	if (device.browser.safari && device.browser.version < 6) {
  		//Safari seems to have addListener but no events are fired ?!
  		device.support.matchmedialistener = false;
  	}
  
  	device.support.orientation = !!("orientation" in window && "onorientationchange" in window);
  
  	device.support.retina = (window.retina || window.devicePixelRatio >= 2);
  
  	device.support.websocket = ('WebSocket' in window);
  
  	device.support.input = {};
  	device.support.input.placeholder = ('placeholder' in document.createElement("input"));
  
  //******** Match Media ********
  	
  	/** 
  	 * Event API for Screen width media queries.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.media
  	 * @public
  	 */
  	device.media = {};
  	
  	/**
  	 * Enumeration containing the names of predefined Screen width media query range sets.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.media.RANGESETS
  	 * @public
  	 */
  	
  	/**
  	 * A 3 step range set (S-L).
  	 * 
  	 * @name sap.ui.Device.media.RANGESETS#SAP_3STEPS
  	 * @public
  	 */
  	/**
  	 * A 4 step range set (S-XL).
  	 * 
  	 * @name sap.ui.Device.media.RANGESETS#SAP_4STEPS
  	 * @public
  	 */
  	/**
  	 * A 6 step range set (XS-XXL).
  	 * 
  	 * @name sap.ui.Device.media.RANGESETS#SAP_6STEPS
  	 * @public
  	 */
  	/**
  	 * A 3 step range set (Phone, Tablet, Desktop). <br/>
  	 * <br/>
  	 * This range set is initialized always by default.<br/>
  	 * Phone is < 600px<br/>
  	 * Tablet is 600px >= Tablet < 1024<br/>
  	 * Desktop is > 1024px<br/>
  	 * <br/>
  	 * There are 5 css classes to hide elements based on the width of the screen:
  	 * <ul>
  	 * 	<li>sapUiHideOnPhone - will be hidden if the screen has 600px or more</li>
  	 * 	<li>sapUiHideOnTablet - will be hidden if the screen has less than 600px or more than 1023px</li>
  	 * 	<li>sapUiHideOnDesktop - will be hidden if the screen is smaller than 1024px</li>
  	 * 	<li>sapUiVisibleOnlyOnPhone - will be visible if the screen has less than 600px</li>
  	 * 	<li>sapUiVisibleOnlyOnTablet - will be visible if the screen has 600px or more but less than 1024px</li>
  	 * 	<li>sapUiVisibleOnlyOnDesktop - will be visible if the screen has 1024px or more</li>
  	 * </ul>
  	 * @alias sap.ui.Device.media.RANGESETS#SAP_STANDARD
  	 * @public
  	 */
  	
  	var RANGESETS = {
  		"SAP_3STEPS": "3Step",
  		"SAP_4STEPS": "4Step",
  		"SAP_6STEPS": "6Step",
  		"SAP_STANDARD": "Std"
  	};
  	device.media.RANGESETS = RANGESETS;
  	
  	device.media._predefinedRangeSets = {};
  	device.media._predefinedRangeSets[RANGESETS.SAP_3STEPS] = {points: [520, 960], unit: "px", name: RANGESETS.SAP_3STEPS, names: ["S", "M", "L"]};
  	device.media._predefinedRangeSets[RANGESETS.SAP_4STEPS] = {points: [520, 760, 960], unit: "px", name: RANGESETS.SAP_4STEPS, names: ["S", "M", "L", "XL"]};
  	device.media._predefinedRangeSets[RANGESETS.SAP_6STEPS] = {points: [241, 400, 541, 768, 960], unit: "px", name: RANGESETS.SAP_6STEPS, names: ["XS", "S", "M", "L", "XL", "XXL"]};
  	device.media._predefinedRangeSets[RANGESETS.SAP_STANDARD] = {points: [600, 1024], unit: "px", name: RANGESETS.SAP_STANDARD, names: ["Phone", "Tablet", "Desktop"]};
  	
  	var _defaultRangeSet = RANGESETS.SAP_STANDARD;
  	var media_timeout = device.support.matchmedialistener ? 0 : 100;
  	var _querysets = {};
  	var media_currentwidth = null;
  	
  	function getQuery(from, to, unit){
  		unit = unit || "px";
  		var q = "screen";
  		if (from > 0) {
  			q = q + " and (min-width:" + from + unit + ")";
  		}
  		if (to > 0) {
  			q = q + " and (max-width:" + to + unit + ")";
  		}
  		return q;
  	}
  	
  	function handleChange(name){
  		if (!device.support.matchmedialistener && media_currentwidth == windowSize()[0]) {
  			return; //Skip unnecessary resize events
  		}
  		
  		if (_querysets[name].timer) {
  			clearTimeout(_querysets[name].timer);
  			_querysets[name].timer = null;
  		}
  		
  		_querysets[name].timer = setTimeout(function() {
  			var mParams = checkQueries(name, false);
  			if (mParams) {
  				fireEvent("media_" + name, mParams);
  			}
  		}, media_timeout);
  	}
  	
  	function getRangeInfo(sSetName, iRangeIdx){
  		var q = _querysets[sSetName].queries[iRangeIdx];
  		var info = {from: q.from, unit: _querysets[sSetName].unit};
  		if (q.to >= 0) {
  			info.to = q.to;
  		}
  		if (_querysets[sSetName].names) {
  			info.name = _querysets[sSetName].names[iRangeIdx];
  		}
  		return info;
  	}
  	
  	function checkQueries(name, infoOnly){
  		if (_querysets[name]) {
  			var aQueries = _querysets[name].queries;
  			var info = null;
  			for (var i = 0, len = aQueries.length; i < len; i++) {
  				var q = aQueries[i];
  				if ((q != _querysets[name].currentquery || infoOnly) && device.media.matches(q.from, q.to, _querysets[name].unit)) {
  					if (!infoOnly) {
  						_querysets[name].currentquery = q;
  					}
  					if (!_querysets[name].noClasses && _querysets[name].names && !infoOnly) {
  						refreshCSSClasses(name, _querysets[name].names[i]);
  					}
  					info = getRangeInfo(name, i);
  				}
  			}
  			
  			return info;
  		}
  		logger.log(WARNING, "No queryset with name " + name + " found", 'DEVICE.MEDIA');
  		return null;
  	}
  	
  	function refreshCSSClasses(sSetName, sRangeName, bRemove){
  		 var sClassPrefix = "sapUiMedia-" + sSetName + "-";
  		 changeRootCSSClass(sClassPrefix + sRangeName, bRemove, sClassPrefix);
  	}
  	
  	function changeRootCSSClass(sClassName, bRemove, sPrefix){
  		var oRoot = document.documentElement;
  		if (oRoot.className.length == 0) {
  			if (!bRemove) {
  				oRoot.className = sClassName;
  			}
  		} else {
  			var aCurrentClasses = oRoot.className.split(" ");
  			var sNewClasses = "";
  			for (var i = 0; i < aCurrentClasses.length; i++) {
  				if ((sPrefix && aCurrentClasses[i].indexOf(sPrefix) != 0) || (!sPrefix && aCurrentClasses[i] != sClassName)) {
  					sNewClasses = sNewClasses + aCurrentClasses[i] + " ";
  				}
  			}
  			if (!bRemove) {
  				sNewClasses = sNewClasses + sClassName;
  			}
  			oRoot.className = sNewClasses;
  		}
  	}
  	
  	function windowSize(){
  		return [document.documentElement.clientWidth, document.documentElement.clientHeight];
  	}
  	
  	function convertToPx(val, unit){
  		if (unit === "em" || unit === "rem") {
  			var s = window.getComputedStyle || function(e) {
  					return e.currentStyle;
  				};
  				var x = s(document.documentElement).fontSize;
  				var f = (x && x.indexOf("px") >= 0) ? parseFloat(x, 10) : 16;
  				return val * f;
  		}
  		return val;
  	}
  
  	function match_legacy(from, to, unit){
  		from = convertToPx(from, unit);
  		to = convertToPx(to, unit);
  		
  		var width = windowSize()[0];
  		var a = from < 0 || from <= width;
  		var b = to < 0 || width <= to;
  		return a && b;
  	}
  
  	function match(from, to, unit){
  		var q = getQuery(from, to, unit);
  		var mm = window.matchMedia(q); //FF returns null when running within an iframe with display:none
  		return mm && mm.matches;
  	}
  
  	device.media.matches = device.support.matchmedia ? match : match_legacy;
  	
  	/**
  	 * Registers the given handler to the range change event, which is fired when a new range of the set is entered.
  	 * 
  	 * The handler has one map parameter <code>mParams</code>:
  	 * <ul>
  	 * <li>mParams.from: the range start value</li>
  	 * <li>mParams.to: the range end value, not defined for the last range (INFINITY)</li>
  	 * <li>mParams.unit: the used unit, e.g. px</li>
  	 * <li>mParams.name: the range name if defined</li>
  	 * </ul>
  	 * 
  	 * @param {Function} fnFunction The function to call, when the range change event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @param {String} sName The name of the range set to listen to.
  	 * @name sap.ui.Device.media#attachHandler
  	 * @function
  	 * @public
  	 */
  	device.media.attachHandler = function(fnFunction, oListener, sName){
  		var name = sName || _defaultRangeSet;
  		attachEvent("media_" + name, fnFunction, oListener);
  	};
  
  	/**
  	 * Deregisters a previously registered handler from the range change event.
  	 * 
  	 * @param {Function} fnFunction The function to call, when the range change event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @param {String} sName The name of the range set to listen to.
  	 * @name sap.ui.Device.media#detachHandler
  	 * @function
  	 * @public
  	 */
  	device.media.detachHandler = function(fnFunction, oListener, sName){
  		var name = sName || _defaultRangeSet;
  		detachEvent("media_" + name, fnFunction, oListener);
  	};
  	
  	/** 
  	 * Initializes a Screen width media query range set.
  	 * 
  	 * This function can either be called only with the name parameter to initialize a predefined range set,
  	 * e.g. <code>sap.ui.Device.media.initRangeSet(sap.ui.Device.media.RANGESETS.SAP_3STEPS)</code>.
  	 * 
  	 * Or it is possible to define a custom range set as in the following example:
  	 * <code>sap.ui.Device.media.initRangeSet("MyRangeSet", [200, 400], "px", ["Small", "Medium", "Large"])</code> defines 3 ranges:
  	 * <ul>
  	 * <li>0px-199.999px with name "Small"</li>
  	 * <li>200px-399.999px with name "Medium"</li>
  	 * <li>400px-INFINITY with name "Large"</li>
  	 * </ul>
  	 * 
  	 * The range names are optional. If they are specified also a CSS class (e.g. sapUiMedia-MyRangeSet-Small) is added to the document root
  	 * depending on the current active range. This can be suppressed via parameter <code>bSuppressClasses</code>.
  	 * 
  	 * @param {String} sName The name of the range set. Either a predefined or custom one. The name must be a valid id (consist of letters and digits).
  	 * @param {int[]} aRangeBorders The range borders
  	 * @param {String} [sUnit] The unit which should be used. Allowed values are px (default), em or rem.
  	 * @param {String[]} [aRangeNames] The names of the ranges. The names must be a valid id (consist of letters and digits).
  	 * @param {boolean} [bSuppressClasses] Whether writing CSS classes to the document root should be suppressed
  	 * @name sap.ui.Device.media#initRangeSet
  	 * @function
  	 * @public
  	 */
  	device.media.initRangeSet = function(sName, aRangeBorders, sUnit, aRangeNames, bSuppressClasses){
  		//TODO Do some Assertions and parameter checking
  		var oConfig;
  		if (!sName) {
  			oConfig = device.media._predefinedRangeSets[_defaultRangeSet];
  		} else if (sName && device.media._predefinedRangeSets[sName]) {
  			oConfig = device.media._predefinedRangeSets[sName];
  		} else {
  			oConfig = {name: sName, unit: (sUnit || "px").toLowerCase(), points: aRangeBorders || [], names: aRangeNames, noClasses: !!bSuppressClasses};
  		}
  		
  		if (device.media.hasRangeSet(oConfig.name)) {
  			logger.log(INFO, "Range set " + oConfig.name + " hase already been initialized", 'DEVICE.MEDIA');
  			return;
  		}
  		
  		sName = oConfig.name;
  		oConfig.queries = [];
  		oConfig.timer = null;
  		oConfig.currentquery = null;
  		oConfig.listener = function(){
  			return handleChange(sName);
  		};
  			
  		var from, to, query;
  		var aPoints = oConfig.points;
  		for (var i = 0, len = aPoints.length; i <= len; i++) {
  			from = (i == 0) ? 0 : aPoints[i - 1];
  			to = (i == aPoints.length) ? -1 : aPoints[i];
  			query = getQuery(from, to, oConfig.unit);
  			oConfig.queries.push({
  				query: query,
  				from: from,
  				to: to
  			});
  		}
  		
  		if (oConfig.names && oConfig.names.length != oConfig.queries.length) {
  			oConfig.names = null;
  		}
  		
  		_querysets[oConfig.name] = oConfig;
  			
  		if (device.support.matchmedialistener) { //FF, Safari, Chrome, IE10?
  			var queries = oConfig.queries;
  			for (var i = 0; i < queries.length; i++) {
  				var q = queries[i];
  				q.media = window.matchMedia(q.query);
  				q.media.addListener(oConfig.listener);
  			}
  		} else { //IE, Safari (<6?)	
  			if (window.addEventListener) {
  				window.addEventListener("resize", oConfig.listener, false);
  				window.addEventListener("orientationchange", oConfig.listener, false);
  			} else { //IE8
  				window.attachEvent("onresize", oConfig.listener);
  			}
  		}
  		
  		oConfig.listener();
  	};
  	
  	/**
  	 * Returns information about the current active range of the range set with the given name.
  	 * 
  	 * @param {String} sName The name of the range set.
  	 * @name sap.ui.Device.media#getCurrentRange
  	 * @return {Map} the information about the current active range (same structure like the handler parameters (@see sap.ui.Device.media#attachHandler))
  	 * @function
  	 * @public
  	 */
  	device.media.getCurrentRange = function(sName){
  		if (!device.media.hasRangeSet(sName)) {
  			return null;
  		}
  		return checkQueries(sName, true);
  	};
  	
  	/**
  	 * Returns whether a range set with the given name is initialized.
  	 * 
  	 * @param {String} sName The name of the range set.
  	 * @name sap.ui.Device.media#hasRangeSet
  	 * @return {boolean}
  	 * @function
  	 * @public
  	 */
  	device.media.hasRangeSet = function(sName){
  		return sName && !!_querysets[sName];
  	};
  	
  	/**
  	 * Removes a previously initialized range set and detaches all registered handlers.
  	 * 
  	 * Initialized predefined range sets (@see sap.ui.Device.media#RANGESETS) cannot be removed.
  	 * 
  	 * @param {String} sName The name of the range set.
  	 * @name sap.ui.Device.media#removeRangeSet
  	 * @function
  	 * @protected
  	 */
  	device.media.removeRangeSet = function(sName){
  		if (!device.media.hasRangeSet(sName)) {
  			logger.log(INFO, "RangeSet " + sName + " not found, thus could not be removed.", 'DEVICE.MEDIA');
  			return;
  		}
  
  		for (var x in RANGESETS) {
  			if (sName === RANGESETS[x]) {
  				logger.log(WARNING, "Cannot remove default rangeset - no action taken.", 'DEVICE.MEDIA');
  				return;
  			}
  		}
  		
  		var oConfig = _querysets[sName];
  		if (device.support.matchmedialistener) { //FF, Safari, Chrome, IE10?
  			var queries = oConfig.queries;
  			for (var i = 0; i < queries.length; i++) {
  				queries[i].media.removeListener(oConfig.listener);
  			}
  		} else { //IE, Safari (<6?)	
  			if (window.removeEventListener) {
  				window.removeEventListener("resize", oConfig.listener, false);
  				window.removeEventListener("orientationchange", oConfig.listener, false);
  			} else { //IE8
  				window.detachEvent("onresize", oConfig.listener);
  			}
  		}
  		
  		refreshCSSClasses(sName, "", true);
  		delete mEventRegistry["media_" + sName];
  		delete _querysets[sName];
  	};
  
  //******** System Detection ********
  
  	/** 
  	 * Contains information about the system.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.system
  	 * @public
  	 */
  	/**
  	 * Enumeration containing the names of known types of the devices.
  	 * 
  	 * @namespace
  	 * @name sap.ui.Device.system.SYSTEMTYPE
  	 * @public
  	 */
  	/**
  	 * Flag indicating if the device is a tablet.
  	 * 
  	 * @name sap.ui.Device.system#tablet
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating if the device is a phone.
  	 * 
  	 * @name sap.ui.Device.system#phone
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating if the device is a desktop.
  	 * 
  	 * @name sap.ui.Device.system#desktop
  	 * @type boolean
  	 * @public
  	 */
  	/**
  	 * Flag indicating if the device is a combination of desktop and tablet.
  	 * 
  	 * This property is mainly targeting the windows 8 devices where the mouse and touch event may supported
  	 * natively by the browser.
  	 * 
  	 * This property is set to true only when both mouse and touch event are natively supported.
  	 * 
  	 * @alias sap.ui.Device.system#combi
  	 * @type boolean
  	 * @public
  	 */
  
  	var SYSTEMTYPE = {
  			"TABLET" : "tablet",
  			"PHONE" : "phone",
  			"DESKTOP" : "desktop",
  			"COMBI" : "combi"
  	};
  
  	var isWin8 = !!device.os.windows && device.os.version === 8;
  	var isWin7 = !!device.os.windows && device.os.version === 7;
  
  	device.system = {};
  
  	function getSystem(_simMobileOnDesktop) {
  		var t = isTablet();
  		
  		var s = {};
  		s.tablet = ((device.support.touch && !isWin7) || isWin8 || !!_simMobileOnDesktop) && t;
  		s.phone = device.os.windows_phone || ((device.support.touch && !isWin7) || !!_simMobileOnDesktop) && !t;
  		s.desktop = (!s.tablet && !s.phone) || isWin8 || isWin7;
  		s.combi = (s.desktop && s.tablet);
  		s.SYSTEMTYPE = SYSTEMTYPE;
  		
  		for (var type in SYSTEMTYPE) {
  			changeRootCSSClass("sap-" + SYSTEMTYPE[type], !s[SYSTEMTYPE[type]]);
  		}
  		return s;
  	}
  
  	function isTablet() {
  		var android_phone = (/(?=android)(?=.*mobile)/i.test(navigator.userAgent));
  		// According to google documentation: https://developer.chrome.com/multidevice/webview/overview, the WebView shipped with Android 4.4 (KitKat) is based on the same code as Chrome for Android.
  		// If you're attempting to differentiate between the WebView and Chrome for Android, you should look for the presence of the Version/_X.X_ string in the WebView user-agent string
  		// The stock browser of Samsung device uses Chrome kernal from Android version 4.4. It behaves differently than the Chrome Webview, therefore it's excluded from this check by checking the 'SAMSUNG'
  		// string in the user agent.
  		var bChromeWebView = device.os.android && device.browser.chrome && (device.os.version >= 4.4) && /Version\/\d.\d/.test(navigator.userAgent) && !/SAMSUNG/.test(navigator.userAgent);
  		if (device.os.name === device.os.OS.IOS) {
  			return /ipad/i.test(navigator.userAgent);
  		} else {
  			if (device.support.touch) {
  				if (isWin8) {
  					return true;
  				}
  				
  				//in real mobile device
  				var densityFactor = window.devicePixelRatio ? window.devicePixelRatio : 1; // may be undefined in Windows Phone devices
  				if (!bChromeWebView && (device.os.name === device.os.OS.ANDROID) && device.browser.webkit && (device.browser.webkitVersion > 537.10)) {
  					// On Android sometimes window.screen.width returns the logical CSS pixels, sometimes the physical device pixels;
  					// Tests on multiple devices suggest this depends on the Webkit version.
  					// The Webkit patch which changed the behavior was done here: https://bugs.webkit.org/show_bug.cgi?id=106460
  					// Chrome 27 with Webkit 537.36 returns the logical pixels,
  					// Chrome 18 with Webkit 535.19 returns the physical pixels.
  					// The BlackBerry 10 browser with Webkit 537.10+ returns the physical pixels.
  					// So it appears like somewhere above Webkit 537.10 we do not hve to divide by the devicePixelRatio anymore.
  
  					// update: Chrome WebView returns physical pixels therefore it's excluded from this special check
  					densityFactor = 1;
  				}
  
  				//this is how android distinguishes between tablet and phone
  				//http://android-developers.blogspot.de/2011/07/new-tools-for-managing-screen-sizes.html
  				var bTablet = (Math.min(window.screen.width / densityFactor, window.screen.height / densityFactor) >= 600);
  
  				// special workaround for Nexus 7 where the window.screen.width is 600px or 601px in portrait mode (=> tablet) 
  				// but window.screen.height 552px in landscape mode (=> phone), because the browser UI takes some space on top.
  				// So the detected device type depends on the orientation :-(
  				// actually this is a Chrome bug, as "width"/"height" should return the entire screen's dimensions and
  				// "availWidth"/"availHeight" should return the size available after subtracting the browser UI
  				if (isLandscape()
  						&& (window.screen.height === 552 || window.screen.height === 553) // old/new Nexus 7  
  						&& (/Nexus 7/i.test(navigator.userAgent))) {
  					bTablet = true;
  				}
  
  				return bTablet;
  			} else {
  				// in desktop browser, it's detected as tablet when
  				// 1. Windows 8 device with a touch screen where "Touch" is contained in the userAgent
  				// 2. Android emulation and it's not an Android phone
  				return (device.browser.msie && ua.indexOf("Touch") !== -1) || (device.os.name === device.os.OS.ANDROID && !android_phone);
  			}
  		}
  	}
  	
  	function setSystem(_simMobileOnDesktop) {
  		device.system = getSystem(_simMobileOnDesktop);
  		if (device.system.tablet || device.system.phone) {
  			device.browser.mobile = true;
  		}
  	}
  	setSystem();
  
  //******** Orientation Detection ********
  
  	/** 
  	 * Orientation Change Event API.
  	 *
  	 * @namespace
  	 * @name sap.ui.Device.orientation
  	 * @public
  	 */
  
  	device.orientation = {};
  
  	/** 
  	 * Resize Event API.
  	 *
  	 * @namespace
  	 * @name sap.ui.Device.resize
  	 * @public
  	 */
  	device.resize = {};
  	
  	/**
  	 * Registers the given handler to the orientation change event.
  	 *
  	 * The handler has one map parameter <code>mParams</code>:
  	 * <ul>
  	 * <li>mParams.landscape: whether the orientation is currently landscape</li>
  	 * </ul>
  	 *
  	 * @param {Function} fnFunction The function to call, when the orientation change event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @name sap.ui.Device.orientation#attachHandler
  	 * @function
  	 * @public
  	 */
  	device.orientation.attachHandler = function(fnFunction, oListener){
  		attachEvent("orientation", fnFunction, oListener);
  	};
  
  	/**
  	 * Registers the given handler to the resize event.
  	 *
  	 * The handler has one map parameter <code>mParams</code>:
  	 * <ul>
  	 * <li>mParams.height: new height of the window</li>
  	 * <li>mParams.width: new width of the window</li>
  	 * </ul>
  	 *
  	 * @param {Function} fnFunction The function to call, when the resize event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @name sap.ui.Device.resize#attachHandler
  	 * @function
  	 * @public
  	 */
  	device.resize.attachHandler = function(fnFunction, oListener){
  		attachEvent("resize", fnFunction, oListener);
  	};
  
  	/**
  	 * Deregisters a previously registered handler from the orientation change event.
  	 * @param {Function} fnFunction The function to call, when the orientation change event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @name sap.ui.Device.orientation#detachHandler
  	 * @function
  	 * @public
  	 */
  	device.orientation.detachHandler = function(fnFunction, oListener){
  		detachEvent("orientation", fnFunction, oListener);
  	};
  
  	/**
  	 * Deregisters a previously registered handler from the resize event.
  	 * @param {Function} fnFunction The function to call, when the resize event occurs.
  	 * @param {Object} [oListener] The 'this' context of the handler function.
  	 * @name sap.ui.Device.resize#detachHandler
  	 * @function
  	 * @public
  	 */
  	device.resize.detachHandler = function(fnFunction, oListener){
  		detachEvent("resize", fnFunction, oListener);
  	};
  
  	function setOrientationInfo(oInfo){
  		oInfo.landscape = isLandscape(true);
  		oInfo.portrait = !oInfo.landscape;
  	}
  
  	function handleOrientationChange(){
  		setOrientationInfo(device.orientation);
  		fireEvent("orientation", {landscape: device.orientation.landscape});
  	}
  
  	function handleResizeChange(){
  		setResizeInfo(device.resize);
  		fireEvent("resize", {height: device.resize.height, width: device.resize.width});
  	}
  
  	function setResizeInfo(oInfo){
  		oInfo.width = windowSize()[0];
  		oInfo.height = windowSize()[1];
  	}
  
  	function handleOrientationResizeChange(){
  		var wasL = device.orientation.landscape;
  		var isL = isLandscape();
  		if (wasL != isL) {
  			handleOrientationChange();
  		}
  		//throttle resize events because most browsers throw one or more resize events per pixel
  		//for every resize event inside the period from 150ms (starting from the first resize event),
  		//we only fire one resize event after this period
  		if (!iResizeTimeout) {
  			iResizeTimeout = window.setTimeout(handleResizeTimeout, 150);
  		}
  	}
  
  	function handleResizeTimeout() {
  		handleResizeChange();
  		iResizeTimeout = null;
  	}
  
  	var bOrientationchange = false;
  	var bResize = false;
  	var iOrientationTimeout;
  	var iResizeTimeout;
  	var iClearFlagTimeout;
  	var iWindowHeightOld = windowSize()[1];
  	var iWindowWidthOld = windowSize()[0];
  	var bKeyboardOpen = false;
  	var iLastResizeTime;
  	var rInputTagRegex = /INPUT|TEXTAREA|SELECT/;
  	// On iPhone with iOS version 7.0.x and on iPad with iOS version 7.x (tested with all versions below 7.1.1), there's a invalide resize event fired
  	// when changing the orientation while keyboard is shown.
  	var bSkipFirstResize = device.os.ios && device.browser.name === "sf" &&
  		((device.system.phone && device.os.version >= 7 && device.os.version < 7.1) || (device.system.tablet && device.os.version >= 7));
  	
  	function isLandscape(bFromOrientationChange){
  		if (device.support.touch && device.support.orientation) {
  			//if on screen keyboard is open and the call of this method is from orientation change listener, reverse the last value.
  			//this is because when keyboard opens on android device, the height can be less than the width even in portrait mode.
  			if (bKeyboardOpen && bFromOrientationChange) {
  				return !device.orientation.landscape;
  			}
  			//when keyboard opens, the last orientation change value will be retured.
  			if (bKeyboardOpen) {
  				return device.orientation.landscape;
  			}
  			//otherwise compare the width and height of window
  		} else {
  			//most desktop browsers and windows phone/tablet which not support orientationchange
  			if (device.support.matchmedia && device.support.orientation) {
  				return !!window.matchMedia("(orientation: landscape)").matches;
  			}
  		}
  		var size = windowSize();
  		return size[0] > size[1];
  	}
  
  	function handleMobileOrientationResizeChange(evt) {
  		if (evt.type == "resize") {
  			// supress the first invalid resize event fired before orientationchange event while keyboard is open on iPhone 7.0.x
  			// because this event has wrong size infos
  			if (bSkipFirstResize && rInputTagRegex.test(document.activeElement.tagName) && !bOrientationchange) {
  				return;
  			}
  
  			var iWindowHeightNew = windowSize()[1];
  			var iWindowWidthNew = windowSize()[0];
  			var iTime = new Date().getTime();
  			//skip multiple resize events by only one orientationchange
  			if (iWindowHeightNew === iWindowHeightOld && iWindowWidthNew === iWindowWidthOld) {
  				return;
  			}
  			bResize = true;
  			//on mobile devices opening the keyboard on some devices leads to a resize event
  			//in this case only the height changes, not the width
  			if ((iWindowHeightOld != iWindowHeightNew) && (iWindowWidthOld == iWindowWidthNew)) {
  				//Asus Transformer tablet fires two resize events when orientation changes while keyboard is open.
  				//Between these two events, only the height changes. The check of if keyboard is open has to be skipped because
  				//it may be judged as keyboard closed but the keyboard is still open which will affect the orientation detection
  				if (!iLastResizeTime || (iTime - iLastResizeTime > 300)) {
  					bKeyboardOpen = (iWindowHeightNew < iWindowHeightOld);
  				}
  				handleResizeChange();
  			} else {
  				iWindowWidthOld = iWindowWidthNew;
  			}
  			iLastResizeTime = iTime;
  			iWindowHeightOld = iWindowHeightNew;
  
  			if (iClearFlagTimeout) {
  				window.clearTimeout(iClearFlagTimeout);
  				iClearFlagTimeout = null;
  			}
  			//Some Android build-in browser fires a resize event after the viewport is applied.
  			//This resize event has to be dismissed otherwise when the next orientationchange event happens,
  			//a UI5 resize event will be fired with the wrong window size.
  			iClearFlagTimeout = window.setTimeout(clearFlags, 1200);
  		} else if (evt.type == "orientationchange") {
  			bOrientationchange = true;
  		}
  
  		if (iOrientationTimeout) {
  			clearTimeout(iOrientationTimeout);
  			iOrientationTimeout = null;
  		}
  		iOrientationTimeout = window.setTimeout(handleMobileTimeout, 50);
  	}
  
  	function handleMobileTimeout() {
  		if (bOrientationchange && bResize) {
  			handleOrientationChange();
  			handleResizeChange();
  			bOrientationchange = false;
  			bResize = false;
  			if (iClearFlagTimeout) {
  				window.clearTimeout(iClearFlagTimeout);
  				iClearFlagTimeout = null;
  			}
  		}
  		iOrientationTimeout = null;
  	}
  
  	function clearFlags(){
  		bOrientationchange = false;
  		bResize = false;
  		iClearFlagTimeout = null;
  	}
  
  //******** Update browser settings for test purposes ********
  
  	device._update = function(_simMobileOnDesktop) {
  		ua = navigator.userAgent;
  		logger.log(WARNING, "Device API values manipulated: NOT PRODUCTIVE FEATURE!!! This should be only used for test purposes. Only use if you know what you are doing.");
  		setBrowser();
  		setOS();
  		setSystem(_simMobileOnDesktop);
  	};
  
  //********************************************************
  	
  	setResizeInfo(device.resize);
  	setOrientationInfo(device.orientation);
  
  	//Add API to global namespace
  	window.sap.ui.Device = device;
  
  	// Add handler for orientationchange and resize after initialization of Device API (IE8 fires onresize synchronously)
  	if (device.support.touch && device.support.orientation) {
  		//logic for mobile devices which support orientationchange (like ios, android, blackberry)
  		window.addEventListener("resize", handleMobileOrientationResizeChange, false);
  		window.addEventListener("orientationchange", handleMobileOrientationResizeChange, false);
  	} else {
  		if (window.addEventListener) {
  			//most desktop browsers and windows phone/tablet which not support orientationchange
  			window.addEventListener("resize", handleOrientationResizeChange, false);
  		} else {
  			//IE8
  			window.attachEvent("onresize", handleOrientationResizeChange);
  		}
  	}
  
  	//Always initialize the default media range set
  	device.media.initRangeSet();
  
  	// define module if API is available
  	if (sap.ui.define) {
  		sap.ui.define("sap/ui/Device", [], function() {
  			return device;
  		});
  	}
  
  }());
  /*!
   * URI.js - Mutating URLs
   *
   * Version: 1.11.2
   *
   * Author: Rodney Rehm
   * Web: http://medialize.github.com/URI.js/
   *
   * Licensed under
   *   MIT License http://www.opensource.org/licenses/mit-license
   *   GPL v3 http://opensource.org/licenses/GPL-3.0
   *
   */
  (function (root, factory) {
      // https://github.com/umdjs/umd/blob/master/returnExports.js
      if (typeof exports === 'object') {
          // Node
          module.exports = factory(require('./punycode'), require('./IPv6'), require('./SecondLevelDomains'));
      } else if (typeof define === 'function' && define.amd) {
          // AMD. Register as an anonymous module.
        // ##### BEGIN: MODIFIED BY SAP
        // define(['./punycode', './IPv6', './SecondLevelDomains'], factory);
        // we can't support loading URI.js via AMD define. URI.js is packaged with SAPUI5 code 
        // and define() doesn't execute synchronously. So the UI5 code executed after URI.js 
        // fails as it is missing the URI.js code.
        // Instead we use the standard init code and only expose the result via define()
        // The (optional) dependencies are lost or must be loaded in advance
        root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);
        define([], function() { return root.URI; });
        // ##### END: MODIFIED BY SAP
      } else {
          // Browser globals (root is window)
          root.URI = factory(root.punycode, root.IPv6, root.SecondLevelDomains, root);
      }
  }(this, function (punycode, IPv6, SLD, root) {
  "use strict";
  
  // save current URI variable, if any
  var _URI = root && root.URI;
  
  function URI(url, base) {
      // Allow instantiation without the 'new' keyword
      if (!(this instanceof URI)) {
          return new URI(url, base);
      }
  
      if (url === undefined) {
          if (typeof location !== 'undefined') {
              url = location.href + "";
          } else {
              url = "";
          }
      }
  
      this.href(url);
  
      // resolve to base according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#constructor
      if (base !== undefined) {
          return this.absoluteTo(base);
      }
  
      return this;
  };
  
  var p = URI.prototype;
  var hasOwn = Object.prototype.hasOwnProperty;
  
  function escapeRegEx(string) {
      // https://github.com/medialize/URI.js/commit/85ac21783c11f8ccab06106dba9735a31a86924d#commitcomment-821963
      return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
  }
  
  function getType(value) {
      // IE8 doesn't return [Object Undefined] but [Object Object] for undefined value
      if (value === undefined) {
          return 'Undefined';
      }
  
      return String(Object.prototype.toString.call(value)).slice(8, -1);
  }
  
  function isArray(obj) {
      return getType(obj) === "Array";
  }
  
  function filterArrayValues(data, value) {
      var lookup = {};
      var i, length;
  
      if (isArray(value)) {
          for (i = 0, length = value.length; i < length; i++) {
              lookup[value[i]] = true;
          }
      } else {
          lookup[value] = true;
      }
  
      for (i = 0, length = data.length; i < length; i++) {
          if (lookup[data[i]] !== undefined) {
              data.splice(i, 1);
              length--;
              i--;
          }
      }
  
      return data;
  }
  
  function arrayContains(list, value) {
      var i, length;
      
      // value may be string, number, array, regexp
      if (isArray(value)) {
          // Note: this can be optimized to O(n) (instead of current O(m * n))
          for (i = 0, length = value.length; i < length; i++) {
              if (!arrayContains(list, value[i])) {
                  return false;
              }
          }
          
          return true;
      }
      
      var _type = getType(value);
      for (i = 0, length = list.length; i < length; i++) {
          if (_type === 'RegExp') {
              if (typeof list[i] === 'string' && list[i].match(value)) {
                  return true;
              }
          } else if (list[i] === value) {
              return true;
          }
      }
  
      return false;
  }
  
  function arraysEqual(one, two) {
      if (!isArray(one) || !isArray(two)) {
          return false;
      }
      
      // arrays can't be equal if they have different amount of content
      if (one.length !== two.length) {
          return false;
      }
  
      one.sort();
      two.sort();
  
      for (var i = 0, l = one.length; i < l; i++) {
          if (one[i] !== two[i]) {
              return false;
          }
      }
      
      return true;
  }
  
  URI._parts = function() {
      return {
          protocol: null,
          username: null,
          password: null,
          hostname: null,
          urn: null,
          port: null,
          path: null,
          query: null,
          fragment: null,
          // state
          duplicateQueryParameters: URI.duplicateQueryParameters,
          escapeQuerySpace: URI.escapeQuerySpace
      };
  };
  // state: allow duplicate query parameters (a=1&a=1)
  URI.duplicateQueryParameters = false;
  // state: replaces + with %20 (space in query strings)
  URI.escapeQuerySpace = true;
  // static properties
  URI.protocol_expression = /^[a-z][a-z0-9-+-]*$/i;
  URI.idn_expression = /[^a-z0-9\.-]/i;
  URI.punycode_expression = /(xn--)/i;
  // well, 333.444.555.666 matches, but it sure ain't no IPv4 - do we care?
  URI.ip4_expression = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
  // credits to Rich Brown
  // source: http://forums.intermapper.com/viewtopic.php?p=1096#1096
  // specification: http://www.ietf.org/rfc/rfc4291.txt
  URI.ip6_expression = /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
  // gruber revised expression - http://rodneyrehm.de/t/url-regex.html
  URI.find_uri_expression = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig;
  // http://www.iana.org/assignments/uri-schemes.html
  // http://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers#Well-known_ports
  URI.defaultPorts = {
      http: "80",
      https: "443",
      ftp: "21",
      gopher: "70",
      ws: "80",
      wss: "443"
  };
  // allowed hostname characters according to RFC 3986
  // ALPHA DIGIT "-" "." "_" "~" "!" "$" "&" "'" "(" ")" "*" "+" "," ";" "=" %encoded
  // I've never seen a (non-IDN) hostname other than: ALPHA DIGIT . -
  URI.invalid_hostname_characters = /[^a-zA-Z0-9\.-]/;
  // map DOM Elements to their URI attribute
  URI.domAttributes = {
      'a': 'href',
      'blockquote': 'cite',
      'link': 'href',
      'base': 'href',
      'script': 'src',
      'form': 'action',
      'img': 'src',
      'area': 'href',
      'iframe': 'src',
      'embed': 'src',
      'source': 'src',
      'track': 'src',
      'input': 'src' // but only if type="image"
  };
  URI.getDomAttribute = function(node) {
      if (!node || !node.nodeName) {
          return undefined;
      }
      
      var nodeName = node.nodeName.toLowerCase();
      // <input> should only expose src for type="image"
      if (nodeName === 'input' && node.type !== 'image') {
          return undefined;
      }
      
      return URI.domAttributes[nodeName];
  };
  
  function escapeForDumbFirefox36(value) {
      // https://github.com/medialize/URI.js/issues/91
      return escape(value);
  }
  
  // encoding / decoding according to RFC3986
  function strictEncodeURIComponent(string) {
      // see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/encodeURIComponent
      return encodeURIComponent(string)
          .replace(/[!'()*]/g, escapeForDumbFirefox36)
          .replace(/\*/g, "%2A");
  }
  URI.encode = strictEncodeURIComponent;
  URI.decode = decodeURIComponent;
  URI.iso8859 = function() {
      URI.encode = escape;
      URI.decode = unescape;
  };
  URI.unicode = function() {
      URI.encode = strictEncodeURIComponent;
      URI.decode = decodeURIComponent;
  };
  URI.characters = {
      pathname: {
          encode: {
              // RFC3986 2.1: For consistency, URI producers and normalizers should
              // use uppercase hexadecimal digits for all percent-encodings.
              expression: /%(24|26|2B|2C|3B|3D|3A|40)/ig,
              map: {
                  // -._~!'()*
                  "%24": "$",
                  "%26": "&",
                  "%2B": "+",
                  "%2C": ",",
                  "%3B": ";",
                  "%3D": "=",
                  "%3A": ":",
                  "%40": "@"
              }
          },
          decode: {
              expression: /[\/\?#]/g,
              map: {
                  "/": "%2F",
                  "?": "%3F",
                  "#": "%23"
              }
          }
      },
      reserved: {
          encode: {
              // RFC3986 2.1: For consistency, URI producers and normalizers should
              // use uppercase hexadecimal digits for all percent-encodings.
              expression: /%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,
              map: {
                  // gen-delims
                  "%3A": ":",
                  "%2F": "/",
                  "%3F": "?",
                  "%23": "#",
                  "%5B": "[",
                  "%5D": "]",
                  "%40": "@",
                  // sub-delims
                  "%21": "!",
                  "%24": "$",
                  "%26": "&",
                  "%27": "'",
                  "%28": "(",
                  "%29": ")",
                  "%2A": "*",
                  "%2B": "+",
                  "%2C": ",",
                  "%3B": ";",
                  "%3D": "="
              }
          }
      }
  };
  URI.encodeQuery = function(string, escapeQuerySpace) {
      var escaped = URI.encode(string + "");
      return escapeQuerySpace ? escaped.replace(/%20/g, '+') : escaped;
  };
  URI.decodeQuery = function(string, escapeQuerySpace) {
      string += "";
      try {
          return URI.decode(escapeQuerySpace ? string.replace(/\+/g, '%20') : string);
      } catch(e) {
          // we're not going to mess with weird encodings,
          // give up and return the undecoded original string
          // see https://github.com/medialize/URI.js/issues/87
          // see https://github.com/medialize/URI.js/issues/92
          return string;
      }
  };
  URI.recodePath = function(string) {
      var segments = (string + "").split('/');
      for (var i = 0, length = segments.length; i < length; i++) {
          segments[i] = URI.encodePathSegment(URI.decode(segments[i]));
      }
  
      return segments.join('/');
  };
  URI.decodePath = function(string) {
      var segments = (string + "").split('/');
      for (var i = 0, length = segments.length; i < length; i++) {
          segments[i] = URI.decodePathSegment(segments[i]);
      }
  
      return segments.join('/');
  };
  // generate encode/decode path functions
  var _parts = {'encode':'encode', 'decode':'decode'};
  var _part;
  var generateAccessor = function(_group, _part) {
      return function(string) {
          return URI[_part](string + "").replace(URI.characters[_group][_part].expression, function(c) {
              return URI.characters[_group][_part].map[c];
          });
      };
  };
  
  for (_part in _parts) {
      URI[_part + "PathSegment"] = generateAccessor("pathname", _parts[_part]);
  }
  
  URI.encodeReserved = generateAccessor("reserved", "encode");
  
  URI.parse = function(string, parts) {
      var pos;
      if (!parts) {
          parts = {};
      }
      // [protocol"://"[username[":"password]"@"]hostname[":"port]"/"?][path]["?"querystring]["#"fragment]
  
      // extract fragment
      pos = string.indexOf('#');
      if (pos > -1) {
          // escaping?
          parts.fragment = string.substring(pos + 1) || null;
          string = string.substring(0, pos);
      }
  
      // extract query
      pos = string.indexOf('?');
      if (pos > -1) {
          // escaping?
          parts.query = string.substring(pos + 1) || null;
          string = string.substring(0, pos);
      }
  
      // extract protocol
      if (string.substring(0, 2) === '//') {
          // relative-scheme
          parts.protocol = null;
          string = string.substring(2);
          // extract "user:pass@host:port"
          string = URI.parseAuthority(string, parts);
      } else {
          pos = string.indexOf(':');
          if (pos > -1) {
              parts.protocol = string.substring(0, pos) || null;
              if (parts.protocol && !parts.protocol.match(URI.protocol_expression)) {
                  // : may be within the path
                  parts.protocol = undefined;
              } else if (parts.protocol === 'file') {
                  // the file scheme: does not contain an authority
                  string = string.substring(pos + 3);
              } else if (string.substring(pos + 1, pos + 3) === '//') {
                  string = string.substring(pos + 3);
  
                  // extract "user:pass@host:port"
                  string = URI.parseAuthority(string, parts);
              } else {
                  string = string.substring(pos + 1);
                  parts.urn = true;
              }
          }
      }
  
      // what's left must be the path
      parts.path = string;
  
      // and we're done
      return parts;
  };
  URI.parseHost = function(string, parts) {
      // extract host:port
      var pos = string.indexOf('/');
      var bracketPos;
      var t;
  
      if (pos === -1) {
          pos = string.length;
      }
  
      if (string.charAt(0) === "[") {
          // IPv6 host - http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-04#section-6
          // I claim most client software breaks on IPv6 anyways. To simplify things, URI only accepts
          // IPv6+port in the format [2001:db8::1]:80 (for the time being)
          bracketPos = string.indexOf(']');
          parts.hostname = string.substring(1, bracketPos) || null;
          parts.port = string.substring(bracketPos+2, pos) || null;
      } else if (string.indexOf(':') !== string.lastIndexOf(':')) {
          // IPv6 host contains multiple colons - but no port
          // this notation is actually not allowed by RFC 3986, but we're a liberal parser
          parts.hostname = string.substring(0, pos) || null;
          parts.port = null;
      } else {
          t = string.substring(0, pos).split(':');
          parts.hostname = t[0] || null;
          parts.port = t[1] || null;
      }
  
      if (parts.hostname && string.substring(pos).charAt(0) !== '/') {
          pos++;
          string = "/" + string;
      }
  
      return string.substring(pos) || '/';
  };
  URI.parseAuthority = function(string, parts) {
      string = URI.parseUserinfo(string, parts);
      return URI.parseHost(string, parts);
  };
  URI.parseUserinfo = function(string, parts) {
      // extract username:password
      var firstSlash = string.indexOf('/');
      var pos = firstSlash > -1 
          ? string.lastIndexOf('@', firstSlash) 
          : string.indexOf('@');
      var t;
  
      // authority@ must come before /path
      if (pos > -1 && (firstSlash === -1 || pos < firstSlash)) {
          t = string.substring(0, pos).split(':');
          parts.username = t[0] ? URI.decode(t[0]) : null;
          t.shift();
          parts.password = t[0] ? URI.decode(t.join(':')) : null;
          string = string.substring(pos + 1);
      } else {
          parts.username = null;
          parts.password = null;
      }
  
      return string;
  };
  URI.parseQuery = function(string, escapeQuerySpace) {
      if (!string) {
          return {};
      }
  
      // throw out the funky business - "?"[name"="value"&"]+
      string = string.replace(/&+/g, '&').replace(/^\?*&*|&+$/g, '');
  
      if (!string) {
          return {};
      }
  
      var items = {};
      var splits = string.split('&');
      var length = splits.length;
      var v, name, value;
  
      for (var i = 0; i < length; i++) {
          v = splits[i].split('=');
          name = URI.decodeQuery(v.shift(), escapeQuerySpace);
          // no "=" is null according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#collect-url-parameters
          value = v.length ? URI.decodeQuery(v.join('='), escapeQuerySpace) : null;
  
          if (items[name]) {
              if (typeof items[name] === "string") {
                  items[name] = [items[name]];
              }
  
              items[name].push(value);
          } else {
              items[name] = value;
          }
      }
  
      return items;
  };
  
  URI.build = function(parts) {
      var t = "";
  
      if (parts.protocol) {
          t += parts.protocol + ":";
      }
  
      if (!parts.urn && (t || parts.hostname)) {
          t += '//';
      }
  
      t += (URI.buildAuthority(parts) || '');
  
      if (typeof parts.path === "string") {
          if (parts.path.charAt(0) !== '/' && typeof parts.hostname === "string") {
              t += '/';
          }
  
          t += parts.path;
      }
  
      if (typeof parts.query === "string" && parts.query) {
          t += '?' + parts.query;
      }
  
      if (typeof parts.fragment === "string" && parts.fragment) {
          t += '#' + parts.fragment;
      }
      return t;
  };
  URI.buildHost = function(parts) {
      var t = "";
  
      if (!parts.hostname) {
          return "";
      } else if (URI.ip6_expression.test(parts.hostname)) {
          if (parts.port) {
              t += "[" + parts.hostname + "]:" + parts.port;
          } else {
              // don't know if we should always wrap IPv6 in []
              // the RFC explicitly says SHOULD, not MUST.
              t += parts.hostname;
          }
      } else {
          t += parts.hostname;
          if (parts.port) {
              t += ':' + parts.port;
          }
      }
  
      return t;
  };
  URI.buildAuthority = function(parts) {
      return URI.buildUserinfo(parts) + URI.buildHost(parts);
  };
  URI.buildUserinfo = function(parts) {
      var t = "";
  
      if (parts.username) {
          t += URI.encode(parts.username);
  
          if (parts.password) {
              t += ':' + URI.encode(parts.password);
          }
  
          t += "@";
      }
  
      return t;
  };
  URI.buildQuery = function(data, duplicateQueryParameters, escapeQuerySpace) {
      // according to http://tools.ietf.org/html/rfc3986 or http://labs.apache.org/webarch/uri/rfc/rfc3986.html
      // being »-._~!$&'()*+,;=:@/?« %HEX and alnum are allowed
      // the RFC explicitly states ?/foo being a valid use case, no mention of parameter syntax!
      // URI.js treats the query string as being application/x-www-form-urlencoded
      // see http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type
  
      var t = "";
      var unique, key, i, length;
      for (key in data) {
          if (hasOwn.call(data, key) && key) {
              if (isArray(data[key])) {
                  unique = {};
                  for (i = 0, length = data[key].length; i < length; i++) {
                      if (data[key][i] !== undefined && unique[data[key][i] + ""] === undefined) {
                          t += "&" + URI.buildQueryParameter(key, data[key][i], escapeQuerySpace);
                          if (duplicateQueryParameters !== true) {
                              unique[data[key][i] + ""] = true;
                          }
                      }
                  }
              } else if (data[key] !== undefined) {
                  t += '&' + URI.buildQueryParameter(key, data[key], escapeQuerySpace);
              }
          }
      }
  
      return t.substring(1);
  };
  URI.buildQueryParameter = function(name, value, escapeQuerySpace) {
      // http://www.w3.org/TR/REC-html40/interact/forms.html#form-content-type -- application/x-www-form-urlencoded
      // don't append "=" for null values, according to http://dvcs.w3.org/hg/url/raw-file/tip/Overview.html#url-parameter-serialization
      return URI.encodeQuery(name, escapeQuerySpace) + (value !== null ? "=" + URI.encodeQuery(value, escapeQuerySpace) : "");
  };
  
  URI.addQuery = function(data, name, value) {
      if (typeof name === "object") {
          for (var key in name) {
              if (hasOwn.call(name, key)) {
                  URI.addQuery(data, key, name[key]);
              }
          }
      } else if (typeof name === "string") {
          if (data[name] === undefined) {
              data[name] = value;
              return;
          } else if (typeof data[name] === "string") {
              data[name] = [data[name]];
          }
  
          if (!isArray(value)) {
              value = [value];
          }
  
          data[name] = data[name].concat(value);
      } else {
          throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");
      }
  };
  URI.removeQuery = function(data, name, value) {
      var i, length, key;
      
      if (isArray(name)) {
          for (i = 0, length = name.length; i < length; i++) {
              data[name[i]] = undefined;
          }
      } else if (typeof name === "object") {
          for (key in name) {
              if (hasOwn.call(name, key)) {
                  URI.removeQuery(data, key, name[key]);
              }
          }
      } else if (typeof name === "string") {
          if (value !== undefined) {
              if (data[name] === value) {
                  data[name] = undefined;
              } else if (isArray(data[name])) {
                  data[name] = filterArrayValues(data[name], value);
              }
          } else {
              data[name] = undefined;
          }
      } else {
          throw new TypeError("URI.addQuery() accepts an object, string as the first parameter");
      }
  };
  URI.hasQuery = function(data, name, value, withinArray) {
      if (typeof name === "object") {
          for (var key in name) {
              if (hasOwn.call(name, key)) {
                  if (!URI.hasQuery(data, key, name[key])) {
                      return false;
                  }
              }
          }
          
          return true;
      } else if (typeof name !== "string") {
          throw new TypeError("URI.hasQuery() accepts an object, string as the name parameter");
      }
  
      switch (getType(value)) {
          case 'Undefined':
              // true if exists (but may be empty)
              return name in data; // data[name] !== undefined;
  
          case 'Boolean':
              // true if exists and non-empty
              var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);
              return value === _booly;
  
          case 'Function':
              // allow complex comparison
              return !!value(data[name], name, data);
  
          case 'Array':
              if (!isArray(data[name])) {
                  return false;
              }
  
              var op = withinArray ? arrayContains : arraysEqual;
              return op(data[name], value);
  
          case 'RegExp':
              if (!isArray(data[name])) {
                  return Boolean(data[name] && data[name].match(value));
              }
  
              if (!withinArray) {
                  return false;
              }
  
              return arrayContains(data[name], value);
  
          case 'Number':
              value = String(value);
              // omit break;
          case 'String':
              if (!isArray(data[name])) {
                  return data[name] === value;
              }
  
              if (!withinArray) {
                  return false;
              }
  
              return arrayContains(data[name], value);
  
          default:
              throw new TypeError("URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter");
      }
  };
  
  
  URI.commonPath = function(one, two) {
      var length = Math.min(one.length, two.length);
      var pos;
  
      // find first non-matching character
      for (pos = 0; pos < length; pos++) {
          if (one.charAt(pos) !== two.charAt(pos)) {
              pos--;
              break;
          }
      }
  
      if (pos < 1) {
          return one.charAt(0) === two.charAt(0) && one.charAt(0) === '/' ? '/' : '';
      }
      
      // revert to last /
      if (one.charAt(pos) !== '/' || two.charAt(pos) !== '/') {
          pos = one.substring(0, pos).lastIndexOf('/');
      }
  
      return one.substring(0, pos + 1);
  };
  
  URI.withinString = function(string, callback) {
      // expression used is "gruber revised" (@gruber v2) determined to be the best solution in
      // a regex sprint we did a couple of ages ago at
      // * http://mathiasbynens.be/demo/url-regex
      // * http://rodneyrehm.de/t/url-regex.html
  
      return string.replace(URI.find_uri_expression, callback);
  };
  
  URI.ensureValidHostname = function(v) {
      // Theoretically URIs allow percent-encoding in Hostnames (according to RFC 3986)
      // they are not part of DNS and therefore ignored by URI.js
  
      if (v.match(URI.invalid_hostname_characters)) {
          // test punycode
          if (!punycode) {
              throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-] and Punycode.js is not available");
          }
  
          if (punycode.toASCII(v).match(URI.invalid_hostname_characters)) {
              throw new TypeError("Hostname '" + v + "' contains characters other than [A-Z0-9.-]");
          }
      }
  };
  
  // noConflict
  URI.noConflict = function(removeAll) {
      if (removeAll) {
          var unconflicted = {
              URI: this.noConflict()
          };
  
          if (URITemplate && typeof URITemplate.noConflict == "function") {
              unconflicted.URITemplate = URITemplate.noConflict();
          }
  
          if (IPv6 && typeof IPv6.noConflict == "function") {
              unconflicted.IPv6 = IPv6.noConflict();
          }
  
          if (SecondLevelDomains && typeof SecondLevelDomains.noConflict == "function") {
              unconflicted.SecondLevelDomains = SecondLevelDomains.noConflict();
          }
  
          return unconflicted;
      } else if (root.URI === this) {
          root.URI = _URI;
      }
  
      return this;
  };
  
  p.build = function(deferBuild) {
      if (deferBuild === true) {
          this._deferred_build = true;
      } else if (deferBuild === undefined || this._deferred_build) {
          this._string = URI.build(this._parts);
          this._deferred_build = false;
      }
  
      return this;
  };
  
  p.clone = function() {
      return new URI(this);
  };
  
  p.valueOf = p.toString = function() {
      return this.build(false)._string;
  };
  
  // generate simple accessors
  _parts = {protocol: 'protocol', username: 'username', password: 'password', hostname: 'hostname',  port: 'port'};
  generateAccessor = function(_part){
      return function(v, build) {
          if (v === undefined) {
              return this._parts[_part] || "";
          } else {
              this._parts[_part] = v || null;
              this.build(!build);
              return this;
          }
      };
  };
  
  for (_part in _parts) {                                                                                                                                                                                        
      p[_part] = generateAccessor(_parts[_part]);
  }
  
  // generate accessors with optionally prefixed input
  _parts = {query: '?', fragment: '#'};
  generateAccessor = function(_part, _key){
      return function(v, build) {
          if (v === undefined) {
              return this._parts[_part] || "";
          } else {
              if (v !== null) {
                  v = v + "";
                  if (v.charAt(0) === _key) {
                      v = v.substring(1);
                  }
              }
  
              this._parts[_part] = v;
              this.build(!build);
              return this;
          }
      };
  };
  
  for (_part in _parts) {
      p[_part] = generateAccessor(_part, _parts[_part]);
  }
  
  // generate accessors with prefixed output
  _parts = {search: ['?', 'query'], hash: ['#', 'fragment']};
  generateAccessor = function(_part, _key){
      return function(v, build) {
          var t = this[_part](v, build);
          return typeof t === "string" && t.length ? (_key + t) : t;
      };
  };
  
  for (_part in _parts) {
      p[_part] = generateAccessor(_parts[_part][1], _parts[_part][0]);
  }
  
  p.pathname = function(v, build) {
      if (v === undefined || v === true) {
          var res = this._parts.path || (this._parts.hostname ? '/' : '');
          return v ? URI.decodePath(res) : res;
      } else {
          this._parts.path = v ? URI.recodePath(v) : "/";
          this.build(!build);
          return this;
      }
  };
  p.path = p.pathname;
  p.href = function(href, build) {
      var key;
      
      if (href === undefined) {
          return this.toString();
      }
  
      this._string = "";
      this._parts = URI._parts();
  
      var _URI = href instanceof URI;
      var _object = typeof href === "object" && (href.hostname || href.path || href.pathname);
      if (href.nodeName) {
          var attribute = URI.getDomAttribute(href);
          href = href[attribute] || "";
          _object = false;
      }
      
      // window.location is reported to be an object, but it's not the sort
      // of object we're looking for: 
      // * location.protocol ends with a colon
      // * location.query != object.search
      // * location.hash != object.fragment
      // simply serializing the unknown object should do the trick 
      // (for location, not for everything...)
      if (!_URI && _object && href.pathname !== undefined) {
          href = href.toString();
      }
  
      if (typeof href === "string") {
          this._parts = URI.parse(href, this._parts);
      } else if (_URI || _object) {
          var src = _URI ? href._parts : href;
          for (key in src) {
              if (hasOwn.call(this._parts, key)) {
                  this._parts[key] = src[key];
              }
          }
      } else {
          throw new TypeError("invalid input");
      }
  
      this.build(!build);
      return this;
  };
  
  // identification accessors
  p.is = function(what) {
      var ip = false;
      var ip4 = false;
      var ip6 = false;
      var name = false;
      var sld = false;
      var idn = false;
      var punycode = false;
      var relative = !this._parts.urn;
  
      if (this._parts.hostname) {
          relative = false;
          ip4 = URI.ip4_expression.test(this._parts.hostname);
          ip6 = URI.ip6_expression.test(this._parts.hostname);
          ip = ip4 || ip6;
          name = !ip;
          sld = name && SLD && SLD.has(this._parts.hostname);
          idn = name && URI.idn_expression.test(this._parts.hostname);
          punycode = name && URI.punycode_expression.test(this._parts.hostname);
      }
  
      switch (what.toLowerCase()) {
          case 'relative':
              return relative;
  
          case 'absolute':
              return !relative;
  
          // hostname identification
          case 'domain':
          case 'name':
              return name;
  
          case 'sld':
              return sld;
  
          case 'ip':
              return ip;
  
          case 'ip4':
          case 'ipv4':
          case 'inet4':
              return ip4;
  
          case 'ip6':
          case 'ipv6':
          case 'inet6':
              return ip6;
  
          case 'idn':
              return idn;
  
          case 'url':
              return !this._parts.urn;
  
          case 'urn':
              return !!this._parts.urn;
  
          case 'punycode':
              return punycode;
      }
  
      return null;
  };
  
  // component specific input validation
  var _protocol = p.protocol;
  var _port = p.port;
  var _hostname = p.hostname;
  
  p.protocol = function(v, build) {
      if (v !== undefined) {
          if (v) {
              // accept trailing ://
              v = v.replace(/:(\/\/)?$/, '');
  
              if (v.match(/[^a-zA-z0-9\.+-]/)) {
                  throw new TypeError("Protocol '" + v + "' contains characters other than [A-Z0-9.+-]");
              }
          }
      }
      return _protocol.call(this, v, build);
  };
  p.scheme = p.protocol;
  p.port = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v !== undefined) {
          if (v === 0) {
              v = null;
          }
  
          if (v) {
              v += "";
              if (v.charAt(0) === ":") {
                  v = v.substring(1);
              }
  
              if (v.match(/[^0-9]/)) {
                  throw new TypeError("Port '" + v + "' contains characters other than [0-9]");
              }
          }
      }
      return _port.call(this, v, build);
  };
  p.hostname = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v !== undefined) {
          var x = {};
          URI.parseHost(v, x);
          v = x.hostname;
      }
      return _hostname.call(this, v, build);
  };
  
  // compound accessors
  p.host = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined) {
          return this._parts.hostname ? URI.buildHost(this._parts) : "";
      } else {
          URI.parseHost(v, this._parts);
          this.build(!build);
          return this;
      }
  };
  p.authority = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined) {
          return this._parts.hostname ? URI.buildAuthority(this._parts) : "";
      } else {
          URI.parseAuthority(v, this._parts);
          this.build(!build);
          return this;
      }
  };
  p.userinfo = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined) {
          if (!this._parts.username) {
              return "";
          }
  
          var t = URI.buildUserinfo(this._parts);
          return t.substring(0, t.length -1);
      } else {
          if (v[v.length-1] !== '@') {
              v += '@';
          }
  
          URI.parseUserinfo(v, this._parts);
          this.build(!build);
          return this;
      }
  };
  p.resource = function(v, build) {
      var parts;
      
      if (v === undefined) {
          return this.path() + this.search() + this.hash();
      }
      
      parts = URI.parse(v);
      this._parts.path = parts.path;
      this._parts.query = parts.query;
      this._parts.fragment = parts.fragment;
      this.build(!build);
      return this;
  };
  
  // fraction accessors
  p.subdomain = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      // convenience, return "www" from "www.example.org"
      if (v === undefined) {
          if (!this._parts.hostname || this.is('IP')) {
              return "";
          }
  
          // grab domain and add another segment
          var end = this._parts.hostname.length - this.domain().length - 1;
          return this._parts.hostname.substring(0, end) || "";
      } else {
          var e = this._parts.hostname.length - this.domain().length;
          var sub = this._parts.hostname.substring(0, e);
          var replace = new RegExp('^' + escapeRegEx(sub));
  
          if (v && v.charAt(v.length - 1) !== '.') {
              v += ".";
          }
  
          if (v) {
              URI.ensureValidHostname(v);
          }
  
          this._parts.hostname = this._parts.hostname.replace(replace, v);
          this.build(!build);
          return this;
      }
  };
  p.domain = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (typeof v === 'boolean') {
          build = v;
          v = undefined;
      }
  
      // convenience, return "example.org" from "www.example.org"
      if (v === undefined) {
          if (!this._parts.hostname || this.is('IP')) {
              return "";
          }
  
          // if hostname consists of 1 or 2 segments, it must be the domain
          var t = this._parts.hostname.match(/\./g);
          if (t && t.length < 2) {
              return this._parts.hostname;
          }
  
          // grab tld and add another segment
          var end = this._parts.hostname.length - this.tld(build).length - 1;
          end = this._parts.hostname.lastIndexOf('.', end -1) + 1;
          return this._parts.hostname.substring(end) || "";
      } else {
          if (!v) {
              throw new TypeError("cannot set domain empty");
          }
  
          URI.ensureValidHostname(v);
  
          if (!this._parts.hostname || this.is('IP')) {
              this._parts.hostname = v;
          } else {
              var replace = new RegExp(escapeRegEx(this.domain()) + "$");
              this._parts.hostname = this._parts.hostname.replace(replace, v);
          }
  
          this.build(!build);
          return this;
      }
  };
  p.tld = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (typeof v === 'boolean') {
          build = v;
          v = undefined;
      }
  
      // return "org" from "www.example.org"
      if (v === undefined) {
          if (!this._parts.hostname || this.is('IP')) {
              return "";
          }
  
          var pos = this._parts.hostname.lastIndexOf('.');
          var tld = this._parts.hostname.substring(pos + 1);
  
          if (build !== true && SLD && SLD.list[tld.toLowerCase()]) {
              return SLD.get(this._parts.hostname) || tld;
          }
  
          return tld;
      } else {
          var replace;
          
          if (!v) {
              throw new TypeError("cannot set TLD empty");
          } else if (v.match(/[^a-zA-Z0-9-]/)) {
              if (SLD && SLD.is(v)) {
                  replace = new RegExp(escapeRegEx(this.tld()) + "$");
                  this._parts.hostname = this._parts.hostname.replace(replace, v);
              } else {
                  throw new TypeError("TLD '" + v + "' contains characters other than [A-Z0-9]");
              }
          } else if (!this._parts.hostname || this.is('IP')) {
              throw new ReferenceError("cannot set TLD on non-domain host");
          } else {
              replace = new RegExp(escapeRegEx(this.tld()) + "$");
              this._parts.hostname = this._parts.hostname.replace(replace, v);
          }
  
          this.build(!build);
          return this;
      }
  };
  p.directory = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined || v === true) {
          if (!this._parts.path && !this._parts.hostname) {
              return '';
          }
  
          if (this._parts.path === '/') {
              return '/';
          }
  
          var end = this._parts.path.length - this.filename().length - 1;
          var res = this._parts.path.substring(0, end) || (this._parts.hostname ? "/" : "");
  
          return v ? URI.decodePath(res) : res;
  
      } else {
          var e = this._parts.path.length - this.filename().length;
          var directory = this._parts.path.substring(0, e);
          var replace = new RegExp('^' + escapeRegEx(directory));
  
          // fully qualifier directories begin with a slash
          if (!this.is('relative')) {
              if (!v) {
                  v = '/';
              }
  
              if (v.charAt(0) !== '/') {
                  v = "/" + v;
              }
          }
  
          // directories always end with a slash
          if (v && v.charAt(v.length - 1) !== '/') {
              v += '/';
          }
  
          v = URI.recodePath(v);
          this._parts.path = this._parts.path.replace(replace, v);
          this.build(!build);
          return this;
      }
  };
  p.filename = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined || v === true) {
          if (!this._parts.path || this._parts.path === '/') {
              return "";
          }
  
          var pos = this._parts.path.lastIndexOf('/');
          var res = this._parts.path.substring(pos+1);
  
          return v ? URI.decodePathSegment(res) : res;
      } else {
          var mutatedDirectory = false;
          
          if (v.charAt(0) === '/') {
              v = v.substring(1);
          }
  
          if (v.match(/\.?\//)) {
              mutatedDirectory = true;
          }
  
          var replace = new RegExp(escapeRegEx(this.filename()) + "$");
          v = URI.recodePath(v);
          this._parts.path = this._parts.path.replace(replace, v);
  
          if (mutatedDirectory) {
              this.normalizePath(build);
          } else {
              this.build(!build);
          }
  
          return this;
      }
  };
  p.suffix = function(v, build) {
      if (this._parts.urn) {
          return v === undefined ? '' : this;
      }
  
      if (v === undefined || v === true) {
          if (!this._parts.path || this._parts.path === '/') {
              return "";
          }
  
          var filename = this.filename();
          var pos = filename.lastIndexOf('.');
          var s, res;
  
          if (pos === -1) {
              return "";
          }
  
          // suffix may only contain alnum characters (yup, I made this up.)
          s = filename.substring(pos+1);
          res = (/^[a-z0-9%]+$/i).test(s) ? s : "";
          return v ? URI.decodePathSegment(res) : res;
      } else {
          if (v.charAt(0) === '.') {
              v = v.substring(1);
          }
  
          var suffix = this.suffix();
          var replace;
  
          if (!suffix) {
              if (!v) {
                  return this;
              }
  
              this._parts.path += '.' + URI.recodePath(v);
          } else if (!v) {
              replace = new RegExp(escapeRegEx("." + suffix) + "$");
          } else {
              replace = new RegExp(escapeRegEx(suffix) + "$");
          }
  
          if (replace) {
              v = URI.recodePath(v);
              this._parts.path = this._parts.path.replace(replace, v);
          }
  
          this.build(!build);
          return this;
      }
  };
  p.segment = function(segment, v, build) {
      var separator = this._parts.urn ? ':' : '/';
      var path = this.path();
      var absolute = path.substring(0, 1) === '/';
      var segments = path.split(separator);
  
      if (segment !== undefined && typeof segment !== 'number') {
          build = v;
          v = segment;
          segment = undefined;
      }
  
      if (segment !== undefined && typeof segment !== 'number') {
          throw new Error("Bad segment '" + segment + "', must be 0-based integer");
      }
  
      if (absolute) {
          segments.shift();
      }
  
      if (segment < 0) {
          // allow negative indexes to address from the end
          segment = Math.max(segments.length + segment, 0);
      }
  
      if (v === undefined) {
          return segment === undefined
              ? segments
              : segments[segment];
      } else if (segment === null || segments[segment] === undefined) {
          if (isArray(v)) {
              segments = [];
              // collapse empty elements within array
              for (var i=0, l=v.length; i < l; i++) {
                  if (!v[i].length && (!segments.length || !segments[segments.length -1].length)) {
                      continue;
                  }
                  
                  if (segments.length && !segments[segments.length -1].length) {
                      segments.pop();
                  }
                  
                  segments.push(v[i]);
              }
          } else if (v || (typeof v === "string")) {
              if (segments[segments.length -1] === "") {
                  // empty trailing elements have to be overwritten
                  // to prevent results such as /foo//bar
                  segments[segments.length -1] = v;
              } else {
                  segments.push(v);
              }
          }
      } else {
          if (v || (typeof v === "string" && v.length)) {
              segments[segment] = v;
          } else {
              segments.splice(segment, 1);
          }
      }
  
      if (absolute) {
          segments.unshift("");
      }
  
      return this.path(segments.join(separator), build);
  };
  p.segmentCoded = function(segment, v, build) {
      var segments, i, l;
  
      if (typeof segment !== 'number') {
          build = v;
          v = segment;
          segment = undefined;
      }
  
      if (v === undefined) {
          segments = this.segment(segment, v, build);
          if (!isArray(segments)) {
              segments = segments !== undefined ? URI.decode(segments) : undefined;
          } else {
              for (i = 0, l = segments.length; i < l; i++) {
                  segments[i] = URI.decode(segments[i]);
              }
          }
  
          return segments;
      }
  
      if (!isArray(v)) {
          v = typeof v === 'string' ? URI.encode(v) : v;
      } else {
          for (i = 0, l = v.length; i < l; i++) {
              v[i] = URI.decode(v[i]);
          }
      }
  
      return this.segment(segment, v, build);
  };
  
  // mutating query string
  var q = p.query;
  p.query = function(v, build) {
      if (v === true) {
          return URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
      } else if (typeof v === "function") {
          var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
          var result = v.call(this, data);
          this._parts.query = URI.buildQuery(result || data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
          this.build(!build);
          return this;
      } else if (v !== undefined && typeof v !== "string") {
          this._parts.query = URI.buildQuery(v, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
          this.build(!build);
          return this;
      } else {
          return q.call(this, v, build);
      }
  };
  p.setQuery = function(name, value, build) {
      var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
      
      if (typeof name === "object") {
          for (var key in name) {
              if (hasOwn.call(name, key)) {
                  data[key] = name[key];
              }
          }
      } else if (typeof name === "string") {
          data[name] = value !== undefined ? value : null;
      } else {
          throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");
      }
      
      this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
      if (typeof name !== "string") {
          build = value;
      }
  
      this.build(!build);
      return this;
  };
  p.addQuery = function(name, value, build) {
      var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
      URI.addQuery(data, name, value === undefined ? null : value);
      this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
      if (typeof name !== "string") {
          build = value;
      }
  
      this.build(!build);
      return this;
  };
  p.removeQuery = function(name, value, build) {
      var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
      URI.removeQuery(data, name, value);
      this._parts.query = URI.buildQuery(data, this._parts.duplicateQueryParameters, this._parts.escapeQuerySpace);
      if (typeof name !== "string") {
          build = value;
      }
  
      this.build(!build);
      return this;
  };
  p.hasQuery = function(name, value, withinArray) {
      var data = URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace);
      return URI.hasQuery(data, name, value, withinArray);
  };
  p.setSearch = p.setQuery;
  p.addSearch = p.addQuery;
  p.removeSearch = p.removeQuery;
  p.hasSearch = p.hasQuery;
  
  // sanitizing URLs
  p.normalize = function() {
      if (this._parts.urn) {
          return this
              .normalizeProtocol(false)
              .normalizeQuery(false)
              .normalizeFragment(false)
              .build();
      }
  
      return this
          .normalizeProtocol(false)
          .normalizeHostname(false)
          .normalizePort(false)
          .normalizePath(false)
          .normalizeQuery(false)
          .normalizeFragment(false)
          .build();
  };
  p.normalizeProtocol = function(build) {
      if (typeof this._parts.protocol === "string") {
          this._parts.protocol = this._parts.protocol.toLowerCase();
          this.build(!build);
      }
  
      return this;
  };
  p.normalizeHostname = function(build) {
      if (this._parts.hostname) {
          if (this.is('IDN') && punycode) {
              this._parts.hostname = punycode.toASCII(this._parts.hostname);
          } else if (this.is('IPv6') && IPv6) {
              this._parts.hostname = IPv6.best(this._parts.hostname);
          }
  
          this._parts.hostname = this._parts.hostname.toLowerCase();
          this.build(!build);
      }
  
      return this;
  };
  p.normalizePort = function(build) {
      // remove port of it's the protocol's default
      if (typeof this._parts.protocol === "string" && this._parts.port === URI.defaultPorts[this._parts.protocol]) {
          this._parts.port = null;
          this.build(!build);
      }
  
      return this;
  };
  p.normalizePath = function(build) {
      if (this._parts.urn) {
          return this;
      }
  
      if (!this._parts.path || this._parts.path === '/') {
          return this;
      }
  
      var _was_relative;
      var _path = this._parts.path;
      var _parent, _pos;
  
      // handle relative paths
      if (_path.charAt(0) !== '/') {
          _was_relative = true;
          _path = '/' + _path;
      }
  
      // resolve simples
      _path = _path
          .replace(/(\/(\.\/)+)|(\/\.$)/g, '/')
          .replace(/\/{2,}/g, '/');
  
      // resolve parents
      while (true) {
          _parent = _path.indexOf('/../');
          if (_parent === -1) {
              // no more ../ to resolve
              break;
          } else if (_parent === 0) {
              // top level cannot be relative...
              _path = _path.substring(3);
              break;
          }
  
          _pos = _path.substring(0, _parent).lastIndexOf('/');
          if (_pos === -1) {
              _pos = _parent;
          }
          _path = _path.substring(0, _pos) + _path.substring(_parent + 3);
      }
  
      // revert to relative
      if (_was_relative && this.is('relative')) {
          _path = _path.substring(1);
      }
  
      _path = URI.recodePath(_path);
      this._parts.path = _path;
      this.build(!build);
      return this;
  };
  p.normalizePathname = p.normalizePath;
  p.normalizeQuery = function(build) {
      if (typeof this._parts.query === "string") {
          if (!this._parts.query.length) {
              this._parts.query = null;
          } else {
              this.query(URI.parseQuery(this._parts.query, this._parts.escapeQuerySpace));
          }
  
          this.build(!build);
      }
  
      return this;
  };
  p.normalizeFragment = function(build) {
      if (!this._parts.fragment) {
          this._parts.fragment = null;
          this.build(!build);
      }
  
      return this;
  };
  p.normalizeSearch = p.normalizeQuery;
  p.normalizeHash = p.normalizeFragment;
  
  p.iso8859 = function() {
      // expect unicode input, iso8859 output
      var e = URI.encode;
      var d = URI.decode;
  
      URI.encode = escape;
      URI.decode = decodeURIComponent;
      this.normalize();
      URI.encode = e;
      URI.decode = d;
      return this;
  };
  
  p.unicode = function() {
      // expect iso8859 input, unicode output
      var e = URI.encode;
      var d = URI.decode;
  
      URI.encode = strictEncodeURIComponent;
      URI.decode = unescape;
      this.normalize();
      URI.encode = e;
      URI.decode = d;
      return this;
  };
  
  p.readable = function() {
      var uri = this.clone();
      // removing username, password, because they shouldn't be displayed according to RFC 3986
      uri.username("").password("").normalize();
      var t = '';
      if (uri._parts.protocol) {
          t += uri._parts.protocol + '://';
      }
  
      if (uri._parts.hostname) {
          if (uri.is('punycode') && punycode) {
              t += punycode.toUnicode(uri._parts.hostname);
              if (uri._parts.port) {
                  t += ":" + uri._parts.port;
              }
          } else {
              t += uri.host();
          }
      }
  
      if (uri._parts.hostname && uri._parts.path && uri._parts.path.charAt(0) !== '/') {
          t += '/';
      }
  
      t += uri.path(true);
      if (uri._parts.query) {
          var q = '';
          for (var i = 0, qp = uri._parts.query.split('&'), l = qp.length; i < l; i++) {
              var kv = (qp[i] || "").split('=');
              q += '&' + URI.decodeQuery(kv[0], this._parts.escapeQuerySpace)
                  .replace(/&/g, '%26');
  
              if (kv[1] !== undefined) {
                  q += "=" + URI.decodeQuery(kv[1], this._parts.escapeQuerySpace)
                      .replace(/&/g, '%26');
              }
          }
          t += '?' + q.substring(1);
      }
  
      t += URI.decodeQuery(uri.hash(), true);
      return t;
  };
  
  // resolving relative and absolute URLs
  p.absoluteTo = function(base) {
      var resolved = this.clone();
      var properties = ['protocol', 'username', 'password', 'hostname', 'port'];
      var basedir, i, p;
  
      if (this._parts.urn) {
          throw new Error('URNs do not have any generally defined hierarchical components');
      }
  
      if (!(base instanceof URI)) {
          base = new URI(base);
      }
      
      if (!resolved._parts.protocol) {
          resolved._parts.protocol = base._parts.protocol;
      }
      
      if (this._parts.hostname) {
          return resolved;
      }
  
      for (i = 0; p = properties[i]; i++) {
          resolved._parts[p] = base._parts[p];
      }
      
      properties = ['query', 'path'];
      for (i = 0; p = properties[i]; i++) {
          if (!resolved._parts[p] && base._parts[p]) {
              resolved._parts[p] = base._parts[p];
          }
      }
  
      if (resolved.path().charAt(0) !== '/') {
          basedir = base.directory();
          resolved._parts.path = (basedir ? (basedir + '/') : '') + resolved._parts.path;
          resolved.normalizePath();
      }
  
      resolved.build();
      return resolved;
  };
  p.relativeTo = function(base) {
      var relative = this.clone().normalize();
      var relativeParts, baseParts, common, relativePath, basePath;
  
      if (relative._parts.urn) {
          throw new Error('URNs do not have any generally defined hierarchical components');
      }
  
      base = new URI(base).normalize();
      relativeParts = relative._parts;
      baseParts = base._parts;
      relativePath = relative.path();
      basePath = base.path();
  
      if (relativePath.charAt(0) !== '/') {
          throw new Error('URI is already relative');
      }
  
      if (basePath.charAt(0) !== '/') {
          throw new Error('Cannot calculate a URI relative to another relative URI');
      }
  
      if (relativeParts.protocol === baseParts.protocol) {
          relativeParts.protocol = null;
      }
  
      if (relativeParts.username !== baseParts.username || relativeParts.password !== baseParts.password) {
          return relative.build();
      }
  
      if (relativeParts.protocol !== null || relativeParts.username !== null || relativeParts.password !== null) {
          return relative.build();
      }
  
      if (relativeParts.hostname === baseParts.hostname && relativeParts.port === baseParts.port) {
          relativeParts.hostname = null;
          relativeParts.port = null;
      } else {
          return relative.build();
      }
  
      if (relativePath === basePath) {
          relativeParts.path = '';
          return relative.build();
      }
      
      // determine common sub path
      common = URI.commonPath(relative.path(), base.path());
  
      // If the paths have nothing in common, return a relative URL with the absolute path.
      if (!common) {
          return relative.build();
      }
  
      var parents = baseParts.path
          .substring(common.length)
          .replace(/[^\/]*$/, '')
          .replace(/.*?\//g, '../');
  
      relativeParts.path = parents + relativeParts.path.substring(common.length);
  
      return relative.build();
  };
  
  // comparing URIs
  p.equals = function(uri) {
      var one = this.clone();
      var two = new URI(uri);
      var one_map = {};
      var two_map = {};
      var checked = {};
      var one_query, two_query, key;
  
      one.normalize();
      two.normalize();
  
      // exact match
      if (one.toString() === two.toString()) {
          return true;
      }
  
      // extract query string
      one_query = one.query();
      two_query = two.query();
      one.query("");
      two.query("");
  
      // definitely not equal if not even non-query parts match
      if (one.toString() !== two.toString()) {
          return false;
      }
  
      // query parameters have the same length, even if they're permuted
      if (one_query.length !== two_query.length) {
          return false;
      }
  
      one_map = URI.parseQuery(one_query, this._parts.escapeQuerySpace);
      two_map = URI.parseQuery(two_query, this._parts.escapeQuerySpace);
  
      for (key in one_map) {
          if (hasOwn.call(one_map, key)) {
              if (!isArray(one_map[key])) {
                  if (one_map[key] !== two_map[key]) {
                      return false;
                  }
              } else if (!arraysEqual(one_map[key], two_map[key])) {
                  return false;
              }
  
              checked[key] = true;
          }
      }
  
      for (key in two_map) {
          if (hasOwn.call(two_map, key)) {
              if (!checked[key]) {
                  // two contains a parameter not present in one
                  return false;
              }
          }
      }
  
      return true;
  };
  
  // state
  p.duplicateQueryParameters = function(v) {
      this._parts.duplicateQueryParameters = !!v;
      return this;
  };
  
  p.escapeQuerySpace = function(v) {
      this._parts.escapeQuerySpace = !!v;
      return this;
  };
  
  return URI;
  }));
  /*!
   * jQuery UI Position 1.10.4
   * http://jqueryui.com
   *
   * Copyright 2014 jQuery Foundation and other contributors
   * Released under the MIT license.
   * http://jquery.org/license
   *
   * http://api.jqueryui.com/position/
   */
  (function( $, undefined ) {
  
  $.ui = $.ui || {};
  
  var cachedScrollbarWidth,
  	max = Math.max,
  	abs = Math.abs,
  	round = Math.round,
  	rhorizontal = /left|center|right/,
  	rvertical = /top|center|bottom/,
  	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
  	rposition = /^\w+/,
  	rpercent = /%$/,
  	_position = $.fn.position;
  
  function getOffsets( offsets, width, height ) {
  	return [
  		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
  		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
  	];
  }
  
  function parseCss( element, property ) {
  	return parseInt( $.css( element, property ), 10 ) || 0;
  }
  
  function getDimensions( elem ) {
  	var raw = elem[0];
  	if ( raw.nodeType === 9 ) {
  		return {
  			width: elem.width(),
  			height: elem.height(),
  			offset: { top: 0, left: 0 }
  		};
  	}
  	if ( $.isWindow( raw ) ) {
  		return {
  			width: elem.width(),
  			height: elem.height(),
  			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
  		};
  	}
  	if ( raw.preventDefault ) {
  		return {
  			width: 0,
  			height: 0,
  			offset: { top: raw.pageY, left: raw.pageX }
  		};
  	}
  	return {
  		width: elem.outerWidth(),
  		height: elem.outerHeight(),
  		offset: elem.offset()
  	};
  }
  
  $.position = {
  	scrollbarWidth: function() {
  		if ( cachedScrollbarWidth !== undefined ) {
  			return cachedScrollbarWidth;
  		}
  		var w1, w2,
  			div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
  			innerDiv = div.children()[0];
  
  		$( "body" ).append( div );
  		w1 = innerDiv.offsetWidth;
  		div.css( "overflow", "scroll" );
  
  		w2 = innerDiv.offsetWidth;
  
  		if ( w1 === w2 ) {
  			w2 = div[0].clientWidth;
  		}
  
  		div.remove();
  
  		return (cachedScrollbarWidth = w1 - w2);
  	},
  	getScrollInfo: function( within ) {
  		var overflowX = within.isWindow || within.isDocument ? "" :
  				within.element.css( "overflow-x" ),
  			overflowY = within.isWindow || within.isDocument ? "" :
  				within.element.css( "overflow-y" ),
  			hasOverflowX = overflowX === "scroll" ||
  				( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
  			hasOverflowY = overflowY === "scroll" ||
  				( overflowY === "auto" && within.height < within.element[0].scrollHeight );
  		return {
  			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
  			height: hasOverflowX ? $.position.scrollbarWidth() : 0
  		};
  	},
  	getWithinInfo: function( element ) {
  		var withinElement = $( element || window ),
  			isWindow = $.isWindow( withinElement[0] ),
  			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
  		return {
  			element: withinElement,
  			isWindow: isWindow,
  			isDocument: isDocument,
  			offset: withinElement.offset() || { left: 0, top: 0 },
  			scrollLeft: withinElement.scrollLeft(),
  			scrollTop: withinElement.scrollTop(),
  			width: isWindow ? withinElement.width() : withinElement.outerWidth(),
  			height: isWindow ? withinElement.height() : withinElement.outerHeight()
  		};
  	}
  };
  
  $.fn.position = function( options ) {
  	if ( !options || !options.of ) {
  		return _position.apply( this, arguments );
  	}
  
  	// make a copy, we don't want to modify arguments
  	options = $.extend( {}, options );
  
  	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
  		target = $( options.of ),
  		within = $.position.getWithinInfo( options.within ),
  		scrollInfo = $.position.getScrollInfo( within ),
  		collision = ( options.collision || "flip" ).split( " " ),
  		offsets = {};
  
  	dimensions = getDimensions( target );
  	if ( target[0].preventDefault ) {
  		// force left top to allow flipping
  		options.at = "left top";
  	}
  	targetWidth = dimensions.width;
  	targetHeight = dimensions.height;
  	targetOffset = dimensions.offset;
  	// clone to reuse original targetOffset later
  	basePosition = $.extend( {}, targetOffset );
  
  	// force my and at to have valid horizontal and vertical positions
  	// if a value is missing or invalid, it will be converted to center
  	$.each( [ "my", "at" ], function() {
  		var pos = ( options[ this ] || "" ).split( " " ),
  			horizontalOffset,
  			verticalOffset;
  
  		if ( pos.length === 1) {
  			pos = rhorizontal.test( pos[ 0 ] ) ?
  				pos.concat( [ "center" ] ) :
  				rvertical.test( pos[ 0 ] ) ?
  					[ "center" ].concat( pos ) :
  					[ "center", "center" ];
  		}
  		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
  		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
  
  		// calculate offsets
  		horizontalOffset = roffset.exec( pos[ 0 ] );
  		verticalOffset = roffset.exec( pos[ 1 ] );
  		offsets[ this ] = [
  			horizontalOffset ? horizontalOffset[ 0 ] : 0,
  			verticalOffset ? verticalOffset[ 0 ] : 0
  		];
  
  		// reduce to just the positions without the offsets
  		options[ this ] = [
  			rposition.exec( pos[ 0 ] )[ 0 ],
  			rposition.exec( pos[ 1 ] )[ 0 ]
  		];
  	});
  
  	// normalize collision option
  	if ( collision.length === 1 ) {
  		collision[ 1 ] = collision[ 0 ];
  	}
  
  	if ( options.at[ 0 ] === "right" ) {
  		basePosition.left += targetWidth;
  	} else if ( options.at[ 0 ] === "center" ) {
  		basePosition.left += targetWidth / 2;
  	}
  
  	if ( options.at[ 1 ] === "bottom" ) {
  		basePosition.top += targetHeight;
  	} else if ( options.at[ 1 ] === "center" ) {
  		basePosition.top += targetHeight / 2;
  	}
  
  	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
  	basePosition.left += atOffset[ 0 ];
  	basePosition.top += atOffset[ 1 ];
  
  	return this.each(function() {
  		var collisionPosition, using,
  			elem = $( this ),
  			elemWidth = elem.outerWidth(),
  			elemHeight = elem.outerHeight(),
  			marginLeft = parseCss( this, "marginLeft" ),
  			marginTop = parseCss( this, "marginTop" ),
  			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
  			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
  			position = $.extend( {}, basePosition ),
  			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
  
  		if ( options.my[ 0 ] === "right" ) {
  			position.left -= elemWidth;
  		} else if ( options.my[ 0 ] === "center" ) {
  			position.left -= elemWidth / 2;
  		}
  
  		if ( options.my[ 1 ] === "bottom" ) {
  			position.top -= elemHeight;
  		} else if ( options.my[ 1 ] === "center" ) {
  			position.top -= elemHeight / 2;
  		}
  
  		position.left += myOffset[ 0 ];
  		position.top += myOffset[ 1 ];
  
  		// if the browser doesn't support fractions, then round for consistent results
  		if ( !$.support.offsetFractions ) {
  			position.left = round( position.left );
  			position.top = round( position.top );
  		}
  
  		collisionPosition = {
  			marginLeft: marginLeft,
  			marginTop: marginTop
  		};
  
  		$.each( [ "left", "top" ], function( i, dir ) {
  			if ( $.ui.position[ collision[ i ] ] ) {
  				$.ui.position[ collision[ i ] ][ dir ]( position, {
  					targetWidth: targetWidth,
  					targetHeight: targetHeight,
  					elemWidth: elemWidth,
  					elemHeight: elemHeight,
  					collisionPosition: collisionPosition,
  					collisionWidth: collisionWidth,
  					collisionHeight: collisionHeight,
  					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
  					my: options.my,
  					at: options.at,
  					within: within,
  					elem : elem
  				});
  			}
  		});
  
  		if ( options.using ) {
  			// adds feedback as second argument to using callback, if present
  			using = function( props ) {
  				var left = targetOffset.left - position.left,
  					right = left + targetWidth - elemWidth,
  					top = targetOffset.top - position.top,
  					bottom = top + targetHeight - elemHeight,
  					feedback = {
  						target: {
  							element: target,
  							left: targetOffset.left,
  							top: targetOffset.top,
  							width: targetWidth,
  							height: targetHeight
  						},
  						element: {
  							element: elem,
  							left: position.left,
  							top: position.top,
  							width: elemWidth,
  							height: elemHeight
  						},
  						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
  						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
  					};
  				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
  					feedback.horizontal = "center";
  				}
  				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
  					feedback.vertical = "middle";
  				}
  				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
  					feedback.important = "horizontal";
  				} else {
  					feedback.important = "vertical";
  				}
  				options.using.call( this, props, feedback );
  			};
  		}
  
  		elem.offset( $.extend( position, { using: using } ) );
  	});
  };
  
  $.ui.position = {
  	fit: {
  		left: function( position, data ) {
  			var within = data.within,
  				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
  				outerWidth = within.width,
  				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  				overLeft = withinOffset - collisionPosLeft,
  				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
  				newOverRight;
  
  			// element is wider than within
  			if ( data.collisionWidth > outerWidth ) {
  				// element is initially over the left side of within
  				if ( overLeft > 0 && overRight <= 0 ) {
  					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
  					position.left += overLeft - newOverRight;
  				// element is initially over right side of within
  				} else if ( overRight > 0 && overLeft <= 0 ) {
  					position.left = withinOffset;
  				// element is initially over both left and right sides of within
  				} else {
  					if ( overLeft > overRight ) {
  						position.left = withinOffset + outerWidth - data.collisionWidth;
  					} else {
  						position.left = withinOffset;
  					}
  				}
  			// too far left -> align with left edge
  			} else if ( overLeft > 0 ) {
  				position.left += overLeft;
  			// too far right -> align with right edge
  			} else if ( overRight > 0 ) {
  				position.left -= overRight;
  			// adjust based on position and margin
  			} else {
  				position.left = max( position.left - collisionPosLeft, position.left );
  			}
  		},
  		top: function( position, data ) {
  			var within = data.within,
  				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
  				outerHeight = data.within.height,
  				collisionPosTop = position.top - data.collisionPosition.marginTop,
  				overTop = withinOffset - collisionPosTop,
  				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
  				newOverBottom;
  
  			// element is taller than within
  			if ( data.collisionHeight > outerHeight ) {
  				// element is initially over the top of within
  				if ( overTop > 0 && overBottom <= 0 ) {
  					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
  					position.top += overTop - newOverBottom;
  				// element is initially over bottom of within
  				} else if ( overBottom > 0 && overTop <= 0 ) {
  					position.top = withinOffset;
  				// element is initially over both top and bottom of within
  				} else {
  					if ( overTop > overBottom ) {
  						position.top = withinOffset + outerHeight - data.collisionHeight;
  					} else {
  						position.top = withinOffset;
  					}
  				}
  			// too far up -> align with top
  			} else if ( overTop > 0 ) {
  				position.top += overTop;
  			// too far down -> align with bottom edge
  			} else if ( overBottom > 0 ) {
  				position.top -= overBottom;
  			// adjust based on position and margin
  			} else {
  				position.top = max( position.top - collisionPosTop, position.top );
  			}
  		}
  	},
  	flip: {
  		left: function( position, data ) {
  			var within = data.within,
  				withinOffset = within.offset.left + within.scrollLeft,
  				outerWidth = within.width,
  				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
  				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  				overLeft = collisionPosLeft - offsetLeft,
  				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
  				myOffset = data.my[ 0 ] === "left" ?
  					-data.elemWidth :
  					data.my[ 0 ] === "right" ?
  						data.elemWidth :
  						0,
  				atOffset = data.at[ 0 ] === "left" ?
  					data.targetWidth :
  					data.at[ 0 ] === "right" ?
  						-data.targetWidth :
  						0,
  				offset = -2 * data.offset[ 0 ],
  				newOverRight,
  				newOverLeft;
  
  			if ( overLeft < 0 ) {
  				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
  				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
  					position.left += myOffset + atOffset + offset;
  				}
  			}
  			else if ( overRight > 0 ) {
  				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
  				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
  					position.left += myOffset + atOffset + offset;
  				}
  			}
  		},
  		top: function( position, data ) {
  			var within = data.within,
  				withinOffset = within.offset.top + within.scrollTop,
  				outerHeight = within.height,
  				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
  				collisionPosTop = position.top - data.collisionPosition.marginTop,
  				overTop = collisionPosTop - offsetTop,
  				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
  				top = data.my[ 1 ] === "top",
  				myOffset = top ?
  					-data.elemHeight :
  					data.my[ 1 ] === "bottom" ?
  						data.elemHeight :
  						0,
  				atOffset = data.at[ 1 ] === "top" ?
  					data.targetHeight :
  					data.at[ 1 ] === "bottom" ?
  						-data.targetHeight :
  						0,
  				offset = -2 * data.offset[ 1 ],
  				newOverTop,
  				newOverBottom;
  			if ( overTop < 0 ) {
  				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
  				if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
  					position.top += myOffset + atOffset + offset;
  				}
  			}
  			else if ( overBottom > 0 ) {
  				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
  				if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
  					position.top += myOffset + atOffset + offset;
  				}
  			}
  		}
  	},
  	flipfit: {
  		left: function() {
  			$.ui.position.flip.left.apply( this, arguments );
  			$.ui.position.fit.left.apply( this, arguments );
  		},
  		top: function() {
  			$.ui.position.flip.top.apply( this, arguments );
  			$.ui.position.fit.top.apply( this, arguments );
  		}
  	}
  };
  
  // fraction support test
  (function () {
  	var testElement, testElementParent, testElementStyle, offsetLeft, i,
  		body = document.getElementsByTagName( "body" )[ 0 ],
  		div = document.createElement( "div" );
  
  	//Create a "fake body" for testing based on method used in jQuery.support
  	testElement = document.createElement( body ? "div" : "body" );
  	testElementStyle = {
  		visibility: "hidden",
  		width: 0,
  		height: 0,
  		border: 0,
  		margin: 0,
  		background: "none"
  	};
  	if ( body ) {
  		$.extend( testElementStyle, {
  			position: "absolute",
  			left: "-1000px",
  			top: "-1000px"
  		});
  	}
  	for ( i in testElementStyle ) {
  		testElement.style[ i ] = testElementStyle[ i ];
  	}
  	testElement.appendChild( div );
  	testElementParent = body || document.documentElement;
  	testElementParent.insertBefore( testElement, testElementParent.firstChild );
  
  	div.style.cssText = "position: absolute; left: 10.7432222px;";
  
  	offsetLeft = $( div ).offset().left;
  	$.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11;
  
  	testElement.innerHTML = "";
  	testElementParent.removeChild( testElement );
  })();
  
  }( jQuery ) );
  /*!
   * SAP UI development toolkit for HTML5 (SAPUI5/OpenUI5)
   * (c) Copyright 2009-2015 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  // Provides ECMA Script 6 Polyfill
  (function(jQuery) {
  	"use strict";
  	
  	/*
  	 * No Documentation by intention.
  	 * This class represents a polyfill for ECMA Script 6 Promises
  	 * see http://www.html5rocks.com/en/tutorials/es6/promises/
  	 */
  	
  	var Promise = function(fAction) {
  		if (typeof (fAction) != "function") {
  			throw new TypeError("Argument is not a function");
  		}
  		
  		this._deferred = new jQuery.Deferred();
  
  		try {
  			var that = this;
  			fAction(function(oVal){
  				_finalize(that, oVal, true); //force async resolve
  			}, function(oVal){
  				_finalize(that, oVal, false); //force async reject
  			});
  		} catch (e) { //Error in action rejects the promise
  			_finalize(this, e, false);
  		}
  	};
  	
  	// *** Instance Promise functions ***
  	
  	Promise.prototype.then = function(fOnFulfilled, fOnRejected){
  		var oFollowUpPromise = new Promise(_dummy);
  		this._deferred.then(_doWrap(fOnFulfilled, oFollowUpPromise, true), _doWrap(fOnRejected, oFollowUpPromise, false));
  		return oFollowUpPromise;
  	};
  	
  	Promise.prototype["catch"] = function(fOnRejected){
  		return this.then(undefined, fOnRejected);
  	};
  	
  	
  	// *** Static Promise functions ***
  	
  	Promise.all = function(aPromises){
  		return new Promise(function(fResolve, fReject){
  			if (!jQuery.isArray(aPromises)) {
  				fReject(new TypeError("invalid argument"));
  				return;
  			}
  			if (aPromises.length == 0) {
  				fResolve([]);
  				return;
  			}
  			
  			var bFailed = false,
  				aValues = new Array(aPromises.length),
  				iCount = 0;
  			
  			function _check(iIdx){
  				Promise.resolve(aPromises[iIdx]).then(function(oObj){
  					if (!bFailed) {
  						iCount++;
  						aValues[iIdx] = oObj;
  						if (iCount == aPromises.length) {
  							fResolve(aValues);
  						}
  					}
  				}, function(oObj){
  					if (!bFailed) {
  						bFailed = true;
  						fReject(oObj);
  					}
  				});
  			}
  			
  			for (var i = 0; i < aPromises.length; i++) {
  				_check(i);
  			}
  		});
  	};
  	
  	Promise.race = function(aPromises){
  		return new Promise(function(fResolve, fReject){
  			if (!jQuery.isArray(aPromises)) {
  				fReject(new TypeError("invalid argument"));
  			}
  			
  			var bFinal = false;
  			
  			for (var i = 0; i < aPromises.length; i++) {
  				/*eslint-disable no-loop-func */
  				Promise.resolve(aPromises[i]).then(function(oObj){
  					if (!bFinal) {
  						bFinal = true;
  						fResolve(oObj);
  					}
  				}, function(oObj){
  					if (!bFinal) {
  						bFinal = true;
  						fReject(oObj);
  					}
  				});
  				/*eslint-enable no-loop-func */
  			}
  		});
  	};
  	
  	Promise.resolve = function(oObj){
  		return oObj instanceof Promise ? oObj : _resolve(new Promise(_dummy), oObj);
  	};
  	
  	Promise.reject = function(oObj){
  		return _finalize(new Promise(_dummy), oObj, false);
  	};
  	
  	
  	// *** Helper functions ***
  	
  	function _dummy(){}
  	
  	function _isThenable(oObj){
  		return oObj && oObj.then && typeof (oObj.then) == "function";
  	}
  	
  	function _finalize(oPromise, oObj, bResolve){
  		setTimeout(function(){
  			if (_isThenable(oObj) && bResolve) { //Assimilation
  				_resolve(oPromise, oObj);
  			} else {
  				oPromise._deferred[bResolve ? "resolve" : "reject"](oObj);
  			}
  		}, 0);
  		return oPromise;
  	}
  	
  	function _resolve(oPromise, oObj){
  		if (_isThenable(oObj)) {
  			var bFinal = false;
  			try {
  				oObj.then(function(oVal){
  					_finalize(oPromise, oVal, true);
  					bFinal = true;
  				}, function(oVal){
  					_finalize(oPromise, oVal, false);
  					bFinal = true;
  				});
  			} catch (e) {
  				if (!bFinal) {
  					_finalize(oPromise, e, false);
  				} else {
  					jQuery.sap.log.debug("Promise: Error in then: " + e); //Error is ignored
  				}
  			}
  		} else {
  			_finalize(oPromise, oObj, true);
  		}
  		return oPromise;
  	}
  	
  	function _doWrap(fAction, oPromise, bResolve){
  		return function(oObj){
  			if (!fAction) {
  				_finalize(oPromise, oObj, bResolve);
  			} else {
  				try {
  					_resolve(oPromise, fAction(oObj));
  				} catch (e) { //catch error in fAction
  					_finalize(oPromise, e, false);
  				}
  			}
  		};
  	}
  	
  	
  	// *** Polyfill ***
  	
  	if (!window.Promise) {
  		window.Promise = Promise;
  	}
  
  	if (window.sap && window.sap.__ui5PublishPromisePolyfill) { //For testing purposes
  		window._UI5Promise = Promise;
  	}
  	
  })(jQuery);
  /*!
   * SAP UI development toolkit for HTML5 (SAPUI5/OpenUI5)
   * (c) Copyright 2009-2015 SAP SE or an SAP affiliate company.
   * Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
   */
  
  /*global URI, Promise, alert, console, XMLHttpRequest */
  
  /**
   * @class Provides base functionality of the SAP jQuery plugin as extension of the jQuery framework.<br/>
   * See also <a href="http://api.jquery.com/jQuery/">jQuery</a> for details.<br/>
   * Although these functions appear as static ones, they are meant to be used on jQuery instances.<br/>
   * If not stated differently, the functions follow the fluent interface paradigm and return the jQuery instance for chaining of statements.
   *
   * Example for usage of an instance method:
   * <pre>
   *   var oRect = jQuery("#myDiv").rect();
   *   alert("Top Position: " + oRect.top);
   * </pre>
   *
   * @name jQuery
   * @static
   * @public
   */
  
  (function() {
  
  	if (!window.jQuery ) {
  		throw new Error("SAPUI5 requires jQuery as a prerequisite (>= version 1.7)");
  	}
  
  	// ensure not to initialize twice
  	if (jQuery.sap) {
  		return;
  	}
  
  	/**
  	 * Window that the sap plugin has been initialized for.
  	 * @private
  	 */
  	var _window = window;
  
  	// early logging support
  	var _earlyLogs = [];
  	function _earlyLog(sLevel, sMessage) {
  		_earlyLogs.push({
  			level: sLevel,
  			message: sMessage
  		});
  	}
  
  	var _sBootstrapUrl;
  
  	// -------------------------- VERSION -------------------------------------
  
  	var rVersion = /^[0-9]+(?:\.([0-9]+)(?:\.([0-9]+))?)?(.*)$/;
  
  	/**
  	 * Returns a Version instance created from the given parameters.
  	 *
  	 * This function can either be called as a constructor (using <code>new</code>) or as a normal function.
  	 * It always returns an immutable Version instance.
  	 *
  	 * The parts of the version number (major, minor, patch, suffix) can be provided in several ways:
  	 * <ul>
  	 * <li>Version("1.2.3-SNAPSHOT") - as a dot-separated string. Any non-numerical char or a dot followed by a non-numerical char starts the suffix portion.
  	 * Any missing major, minor or patch versions will be set to 0.</li>
  	 * <li>Version(1,2,3,"-SNAPSHOT") - as individual parameters. Major, minor and patch must be integer numbers or empty, suffix must be a string not starting with digits.</li>
  	 * <li>Version([1,2,3,"-SNAPSHOT"]) - as an array with the individual parts. The same type restrictions apply as before.</li>
  	 * <li>Version(otherVersion) - as a Version instance (cast operation). Returns the given instance instead of creating a new one.</li>
  	 * </ul>
  	 *
  	 * To keep the code size small, this implementation mainly validates the single string variant.
  	 * All other variants are only validated to some degree. It is the responsibility of the caller to
  	 * provide proper parts.
  	 *
  	 * @param {int|string|any[]|jQuery.sap.Version} vMajor the major part of the version (int) or any of the single parameter variants explained above.
  	 * @param {int} iMinor the minor part of the version number
  	 * @param {int} iPatch the patch part of the version number
  	 * @param {string} sSuffix the suffix part of the version number
  	 * @return {jQuery.sap.Version} the version object as determined from the parameters
  	 *
  	 * @class Represents a version consisting of major, minor, patch version and suffix, e.g. '1.2.7-SNAPSHOT'.
  	 *
  	 * @author SAP SE
  	 * @version 1.28.5
  	 * @constructor
  	 * @public
  	 * @since 1.15.0
  	 * @name jQuery.sap.Version
  	 */
  	function Version(vMajor, iMinor, iPatch, sSuffix) {
  		if ( vMajor instanceof Version ) {
  			// note: even a constructor may return a value different from 'this'
  			return vMajor;
  		}
  		if ( !(this instanceof Version) ) {
  			// act as a cast operator when called as function (not as a constructor)
  			return new Version(vMajor, iMinor, iPatch, sSuffix);
  		}
  
  		var m;
  		if (typeof vMajor === "string") {
  			m = rVersion.exec(vMajor);
  		} else if (jQuery.isArray(vMajor)) {
  			m = vMajor;
  		} else {
  			m = arguments;
  		}
  		m = m || [];
  
  		function norm(v) {
  			v = parseInt(v,10);
  			return isNaN(v) ? 0 : v;
  		}
  		vMajor = norm(m[0]);
  		iMinor = norm(m[1]);
  		iPatch = norm(m[2]);
  		sSuffix = String(m[3] || "");
  
  		/**
  		 * Returns a string representation of this version.
  		 *
  		 * @return {string} a string representation of this version.
  		 * @name jQuery.sap.Version#toString
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.toString = function() {
  			return vMajor + "." + iMinor + "." + iPatch + sSuffix;
  		};
  
  		/**
  		 * Returns the major version part of this version.
  		 *
  		 * @return {int} the major version part of this version
  		 * @name jQuery.sap.Version#getMajor
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.getMajor = function() {
  			return vMajor;
  		};
  
  		/**
  		 * Returns the minor version part of this version.
  		 *
  		 * @return {int} the minor version part of this version
  		 * @name jQuery.sap.Version#getMinor
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.getMinor = function() {
  			return iMinor;
  		};
  
  		/**
  		 * Returns the patch (or micro) version part of this version.
  		 *
  		 * @return {int} the patch version part of this version
  		 * @name jQuery.sap.Version#getPatch
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.getPatch = function() {
  			return iPatch;
  		};
  
  		/**
  		 * Returns the version suffix of this version.
  		 *
  		 * @return {string} the version suffix of this version
  		 * @name jQuery.sap.Version#getSuffix
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.getSuffix = function() {
  			return sSuffix;
  		};
  
  		/**
  		 * Compares this version with a given one.
  		 *
  		 * The version with which this version should be compared can be given as
  		 * <code>jQuery.sap.Version</code> instance, as a string (e.g. <code>v.compareto("1.4.5")</code>)
  		 * or major, minor, patch and suffix cab be given as separate parameters (e.g. <code>v.compareTo(1, 4, 5)</code>)
  		 * or in an array (e.g. <code>v.compareTo([1, 4, 5])</code>).
  		 *
  		 * @return {int} 0, if the given version is equal to this version, a negative value if the given version is greater and a positive value otherwise
  		 * @name jQuery.sap.Version#compareTo
  		 * @public
  		 * @since 1.15.0
  		 * @function
  		 */
  		this.compareTo = function() {
  			var vOther = Version.apply(window, arguments);
  			/*eslint-disable no-nested-ternary */
  			return vMajor - vOther.getMajor() ||
  					iMinor - vOther.getMinor() ||
  					iPatch - vOther.getPatch() ||
  					((sSuffix < vOther.getSuffix()) ? -1 : (sSuffix === vOther.getSuffix()) ? 0 : 1);
  			/*eslint-enable no-nested-ternary */
  		};
  
  	}
  
  	/**
  	 * Checks whether this version is in the range of the given versions (start included, end excluded).
  	 *
  	 * The boundaries against which this version should be checked can be given as
  	 * <code>jQuery.sap.Version</code> instances (e.g. <code>v.inRange(v1, v2)</code>), as strings (e.g. <code>v.inRange("1.4", "2.7")</code>)
  	 * or as arrays (e.g. <code>v.inRange([1,4], [2,7])</code>).
  	 *
  	 * @param {string|any[]|jQuery.sap.Version} vMin the start of the range (inclusive)
  	 * @param {string|any[]|jQuery.sap.Version} vMax the end of the range (exclusive)
  	 * @return {boolean} <code>true</code> if this version is greater or equal to <code>vMin</code> and smaller than <code>vMax</code>, <code>false</code> otherwise.
  	 * @name jQuery.sap.Version#inRange
  	 * @public
  	 * @since 1.15.0
  	 * @function
  	 */
  	Version.prototype.inRange = function(vMin, vMax) {
  		return this.compareTo(vMin) >= 0 && this.compareTo(vMax) < 0;
  	};
  
  	// -----------------------------------------------------------------------
  
  	var oJQVersion = Version(jQuery.fn.jquery);
  	if ( !oJQVersion.inRange("1.7.0", "2.0.0") ) {
  		_earlyLog("error", "SAPUI5 requires a jQuery version of 1.7 or higher, but lower than 2.0; current version is " + jQuery.fn.jquery);
  	}
  
  	// TODO move to a separate module? Only adds 385 bytes (compressed), but...
  	if ( !jQuery.browser ) {
  		// re-introduce the jQuery.browser support if missing (jQuery-1.9ff)
  		jQuery.browser = (function( ua ) {
  
  			var rwebkit = /(webkit)[ \/]([\w.]+)/,
  				ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
  				rmsie = /(msie) ([\w.]+)/,
  				rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
  				ua = ua.toLowerCase(),
  				match = rwebkit.exec( ua ) ||
  					ropera.exec( ua ) ||
  					rmsie.exec( ua ) ||
  					ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
  					[],
  				browser = {};
  
  			if ( match[1] ) {
  				browser[ match[1] ] = true;
  				browser.version = match[2] || "0";
  				if ( browser.webkit ) {
  					browser.safari = true;
  				}
  			}
  
  			return browser;
  
  		}(window.navigator.userAgent));
  	}
  
  	// Fixes the CORS issue (introduced by jQuery 1.7) when loading resources
  	// (e.g. SAPUI5 script) from other domains for IE browsers.
  	// The CORS check in jQuery filters out such browsers who do not have the
  	// property "withCredentials" which is the IE and Opera and prevents those
  	// browsers to request data from other domains with jQuery.ajax. The CORS
  	// requests are simply forbidden nevertheless if it works. In our case we
  	// simply load our script resources from another domain when using the CDN
  	// variant of SAPUI5. The following fix is also recommended by jQuery:
  	if (!!sap.ui.Device.browser.internet_explorer) {
  		jQuery.support = jQuery.support || {};
  		jQuery.support.cors = true;
  	}
  
  
  	/**
  	 * Find the script URL where the SAPUI5 is loaded from and return an object which
  	 * contains the identified script-tag and resource root
  	 */
  	var _oBootstrap = (function() {
  		var oTag, sUrl, sResourceRoot,
  			reConfigurator = /^(.*\/)?download\/configurator[\/\?]/,
  			reBootScripts = /^(.*\/)?(sap-ui-(core|custom|boot|merged)(-.*)?)\.js([?#]|$)/,
  			reResources = /^(.*\/)?resources\//;
  
  		// check all script tags that have a src attribute
  		jQuery("script[src]").each(function() {
  			var src = this.getAttribute("src"),
  				m;
  			if ( (m = src.match(reConfigurator)) !== null ) {
  				// guess 1: script tag src contains "/download/configurator[/?]" (for dynamically created bootstrap files)
  				oTag = this;
  				sUrl = src;
  				sResourceRoot = (m[1] || "") + "resources/";
  				return false;
  			} else if ( (m = src.match(reBootScripts)) !== null ) {
  				// guess 2: src contains one of the well known boot script names
  				oTag = this;
  				sUrl = src;
  				sResourceRoot = m[1] || "";
  				return false;
  			} else if ( this.id == 'sap-ui-bootstrap' && (m = src.match(reResources)) ) {
  				// guess 2: script tag has well known id and src contains "resources/"
  				oTag = this;
  				sUrl = src;
  				sResourceRoot = m[0];
  				return false;
  			}
  		});
  		return {
  			tag: oTag,
  			url: sUrl,
  			resourceRoot: sResourceRoot
  		};
  	})();
  
  	/**
  	 * Determine whether sap-bootstrap-debug is set, run debugger statement and allow
  	 * to restart the core from a new URL
  	 */
  	(function() {
  		if (/sap-bootstrap-debug=(true|x|X)/.test(location.search)) {
  			window["sap-ui-bRestart"] = false;
  			window["sap-ui-sRestartUrl"] = "http://localhost:8080/sapui5/resources/sap-ui-core.js";
  
  			// function to replace the bootstrap tag with a newly created script tag to enable
  			// restarting the core from a different server
  			var restartCore = function() {
  				var oScript = _oBootstrap.tag,
  					sScript = "<script src=\"" + window["sap-ui-sRestartUrl"] + "\"";
  				jQuery.each(oScript.attributes, function(i, oAttr) {
  					if (oAttr.nodeName.indexOf("data-sap-ui-") == 0) {
  						sScript += " " + oAttr.nodeName + "=\"" + oAttr.nodeValue + "\"";
  					}
  				});
  				sScript += "></script>";
  				oScript.parentNode.removeChild(oScript);
  
  				// clean up cachebuster stuff
  				jQuery("#sap-ui-bootstrap-cachebusted").remove();
  				window["sap-ui-config"] && window["sap-ui-config"].resourceRoots && (window["sap-ui-config"].resourceRoots[""] = undefined);
  
  				document.write(sScript);
  				var oRestart = new Error("Aborting UI5 bootstrap and restarting from: " + window["sap-ui-sRestartUrl"]);
  				oRestart.name = "Restart";
  
  				// clean up
  				delete window["sap-ui-bRestart"];
  				delete window["sap-ui-sRestartUrl"];
  
  				throw oRestart;
  			};
  
  			// debugger stops here. To restart UI5 from somewhere else (default: localhost), set:
  			//    window["sap-ui-bRestart"] = true
  			// If you want to restart from a different server than localhost, you can adapt the URL, e.g.:
  			//    window["sap-ui-sRestartUrl"] = "http://someserver:8080/sapui5/resources/sap-ui-core.js"
  			/*eslint-disable no-debugger */
  			debugger;
  			/*eslint-enable no-debugger */
  			if (window["sap-ui-bRestart"]) {
  				restartCore();
  			}
  		}
  	})();
  
  	/**
  	 * Determine whether to use debug sources depending on URL parameter and local storage
  	 * and load debug library if necessary
  	 */
  	(function() {
  		//Check URI param
  		var bDebugSources = /sap-ui-debug=(true|x|X)/.test(location.search),
  			bIsOptimized = window["sap-ui-optimized"];
  
  		//Check local storage
  		try { //Necessary for FF when Cookies are deactivated
  			bDebugSources = bDebugSources || (window.localStorage.getItem("sap-ui-debug") == "X");
  		} catch (e) {}
  
  		window["sap-ui-debug"] = bDebugSources;
  
  		// if bootstap URL already contains -dbg URL, just set sap-ui-loaddbg
  		if (/-dbg\.js([?#]|$)/.test(_oBootstrap.url)) {
  			window["sap-ui-loaddbg"] = true;
  			window["sap-ui-debug"] = true;
  		}
  
  		// if current sources are optimized and debug sources are wanted, restart with debug URL
  		if (bIsOptimized && bDebugSources) {
  			var sDebugUrl = _oBootstrap.url.replace(/\/(?:sap-ui-cachebuster\/)?([^\/]+)\.js/, "/$1-dbg.js");
  			window["sap-ui-optimized"] = false;
  			window["sap-ui-loaddbg"] = true;
  			document.write("<script type=\"text/javascript\" src=\"" + sDebugUrl + "\"></script>");
  			var oRestart = new Error("Aborting UI5 bootstrap and restarting from: " + sDebugUrl);
  			oRestart.name = "Restart";
  			throw oRestart;
  		}
  	})();
  
  	/*
  	 * Merged, raw (un-interpreted) configuration data from the following sources
  	 * (last one wins)
  	 * <ol>
  	 * <li>global configuration object <code>window["sap-ui-config"]</code> (could be either a string/url or a configuration object)</li>
  	 * <li><code>data-sap-ui-config</code> attribute of the bootstrap script tag</li>
  	 * <li>other <code>data-sap-ui-<i>xyz</i></code> attributes of the bootstrap tag</li>
  	 * </ol>
  	 */
  	var oCfgData = _window["sap-ui-config"] = (function() {
  
  		function normalize(o) {
  			jQuery.each(o, function(i, v) {
  				var il = i.toLowerCase();
  				if ( !o.hasOwnProperty(il) ) {
  					o[il] = v;
  					delete o[i];
  				}
  			});
  			return o;
  		}
  
  		var oScriptTag = _oBootstrap.tag,
  			oCfg = _window["sap-ui-config"],
  			sCfgFile = "sap-ui-config.json";
  
  		// load the configuration from an external JSON file
  		if (typeof oCfg === "string") {
  			_earlyLog("warning", "Loading external bootstrap configuration from \"" + oCfg + "\". This is a design time feature and not for productive usage!");
  			if (oCfg !== sCfgFile) {
  				_earlyLog("warning", "The external bootstrap configuration file should be named \"" + sCfgFile + "\"!");
  			}
  			jQuery.ajax({
  				url : oCfg,
  				dataType : 'json',
  				async : false,
  				success : function(oData, sTextStatus, jqXHR) {
  					oCfg = oData;
  				},
  				error : function(jqXHR, sTextStatus, oError) {
  					_earlyLog("error", "Loading externalized bootstrap configuration from \"" + oCfg + "\" failed! Reason: " + oError + "!");
  					oCfg = undefined;
  				}
  			});
  		}
  
  		oCfg = normalize(oCfg || {});
  		oCfg.resourceroots = oCfg.resourceroots || {};
  		oCfg.themeroots = oCfg.themeroots || {};
  		oCfg.resourceroots[''] = oCfg.resourceroots[''] || _oBootstrap.resourceRoot;
  
  		oCfg['xx-loadallmode'] = /(^|\/)(sap-?ui5|[^\/]+-all).js([?#]|$)/.test(_oBootstrap.url);
  
  		// if a script tag has been identified, collect its configuration info
  		if ( oScriptTag ) {
  			// evaluate the config attribute first - if present
  			var sConfig = oScriptTag.getAttribute("data-sap-ui-config");
  			if ( sConfig ) {
  				try {
  					/*eslint-disable no-new-func */
  					jQuery.extend(oCfg, normalize((new Function("return {" + sConfig + "};"))())); // TODO jQuery.parseJSON would be better but imposes unwanted restrictions on valid syntax
  					/*eslint-enable no-new-func */
  				} catch (e) {
  					// no log yet, how to report this error?
  					_earlyLog("error", "failed to parse data-sap-ui-config attribute: " + (e.message || e));
  				}
  			}
  
  			// merge with any existing "data-sap-ui-" attributes
  			jQuery.each(oScriptTag.attributes, function(i, attr) {
  				var m = attr.name.match(/^data-sap-ui-(.*)$/);
  				if ( m ) {
  					// the following (deactivated) conversion would implement multi-word names like "resource-roots"
  					m = m[1].toLowerCase(); // .replace(/\-([a-z])/g, function(s,w) { return w.toUpperCase(); })
  					if ( m === 'resourceroots' ) {
  						// merge map entries instead of overwriting map
  						jQuery.extend(oCfg[m], jQuery.parseJSON(attr.value));
  					} else if ( m === 'theme-roots' ) {
  						// merge map entries, but rename to camelCase
  						jQuery.extend(oCfg.themeroots, jQuery.parseJSON(attr.value));
  					} else if ( m !== 'config' ) {
  						oCfg[m] = attr.value;
  					}
  				}
  			});
  		}
  
  		return oCfg;
  	}());
  
  	// check whether noConflict must be used...
  	if ( oCfgData.noconflict === true || oCfgData.noconflict === "true"  || oCfgData.noconflict === "x" ) {
  		jQuery.noConflict();
  	}
  
  	/**
  	 * Root Namespace for the jQuery plug-in provided by SAP SE.
  	 *
  	 * @version 1.28.5
  	 * @namespace
  	 * @public
  	 * @static
  	 */
  	jQuery.sap = {};
  
  	// -------------------------- VERSION -------------------------------------
  
  	jQuery.sap.Version = Version;
  
  	// -------------------------- DEBUG LOCAL STORAGE -------------------------------------
  
  	jQuery.sap.debug = function(bEnable) {
  		if (!window.localStorage) {
  			return null;
  		}
  
  		function reloadHint(bUsesDbgSrc){
  			/*eslint-disable no-alert */
  			alert("Usage of debug sources is " + (bUsesDbgSrc ? "on" : "off") + " now.\nFor the change to take effect, you need to reload the page.");
  			/*eslint-enable no-alert */
  		}
  
  		if (bEnable === true) {
  			window.localStorage.setItem("sap-ui-debug", "X");
  			reloadHint(true);
  		} else if (bEnable === false) {
  			window.localStorage.removeItem("sap-ui-debug");
  			reloadHint(false);
  		}
  
  		return window.localStorage.getItem("sap-ui-debug") == "X";
  	};
  
  	// -------------------------- STATISTICS LOCAL STORAGE -------------------------------------
  
  	jQuery.sap.statistics = function(bEnable) {
  		if (!window.localStorage) {
  			return null;
  		}
  
  		function reloadHint(bUsesDbgSrc){
  			/*eslint-disable no-alert */
  			alert("Usage of Gateway statistics " + (bUsesDbgSrc ? "on" : "off") + " now.\nFor the change to take effect, you need to reload the page.");
  			/*eslint-enable no-alert */
  		}
  
  		if (bEnable === true) {
  			window.localStorage.setItem("sap-ui-statistics", "X");
  			reloadHint(true);
  		} else if (bEnable === false) {
  			window.localStorage.removeItem("sap-ui-statistics");
  			reloadHint(false);
  		}
  
  		return window.localStorage.getItem("sap-ui-statistics") == "X";
  	};
  
  	// -------------------------- Logging -------------------------------------
  
  	(function() {
  
  		var FATAL = 0, ERROR = 1, WARNING = 2, INFO = 3, DEBUG = 4, TRACE = 5,
  
  		/**
  		 * Unique prefix for this instance of the core in a multi-frame environment.
  		 */
  			sWindowName = (window.top == window) ? "" : "[" + window.location.pathname.split('/').slice(-1)[0] + "] ",
  		// Note: comparison must use type coercion (==, not ===), otherwise test fails in IE
  
  		/**
  		 * The array that holds the log entries that have been recorded so far
  		 */
  			aLog = [],
  
  		/**
  		 * Maximum log level to be recorded (per component).
  		 */
  			mMaxLevel = { '' : ERROR },
  
  		/**
  		 * Registered listener to be informed about new log entries.
  		 */
  			oListener = null;
  
  		function pad0(i,w) {
  			return ("000" + String(i)).slice(-w);
  		}
  
  		function level(sComponent) {
  			return (!sComponent || isNaN(mMaxLevel[sComponent])) ? mMaxLevel[''] : mMaxLevel[sComponent];
  		}
  
  		function listener(){
  			if (!oListener) {
  				oListener = {
  					listeners: [],
  					onLogEntry: function(oLogEntry){
  						for (var i = 0; i < oListener.listeners.length; i++) {
  							if (oListener.listeners[i].onLogEntry) {
  								oListener.listeners[i].onLogEntry(oLogEntry);
  							}
  						}
  					},
  					attach: function(oLogger, oLstnr){
  						if (oLstnr) {
  							oListener.listeners.push(oLstnr);
  							if (oLstnr.onAttachToLog) {
  								oLstnr.onAttachToLog(oLogger);
  							}
  						}
  					},
  					detach: function(oLogger, oLstnr){
  						for (var i = 0; i < oListener.listeners.length; i++) {
  							if (oListener.listeners[i] === oLstnr) {
  								if (oLstnr.onDetachFromLog) {
  									oLstnr.onDetachFromLog(oLogger);
  								}
  								oListener.listeners.splice(i,1);
  								return;
  							}
  						}
  					}
  				};
  			}
  			return oListener;
  		}
  
  		/**
  		 * Creates a new log entry depending on its level and component.
  		 *
  		 * If the given level is higher than the max level for the given component
  		 * (or higher than the global level, if no component is given),
  		 * then no entry is created.
  		 */
  		function log(iLevel, sMessage, sDetails, sComponent) {
  			if (iLevel <= level(sComponent) ) {
  				var oNow = new Date(),
  					oLogEntry = {
  						time     : pad0(oNow.getHours(),2) + ":" + pad0(oNow.getMinutes(),2) + ":" + pad0(oNow.getSeconds(),2),
  						date     : pad0(oNow.getFullYear(),4) + "-" + pad0(oNow.getMonth() + 1,2) + "-" + pad0(oNow.getDate(),2),
  						timestamp: oNow.getTime(),
  						level    : iLevel,
  						message  : String(sMessage || ""),
  						details  : String(sDetails || ""),
  						component: String(sComponent || "")
  					};
  				aLog.push( oLogEntry );
  				if (oListener) {
  					oListener.onLogEntry(oLogEntry);
  				}
  
  				/*
  				 * Console Log, also tries to log to the window.console, if available.
  				 *
  				 * Unfortunately, the support for window.console is quite different between the UI5 browsers. The most important differences are:
  				 * - in IE (checked until IE9), the console object does not exist in a window, until the developer tools are opened for that window.
  				 *   After opening the dev tools, the console remains available even when the tools are closed again. Only using a new window (or tab)
  				 *   restores the old state without console.
  				 *   When the console is available, it provides most standard methods, but not debug and trace
  				 * - in FF3.6 the console is not available, until FireBug is opened. It disappears again, when fire bug is closed.
  				 *   But when the settings for a web site are stored (convenience), the console remains open
  				 *   When the console is available, it supports all relevant methods
  				 * - in FF9.0, the console is always available, but method assert is only available when firebug is open
  				 * - in Webkit browsers, the console object is always available and has all required methods
  				 *   - Exception: in the iOS Simulator, console.info() does not exist
  				 */
  				/*eslint-disable no-console */
  				if (window.console) { // in IE and FF, console might not exist; in FF it might even disappear
  					var logText = oLogEntry.date + " " + oLogEntry.time + " " + sWindowName + oLogEntry.message + " - " + oLogEntry.details + " " + oLogEntry.component;
  					switch (iLevel) {
  					case FATAL:
  					case ERROR: console.error(logText); break;
  					case WARNING: console.warn(logText); break;
  					case INFO: console.info ? console.info(logText) : console.log(logText); break;    // info not available in iOS simulator
  					case DEBUG: console.debug ? console.debug(logText) : console.log(logText); break; // debug not available in IE, fallback to log
  					case TRACE: console.trace ? console.trace(logText) : console.log(logText); break; // trace not available in IE, fallback to log (no trace)
  					}
  				}
  				/*eslint-enable no-console */
  				return oLogEntry;
  			}
  		}
  
  		/**
  		 * Creates a new Logger instance which will use the given component string
  		 * for all logged messages without a specific component.
  		 *
  		 * @param {string} sDefaultComponent
  		 *
  		 * @class A Logger class
  		 * @name jQuery.sap.log.Logger
  		 * @since 1.1.2
  		 * @public
  		 */
  		function Logger(sDefaultComponent) {
  
  			/**
  			 * Creates a new fatal-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log instance for method chaining
  			 * @name jQuery.sap.log.Logger#fatal
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.fatal = function (sMessage, sDetails, sComponent) {
  				log(FATAL, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  
  			/**
  			 * Creates a new error-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log instance
  			 * @name jQuery.sap.log.Logger#error
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.error = function error(sMessage, sDetails, sComponent) {
  				log(ERROR, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  
  			/**
  			 * Creates a new warning-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log instance
  			 * @name jQuery.sap.log.Logger#warning
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.warning = function warning(sMessage, sDetails, sComponent) {
  				log(WARNING, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  			/**
  			 * Creates a new info-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log instance
  			 * @name jQuery.sap.log.Logger#info
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.info = function info(sMessage, sDetails, sComponent) {
  				log(INFO, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  			/**
  			 * Creates a new debug-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log instance
  			 * @name jQuery.sap.log.Logger#debug
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.debug = function debug(sMessage, sDetails, sComponent) {
  				log(DEBUG, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  			/**
  			 * Creates a new trace-level entry in the log with the given message, details and calling component.
  			 *
  			 * @param {string} sMessage Message text to display
  			 * @param {string} [sDetails=''] Details about the message, might be omitted
  			 * @param {string} [sComponent=''] Name of the component that produced the log entry
  			 * @return {jQuery.sap.log.Logger} The log-instance
  			 * @name jQuery.sap.log.Logger#trace
  			 * @function
  			 * @public
  			 * @SecSink {0 1 2|SECRET} Could expose secret data in logs
  			 */
  			this.trace = function trace(sMessage, sDetails, sComponent) {
  				log(TRACE, sMessage, sDetails, sComponent || sDefaultComponent);
  				return this;
  			};
  
  			/**
  			 * Defines the maximum jQuery.sap.log.Level of log entries that will be recorded.
  			 * Log entries with a higher (less important) log level will be omitted from the log.
  			 * When a component name is given, the log level will be configured for that component
  			 * only, otherwise the log level for the default component of this logger is set.
  			 * For the global logger, the global default level is set.
  			 *
  			 * <b>Note</b>: Setting a global default log level has no impact on already defined
  			 * component log levels. They always override the global default log level.
  			 *
  			 * @param {jQuery.sap.log.Level} iLogLevel
  			 * @param {string} [sComponent] The log component to set the log level for.
  			 * @return {jQuery.sap.log} The global logger to allow method chaining
  			 * @name jQuery.sap.log.Logger#setLevel
  			 * @function
  			 * @public
  			 */
  			this.setLevel = function setLevel(iLogLevel, sComponent) {
  				sComponent = sComponent || sDefaultComponent || '';
  				mMaxLevel[sComponent] = iLogLevel;
  				var mBackMapping = [];
  				jQuery.each(jQuery.sap.log.LogLevel, function(idx, v){
  					mBackMapping[v] = idx;
  				});
  				log(INFO, "Changing log level " + (sComponent ? "for '" + sComponent + "' " : "") + "to " + mBackMapping[iLogLevel], "", "jQuery.sap.log");
  				return this;
  			};
  
  			/**
  			 * Returns the log level currently effective for the given component.
  			 * If no component is given or when no level has been configured for a
  			 * given component, the log level for the default component of this logger is returned.
  			 *
  			 * @param {string} [sComponent] Name of the component to retrieve the log level for
  			 * @return {int} The log level for the given component or the default log level
  			 * @name jQuery.sap.log.Logger#getLevel
  			 * @function
  			 * @public
  			 * @since 1.1.2
  			 */
  			this.getLevel = function getLevel(sComponent) {
  				return level(sComponent || sDefaultComponent);
  			};
  
  			/**
  			 * Checks whether logging is enabled for the given log level,
  			 * depending on the currently effective log level for the given component.
  			 *
  			 * If no component is given, the default component of this logger will be taken into account.
  			 *
  			 * @param {int} [iLevel=Level.DEBUG] the log level in question
  			 * @param {string} [sComponent] Name of the component to check the log level for
  			 * @return {boolean} Whether logging is enabled or not
  			 * @name jQuery.sap.log.Logger#isLoggable
  			 * @function
  			 * @public
  			 * @since 1.13.2
  			 */
  			this.isLoggable = function (iLevel, sComponent) {
  				return (iLevel == null ? DEBUG : iLevel) <= level(sComponent || sDefaultComponent);
  			};
  		}
  
  		/**
  		 * A Logging API for JavaScript.
  		 *
  		 * Provides methods to manage a client-side log and to create entries in it. Each of the logging methods
  		 * {@link jQuery.sap.log.#debug}, {@link jQuery.sap.log.#info}, {@link jQuery.sap.log.#warning},
  		 * {@link jQuery.sap.log.#error} and {@link jQuery.sap.log.#fatal} creates and records a log entry,
  		 * containing a timestamp, a log level, a message with details and a component info.
  		 * The log level will be one of {@link jQuery.sap.log.Level} and equals the name of the concrete logging method.
  		 *
  		 * By using the {@link jQuery.sap.log#setLevel} method, consumers can determine the least important
  		 * log level which should be recorded. Less important entries will be filtered out. (Note that higher numeric
  		 * values represent less important levels). The initially set level depends on the mode that UI5 is running in.
  		 * When the optimized sources are executed, the default level will be {@link jQuery.sap.log.Level.ERROR}.
  		 * For normal (debug sources), the default level is {@link jQuery.sap.log.Level.DEBUG}.
  		 *
  		 * All logging methods allow to specify a <b>component</b>. These components are simple strings and
  		 * don't have a special meaning to the UI5 framework. However they can be used to semantically group
  		 * log entries that belong to the same software component (or feature). There are two APIs that help
  		 * to manage logging for such a component. With <code>{@link jQuery.sap.log.getLogger}(sComponent)</code>,
  		 * one can retrieve a logger that automatically adds the given <code>sComponent</code> as component
  		 * parameter to each log entry, if no other component is specified. Typically, JavaScript code will
  		 * retrieve such a logger once during startup and reuse it for the rest of its lifecycle.
  		 * Second, the {@link jQuery.sap.log.Logger#setLevel}(iLevel, sComponent) method allows to set the log level
  		 * for a specific component only. This allows a more fine granular control about the created logging entries.
  		 * {@link jQuery.sap.log.Logger.getLevel} allows to retrieve the currently effective log level for a given
  		 * component.
  		 *
  		 * {@link jQuery.sap.log#getLog} returns an array of the currently collected log entries.
  		 *
  		 * Furthermore, a listener can be registered to the log. It will be notified whenever a new entry
  		 * is added to the log. The listener can be used for displaying log entries in a separate page area,
  		 * or for sending it to some external target (server).
  		 *
  		 * @author SAP SE
  		 * @since 0.9.0
  		 * @namespace
  		 * @public
  		 * @borrows jQuery.sap.log.Logger#fatal as fatal
  		 * @borrows jQuery.sap.log.Logger#error as error
  		 * @borrows jQuery.sap.log.Logger#warning as warning
  		 * @borrows jQuery.sap.log.Logger#info as info
  		 * @borrows jQuery.sap.log.Logger#debug as debug
  		 * @borrows jQuery.sap.log.Logger#trace as trace
  		 * @borrows jQuery.sap.log.Logger#getLevel as getLevel
  		 * @borrows jQuery.sap.log.Logger#setLevel as setLevel
  		 * @borrows jQuery.sap.log.Logger#isLoggable as isLoggable
  		 */
  		jQuery.sap.log = jQuery.extend(new Logger(), /** @lends jQuery.sap.log */ {
  
  			/**
  			 * Enumeration of the configurable log levels that a Logger should persist to the log.
  			 *
  			 * Only if the current LogLevel is higher than the level {@link jQuery.sap.log.Level} of the currently added log entry,
  			 * then this very entry is permanently added to the log. Otherwise it is ignored.
  			 * @see jQuery.sap.log.Logger#setLevel
  			 * @namespace
  			 * @public
  			 */
  			Level : {
  
  				/**
  				 * Do not log anything
  				 * @public
  				 */
  				NONE : FATAL - 1,
  
  				/**
  				 * Fatal level. Use this for logging unrecoverable situations
  				 * @public
  				 */
  				FATAL : FATAL,
  
  				/**
  				 * Error level. Use this for logging of erroneous but still recoverable situations
  				 * @public
  				 */
  				ERROR : ERROR,
  
  				/**
  				 * Warning level. Use this for logging unwanted but foreseen situations
  				 * @public
  				 */
  				WARNING : WARNING,
  
  				/**
  				 * Info level. Use this for logging information of purely informative nature
  				 * @public
  				 */
  				INFO : INFO,
  
  				/**
  				 * Debug level. Use this for logging information necessary for debugging
  				 * @public
  				 */
  				DEBUG : DEBUG,
  
  				/**
  				 * Trace level. Use this for tracing the program flow.
  				 * @public
  				 */
  				TRACE : TRACE, /* TODO Think about changing to 10 and thus to pull out of logging... -> Make tracing explicit */
  
  				/**
  				 * Trace level to log everything.
  				 */
  				ALL : (TRACE + 1) /* TODO if TRACE is changed to make sure this is 6 again. There would then be some special TRACE handling. */
  			},
  
  			/**
  			 * Returns a {@link jQuery.sap.log.Logger} for the given component.
  			 *
  			 * The method might or might not return the same logger object across multiple calls.
  			 * While loggers are assumed to be light weight objects, consumers should try to
  			 * avoid redundant calls and instead keep references to already retrieved loggers.
  			 *
  			 * The optional second parameter <code>iDefaultLogLevel</code> allows to specify
  			 * a default log level for the component. It is only applied when no log level has been
  			 * defined so far for that component (ignoring inherited log levels). If this method is
  			 * called multiple times for the same component but with different log levels,
  			 * only the first call one might be taken into account.
  			 *
  			 * @param {string} sComponent Component to create the logger for
  			 * @param {int} [iDefaultLogLevel] a default log level to be used for the component,
  			 *   if no log level has been defined for it so far.
  			 * @return {jQuery.sap.log.Logger} A logger for the component.
  			 * @public
  			 * @static
  			 * @since 1.1.2
  			 */
  			getLogger : function(sComponent, iDefaultLogLevel) {
  				if ( !isNaN(iDefaultLogLevel) && mMaxLevel[sComponent] == null ) {
  					mMaxLevel[sComponent] = iDefaultLogLevel;
  				}
  				return new Logger(sComponent);
  			},
  
  			/**
  			 * Returns the logged entries recorded so far as an array.
  			 *
  			 * Log entries are plain JavaScript objects with the following properties
  			 * <ul>
  			 * <li>timestamp {number} point in time when the entry was created
  			 * <li>level {int} LogLevel level of the entry
  			 * <li>message {string} message text of the entry
  			 * </ul>
  			 *
  			 * @return {object[]} an array containing the recorded log entries
  			 * @public
  			 * @static
  			 * @since 1.1.2
  			 */
  			getLogEntries : function () {
  				return aLog.slice();
  			},
  
  			/**
  			 * Allows to add a new LogListener that will be notified for new log entries.
  			 * The given object must provide method <code>onLogEntry</code> and can also be informed
  			 * about <code>onDetachFromLog</code> and <code>onAttachToLog</code>
  			 * @param {object} oListener The new listener object that should be informed
  			 * @return {jQuery.sap.log} The global logger
  			 * @public
  			 * @static
  			 */
  			addLogListener : function(oListener) {
  				listener().attach(this, oListener);
  				return this;
  			},
  
  			/**
  			 * Allows to remove a registered LogListener.
  			 * @param {object} oListener The new listener object that should be removed
  			 * @return {jQuery.sap.log} The global logger
  			 * @public
  			 * @static
  			 */
  			removeLogListener : function(oListener) {
  				listener().detach(this, oListener);
  				return this;
  			}
  
  		});
  
  		/**
  		 * Enumeration of levels that can be used in a call to {@link jQuery.sap.log.Logger#setLevel}(iLevel, sComponent).
  		 *
  		 * @deprecated Since 1.1.2. To streamline the Logging API a bit, the separation between Level and LogLevel has been given up.
  		 * Use the (enriched) enumeration {@link jQuery.sap.log.Level} instead.
  		 * @namespace
  		 * @public
  		 */
  		jQuery.sap.log.LogLevel = jQuery.sap.log.Level;
  
  		/**
  		 * Retrieves the currently recorded log entries.
  		 * @deprecated Since 1.1.2. To avoid confusion with getLogger, this method has been renamed to {@link jQuery.sap.log.getLogEntries}.
  		 * @function
  		 * @public
  		 * @static
  		 */
  		jQuery.sap.log.getLog = jQuery.sap.log.getLogEntries;
  
  		/**
  		 * A simple assertion mechanism that logs a message when a given condition is not met.
  		 *
  		 * <b>Note:</b> Calls to this method might be removed when the JavaScript code
  		 *              is optimized during build. Therefore, callers should not rely on any side effects
  		 *              of this method.
  		 *
  		 * @param {boolean} bResult result of the checked assertion
  		 * @param {string} sMessage message that will be raised when the result is <code>false</code>
  		 *
  		 * @public
  		 * @static
  		 * @SecSink {1|SECRET} Could expose secret data in logs
  		 */
  		jQuery.sap.assert = function(bResult, sMessage) {
  			if ( !bResult ) {
  				/*eslint-disable no-console */
  				if ( window.console && console.assert ) {
  					console.assert(bResult, sWindowName + sMessage);
  				} else {
  					// console is not always available (IE, FF) and IE doesn't support console.assert
  					jQuery.sap.log.debug("[Assertions] " + sMessage);
  				}
  				/*eslint-enable no-console */
  			}
  		};
  
  		// against all our rules: use side effect of assert to differentiate between optimized and productive code
  		jQuery.sap.assert( !!(mMaxLevel[''] = DEBUG), "will be removed in optimized version");
  		// evaluate configuration
  		oCfgData.loglevel = (function() {
  			var m = /(?:\?|&)sap-ui-log(?:L|-l)evel=([^&]*)/.exec(window.location.search);
  			return m && m[1];
  		}()) || oCfgData.loglevel;
  		if ( oCfgData.loglevel ) {
  			jQuery.sap.log.setLevel(jQuery.sap.log.Level[oCfgData.loglevel.toUpperCase()] || parseInt(oCfgData.loglevel,10));
  		}
  
  		jQuery.sap.log.info("SAP Logger started.");
  		// log early logs
  		jQuery.each(_earlyLogs, function(i,e) {
  			jQuery.sap.log[e.level](e.message);
  		});
  		_earlyLogs = null;
  
  
  	}());
  
  	// ---------------------------------------------------------------------------------------------------
  
  	/**
  	 * Returns a new constructor function that creates objects with
  	 * the given prototype.
  	 *
  	 * @param {object} oPrototype
  	 * @return {function} the newly created constructor function
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.factory = function factory(oPrototype) {
  		function Factory() {}
  		Factory.prototype = oPrototype;
  		return Factory;
  	};
  
  	/**
  	 * Returns a new object which has the given oPrototype as its prototype.
  	 *
  	 * If several objects with the same prototype are to be created,
  	 * {@link jQuery.sap.factory} should be used instead.
  	 *
  	 * @param {object} oPrototype
  	 * @return {object} new object
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.newObject = function newObject(oPrototype) {
  		return new (jQuery.sap.factory(oPrototype))();
  	};
  
  	/**
  	 * Returns a new function that returns the given <code>oValue</code> (using its closure).
  	 *
  	 * Avoids the need for a dedicated member for the value.
  	 *
  	 * As closures don't come for free, this function should only be used when polluting
  	 * the enclosing object is an absolute "must-not" (as it is the case in public base classes).
  	 *
  	 * @param {object} oValue
  	 *
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.getter = function getter(oValue) {
  		return function() {
  			return oValue;
  		};
  	};
  
  	/**
  	 * Returns a JavaScript object which is identified by a sequence of names.
  	 *
  	 * A call to <code>getObject("a.b.C")</code> has essentially the same effect
  	 * as accessing <code>window.a.b.C</code> but with the difference that missing
  	 * intermediate objects (a or b in the example above) don't lead to an exception.
  	 *
  	 * When the addressed object exists, it is simply returned. If it doesn't exists,
  	 * the behavior depends on the value of the second, optional parameter
  	 * <code>iNoCreates</code> (assuming 'n' to be the number of names in the name sequence):
  	 * <ul>
  	 * <li>NaN: if iNoCreates is not a number and the addressed object doesn't exist,
  	 *          then <code>getObject()</code> returns <code>undefined</code>.
  	 * <li>0 &lt; iNoCreates &lt; n: any non-existing intermediate object is created, except
  	 *          the <i>last</i> <code>iNoCreates</code> ones.
  	 * </ul>
  	 *
  	 * Example:
  	 * <pre>
  	 *   getObject()            -- returns the context object (either param or window)
  	 *   getObject("a.b.C")     -- will only try to get a.b.C and return undefined if not found.
  	 *   getObject("a.b.C", 0)  -- will create a, b, and C in that order if they don't exists
  	 *   getObject("a.b.c", 1)  -- will create a and b, but not C.
  	 * </pre>
  	 *
  	 * When a <code>oContext</code> is given, the search starts in that object.
  	 * Otherwise it starts in the <code>window</code> object that this plugin
  	 * has been created in.
  	 *
  	 * Note: Although this method internally uses <code>object["key"]</code> to address object
  	 *       properties, it does not support all possible characters in a name.
  	 *       Especially the dot ('.') is not supported in the individual name segments,
  	 *       as it is always interpreted as a name separator.
  	 *
  	 * @param {string} sName  a dot separated sequence of names that identify the required object
  	 * @param {int}    [iNoCreates=NaN] number of objects (from the right) that should not be created
  	 * @param {object} [oContext=window] the context to execute the search in
  	 *
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.getObject = function getObject(sName, iNoCreates, oContext) {
  		var oObject = oContext || _window,
  			aNames = (sName || "").split("."),
  			l = aNames.length,
  			iEndCreate = isNaN(iNoCreates) ? 0 : l - iNoCreates,
  			i;
  
  		for (i = 0; oObject && i < l; i++) {
  			if (!oObject[aNames[i]] && i < iEndCreate ) {
  				oObject[aNames[i]] = {};
  			}
  			oObject = oObject[aNames[i]];
  		}
  		return oObject;
  
  	};
  
  	/**
  	 * Sets an object property to a given value, where the property is
  	 * identified by a sequence of names (path).
  	 *
  	 * When a <code>oContext</code> is given, the path starts in that object.
  	 * Otherwise it starts in the <code>window</code> object that this plugin
  	 * has been created for.
  	 *
  	 * Note: Although this method internally uses <code>object["key"]</code> to address object
  	 *       properties, it does not support all possible characters in a name.
  	 *       Especially the dot ('.') is not supported in the individual name segments,
  	 *       as it is always interpreted as a name separator.
  	 *
  	 * @param {string} sName  a dot separated sequence of names that identify the property
  	 * @param {any}    vValue value to be set, can have any type
  	 * @param {object} [oContext=window] the context to execute the search in
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.setObject = function (sName, vValue, oContext) {
  		var oObject = oContext || _window,
  			aNames = (sName || "").split("."),
  			l = aNames.length, i;
  
  		if ( l > 0 ) {
  			for (i = 0; oObject && i < l - 1; i++) {
  				if (!oObject[aNames[i]] ) {
  					oObject[aNames[i]] = {};
  				}
  				oObject = oObject[aNames[i]];
  			}
  			oObject[aNames[l - 1]] = vValue;
  		}
  	};
  
  	// ---------------------- sync point -------------------------------------------------------------
  
  	/*
  	 * Internal class that can help to synchronize a set of asynchronous tasks.
  	 * Each task must be registered in the sync point by calling startTask with
  	 * an (purely informative) title. The returned value must be used in a later
  	 * call to finishTask.
  	 * When finishTask has been called for all tasks that have been started,
  	 * the fnCallback will be fired.
  	 * When a timeout is given and reached, the callback is called at that
  	 * time, no matter whether all tasks have been finished or not.
  	 */
  	function SyncPoint(sName, fnCallback, iTimeout) {
  		var aTasks = [],
  			iOpenTasks = 0,
  			iFailures = 0,
  			sTimer;
  
  		this.startTask = function(sTitle) {
  			var iId = aTasks.length;
  			aTasks[iId] = { name : sTitle, finished : false };
  			iOpenTasks++;
  			return iId;
  		};
  
  		this.finishTask = function(iId, bSuccess) {
  			if ( !aTasks[iId] || aTasks[iId].finished ) {
  				throw new Error("trying to finish non existing or already finished task");
  			}
  			aTasks[iId].finished = true;
  			iOpenTasks--;
  			if ( bSuccess === false ) {
  				iFailures++;
  			}
  			if ( iOpenTasks === 0 ) {
  				jQuery.sap.log.info("Sync point '" + sName + "' finished (tasks:" + aTasks.length + ", open:" + iOpenTasks + ", failures:" + iFailures + ")");
  				if ( sTimer ) {
  					clearTimeout(sTimer);
  					sTimer = null;
  				}
  				finish();
  			}
  		};
  
  		function finish() {
  			fnCallback && fnCallback(iOpenTasks, iFailures);
  			fnCallback = null;
  		}
  
  		if ( !isNaN(iTimeout) ) {
  			sTimer = setTimeout(function() {
  				jQuery.sap.log.info("Sync point '" + sName + "' timed out (tasks:" + aTasks.length + ", open:" + iOpenTasks + ", failures:" + iFailures + ")");
  				finish();
  			}, iTimeout);
  		}
  
  		jQuery.sap.log.info("Sync point '" + sName + "' created" + (iTimeout ? "(timeout after " + iTimeout + " ms)" : ""));
  
  	}
  
  	/**
  	 * Internal function to create a sync point.
  	 * @private
  	 */
  	jQuery.sap.syncPoint = function(sName, fnCallback, iTimeout) {
  		return new SyncPoint(sName, fnCallback, iTimeout);
  	};
  
  	// ---------------------- require/declare --------------------------------------------------------
  
  	var getModuleSystemInfo = (function() {
  
  		/**
  		 * Local logger, by default only logging errors. Can be configured to DEBUG via config parameter.
  		 * @private
  		 */
  		var log = jQuery.sap.log.getLogger("sap.ui.ModuleSystem",
  				(/sap-ui-xx-debug(M|-m)odule(L|-l)oading=(true|x|X)/.test(location.search) || oCfgData["xx-debugModuleLoading"]) ? jQuery.sap.log.Level.DEBUG : jQuery.sap.log.Level.INFO
  			),
  
  		/**
  		 * A map of URL prefixes keyed by the corresponding module name prefix.
  		 * URL prefix can either be given as string or as object with properties url and final.
  		 * When final is set to true, module name prefix cannot be overwritten.
  		 * @see jQuery.sap.registerModulePath
  		 *
  		 * Note that the empty prefix ('') will always match and thus serves as a fallback.
  		 * @private
  		 */
  			mUrlPrefixes = { '' : { 'url' : 'resources/' } },
  
  		/**
  		 * Module neither has been required nor preloaded not declared, but someone asked for it.
  		 */
  			INITIAL = 0,
  
  		/**
  		 * Module has been preloaded, but not required or declared
  		 */
  			PRELOADED = -1,
  
  		/**
  		 * Module has been declared.
  		 */
  			LOADING = 1,
  
  		/**
  		 * Module has been loaded, but not yet executed.
  		 */
  			LOADED = 2,
  
  		/**
  		 * Module is currently being executed
  		 */
  			EXECUTING = 3,
  
  		/**
  		 * Module has been loaded and executed without errors.
  		 */
  			READY = 4,
  
  		/**
  		 * Module either could not be loaded or execution threw an error
  		 */
  			FAILED = 5,
  
  		/**
  		 * Set of modules that have been loaded (required) so far.
  		 *
  		 * Each module is an object that can have the following members
  		 * <ul>
  		 * <li>{int} state one of the module states defined in this function
  		 * <li>{string} url URL where the module has been loaded from
  		 * <li>{any} data temp. raw content of the module (between loaded and ready)
  		 * <li>{string} error an error description for state <code>FAILED</code>
  		 * <li>{any} content the content of the module as exported via define()
  		 * </ul>
  		 * @private
  		 */
  			mModules = {
  				// predefine already loaded modules to avoid redundant loading
  				// "sap/ui/thirdparty/jquery/jquery-1.7.1.js" : { state : READY, url : _sBootstrapUrl, content : jQuery },
  				"sap/ui/thirdparty/URI.js" : { state : READY, url : _sBootstrapUrl, content : URI },
  				"sap/ui/Device.js" : { state : READY, url : _sBootstrapUrl, content : sap.ui.Device },
  				"jquery.sap.global.js" : { state : READY, url : _sBootstrapUrl, content : jQuery }
  			},
  
  			mPreloadModules = {},
  
  		/**
  		 * Information about third party modules that react on AMD loaders and need a workaround
  		 * to be able to work with jQuery.sap.require no matter whether an AMD loader is present or not.
  		 *
  		 * Note: this is a map for future extension
  		 * Note: should be maintained together with raw-module info in .library files
  		 * @private
  		 */
  			mAMDShim = {
  				'sap/ui/thirdparty/blanket.js': true,
  				'sap/ui/thirdparty/crossroads.js': true,
  				'sap/ui/thirdparty/d3.js': true,
  				'sap/ui/thirdparty/datajs.js': true,
  				'sap/ui/thirdparty/handlebars.js': true,
  				'sap/ui/thirdparty/hasher.js': true,
  				'sap/ui/thirdparty/IPv6.js': true,
  				'sap/ui/thirdparty/jquery/jquery-1.11.1.js': true,
  				'sap/ui/thirdparty/jquery/jquery-1.10.2.js': true,
  				'sap/ui/thirdparty/jquery/jquery-1.10.1.js': true,
  				'sap/ui/thirdparty/jquery/jquery.1.7.1.js': true,
  				'sap/ui/thirdparty/jquery/jquery.1.8.1.js': true,
  				'sap/ui/thirdparty/jquery-mobile-custom.js': true,
  				'sap/ui/thirdparty/jszip.js': true,
  				'sap/ui/thirdparty/less.js': true,
  				'sap/ui/thirdparty/punycode.js': true,
  				'sap/ui/thirdparty/require.js': true,
  				'sap/ui/thirdparty/SecondLevelDomains.js': true,
  				'sap/ui/thirdparty/signals.js': true,
  				'sap/ui/thirdparty/URI.js' : true,
  				'sap/ui/thirdparty/URITemplate.js' : true,
  				'sap/ui/demokit/js/esprima.js' : true
  		  },
  
  		/**
  		 * Stack of modules that are currently executed.
  		 *
  		 * Allows to identify the containing module in case of multi module files (e.g. sap-ui-core)
  		 * @private
  		 */
  			_execStack = [ ],
  
  		/**
  		 * A prefix that will be added to module loading log statements and which reflects the nesting of module executions.
  		 * @private
  		 */
  			sLogPrefix = "",
  
  		// max size a script should have when executing it with execScript (IE). Otherwise fallback to eval
  			MAX_EXEC_SCRIPT_LENGTH = 512 * 1024,
  
  			sDocumentLocation = document.location.href.replace(/\?.*|#.*/g, ""),
  
  			FRAGMENT = "fragment",
  			VIEW = "view",
  			mKnownSubtypes = {
  				js :  [VIEW, FRAGMENT, "controller", "designtime"],
  				xml:  [VIEW, FRAGMENT],
  				json: [VIEW, FRAGMENT],
  				html: [VIEW, FRAGMENT]
  			},
  
  			rJSSubtypes = new RegExp("(\\.(?:" + mKnownSubtypes.js.join("|") + "))?\\.js$"),
  			rTypes,
  			rSubTypes;
  
  		(function() {
  			var s = "",
  				sSub = "";
  
  			jQuery.each(mKnownSubtypes, function(sType, aSubtypes) {
  				s = (s ? s + "|" : "") + sType;
  				sSub = (sSub ? sSub + "|" : "") + "(?:(?:" + aSubtypes.join("\\.|") + "\\.)?" + sType + ")";
  			});
  			s = "\\.(" + s + ")$";
  			sSub = "\\.(?:" + sSub + "|[^./]+)$";
  			log.debug("constructed regexp for file types :" + s);
  			log.debug("constructed regexp for file sub-types :" + sSub);
  			rTypes = new RegExp(s);
  			rSubTypes = new RegExp(sSub);
  		}());
  
  		/**
  		 * Name conversion function that converts a name in UI5 module name syntax to a name in requireJS module name syntax.
  		 * @private
  		 */
  		function ui5ToRJS(sName) {
  			if ( /^sap\.ui\.thirdparty\.jquery\.jquery-/.test(sName) ) {
  				return "sap/ui/thirdparty/jquery/jquery-" + sName.slice("sap.ui.thirdparty.jquery.jquery-".length);
  			} else if ( /^jquery\.sap\./.test(sName) ) {
  				return sName;
  			}
  			return sName.replace(/\./g, "/");
  		}
  
  		/**
  		 * Name conversion function that converts a name in unified resource name syntax to a name in UI5 module name syntax.
  		 * If the name cannot be converted (e.g. doesn't end with '.js'), then <code>undefined</code> is returned.
  		 *
  		 * @private
  		 */
  		function urnToUI5(sName) {
  			// UI5 module name syntax is only defined for JS resources
  			if ( !/\.js$/.test(sName) ) {
  				return;
  			}
  
  			sName = sName.slice(0, -3);
  			if ( /^sap\/ui\/thirdparty\/jquery\/jquery-/.test(sName) ) {
  				return "sap.ui.thirdparty.jquery.jquery-" + sName.slice("sap/ui/thirdparty/jquery/jquery-".length);
  			} else if ( /^jquery\.sap\./.test(sName) ) {
  				return sName; // do nothing
  			}
  			return sName.replace(/\//g, ".");
  		}
  
  		// find longest matching prefix for resource name
  		function getResourcePath(sResourceName, sSuffix) {
  
  			// split name into segments
  			var aSegments = sResourceName.split(/\//),
  				l, sNamePrefix, sResult, m;
  
  			// if no suffix was given and if the name is not empty, try to guess the suffix from the last segment
  			if ( arguments.length === 1  &&  aSegments.length > 0 ) {
  				// only known types (and their known subtypes) are accepted
  				m = rSubTypes.exec(aSegments[aSegments.length - 1]);
  				if ( m ) {
  					sSuffix = m[0];
  					aSegments[aSegments.length - 1] = aSegments[aSegments.length - 1].slice(0, m.index);
  				} else {
  					sSuffix = "";
  				}
  			}
  
  			// search for a defined name prefix, starting with the full name and successively removing one segment
  			for (l = aSegments.length; l >= 0; l--) {
  				sNamePrefix = aSegments.slice(0, l).join('/');
  				if ( mUrlPrefixes[sNamePrefix] ) {
  					sResult = mUrlPrefixes[sNamePrefix].url;
  					if ( l < aSegments.length ) {
  						sResult += aSegments.slice(l).join('/');
  					}
  					if ( sResult.slice(-1) === '/' ) {
  						sResult = sResult.slice(0, -1);
  					}
  					return sResult + (sSuffix || '');
  				}
  			}
  
  			jQuery.sap.assert(false, "should never happen");
  		}
  
  		function guessResourceName(sURL) {
  			var sNamePrefix,
  				sUrlPrefix,
  				sResourceName;
  
  			for (sNamePrefix in mUrlPrefixes) {
  				if ( mUrlPrefixes.hasOwnProperty(sNamePrefix) ) {
  
  					// Note: configured URL prefixes are guaranteed to end with a '/'
  					// But to support the legacy scenario promoted by the application tools ( "registerModulePath('Application','Application')" )
  					// the prefix check here has to be done without the slash
  					sUrlPrefix = mUrlPrefixes[sNamePrefix].url.slice(0, -1);
  
  					if ( sURL.indexOf(sUrlPrefix) === 0 ) {
  
  						// calc resource name
  						sResourceName = sNamePrefix + sURL.slice(sUrlPrefix.length);
  						// remove a leading '/' (occurs if name prefix is empty and if match was a full segment match
  						if ( sResourceName.charAt(0) === '/' ) {
  							sResourceName = sResourceName.slice(1);
  						}
  
  						if ( mModules[sResourceName] && mModules[sResourceName].data ) {
  							return sResourceName;
  						}
  					}
  				}
  			}
  
  			// return undefined;
  		}
  
  		function declareModule(sModuleName) {
  			var oModule;
  
  			// sModuleName must be a unified resource name of type .js
  			jQuery.sap.assert(/\.js$/.test(sModuleName), "must be a Javascript module");
  
  			oModule = mModules[sModuleName] || (mModules[sModuleName] = { state : INITIAL });
  
  			if ( oModule.state > INITIAL ) {
  				return oModule;
  			}
  
  			if ( log.isLoggable() ) {
  				log.debug(sLogPrefix + "declare module '" + sModuleName + "'");
  			}
  
  			// avoid cycles
  			oModule.state = READY;
  
  			// the first call to declareModule is assumed to identify the bootstrap module
  			// Note: this is only a guess and fails e.g. when multiple modules are loaded via a script tag
  			// to make it safe, we could convert 'declare' calls to e.g. 'subdeclare' calls at build time.
  			if ( _execStack.length === 0 ) {
  				_execStack.push(sModuleName);
  				oModule.url = oModule.url || _sBootstrapUrl;
  			}
  
  			return oModule;
  		}
  
  		function requireModule(sModuleName) {
  			var m = rJSSubtypes.exec(sModuleName),
  				sBaseName, sType, oModule, aExtensions, i;
  
  			// only for robustness, should not be possible by design (all callers append '.js')
  			if ( !m ) {
  				log.error("can only require Javascript module, not " + sModuleName);
  				return;
  			}
  
  			// in case of having a type specified ignore the type for the module path creation and add it as file extension
  			sBaseName = sModuleName.slice(0, m.index);
  			sType = m[0];			// must be a normalized resource name of type .js sType can be empty or one of view|controller|fragment
  
  			oModule = mModules[sModuleName] || (mModules[sModuleName] = { state : INITIAL });
  
  			if ( log.isLoggable() ) {
  				log.debug(sLogPrefix + "require '" + sModuleName + "' of type '" + sType + "'");
  			}
  
  			// check if module has been loaded already
  			if ( oModule.state !== INITIAL ) {
  				if ( oModule.state === PRELOADED ) {
  					oModule.state = LOADED;
  					execModule(sModuleName);
  				}
  
  				if ( oModule.state === READY ) {
  					if ( log.isLoggable() ) {
  						log.debug(sLogPrefix + "module '" + sModuleName + "' has already been loaded (skipped).");
  					}
  					return this;
  				} else if ( oModule.state === FAILED ) {
  					throw new Error("found in negative cache: '" + sModuleName +  "' from " + oModule.url + ": " + oModule.error);
  				} else {
  					// currently loading
  					return this;
  				}
  			}
  
  			// set marker for loading modules (to break cycles)
  			oModule.state = LOADING;
  
  			// if debug is enabled, try to load debug module first
  			aExtensions = window["sap-ui-loaddbg"] ? ["-dbg", ""] : [""];
  			for (i = 0; i < aExtensions.length && oModule.state !== LOADED; i++) {
  				// create module URL for the current extension
  				oModule.url = getResourcePath(sBaseName, aExtensions[i] + sType);
  				if ( log.isLoggable() ) {
  					log.debug(sLogPrefix + "loading " + (aExtensions[i] ? aExtensions[i] + " version of " : "") + "'" + sModuleName + "' from '" + oModule.url + "'");
  				}
  				/*eslint-disable no-loop-func */
  				jQuery.ajax({
  					url : oModule.url,
  					dataType : 'text',
  					async : false,
  					success : function(response, textStatus, xhr) {
  						oModule.state = LOADED;
  						oModule.data = response;
  					},
  					error : function(xhr, textStatus, error) {
  						oModule.state = FAILED;
  						oModule.error = xhr ? xhr.status + " - " + xhr.statusText : textStatus;
  					}
  				});
  				/*eslint-enable no-loop-func */
  			}
  
  			// execute module __after__ loading it, this reduces the required stack space!
  			if ( oModule.state === LOADED ) {
  				execModule(sModuleName);
  			}
  
  			if ( oModule.state !== READY ) {
  				throw new Error("failed to load '" + sModuleName +  "' from " + oModule.url + ": " + oModule.error);
  			}
  
  		}
  
  		// sModuleName must be a normalized resource name of type .js
  		function execModule(sModuleName) {
  
  			var oModule = mModules[sModuleName],
  				sOldPrefix, sScript, vAMD;
  
  			if ( oModule && oModule.state === LOADED && typeof oModule.data !== "undefined" ) {
  
  				// check whether the module is known to use an existing AMD loader, remember the AMD flag
  				vAMD = mAMDShim[sModuleName] && typeof window.define === "function" && window.define.amd;
  
  				try {
  
  					if ( vAMD ) {
  						// temp. remove the AMD Flag from the loader
  						delete window.define.amd;
  					}
  
  					if ( log.isLoggable() ) {
  						log.debug(sLogPrefix + "executing '" + sModuleName + "'");
  						sOldPrefix = sLogPrefix;
  						sLogPrefix = sLogPrefix + ": ";
  					}
  
  					// execute the script in the window context
  					oModule.state = EXECUTING;
  					_execStack.push(sModuleName);
  					if ( typeof oModule.data === "function" ) {
  						oModule.data.call(window);
  					} else {
  
  						sScript = oModule.data;
  
  						// sourceURL: Firebug, Chrome, Safari and IE11 debugging help, appending the string seems to cost ZERO performance
  						// Note: IE11 supports sourceURL even when running in IE9 or IE10 mode
  						// Note: make URL absolute so Chrome displays the file tree correctly
  						// Note: do not append if there is already a sourceURL / sourceMappingURL
  						if (sScript && !sScript.match(/\/\/[#@] source(Mapping)?URL=.*$/)) {
  							sScript += "\n//# sourceURL=" + URI(oModule.url).absoluteTo(sDocumentLocation);
  						}
  
  						// framework internal hook to intercept the loaded script and modify
  						// it before executing the script - e.g. useful for client side coverage
  						if (typeof jQuery.sap.require._hook === "function") {
  							sScript = jQuery.sap.require._hook(sScript, sModuleName);
  						}
  
  						if (_window.execScript && (!oModule.data || oModule.data.length < MAX_EXEC_SCRIPT_LENGTH) ) {
  							try {
  								oModule.data && _window.execScript(sScript); // execScript fails if data is empty
  							} catch (e) {
  								_execStack.pop();
  								// eval again with different approach - should fail with a more informative exception
  								jQuery.sap.globalEval(oModule.data);
  								throw e; // rethrow err in case globalEval succeeded unexpectedly
  							}
  						} else {
  							_window.eval(sScript);
  						}
  					}
  					_execStack.pop();
  					oModule.state = READY;
  					oModule.data = undefined;
  					// best guess for legacy modules that don't use sap.ui.define
  					// TODO implement fallback for raw modules
  					oModule.content = oModule.content || jQuery.sap.getObject(urnToUI5(sModuleName));
  
  					if ( log.isLoggable() ) {
  						sLogPrefix = sOldPrefix;
  						log.debug(sLogPrefix + "finished executing '" + sModuleName + "'");
  					}
  
  				} catch (err) {
  					oModule.state = FAILED;
  					oModule.error = ((err.toString && err.toString()) || err.message) + (err.line ? "(line " + err.line + ")" : "" );
  					oModule.data = undefined;
  					if ( window["sap-ui-debug"] && (/sap-ui-xx-show(L|-l)oad(E|-e)rrors=(true|x|X)/.test(location.search) || oCfgData["xx-showloaderrors"]) ) {
  						log.error("error while evaluating " + sModuleName + ", embedding again via script tag to enforce a stack trace (see below)");
  						jQuery.sap.includeScript(oModule.url);
  						return;
  					}
  
  				} finally {
  
  					// restore AMD flag
  					if ( vAMD ) {
  						window.define.amd = vAMD;
  					}
  				}
  			}
  		}
  
  		function requireAll(aDependencies, fnCallback) {
  
  			var aModules = [],
  				i, sDepModName;
  
  			for (i = 0; i < aDependencies.length; i++) {
  				sDepModName = aDependencies[i];
  				log.debug(sLogPrefix + "require '" + sDepModName + "'");
  				requireModule(sDepModName + ".js");
  				// best guess for legacy modules that don't use sap.ui.define
  				// TODO implement fallback for raw modules
  				aModules[i] = mModules[sDepModName + ".js"].content || jQuery.sap.getObject(urnToUI5(sDepModName + ".js"));
  				log.debug(sLogPrefix + "require '" + sDepModName + "': done.");
  			}
  
  			fnCallback(aModules);
  		}
  
  		/**
  		 * Constructs an URL to load the module with the given name and file type (suffix).
  		 *
  		 * Searches the longest prefix of the given module name for which a registration
  		 * exists (see {@link jQuery.sap.registerModulePath}) and replaces that prefix
  		 * by the registered URL prefix.
  		 *
  		 * The remainder of the module name is appended to the URL, replacing any dot with a slash.
  		 *
  		 * Finally, the given suffix (typically a file name extension) is added (unconverted).
  		 *
  		 * The returned name (without the suffix) doesn't end with a slash.
  		 *
  		 * @param {string} sModuleName module name to detemrine the path for
  		 * @param {string} sSuffix suffix to be added to the resulting path
  		 * @return {string} calculated path (URL) to the given module
  		 *
  		 * @public
  		 * @static
  		 */
  		jQuery.sap.getModulePath = function(sModuleName, sSuffix) {
  			return getResourcePath(ui5ToRJS(sModuleName), sSuffix);
  		};
  
  		/**
  		 * Determines the URL for a resource given its unified resource name.
  		 *
  		 * Searches the longest prefix of the given resource name for which a registration
  		 * exists (see {@link jQuery.sap.registerResourcePath}) and replaces that prefix
  		 * by the registered URL prefix.
  		 *
  		 * The remainder of the resource name is appended to the URL.
  		 *
  		 * <b>Unified Resource Names</b>
  		 * Several UI5 APIs use <i>Unified Resource Names (URNs)</i> as naming scheme for resources that
  		 * they deal with (e.h. Javascript, CSS, JSON, XML, ...). URNs are similar to the path
  		 * component of an URL:
  		 * <ul>
  		 * <li>they consist of a non-empty sequence of name segments</li>
  		 * <li>segments are separated by a forward slash '/'</li>
  		 * <li>name segments consist of URL path segment characters only. It is recommened to use only ASCII
  		 * letters (upper or lower case), digits and the special characters '$', '_', '-', '.')</li>
  		 * <li>the empty name segment is not supported</li>
  		 * <li>names consisting of dots only, are reserved and must not be used for resources</li>
  		 * <li>names are case sensitive although the underlying server might be case-insensitive</li>
  		 * <li>the behavior with regard to URL encoded characters is not specified, %ddd notation should be avoided</li>
  		 * <li>the meaning of a leading slash is undefined, but might be defined in future. It therefore should be avoided</li>
  		 * </ul>
  		 *
  		 * UI5 APIs that only deal with Javascript resources, use a slight variation of this scheme,
  		 * where the extension '.js' is always omitted (see {@link sap.ui.define}, {@link sap.ui.require}).
  		 *
  		 *
  		 * <b>Relationship to old Module Name Syntax</b>
  		 *
  		 * Older UI5 APIs that deal with resources (like {@link jQuery.sap.registerModulePath},
  		 * {@link jQuery.sap.require} and {@link jQuery.sap.declare}) used a dot-separated naming scheme
  		 * (called 'module names') which was motivated by object names in the global namespace in
  		 * Javascript.
  		 *
  		 * The new URN scheme better matches the names of the corresponding resources (files) as stored
  		 * in a server and the dot ('.') is no longer a forbidden character in a resource name. This finally
  		 * allows to handle resources with different types (extensions) with the same API, not only JS files.
  		 *
  		 * Last but not least does the URN scheme better match the naming conventions used by AMD loaders
  		 * (like <code>requireJS</code>).
  		 *
  		 * @param {string} sResourceName unified resource name of the resource
  		 * @returns {string} URL to load the resource from
  		 * @public
  		 * @experimental Since 1.27.0
  		 * @function
  		 */
  		jQuery.sap.getResourcePath = getResourcePath;
  
  		/**
  		 * Registers an URL prefix for a module name prefix.
  		 *
  		 * Before a module is loaded, the longest registered prefix of its module name
  		 * is searched for and the associated URL prefix is used as a prefix for the request URL.
  		 * The remainder of the module name is attached to the request URL by replacing
  		 * dots ('.') with slashes ('/').
  		 *
  		 * The registration and search operates on full name segments only. So when a prefix
  		 *
  		 *    'sap.com'  ->  'http://www.sap.com/ui5/resources/'
  		 *
  		 * is registered, then it will match the name
  		 *
  		 *    'sap.com.Button'
  		 *
  		 * but not
  		 *
  		 *    'sap.commons.Button'
  		 *
  		 * Note that the empty prefix ('') will always match and thus serves as a fallback for
  		 * any search.
  		 *
  		 * The prefix can either be given as string or as object which contains the url and a 'final' property.
  		 * If 'final' is set to true, overwriting a module prefix is not possible anymore.
  		 *
  		 * @param {string} sModuleName module name to register a path for
  		 * @param {string | object} vUrlPrefix path prefix to register, either a string literal or an object (e.g. {url : 'url/to/res', 'final': true})
  		 * @param {string} [vUrlPrefix.url] path prefix to register
  		 * @param {boolean} [vUrlPrefix.final] flag to avoid overwriting the url path prefix for the given module name at a later point of time
  		 *
  		 * @public
  		 * @static
  		 * @SecSink {1|PATH} Parameter is used for future HTTP requests
  		 */
  		jQuery.sap.registerModulePath = function registerModulePath(sModuleName, vUrlPrefix) {
  			jQuery.sap.assert(!/\//.test(sModuleName), "module path must not contain a slash.");
  			sModuleName = sModuleName.replace(/\./g, "/");
  			// URL must not be empty
  			vUrlPrefix = vUrlPrefix || '.';
  			jQuery.sap.registerResourcePath(sModuleName, vUrlPrefix);
  		};
  
  		/**
  		 * Registers an URL prefix for a resource name prefix.
  		 *
  		 * Before a resource is loaded, the longest registered prefix of its unified resource name
  		 * is searched for and the associated URL prefix is used as a prefix for the request URL.
  		 * The remainder of the resource name is attached to the request URL 1:1.
  		 *
  		 * The registration and search operates on full name segments only. So when a prefix
  		 *
  		 *    'sap/com'  ->  'http://www.sap.com/ui5/resources/'
  		 *
  		 * is registered, then it will match the name
  		 *
  		 *    'sap/com/Button'
  		 *
  		 * but not
  		 *
  		 *    'sap/commons/Button'
  		 *
  		 * Note that the empty prefix ('') will always match and thus serves as a fallback for
  		 * any search.
  		 *
  		 * The url prefix can either be given as string or as object which contains the url and a final flag.
  		 * If final is set to true, overwriting a resource name prefix is not possible anymore.
  		 *
  		 * @param {string} sResourceNamePrefix in unified resource name syntax
  		 * @param {string | object} vUrlPrefix prefix to use instead of the sResourceNamePrefix, either a string literal or an object (e.g. {url : 'url/to/res', 'final': true})
  		 * @param {string} [vUrlPrefix.url] path prefix to register
  		 * @param {boolean} [vUrlPrefix.final] flag to avoid overwriting the url path prefix for the given module name at a later point of time
  		 *
  		 * @public
  		 * @static
  		 * @SecSink {1|PATH} Parameter is used for future HTTP requests
  		 */
  		jQuery.sap.registerResourcePath = function registerResourcePath(sResourceNamePrefix, vUrlPrefix) {
  
  			sResourceNamePrefix = String(sResourceNamePrefix || "");
  
  			if (mUrlPrefixes[sResourceNamePrefix] && mUrlPrefixes[sResourceNamePrefix]["final"] == true) {
  				log.warning( "registerResourcePath with prefix " + sResourceNamePrefix + " already set as final to '" + mUrlPrefixes[sResourceNamePrefix].url + "'. This call is ignored." );
  				return;
  			}
  
  			if ( typeof vUrlPrefix === 'string' || vUrlPrefix instanceof String ) {
  				vUrlPrefix = { 'url' : vUrlPrefix };
  			}
  
  			if ( !vUrlPrefix || vUrlPrefix.url == null ) {
  				delete mUrlPrefixes[sResourceNamePrefix];
  				log.info("registerResourcePath ('" + sResourceNamePrefix + "') (registration removed)");
  			} else {
  				vUrlPrefix.url = String(vUrlPrefix.url);
  				// ensure that the prefix ends with a '/'
  				if ( vUrlPrefix.url.slice(-1) != '/' ) {
  					vUrlPrefix.url += '/';
  				}
  				mUrlPrefixes[sResourceNamePrefix] = vUrlPrefix;
  				log.info("registerResourcePath ('" + sResourceNamePrefix + "', '" + vUrlPrefix.url + "')" + ((vUrlPrefix['final']) ? " (final)" : ""));
  			}
  		};
  
  		/**
  		 * Check whether a given module has been loaded / declared already.
  		 *
  		 * Returns true as soon as a module has been required the first time, even when
  		 * loading/executing it has not finished yet. So the main assertion of a
  		 * return value of <code>true</code> is that the necessary actions have been taken
  		 * to make the module available in the near future. It does not mean, that
  		 * the content of the module is already available!
  		 *
  		 * This fuzzy behavior is necessary to avoid multiple requests for the same module.
  		 * As a consequence of the assertion above, a <i>preloaded</i> module does not
  		 * count as <i>declared</i>. For preloaded modules, an explicit call to
  		 * <code>jQuery.sap.require</code> is necessary to make them available.
  		 *
  		 * If a caller wants to know whether a module needs to be loaded from the server,
  		 * it can set <code>bIncludePreloaded</code> to true. Then, preloaded modules will
  		 * be reported as 'declared' as well by this method.
  		 *
  		 * @param {string} sModuleName name of the module to be checked
  		 * @param {boolean} [bIncludePreloaded=false] whether preloaded modules should be reported as declared.
  		 * @return {boolean} whether the module has been declared already
  		 * @public
  		 * @static
  		 */
  		jQuery.sap.isDeclared = function isDeclared(sModuleName, bIncludePreloaded) {
  			sModuleName = ui5ToRJS(sModuleName) + ".js";
  			return mModules[sModuleName] && (bIncludePreloaded || mModules[sModuleName].state !== PRELOADED);
  		};
  
  		/**
  		 * Returns the names of all declared modules.
  		 * @return {string[]} the names of all declared modules
  		 * @see jQuery.sap.isDeclared
  		 * @public
  		 * @static
  		 */
  		jQuery.sap.getAllDeclaredModules = function() {
  			var aModules = [];
  			jQuery.each(mModules, function(sURN, oModule) {
  				// filter out preloaded modules
  				if ( oModule && oModule.state !== PRELOADED ) {
  					var sModuleName = urnToUI5(sURN);
  					if ( sModuleName ) {
  						aModules.push(sModuleName);
  					}
  				}
  			});
  			return aModules;
  		};
  
  		// take resource roots from configuration
  		if ( oCfgData.resourceroots ) {
  			jQuery.each(oCfgData.resourceroots, jQuery.sap.registerModulePath);
  		}
  
  		// dump the URL prefixes
  		log.info("URL prefixes set to:");
  		for (var n in mUrlPrefixes) {
  			log.info("  " + (n ? "'" + n + "'" : "(default)") + " : " + mUrlPrefixes[n].url + ((mUrlPrefixes[n]['final']) ? " (final)" : "") );
  		}
  
  		/**
  		 * Declares a module as existing.
  		 *
  		 * By default, this function assumes that the module will create a JavaScript object
  		 * with the same name as the module. As a convenience it ensures that the parent
  		 * namespace for that object exists (by calling jQuery.sap.getObject).
  		 * If such an object creation is not desired, <code>bCreateNamespace</code> must be set to false.
  		 *
  		 * @param {string | object}  sModuleName name of the module to be declared
  		 *                           or in case of an object {modName: "...", type: "..."}
  		 *                           where modName is the name of the module and the type
  		 *                           could be a specific dot separated extension e.g.
  		 *                           <code>{modName: "sap.ui.core.Dev", type: "view"}</code>
  		 *                           loads <code>sap/ui/core/Dev.view.js</code> and
  		 *                           registers as <code>sap.ui.core.Dev.view</code>
  		 * @param {boolean} [bCreateNamespace=true] whether to create the parent namespace
  		 *
  		 * @public
  		 * @static
  		 */
  		jQuery.sap.declare = function(sModuleName, bCreateNamespace) {
  
  			var sNamespaceObj = sModuleName;
  
  			// check for an object as parameter for sModuleName
  			// in case of this the object contains the module name and the type
  			// which could be {modName: "sap.ui.core.Dev", type: "view"}
  			if (typeof (sModuleName) === "object") {
  				sNamespaceObj = sModuleName.modName;
  				sModuleName = ui5ToRJS(sModuleName.modName) + (sModuleName.type ? "." + sModuleName.type : "") + ".js";
  			} else {
  				sModuleName = ui5ToRJS(sModuleName) + ".js";
  			}
  
  			declareModule(sModuleName);
  
  			// ensure parent namespace even if module was declared already
  			// (as declare might have been called by require)
  			if (bCreateNamespace !== false) {
  				// ensure parent namespace
  				jQuery.sap.getObject(sNamespaceObj, 1);
  			}
  
  			return this;
  		};
  
  		/**
  		 * Ensures that the given module is loaded and executed before execution of the
  		 * current script continues.
  		 *
  		 * By issuing a call to this method, the caller declares a dependency to the listed modules.
  		 *
  		 * Any required and not yet loaded script will be loaded and execute synchronously.
  		 * Already loaded modules will be skipped.
  		 *
  		 * @param {...string | object}  vModuleName one or more names of modules to be loaded
  		 *                              or in case of an object {modName: "...", type: "..."}
  		 *                              where modName is the name of the module and the type
  		 *                              could be a specific dot separated extension e.g.
  		 *                              <code>{modName: "sap.ui.core.Dev", type: "view"}</code>
  		 *                              loads <code>sap/ui/core/Dev.view.js</code> and
  		 *                              registers as <code>sap.ui.core.Dev.view</code>
  		 *
  		 * @public
  		 * @static
  		 * @function
  		 * @SecSink {0|PATH} Parameter is used for future HTTP requests
  		 */
  		jQuery.sap.require = function(vModuleName, fnCallback) {
  
  			if ( arguments.length > 1 ) {
  				// legacy mode with multiple arguments, each representing a dependency
  				for (var i = 0; i < arguments.length; i++) {
  					jQuery.sap.require(arguments[i]);
  				}
  				return this;
  			}
  
  			// check for an object as parameter for sModuleName
  			// in case of this the object contains the module name and the type
  			// which could be {modName: "sap.ui.core.Dev", type: "view"}
  			if (typeof (vModuleName) === "object") {
  				jQuery.sap.assert(!vModuleName.type || jQuery.inArray(vModuleName.type, mKnownSubtypes.js) >= 0, "type must be empty or one of " + mKnownSubtypes.js.join(", "));
  				vModuleName = ui5ToRJS(vModuleName.modName) + (vModuleName.type ? "." + vModuleName.type : "") + ".js";
  			} else {
  				vModuleName = ui5ToRJS(vModuleName) + ".js";
  			}
  
  			requireModule(vModuleName);
  
  			return this; // TODO
  		};
  
  		/**
  		 * UI5 internal method that loads the given module, specified in requireJS notation (URL like, without extension).
  		 *
  		 * Applications MUST NOT USE THIS METHOD as it will be removed in one of the future versions.
  		 * It is only intended for sap.ui.component.
  		 *
  		 * @param {string} sModuleName Module name in requireJS syntax
  		 * @private
  		 */
  		jQuery.sap._requirePath = function(sModuleName) {
  			requireModule(sModuleName + ".js");
  		};
  
  		window.sap = window.sap || {};
  		sap.ui = sap.ui || {};
  
  		/**
  		 * Defines a Javascript module with its name, its dependencies and a module value or factory.
  		 *
  		 * The typical and only suggested usage of this method is to have one single, top level call to
  		 * <code>sap.ui.define</code> in one Javascript resource (file). When a module is requested by its
  		 * name for the first time, the corresponding resource is determined from the name and the current
  		 * {@link jQuery.sap.registerResourcePath configuration}. The resource will be loaded and executed
  		 * which in turn will execute the top level <code>sap.ui.define</code> call.
  		 *
  		 * If the module name was omitted from that call, it will be substituted by the name that was used to
  		 * request the module. As a preparation step, the dependencies as well as their transitive dependencies,
  		 * will be loaded. Then, the module value will be determined: if a static value (object, literal) was
  		 * given, that value will be the module value. If a function was given, that function will be called
  		 * (providing the module values of the declared dependencies as parameters to the function) and its
  		 * return value will be used as module value. The framework internally associates the resulting value
  		 * with the module name and provides it to the original requestor of the module. Whenever the module
  		 * is requested again, the same value will be returned (modules are executed only once).
  		 *
  		 * <i>Example:</i><br>
  		 * The following example defines a module "SomeClass", but doesn't hard code the module name.
  		 * If stored in a file 'sap/mylib/SomeClass.js', it can be requested as 'sap/mylib/SomeClass'.
  		 * <pre>
  		 *   sap.ui.define(['./Helper', 'sap/m/Bar'], function(Helper,Bar) {
  		 *
  		 *     // create a new class
  		 *     var SomeClass = function();
  		 *
  		 *     // add methods to its prototype
  		 *     SomeClass.prototype.foo = function() {
  		 *
  		 *         // use a function from the dependency 'Helper' in the same package (e.g. 'sap/mylib/Helper' )
  		 *         var mSettings = Helper.foo();
  		 *
  		 *         // create and return a sap.m.Bar (using its local name 'Bar')
  		 *         return new Bar(mSettings);
  		 *
  		 *     }
  		 *
  		 *     // return the class as module value
  		 *     return SomeClass;
  		 *
  		 *   });
  		 * </pre>
  		 * 
  		 * In another module or in an application HTML page, the {@link sap.ui.require} API can be used
  		 * to load the Something module and to work with it:
  		 * 
  		 * <pre>
  		 * sap.ui.require(['sap/mylib/Something'], function(Something) {
  		 * 
  		 *   // instantiate a Something and call foo() on it 
  		 *   new Something().foo();
  		 *   
  		 * });
  		 * </pre>
  		 *
  		 * <b>Module Name Syntax</b><br>
  		 * <code>sap.ui.define</code> uses a simplified variant of the {@link jQuery.sap.getResourcePath
  		 * unified resource name} syntax for the module's own name as well as for its dependencies.
  		 * The only difference to that syntax is, that for <code>sap.ui.define</code> and
  		 * <code>sap.ui.require</code>, the extension (which always would be '.js') has to be omitted.
  		 * Both methods always add this extension internally.
  		 *
  		 * As a convenience, the name of a dependency can start with the segment './' which will be
  		 * replaced by the name of the package that contains the currently defined module (relative name).
  		 *
  		 * It is best practice to omit the name of the defined module (first parameter) and to use
  		 * relative names for the dependencies whenever possible. This reduces the necessary configuration,
  		 * simplifies renaming of packages and allows to map them to a different namespace.
  		 *
  		 *
  		 * <b>Dependency to Modules</b><br>
  		 * If a dependencies array is given, each entry represents the name of another module that
  		 * the currently defined module depends on. All dependency modules are loaded before the value
  		 * of the currently defined module is determined. The module value of each dependency module
  		 * will be provided as a parameter to a factory function, the order of the parameters will match
  		 * the order of the modules in the dependencies array.
  		 *
  		 * <b>Note:</b> the order in which the dependency modules are <i>executed</i> is <b>not</b>
  		 * defined by the order in the dependencies array! The execution order is affected by dependencies
  		 * <i>between</i> the dependency modules as well as by their current state (whether a module
  		 * already has been loaded or not). Neither module implementations nor dependants that require
  		 * a module set must make any assumption about the execution order (other than expressed by
  		 * their dependencies). There is, however, one exception with regard to third party libraries,
  		 * see the list of limitations further down below.
  		 *
  		 * <b>Note:</b>a static module value (a literal provided to <code>sap.ui.define</code>) cannot
  		 * depend on the module values of the depency modules. Instead, modules can use a factory function,
  		 * calculate the static value in that function, potentially based on the dependencies, and return
  		 * the result as module value. The same approach must be taken when the module value is supposed
  		 * to be a function.
  		 *
  		 *
  		 * <b>Asynchronous Contract</b><br>
  		 * <code>sap.ui.define</code> is designed to support real Asynchronous Module Definitions (AMD)
  		 * in future, although it internally still uses the the old synchronous module loading of UI5.
  		 * Callers of <code>sap.ui.define</code> therefore must not rely on any synchronous behavior
  		 * that they might observe with the current implementation.
  		 *
  		 * For example, callers of <code>sap.ui.define</code> must not use the module value immediately
  		 * after invoking <code>sap.ui.define</code>:
  		 *
  		 * <pre>
  		 *   // COUNTER EXAMPLE HOW __NOT__ TO DO IT
  		 *
  		 *   // define a class Something as AMD module
  		 *   sap.ui.define('Something', [], function() {
  		 *     var Something = function();
  		 *     return Something;
  		 *   });
  		 *
  		 *   // DON'T DO THAT!
  		 *   // accessing the class _synchronously_ after sap.ui.define was called
  		 *   new Something();
  		 * </pre>
  		 *
  		 * Applications that need to ensure synchronous module definition or synchronous loading of dependencies
  		 * <b>MUST</b> use the old {@link jQuery.sap.declare} and {@link jQuery.sap.require} APIs.
  		 *
  		 *
  		 * <b>(No) Global References</b><br>
  		 * To be in line with AMD best practices, modules defined with <code>sap.ui.define</code>
  		 * should not make any use of global variables if those variables are also available as module
  		 * values. Instead, they should add dependencies to those modules and use the corresponding parameter
  		 * of the factory function to access the module value.
  		 *
  		 * As the current programming model and the documentation of UI5 heavily rely on global names,
  		 * there will be a transition phase where UI5 enables AMD modules and local references to module
  		 * values in parallel to the old global names. The fourth parameter of <code>sap.ui.define</code>
  		 * has been added to support that transition phase. When this parameter is set to true, the framework
  		 * provides two additional functionalities
  		 *
  		 * <ol>
  		 * <li>before the factory function is called, the existence of the global parent namespace for
  		 *     the current module is ensured</li>
  		 * <li>the module value will be automatically exported under a global name which is derived from
  		 *     the name of the module</li>
  		 * </ol>
  		 *
  		 * The parameter lets the framework know whether any of those two operations is needed or not.
  		 * In future versions of UI5, a central configuration option is planned to suppress those 'exports'.
  		 *
  		 *
  		 * <b>Third Party Modules</b><br>
  		 * Although third party modules don't use UI5 APIs, they still can be listed as dependencies in
  		 * a <code>sap.ui.define</code> call. They will be requested and executed like UI5 modules, but their
  		 * module value will be <code>undefined</code>.
  		 *
  		 * If the currently defined module needs to access the module value of such a third party module,
  		 * it can access the value via its global name (if the module supports such a usage).
  		 *
  		 * Note that UI5 temporarily deactivates an existing AMD loader while it executes third party modules
  		 * known to support AMD. This sounds contradictarily at a first glance as UI5 wants to support AMD,
  		 * but for now it is necessary to fully support UI5 apps that rely on global names for such modules.
  		 *
  		 * Example:
  		 * <pre>
  		 *   // module 'Something' wants to use third party library 'URI.js'
  		 *   // It is packaged by UI5 as non-UI5-module 'sap/ui/thirdparty/URI'
  		 *
  		 *   sap.ui.define('Something', ['sap/ui/thirdparty/URI'], function(URIModuleValue) {
  		 *
  		 *     new URIModuleValue(); // fails as module value is undefined
  		 *
  		 *     //global URI // (optional) declare usage of global name so that static code checks don't complain
  		 *     new URI(); // access to global name 'URI' works
  		 *
  		 *     ...
  		 *   });
  		 * </pre>
  		 *
  		 *
  		 * <b>Differences to requireJS</b><br>
  		 * The current implementation of <code>sap.ui.define</code> differs from <code>requireJS</code>
  		 * or other AMD loaders in several aspects:
  		 * <ul>
  		 * <li>the name <code>sap.ui.define</code> is different from the plain <code>define</code>.
  		 * This has two reasons: first, it avoids the impression that <code>sap.ui.define</code> is
  		 * an exact implementation of an AMD loader. And second, it allows the coexistence of an AMD
  		 * loader (requireJS) and <code>sap.ui.define</code> in one application as long as UI5 or
  		 * apps using UI5 are not fully prepared to run with an AMD loader</li>
  		 * <li><code>sap.ui.define</code> currently loads modules with synchronous XHR calls. This is
  		 * basically a tribute to the synchronous history of UI5.
  		 * <b>BUT:</b> synchronous dependency loading and factory execution explicitly it not part of
  		 * contract of <code>sap.ui.define</code>. To the contrary, it is already clear and planned
  		 * that asynchronous loading will be implemented, at least as an alternative if not as the only
  		 * implementation. Also check section <b>Asynchronous Contract</b> above.<br>
  		 * Applications that need to ensure synchronous loading of dependencies <b>MUST</b> use the old
  		 * {@link jQuery.sap.require} API.</li>
  		 * <li><code>sap.ui.define</code> does not support plugins to use other file types, formats or
  		 * protocols. It is not planned to support this in future</li>
  		 * <li><code>sap.ui.define</code> does <b>not</b> support the 'sugar' of requireJS where CommonJS
  		 * style dependency declarations using <code>sap.ui.require("something")</code> are automagically
  		 * converted into <code>sap.ui.define</code> dependencies before executing the factory function.</li>
  		 * <li><code>sap.ui.define</code> does not support the '../' prefix for module names. Only
  		 * relative names in the same package or in subpackages thereof are supported.</li>
  		 * </ul>
  		 *
  		 *
  		 * <b>Limitations, Design Considerations</b><br>
  		 * <ul>
  		 * <li><b>Limitation</b>: as dependency management is not supported for Non-UI5 modules, the only way
  		 *     to ensure proper execution order for such modules currently is to rely on the order in the
  		 *     dependency array. Obviously, this only works as long as <code>sap.ui.define</code> uses
  		 *     synchronous loading. It will be enhanced when asynchronous loading is implemented.</li>
  		 * <li>it was discussed to enfore asynchronous execution of the module factory function (e.g. with a
  		 *     timeout of 0). But this would have invalidated the current migration scenario where a
  		 *     sync <code>jQuery.sap.require</code> call can load a <code>sap.ui.define</code>'ed module.
  		 *     If the module definition would not execute synchronously, the synchronous contract of the
  		 *     require call would be broken (default behavior in existing UI5 apps)</li>
  		 * <li>a single file must not contain multiple calls to <code>sap.ui.define</code>. Multiple calls
  		 *     currently are only supported in the so called 'preload' files that the UI5 merge tooling produces.
  		 *     The exact details of how this works might be changed in future implementations and are not
  		 *     yet part of the API contract</li>
  		 * </ul>
  		 * @param {string} [sModuleName] name of the module in simplified resource name syntax. 
  		 *        When omitted, the loader determines the name from the request.
  		 * @param {string[]} [aDependencies] list of dependencies of the module
  		 * @param {function|any} vFactory the module value or a function that calculates the value
  		 * @param {boolean} [bExport] whether an export to global names is required - should be used by SAP-owned code only
  		 * @since 1.27.0
  		 * @public
  		 * @experimental Since 1.27.0 - not all aspects of sap.ui.define are settled yet. If the documented
  		 *        constraints and limitations are obeyed, SAP-owned code might use it. If the fourth parameter
  		 *        is not used and if the asynchronous contract is respected, even Non-SAP code might use it.
  		 */
  		sap.ui.define = function(sModuleName, aDependencies, vFactory, bExport) {
  			var sResourceName, i;
  
  			// optional id
  			if ( typeof sModuleName === 'string' ) {
  				sResourceName = sModuleName + '.js';
  			} else {
  				// shift parameters
  				bExport = vFactory;
  				vFactory = aDependencies;
  				aDependencies = sModuleName;
  				sResourceName = _execStack[_execStack.length - 1];
  			}
  			
  			// convert module name to UI5 module name syntax (might fail!)
  			sModuleName = urnToUI5(sResourceName);
  
  			// optional array of dependencies
  			if ( !jQuery.isArray(aDependencies) ) {
  				// shift parameters
  				bExport = vFactory;
  				vFactory = aDependencies;
  				aDependencies = [];
  			} else {
  				// resolve relative module names
  				var sPackage = sResourceName.slice(0,1 + sResourceName.lastIndexOf('/'));
  				for (i = 0; i < aDependencies.length; i++) {
  					if ( /^\.\//.test(aDependencies[i]) ) {
  						aDependencies[i] = sPackage + aDependencies[i].slice(2); // 2 == length of './' prefix
  					}
  				}
  			}
  
  			if ( log.isLoggable() ) {
  				log.debug("define(" + sResourceName + ", " + "['" + aDependencies.join("','") + "']" + ")");
  			}
  
  			var oModule = declareModule(sResourceName);
  
  			// note: dependencies will be converted from RJS to URN inside requireAll
  			requireAll(aDependencies, function(aModules) {
  
  				// factory
  				if ( log.isLoggable() ) {
  					log.debug("define(" + sResourceName + "): calling factory " + typeof vFactory);
  				}
  
  				if ( bExport ) {
  					// ensure parent namespace
  					jQuery.sap.getObject(sModuleName, 1);
  				}
  
  				if ( typeof vFactory === 'function' ) {
  					oModule.content = vFactory.apply(window, aModules);
  				} else {
  					oModule.content = vFactory;
  				}
  
  				// HACK: global export
  				if ( bExport ) {
  					if ( oModule.content == null ) {
  						log.error("module '" + sResourceName + "' returned no content, but should be exported");
  					} else {
  						if ( log.isLoggable() ) {
  							log.debug("exporting content of '" + sResourceName + "': as global object");
  						}
  						jQuery.sap.setObject(sModuleName, oModule.content);
  					}
  				}
  
  			});
  
  		};
  
  		/**
  		 * Resolves one or more module dependencies.
  		 *
  		 * <b>Synchronous Retrieval of a Single Module Value</b>
  		 *
  		 * When called with a single string, that string is assumed to be the name of an already loaded
  		 * module and the value of that module is returned. If the module has not been loaded yet,
  		 * or if it is a Non-UI5 module (e.g. third party module), <code>undefined</code> is returned.
  		 * This signature variant allows synchronous access to module values without initiating module loading.
  		 *
  		 * Sample:
  		 * <pre>
  		 *   var JSONModel = sap.ui.require("sap/ui/model/json/JSONModel");
   		 * </pre>
   		 *
   		 * For modules that are known to be UI5 modules, this signature variant can be used to check whether
   		 * the module has been loaded.
   		 *
  		 * <b>Asynchronous Loading of Multiple Modules</b>
  		 *
  		 * If an array of strings is given and (optionally) a callback function, then the strings
  		 * are interpreted as module names and the corresponding modules (and their transitive
  		 * dependencies) are loaded. Then the callback function will be called asynchronously.
  		 * The module values of the specified modules will be provided as parameters to the callback
  		 * function in the same order in which they appeared in the dependencies array.
  		 *
  		 * The return value for the asynchronous use case is <code>undefined</code>.
  		 *
  		 * <pre>
  		 *   sap.ui.require(['sap/ui/model/json/JSONModel', 'sap/ui/core/UIComponent'], function(JSONModel,UIComponent) {
  		 *
  		 *     var MyComponent = UIComponent.extend('MyComponent', {
  		 *       ...
  		 *     });
  		 *     ...
  		 *
  		 *   });
   		 * </pre>
   		 *
  		 * This method uses the same variation of the {@link jQuery.sap.getResourcePath unified resource name}
  		 * syntax that {@link sap.ui.define} uses: module names are specified without the implicit extension '.js'.
  		 * Relative module names are not supported.
  		 *
  		 * @param {string|string[]} vDependencies dependency (dependencies) to resolve
  		 * @param {function} [fnCallback] callback function to execute after resolving an array of dependencies
  		 * @returns {any|undefined} a single module value or undefined
  		 * @public
  		 * @experimental Since 1.27.0 - not all aspects of sap.ui.require are settled yet. E.g. the return value
  		 * of the asynchronous use case might change (currently it is undefined).
  		 */
  		sap.ui.require = function(vDependencies, fnCallback) {
  			jQuery.sap.assert(typeof vDependencies === 'string' || jQuery.isArray(vDependencies), "dependency param either must be a single string or an array of strings");
  			jQuery.sap.assert(fnCallback == null || typeof fnCallback === 'function', "callback must be a function or null/undefined");
  
  			if ( typeof vDependencies === 'string' ) {
  
  				var sModuleName = vDependencies + '.js',
  					oModule = mModules[sModuleName];
  
  				return oModule ? (oModule.content || jQuery.sap.getObject(urnToUI5(sModuleName))) : undefined;
  
  			}
  
  			requireAll(vDependencies, function(aModules) {
  
  				if ( typeof fnCallback === 'function' ) {
  					// enforce asynchronous execution of callback
  					setTimeout(function() {
  						fnCallback.apply(window, aModules);
  					},0);
  				}
  
  			});
  
  			// return undefined;
  		};
  
  		jQuery.sap.preloadModules = function(sPreloadModule, bAsync, oSyncPoint) {
  
  			var sURL, iTask;
  
  			jQuery.sap.assert(!bAsync || oSyncPoint, "if mode is async, a syncpoint object must be given");
  
  			if ( mPreloadModules[sPreloadModule] ) {
  				return;
  			}
  
  			mPreloadModules[sPreloadModule] = true;
  
  			sURL = jQuery.sap.getModulePath(sPreloadModule, ".json");
  
  			log.debug("preload file " + sPreloadModule);
  			iTask = oSyncPoint && oSyncPoint.startTask("load " + sPreloadModule);
  			jQuery.ajax({
  				dataType : "json",
  				async : bAsync,
  				url : sURL,
  				success : function(data) {
  					if ( data ) {
  						data.url = sURL;
  					}
  					jQuery.sap.registerPreloadedModules(data, bAsync, oSyncPoint);
  					oSyncPoint && oSyncPoint.finishTask(iTask);
  				},
  				error : function(xhr, textStatus, error) {
  					log.error("failed to preload '" + sPreloadModule + "': " + (error || textStatus));
  					oSyncPoint && oSyncPoint.finishTask(iTask, false);
  				}
  			});
  
  		};
  
  		jQuery.sap.registerPreloadedModules = function(oData, bAsync, oSyncPoint) {
  
  			var bOldSyntax = Version(oData.version || "1.0").compareTo("2.0") < 0;
  
  			if ( log.isLoggable() ) {
  				log.debug(sLogPrefix + "adding preloaded modules from '" + oData.url + "'");
  			}
  
  			if ( oData.name ) {
  				mPreloadModules[oData.name] = true;
  			}
  
  			jQuery.each(oData.modules, function(sName,sContent) {
  				sName = bOldSyntax ? ui5ToRJS(sName) + ".js" : sName;
  				if ( !mModules[sName] ) {
  					mModules[sName] = { state : PRELOADED, url : oData.url + "/" + sName, data : sContent, group: oData.name };
  				}
  				// when a library file is preloaded, also mark its preload file as loaded
  				// for normal library preload, this is redundant, but for non-default merged entities
  				// like sap/fiori/core.js it avoids redundant loading of library preload files
  				if ( sName.match(/\/library\.js$/) ) {
  					mPreloadModules[urnToUI5(sName) + "-preload"] = true;
  				}
  			});
  
  			if ( oData.dependencies ) {
  				jQuery.each(oData.dependencies, function(idx,sModuleName) {
  					jQuery.sap.preloadModules(sModuleName, bAsync, oSyncPoint);
  				});
  			}
  		};
  
  		/**
  		 * Removes a set of resources from the resource cache.
  		 *
  		 * @param {string} sName unified resource name of a resource or the name of a preload group to be removed
  		 * @param {boolean} [bPreloadGroup=true] whether the name specifies a preload group, defaults to true
  		 * @param {boolean} [bUnloadAll] Whether all matching resources should be unloaded, even if they have been executed already.
  		 * @param {boolean} [bDeleteExports] Whether exportss (global variables) should be destroyed as well. Will be done for UI5 module names only.
  		 * @experimental Since 1.16.3 API might change completely, apps must not develop against it.
  		 * @private
  		 */
  		jQuery.sap.unloadResources = function(sName, bPreloadGroup, bUnloadAll, bDeleteExports) {
  			var aModules = [];
  
  			if ( bPreloadGroup == null ) {
  				bPreloadGroup = true;
  			}
  
  			if ( bPreloadGroup ) {
  				// collect modules that belong to the given group
  				jQuery.each(mModules, function(sURN, oModule) {
  					if ( oModule && oModule.group === sName ) {
  						aModules.push(sURN);
  					}
  				});
  				// also remove a preload entry
  				delete mPreloadModules[sName];
  
  			} else {
  				// single module
  				if ( mModules[sName] ) {
  					aModules.push(sName);
  				}
  			}
  
  			jQuery.each(aModules, function(i, sURN) {
  				var oModule = mModules[sURN];
  				if ( oModule && bDeleteExports && sURN.match(/\.js$/) ) {
  					jQuery.sap.setObject(urnToUI5(sURN), undefined); // TODO really delete property
  				}
  				if ( oModule && (bUnloadAll || oModule.state === PRELOADED) ) {
  				  delete mModules[sURN];
  				}
  			});
  
  		};
  
  		/**
  		 * Converts a UI5 module name to a unified resource name.
  		 *
  		 * Used by View and Fragment APIs to convert a given module name into an URN.
  		 *
  		 * @experimental Since 1.16.0, not for public usage yet.
  		 * @private
  		 */
  		jQuery.sap.getResourceName = function(sModuleName, sSuffix) {
  			return ui5ToRJS(sModuleName) + (sSuffix || ".js");
  		};
  
  		/**
  		 * Retrieves the resource with the given name, either from the preload cache or from
  		 * the server. The expected data type of the resource can either be specified in the
  		 * options (<code>dataType</code>) or it will be derived from the suffix of the <code>sResourceName</code>.
  		 * The only supported data types so far are xml, html, json and text. If the resource name extension
  		 * doesn't match any of these extensions, the data type must be specified in the options.
  		 *
  		 * If the resource is found in the preload cache, it will be converted from text format
  		 * to the requested <code>dataType</code> using a converter from <code>jQuery.ajaxSettings.converters</code>.
  		 *
  		 * If it is not found, the resource name will be converted to a resource URL (using {@link #getResourcePath})
  		 * and the resulting URL will be requested from the server with a synchronous jQuery.ajax call.
  		 *
  		 * If the resource was found in the local preload cache and any necessary conversion succeeded
  		 * or when the resource was retrieved from the backend successfully, the content of the resource will
  		 * be returned. In any other case, an exception will be thrown, or if option failOnError is set to true,
  		 * <code>null</code> will be returned.
  		 *
  		 * Future implementations of this API might add more options. Generic implementations that accept an
  		 * <code>mOptions</code> object and propagate it to this function should limit the options to the currently
  		 * defined set of options or they might fail for unknown options.
  		 *
  		 * For asynchronous calls the return value of this method is an ECMA Script 6 Promise object which callbacks are triggered
  		 * when the resource is ready:
  		 * If <code>failOnError</code> is <code>false</code> the catch callback of the promise is not called. The argument given to the fullfilled
  		 * callback is null in error case.
  		 * If <code>failOnError</code> is <code>true</code> the catch callback will be triggered. The argument is an Error object in this case.
  		 *
  		 * @param {string} [sResourceName] resourceName in unified resource name syntax
  		 * @param {object} [mOptions] options
  		 * @param {object} [mOptions.dataType] one of "xml", "html", "json" or "text". If not specified it will be derived from the resource name (extension)
  		 * @param {string} [mOptions.name] unified resource name of the resource to load (alternative syntax)
  		 * @param {string} [mOptions.url] url of a resource to load (alternative syntax, name will only be a guess)
  		 * @param {string} [mOptions.headers] Http headers for an eventual XHR request
  		 * @param {string} [mOptions.failOnError=true] whether to propagate load errors or not
  		 * @param {string} [mOptions.async=false] whether the loading should be performed asynchronously.
  		 * @return {string|Document|object|Promise} content of the resource. A string for text or html, an Object for JSON, a Document for XML. For asynchronous calls an ECMA Script 6 Promise object will be returned.
  		 * @throws Error if loading the resource failed
  		 * @private
  		 * @experimental API is not yet fully mature and may change in future.
  		 * @since 1.15.1
  		 */
  		jQuery.sap.loadResource = function(sResourceName, mOptions) {
  
  			var sType,
  				oData,
  				sUrl,
  				oError,
  				oDeferred;
  
  			if ( typeof sResourceName === "string" ) {
  				mOptions = mOptions || {};
  			} else {
  				mOptions = sResourceName || {};
  				sResourceName = mOptions.name;
  				if ( !sResourceName && mOptions.url) {
  					sResourceName = guessResourceName(mOptions.url);
  				}
  			}
  			// defaulting
  			mOptions = jQuery.extend({ failOnError: true, async: false }, mOptions);
  
  			sType = mOptions.dataType;
  			if ( sType == null && sResourceName ) {
  				sType = (sType = rTypes.exec(sResourceName)) && sType[1];
  			}
  
  			jQuery.sap.assert(/^(xml|html|json|text)$/.test(sType), "type must be one of xml, html, json or text");
  
  			oDeferred = mOptions.async ? new jQuery.Deferred() : null;
  
  			function handleData(d, e) {
  				if ( d == null && mOptions.failOnError ) {
  					e = e || new Error("no data returned for " + sResourceName);
  					if (mOptions.async) {
  						oDeferred.reject(e);
  						jQuery.sap.log.error(e);
  						return d;
  					}
  					throw e;
  				}
  
  				if (mOptions.async) {
  					oDeferred.resolve(d);
  				}
  
  				return d;
  			}
  
  			function convertData(d) {
  				var vConverter = jQuery.ajaxSettings.converters["text " + sType];
  				if ( typeof vConverter === "function" ) {
  					d = vConverter(d);
  				}
  				return handleData(d);
  			}
  
  			if ( sResourceName && mModules[sResourceName] ) {
  				oData = mModules[sResourceName].data;
  				mModules[sResourceName].state = LOADED;
  			}
  
  			if ( oData != null ) {
  
  				if (mOptions.async) {
  					//Use timeout to simulate async behavior for this sync case for easier usage
  					setTimeout(function(){
  						convertData(oData);
  					}, 0);
  				} else {
  					oData = convertData(oData);
  				}
  
  			} else {
  
  				jQuery.ajax({
  					url : sUrl = mOptions.url || getResourcePath(sResourceName),
  					async : mOptions.async,
  					dataType : sType,
  					headers: mOptions.headers,
  					success : function(data, textStatus, xhr) {
  						oData = handleData(data);
  					},
  					error : function(xhr, textStatus, error) {
  						oError = new Error("resource " + sResourceName + " could not be loaded from " + sUrl + ". Check for 'file not found' or parse errors. Reason: " + error);
  						oError.status = textStatus;
  						oError.error = error;
  						oError.statusCode = xhr.status;
  						oData = handleData(null, oError);
  					}
  				});
  
  			}
  
  			return mOptions.async ? window.Promise.resolve(oDeferred) : oData;
  		};
  
  		/*
  		 * register a global event handler to detect script execution errors.
  		 * Only works for browsers that support document.currentScript.
  		 * /
  		window.addEventListener("error", function(e) {
  			if ( document.currentScript && document.currentScript.dataset.sapUiModule ) {
  				var error = {
  					message: e.message,
  					filename: e.filename,
  					lineno: e.lineno,
  					colno: e.colno
  				};
  				document.currentScript.dataset.sapUiModuleError = JSON.stringify(error);
  			}
  		});
  		*/
  
  		/**
  		 * Loads the given Javascript resource (URN) asynchronously via as script tag.
  		 * Returns a promise that will be resolved when the load event is fired or reject
  		 * when the error event is fired.
  		 *
  		 * Note: execution errors of the script are not reported as 'error'.
  		 *
  		 * This method is not a full implementation of require. It is intended only for
  		 * loading "preload" files that do not define an own module / module value.
  		 *
  		 * Functionality might be removed/renamed in future, so no code outside the
  		 * sap.ui.core library must use it.
  		 *
  		 * @experimental
  		 * @private
  		 */
  		jQuery.sap._loadJSResourceAsync = function(sResource, bIgnoreErrors) {
  
  			return new Promise(function(resolve,reject) {
  
  				var oModule = mModules[sResource] || (mModules[sResource] = { state : INITIAL });
  				var sUrl = oModule.url = getResourcePath(sResource);
  				oModule.state = LOADING;
  
  				var oScript = window.document.createElement('SCRIPT');
  				oScript.src = sUrl;
  				oScript.dataset.sapUiModule = sResource;
  				oScript.dataset.sapUiModuleError = '';
  				oScript.addEventListener('load', function(e) {
  					jQuery.sap.log.info("Javascript resource loaded: " + sResource);
  // TODO either find a cross-browser solution to detect and assign execution errros or document behavior
  //					var error = e.target.dataset.sapUiModuleError;
  //					if ( error ) {
  //						oModule.state = FAILED;
  //						oModule.error = JSON.parse(error);
  //						jQuery.sap.log.error("failed to load Javascript resource: " + sResource + ":" + error);
  //						reject(oModule.error);
  //					}
  					oModule.state = READY;
  					// TODO oModule.data = ?
  					resolve();
  				});
  				oScript.addEventListener('error', function(e) {
  					jQuery.sap.log.error("failed to load Javascript resource: " + sResource);
  					oModule.state = FAILED;
  					// TODO oModule.error = xhr ? xhr.status + " - " + xhr.statusText : textStatus;
  					if ( bIgnoreErrors ) {
  						resolve();
  					} else {
  						reject();
  					}
  				});
  				appendHead(oScript);
  			});
  
  		};
  
  		return function() {
  
  			//remove final information in mUrlPrefixes
  			var mFlatUrlPrefixes = {};
  				jQuery.each(mUrlPrefixes, function(sKey,oUrlPrefix) {
  				mFlatUrlPrefixes[sKey] = oUrlPrefix.url;
  			});
  
  
  			return { modules : mModules, prefixes : mFlatUrlPrefixes };
  		};
  
  	}());
  
  	// --------------------- script and stylesheet handling --------------------------------------------------
  
  	// appends a link object to the head
  	function appendHead(oElement) {
  		var head = window.document.getElementsByTagName("head")[0];
  		if (head) {
  			head.appendChild(oElement);
  		}
  	}
  
  	/**
  	 * Includes the script (via &lt;script&gt;-tag) into the head for the
  	 * specified <code>sUrl</code> and optional <code>sId</code>.
  	 * <br>
  	 * <i>In case of IE8 only the load callback will work ignoring in case of success and error.</i>
  	 *
  	 * @param {string}
  	 *            sUrl the URL of the script to load
  	 * @param {string}
  	 *            [sId] id that should be used for the script include tag
  	 * @param {function}
  	 *            [fnLoadCallback] callback function to get notified once the script has been loaded
  	 * @param {function}
  	 *            [fnErrorCallback] callback function to get notified once the script loading failed (not supported by IE8)
  	 *
  	 * @public
  	 * @static
  	 * @SecSink {0|PATH} Parameter is used for future HTTP requests
  	 */
  	jQuery.sap.includeScript = function includeScript(sUrl, sId, fnLoadCallback, fnErrorCallback){
  		var oScript = window.document.createElement("script");
  		oScript.src = sUrl;
  		oScript.type = "text/javascript";
  		if (sId) {
  			oScript.id = sId;
  		}
  		if (!!sap.ui.Device.browser.internet_explorer && sap.ui.Device.browser.version < 9) {
  			// in case if IE8 the error callback is not supported!
  			// we can only check the loading via the readystatechange event
  			if (fnLoadCallback) {
  				oScript.onreadystatechange = function() {
  					if (oScript.readyState === "loaded" || oScript.readyState === "complete") {
  						fnLoadCallback();
  						oScript.onreadystatechange = null;
  					}
  				};
  			}
  		} else {
  			if (fnLoadCallback) {
  				jQuery(oScript).load(fnLoadCallback);
  			}
  			if (fnErrorCallback) {
  				jQuery(oScript).error(fnErrorCallback);
  			}
  		}
  		// jQuery("head").append(oScript) doesn't work because they filter for the script
  		// and execute them directly instead adding the SCRIPT tag to the head
  		var oOld;
  		if ((sId && (oOld = jQuery.sap.domById(sId)) && oOld.tagName === "SCRIPT")) {
  			jQuery(oOld).remove(); // replacing scripts will not trigger the load event
  		}
  		appendHead(oScript);
  	};
  
  	var oIEStyleSheetNode;
  	var mIEStyleSheets = jQuery.sap._mIEStyleSheets = {};
  
  	/**
  	 * Includes the specified stylesheet via a &lt;link&gt;-tag in the head of the current document. If there is call to
  	 * <code>includeStylesheet</code> providing the sId of an already included stylesheet, the existing element will be
  	 * replaced.
  	 *
  	 * @param {string}
  	 *          sUrl the URL of the script to load
  	 * @param {string}
  	 *          [sId] id that should be used for the script include tag
  	 * @param {function}
  	 *          [fnLoadCallback] callback function to get notified once the link has been loaded
  	 * @param {function}
  	 *          [fnErrorCallback] callback function to get notified once the link loading failed.
  	 *          In case of usage in IE the error callback will also be executed if an empty stylesheet
  	 *          is loaded. This is the only option how to determine in IE if the load was successful
  	 *          or not since the native onerror callback for link elements doesn't work in IE. The IE
  	 *          always calls the onload callback of the link element.
  	 *
  	 * @public
  	 * @static
  	 * @SecSink {0|PATH} Parameter is used for future HTTP requests
  	 */
  	jQuery.sap.includeStyleSheet = function includeStyleSheet(sUrl, sId, fnLoadCallback, fnErrorCallback) {
  
  		var _createLink = function(sUrl, sId, fnLoadCallback, fnErrorCallback){
  
  			// create the new link element
  			var oLink = document.createElement("link");
  			oLink.type = "text/css";
  			oLink.rel = "stylesheet";
  			oLink.href = sUrl;
  			if (sId) {
  				oLink.id = sId;
  			}
  
  			var fnError = function() {
  				jQuery(oLink).attr("sap-ui-ready", "false");
  				if (fnErrorCallback) {
  					fnErrorCallback();
  				}
  			};
  
  			var fnLoad = function() {
  				jQuery(oLink).attr("sap-ui-ready", "true");
  				if (fnLoadCallback) {
  					fnLoadCallback();
  				}
  			};
  
  			// for IE we will check if the stylesheet contains any rule and then
  			// either trigger the load callback or the error callback
  			if (!!sap.ui.Device.browser.internet_explorer) {
  				var fnLoadOrg = fnLoad;
  				fnLoad = function(oEvent) {
  					var aRules;
  					try {
  						// in cross-origin scenarios the IE can still access the rules of the stylesheet
  						// if the stylesheet has been loaded properly
  						aRules = oEvent.target && oEvent.target.sheet && oEvent.target.sheet.rules;
  						// in cross-origin scenarios now the catch block will be executed because we
  						// cannot access the rules of the stylesheet but for non cross-origin stylesheets
  						// we will get an empty rules array and finally we cannot differ between
  						// empty stylesheet or loading issue correctly => documented in JSDoc!
  					} catch (ex) {
  						// exception happens when the stylesheet could not be loaded from the server
  						// we now ignore this and know that the stylesheet doesn't exists => trigger error
  					}
  					// no rules means error
  					if (aRules && aRules.length > 0) {
  						fnLoadOrg();
  					} else {
  						fnError();
  					}
  				};
  			}
  
  			jQuery(oLink).load(fnLoad);
  			jQuery(oLink).error(fnError);
  			return oLink;
  
  		};
  
  		var _appendStyle = function(sUrl, sId, fnLoadCallback, fnErrorCallback){
  
  			if (sap.ui.Device.browser.internet_explorer && sap.ui.Device.browser.version <= 9 && document.styleSheets.length >= 28) {
  				// in IE9 only 30 links are alowed, so use stylesheet object insted
  				var sRootUrl = URI.parse(document.URL).path;
  				var sAbsoluteUrl = new URI(sUrl).absoluteTo(sRootUrl).toString();
  
  				if (sId) {
  					var oIEStyleSheet = mIEStyleSheets[sId];
  					if (oIEStyleSheet && oIEStyleSheet.href === sAbsoluteUrl) {
  						// if stylesheet was already included and href is the same, do nothing
  						return;
  					}
  				}
  
  				jQuery.sap.log.warning("Stylesheet " + (sId ? sId + " " : "") + "not added as LINK because of IE limits", sUrl, "jQuery.sap.includeStyleSheet");
  
  				if (!oIEStyleSheetNode) {
  					// create a style sheet to add additional style sheet. But for this the Replace logic will not work any more
  					// the callback functions are not used in this case
  					// the sap-ui-ready attribute will not be set -> maybe problems with ThemeCheck
  					oIEStyleSheetNode = document.createStyleSheet();
  				}
  				// add up to 30 style sheets to every of this style sheets. (result is a tree of style sheets)
  				var bAdded = false;
  				for ( var i = 0; i < oIEStyleSheetNode.imports.length; i++) {
  					var oStyleSheet = oIEStyleSheetNode.imports[i];
  					if (oStyleSheet.imports.length < 30) {
  						oStyleSheet.addImport(sAbsoluteUrl);
  						bAdded = true;
  						break;
  					}
  				}
  				if (!bAdded) {
  					oIEStyleSheetNode.addImport(sAbsoluteUrl);
  				}
  
  				if (sId) {
  					// remember id and href URL in internal map as there is no link tag that can be checked
  					mIEStyleSheets[sId] = {
  						href: sAbsoluteUrl
  					};
  				}
  
  				// always make sure to re-append the customcss in the end if it exists
  				var oCustomCss = document.getElementById('sap-ui-core-customcss');
  				if (!jQuery.isEmptyObject(oCustomCss)) {
  					appendHead(oCustomCss);
  				}
  			} else {
  				var oLink = _createLink(sUrl, sId, fnLoadCallback, fnErrorCallback);
  				if (jQuery('#sap-ui-core-customcss').length > 0) {
  					jQuery('#sap-ui-core-customcss').first().before(jQuery(oLink));
  				} else {
  					appendHead(oLink);
  				}
  			}
  
  		};
  
  		// check for existence of the link
  		var oOld = jQuery.sap.domById(sId);
  		if (oOld && oOld.tagName === "LINK" && oOld.rel === "stylesheet") {
  			// link exists, so we replace it - but only if a callback has to be attached or if the href will change. Otherwise don't touch it
  			if (fnLoadCallback || fnErrorCallback || oOld.href !== URI(String(sUrl), URI().search("") /* returns current URL without search params */ ).toString()) {
  				jQuery(oOld).replaceWith(_createLink(sUrl, sId, fnLoadCallback, fnErrorCallback));
  			}
  		} else {
  			_appendStyle(sUrl, sId, fnLoadCallback, fnErrorCallback);
  		}
  
  	};
  
  	// TODO should be in core, but then the 'callback' could not be implemented
  	if ( !(oCfgData.productive === true || oCfgData.productive === "true"  || oCfgData.productive === "x") ) {
  		jQuery(function() {
  			jQuery(document.body).keydown(function(e) {
  				if ( e.keyCode == 80 && e.shiftKey && e.altKey && e.ctrlKey ) {
  					try {
  						jQuery.sap.require("sap.ui.debug.TechnicalInfo");
  					} catch (err1) {
  						// alert("Sorry, failed to activate 'P'-mode!");
  						return;
  					}
  					sap.ui.debug.TechnicalInfo.open(function() {
  						var oInfo = getModuleSystemInfo();
  						return { modules : oInfo.modules, prefixes : oInfo.prefixes, config: oCfgData };
  					});
  				}
  			});
  		});
  
  		jQuery(function() {
  			jQuery(document.body).keydown(function(e) {
  				if ( e.keyCode == 83 /*S*/ && e.shiftKey && e.altKey && e.ctrlKey ) { //TODO: Is this ok?
  					try {
  						jQuery.sap.require("sap.ui.core.support.Support");
  						var oSupport = sap.ui.core.support.Support.getStub();
  						if (oSupport.getType() != sap.ui.core.support.Support.StubType.APPLICATION) {
  							return;
  						}
  						oSupport.openSupportTool();
  					} catch (err2) {
  					}
  				}
  			});
  		});
  	}
  
  	// *********** Include E2E-Trace Scripts *************
  	if (/sap-ui-xx-e2e-trace=(true|x|X)/.test(location.search)) {
  		jQuery.sap.require("sap.ui.core.support.trace.E2eTraceLib" + "" /* Make dynamic dependency */);
  	}
  
  	// *********** feature detection, enriching jQuery.support *************
  	// this might go into its own file once there is more stuff added
  
  	/**
  	 * Holds information about the browser's capabilities and quirks.
  	 * This object is provided and documented by jQuery.
  	 * But it is extended by SAPUI5 with detection for features not covered by jQuery. This documentation ONLY covers the detection properties added by UI5.
  	 * For the standard detection properties, please refer to the jQuery documentation.
  	 *
  	 * These properties added by UI5 are only available temporarily until jQuery adds feature detection on their own.
  	 *
  	 * @name jQuery.support
  	 * @namespace
  	 * @since 1.12
  	 * @public
  	 */
  
  	if (!jQuery.support) {
  		jQuery.support = {};
  	}
  
  	jQuery.extend(jQuery.support, {touch: sap.ui.Device.support.touch}); // this is also defined by jquery-mobile-custom.js, but this information is needed earlier
  
  	var aPrefixes = ["Webkit", "ms", "Moz"];
  	var oStyle = document.documentElement.style;
  
  	var preserveOrTestCssPropWithPrefixes = function(detectionName, propName) {
  		if (jQuery.support[detectionName] === undefined) {
  
  			if (oStyle[propName] !== undefined) { // without vendor prefix
  				jQuery.support[detectionName] = true;
  				// If one of the flex layout properties is supported without the prefix, set the flexBoxPrefixed to false
  				if (propName === "boxFlex" || propName === "flexOrder" || propName === "flexGrow") {
  					// Exception for Chrome up to version 28
  					// because some versions implemented the non-prefixed properties without the functionality
  					if (!sap.ui.Device.browser.chrome || sap.ui.Device.browser.version > 28) {
  						jQuery.support.flexBoxPrefixed = false;
  					}
  				}
  				return;
  
  			} else { // try vendor prefixes
  				propName = propName.charAt(0).toUpperCase() + propName.slice(1);
  				for (var i in aPrefixes) {
  					if (oStyle[aPrefixes[i] + propName] !== undefined) {
  						jQuery.support[detectionName] = true;
  						return;
  					}
  				}
  			}
  			jQuery.support[detectionName] = false;
  		}
  	};
  
  	/**
  	 * Whether the current browser supports (2D) CSS transforms
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.cssTransforms
  	 */
  	preserveOrTestCssPropWithPrefixes("cssTransforms", "transform");
  
  	/**
  	 * Whether the current browser supports 3D CSS transforms
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.cssTransforms3d
  	 */
  	preserveOrTestCssPropWithPrefixes("cssTransforms3d", "perspective");
  
  	/**
  	 * Whether the current browser supports CSS transitions
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.cssTransitions
  	 */
  	preserveOrTestCssPropWithPrefixes("cssTransitions", "transition");
  
  	/**
  	 * Whether the current browser supports (named) CSS animations
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.cssAnimations
  	 */
  	preserveOrTestCssPropWithPrefixes("cssAnimations", "animationName");
  
  	/**
  	 * Whether the current browser supports CSS gradients. Note that ANY support for CSS gradients leads to "true" here, no matter what the syntax is.
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.cssGradients
  	 */
  	if (jQuery.support.cssGradients === undefined) {
  		var oElem = document.createElement('div'),
  		oStyle = oElem.style;
  		try {
  			oStyle.backgroundImage = "linear-gradient(left top, red, white)";
  			oStyle.backgroundImage = "-moz-linear-gradient(left top, red, white)";
  			oStyle.backgroundImage = "-webkit-linear-gradient(left top, red, white)";
  			oStyle.backgroundImage = "-ms-linear-gradient(left top, red, white)";
  			oStyle.backgroundImage = "-webkit-gradient(linear, left top, right bottom, from(red), to(white))";
  		} catch (e) {/* no support...*/}
  		jQuery.support.cssGradients = (oStyle.backgroundImage && oStyle.backgroundImage.indexOf("gradient") > -1);
  
  		oElem = null; // free for garbage collection
  	}
  
  	/**
  	 * Whether the current browser supports only prefixed flexible layout properties
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.flexBoxPrefixed
  	 */
  	jQuery.support.flexBoxPrefixed = true;	// Default to prefixed properties
  
  	/**
  	 * Whether the current browser supports the OLD CSS3 Flexible Box Layout directly or via vendor prefixes
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.flexBoxLayout
  	 */
  	preserveOrTestCssPropWithPrefixes("flexBoxLayout", "boxFlex");
  
  	/**
  	 * Whether the current browser supports the IE10 CSS3 Flexible Box Layout directly or via vendor prefixes
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.ie10FlexBoxLayout
  	 * @since 1.12.0
  	 */
  	// Just using one of the IE10 properties that's not in the new FlexBox spec
  	if (oStyle.msFlexOrder !== undefined) {
  		jQuery.support.ie10FlexBoxLayout = true;
  	}
  
  	/**
  	 * Whether the current browser supports the NEW CSS3 Flexible Box Layout directly or via vendor prefixes
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.newFlexBoxLayout
  	 */
  	preserveOrTestCssPropWithPrefixes("newFlexBoxLayout", "flexGrow");	// Use a new property that IE10 doesn't support
  
  	/**
  	 * Whether the current browser supports any kind of Flexible Box Layout directly or via vendor prefixes
  	 * @type {boolean}
  	 * @public
  	 * @name jQuery.support.hasFlexBoxSupport
  	 */
  	if (jQuery.support.flexBoxLayout || jQuery.support.newFlexBoxLayout || jQuery.support.ie10FlexBoxLayout) {
  		jQuery.support.hasFlexBoxSupport = true;
  	} else {
  		jQuery.support.hasFlexBoxSupport = false;
  	}
  
  	// *********** fixes for (pending) jQuery bugs **********
  	if (!jQuery.support.opacity) {
  		(function() {
  			// jQuery cssHook for setOpacity[IE8] doesn't properly cleanup the CSS filter property
  			var oldSet = jQuery.cssHooks.opacity.set;
  			jQuery.cssHooks.opacity.set = function( elem, value ) {
  				oldSet.apply(this, arguments);
  				if ( !jQuery.trim(elem.style.filter) ) {
  					elem.style.removeAttribute("filter");
  				}
  			};
  		}());
  	}
  
  	// *** Performance measure ***
  	function PerfMeasurement(){
  
  		function Measurement( sId, sInfo, iStart, iEnd ){
  			this.id = sId;
  			this.info = sInfo;
  			this.start = iStart;
  			this.end = iEnd;
  			this.pause = 0;
  			this.resume = 0;
  			this.duration = 0; // used time
  			this.time = 0; // time from start to end
  		}
  
  		var bActive = false;
  		var fnAjax = jQuery.ajax;
  
  		/**
  		 * Gets the current state of the perfomance measurement functionality
  		 *
  		 * @return {boolean} current state of the perfomance measurement functionality
  		 * @name jQuery.sap.measure#getActive
  		 * @function
  		 * @public
  		 */
  		this.getActive = function(){
  			return bActive;
  		};
  
  		/**
  		 * Activates or deactivates the performance measure functionality
  		 *
  		 * @param {boolean} bOn state of the perfomance measurement functionality to set
  		 * @return {boolean} current state of the perfomance measurement functionality
  		 * @name jQuery.sap.measure#setActive
  		 * @function
  		 * @public
  		 */
  		this.setActive = function( bOn ){
  
  			if (bActive == bOn) {
  				return bActive;
  			}
  
  			bActive = bOn;
  
  			if (bActive) {
  				// redefine AJAX call
  				jQuery.ajax = function( url, options ){
  					jQuery.sap.measure.start(url.url, "Request for " + url.url);
  					fnAjax.apply(this,arguments);
  					jQuery.sap.measure.end(url.url);
  				};
  			} else if (fnAjax) {
  				jQuery.ajax = fnAjax;
  			}
  
  			return bActive;
  
  		};
  
  		this.setActive(/sap-ui-measure=(true|x|X)/.test(location.search));
  
  		this.mMeasurements = {};
  
  		/**
  		 * Starts a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @param {string} sInfo Info for the measurement
  		 * @return {object} current measurement containing id, info and start-timestamp (false if error)
  		 * @name jQuery.sap.measure#start
  		 * @function
  		 * @public
  		 */
  		this.start = function( sId, sInfo ){
  			if (!bActive) {
  				return;
  			}
  
  			var iTime = new Date().getTime();
  			var oMeasurement = new Measurement( sId, sInfo, iTime, 0);
  //			jQuery.sap.log.info("Performance measurement start: "+ sId + " on "+ iTime);
  
  			if (oMeasurement) {
  				this.mMeasurements[sId] = oMeasurement;
  				return ({id: oMeasurement.id, info: oMeasurement.info, start: oMeasurement.start });
  			} else {
  				return false;
  			}
  		};
  
  		/**
  		 * Pauses a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @return {object} current measurement containing id, info and start-timestamp, pause-timestamp (false if error)
  		 * @name jQuery.sap.measure#pause
  		 * @function
  		 * @public
  		 */
  		this.pause = function( sId ){
  			if (!bActive) {
  				return;
  			}
  
  			var iTime = new Date().getTime();
  			var oMeasurement = this.mMeasurements[sId];
  			if (oMeasurement && oMeasurement.end > 0) {
  				// already ended -> no pause possible
  				return false;
  			}
  
  			if (oMeasurement && oMeasurement.pause == 0) {
  				// not already paused
  				oMeasurement.pause = iTime;
  				if (oMeasurement.pause >= oMeasurement.resume && oMeasurement.resume > 0) {
  					oMeasurement.duration = oMeasurement.duration + oMeasurement.pause - oMeasurement.resume;
  					oMeasurement.resume = 0;
  				} else if (oMeasurement.pause >= oMeasurement.start) {
  					oMeasurement.duration = oMeasurement.pause - oMeasurement.start;
  				}
  			}
  //			jQuery.sap.log.info("Performance measurement pause: "+ sId + " on "+ iTime + " duration: "+ oMeasurement.duration);
  
  			if (oMeasurement) {
  				return ({id: oMeasurement.id, info: oMeasurement.info, start: oMeasurement.start, pause: oMeasurement.pause });
  			} else {
  				return false;
  			}
  		};
  
  		/**
  		 * Resumes a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @return {object} current measurement containing id, info and start-timestamp, resume-timestamp (false if error)
  		 * @name jQuery.sap.measure#resume
  		 * @function
  		 * @public
  		 */
  		this.resume = function( sId ){
  			if (!bActive) {
  				return;
  			}
  
  			var iTime = new Date().getTime();
  			var oMeasurement = this.mMeasurements[sId];
  //			jQuery.sap.log.info("Performance measurement resume: "+ sId + " on "+ iTime + " duration: "+ oMeasurement.duration);
  
  			if (oMeasurement && oMeasurement.pause > 0) {
  				// already paused
  				oMeasurement.pause = 0;
  				oMeasurement.resume = iTime;
  			}
  
  			if (oMeasurement) {
  				return ({id: oMeasurement.id, info: oMeasurement.info, start: oMeasurement.start, resume: oMeasurement.resume });
  			} else {
  				return false;
  			}
  		};
  
  		/**
  		 * Ends a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @return {object} current measurement containing id, info and start-timestamp, end-timestamp, time, duration (false if error)
  		 * @name jQuery.sap.measure#end
  		 * @function
  		 * @public
  		 */
  		this.end = function( sId ){
  			if (!bActive) {
  				return;
  			}
  
  			var iTime = new Date().getTime();
  			var oMeasurement = this.mMeasurements[sId];
  //			jQuery.sap.log.info("Performance measurement end: "+ sId + " on "+ iTime);
  
  			if (oMeasurement && !oMeasurement.end) {
  				oMeasurement.end = iTime;
  				if (oMeasurement.end >= oMeasurement.resume && oMeasurement.resume > 0) {
  					oMeasurement.duration = oMeasurement.duration + oMeasurement.end - oMeasurement.resume;
  					oMeasurement.resume = 0;
  				} else if (oMeasurement.pause > 0) {
  					// duration already calculated
  					oMeasurement.pause = 0;
  				} else if (oMeasurement.end >= oMeasurement.start) {
  					oMeasurement.duration = oMeasurement.end - oMeasurement.start;
  				}
  				if (oMeasurement.end >= oMeasurement.start) {
  					oMeasurement.time = oMeasurement.end - oMeasurement.start;
  				}
  			}
  
  			if (oMeasurement) {
  				return ({id: oMeasurement.id,
  						info: oMeasurement.info,
  						start: oMeasurement.start,
  						end: oMeasurement.end,
  						time: oMeasurement.time,
  						duration: oMeasurement.duration});
  			} else {
  				return false;
  			}
  		};
  
  		/**
  		 * Gets a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @return {object} current measurement containing id, info and start-timestamp, end-timestamp, time, duration (false if error)
  		 * @name jQuery.sap.measure#getMeasurement
  		 * @function
  		 * @public
  		 */
  		this.getMeasurement = function( sId ){
  			if (!bActive) {
  				return;
  			}
  
  			var oMeasurement = this.mMeasurements[sId];
  
  			if (oMeasurement) {
  				return ({id: oMeasurement.id,
  						info: oMeasurement.info,
  						start: oMeasurement.start,
  						end: oMeasurement.end,
  						time: oMeasurement.time,
  						duration: oMeasurement.duration});
  			} else {
  				return false;
  			}
  		};
  
  		/**
  		 * Clears all performance measurements
  		 *
  		 * @name jQuery.sap.measure#clear
  		 * @function
  		 * @public
  		 */
  		this.clear = function( ){
  			if (!bActive) {
  				return;
  			}
  
  			this.mMeasurements = {};
  		};
  
  		/**
  		 * Removes a performance measure
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @name jQuery.sap.measure#remove
  		 * @function
  		 * @public
  		 */
  		this.remove = function( sId ){
  			if (!bActive) {
  				return;
  			}
  
  			delete this.mMeasurements[sId];
  		};
  
  		/**
  		 * Gets all performance measurements
  		 *
  		 * @return {object} [] current measurement containing id, info and start-timestamp, end-timestamp, time, duration (false if error)
  		 * @name jQuery.sap.measure#getAllMeasurements
  		 * @function
  		 * @public
  		 */
  		this.getAllMeasurements = function( ){
  			if (!bActive) {
  				return;
  			}
  
  			var aMeasurements = [];
  
  			jQuery.each(this.mMeasurements, function(sId, oMeasurement){
  				aMeasurements.push({id: oMeasurement.id,
  									info: oMeasurement.info,
  									start: oMeasurement.start,
  									end: oMeasurement.end,
  									duration: oMeasurement.duration,
  									time: oMeasurement.time});
  			});
  			return aMeasurements;
  		};
  
  		/**
  		 * Adds a performance measurement with all data
  		 * This is usefull to add external measurements (e.g. from a backend) to the common measurement UI
  		 *
  		 * @param {string} sId ID of the measurement
  		 * @param {string} sInfo Info for the measurement
  		 * @param {int} iStart start timestamp
  		 * @param {int} iEnd end timestamp
  		 * @param {int} iTime time in milliseconds
  		 * @param {int} iDuration effective time in milliseconds
  		 * @return {object} [] current measurement containing id, info and start-timestamp, end-timestamp, time, duration (false if error)
  		 * @name jQuery.sap.measure#add
  		 * @function
  		 * @public
  		 */
  		this.add = function( sId, sInfo, iStart, iEnd, iTime, iDuration ){
  			if (!bActive) {
  				return;
  			}
  
  			var oMeasurement = new Measurement( sId, sInfo, iStart, iEnd);
  			oMeasurement.time = iTime;
  			oMeasurement.duration = iDuration;
  
  			if (oMeasurement) {
  				this.mMeasurements[sId] = oMeasurement;
  				return ({id: oMeasurement.id,
  						info: oMeasurement.info,
  						start: oMeasurement.start,
  						end: oMeasurement.end,
  						time: oMeasurement.time,
  						duration: oMeasurement.duration});
  			} else {
  				return false;
  			}
  		};
  	}
  
  	/**
  	 * Namespace for the jQuery performance measurement plug-in provided by SAP SE.
  	 *
  	 * @namespace
  	 * @name jQuery.sap.measure
  	 * @public
  	 * @static
  	 */
  	jQuery.sap.measure = new PerfMeasurement();
  
  	/**
  	 * FrameOptions class
  	 */
  	var FrameOptions = function(mSettings) {
  		/* mSettings: mode, callback, whitelist, whitelistService, timeout, blockEvents, showBlockLayer, allowSameOrigin */
  		this.mSettings = mSettings || {};
  		this.sMode = this.mSettings.mode || FrameOptions.Mode.ALLOW;
  		this.fnCallback = this.mSettings.callback;
  		this.iTimeout = this.mSettings.timeout || 10000;
  		this.bBlockEvents = this.mSettings.blockEvents !== false;
  		this.bShowBlockLayer = this.mSettings.showBlockLayer !== false;
  		this.bAllowSameOrigin = this.mSettings.allowSameOrigin !== false;
  		this.sParentOrigin = '';
  		this.bUnlocked = false;
  		this.bRunnable = false;
  		this.bParentUnlocked = false;
  		this.sStatus = "pending";
  		this.aFPChilds = [];
  
  		var that = this;
  
  		this.iTimer = setTimeout(function() {
  			that._callback(false);
  		}, this.iTimeout);
  
  		var fnHandlePostMessage = function() {
  			that._handlePostMessage.apply(that, arguments);
  		};
  
  		FrameOptions.__window.addEventListener('message', fnHandlePostMessage);
  
  		if (FrameOptions.__parent === FrameOptions.__self || FrameOptions.__parent == null || this.sMode === FrameOptions.Mode.ALLOW) {
  			// unframed page or "allow all" mode
  			this._applyState(true, true);
  		} else {
  			// framed page
  
  			this._lock();
  
  			// "deny" mode blocks embedding page from all origins
  			if (this.sMode === FrameOptions.Mode.DENY) {
  				this._callback(false);
  				return;
  			}
  
  			if (this.bAllowSameOrigin) {
  
  				try {
  					var oParentWindow = FrameOptions.__parent;
  					var bOk = false;
  					var bTrue = true;
  					do {
  						var test = oParentWindow.document.domain;
  						if (oParentWindow == FrameOptions.__top) {
  							if (test != undefined) {
  								bOk = true;
  							}
  							break;
  						}
  						oParentWindow = oParentWindow.parent;
  					} while (bTrue);
  					if (bOk) {
  						this._applyState(true, true);
  					}
  				} catch(e) {
  					// access to the top window is not possible
  					FrameOptions.__parent.postMessage('SAPFrameProtection*require-origin', '*');
  				}
  
  			} else {
  				// same origin not allowed
  				FrameOptions.__parent.postMessage('SAPFrameProtection*require-origin', '*');
  			}
  
  		}
  
  	};
  
  	FrameOptions.Mode = {
  		// only allow with same origin parent
  		TRUSTED: 'trusted',
  
  		// allow all kind of embedding (default)
  		ALLOW: 'allow',
  
  		// deny all kinds of embedding
  		DENY: 'deny'
  	};
  
  	// Allow globals to be mocked in unit test
  	FrameOptions.__window = window;
  	FrameOptions.__parent = parent;
  	FrameOptions.__self = self;
  	FrameOptions.__top = top;
  
  	// List of events to block while framing is unconfirmed
  	FrameOptions._events = [
  		"mousedown", "mouseup", "click", "dblclick", "mouseover", "mouseout",
  		"touchstart", "touchend", "touchmove", "touchcancel",
  		"keydown", "keypress", "keyup"
  	];
  
  	// check if string matches pattern
  	FrameOptions.prototype.match = function(sProbe, sPattern) {
  		if (!(/\*/i.test(sPattern))) {
  			return sProbe == sPattern;
  		} else {
  			sPattern = sPattern.replace(/\//gi, "\\/"); // replace /   with \/
  			sPattern = sPattern.replace(/\./gi, "\\."); // replace .   with \.
  			sPattern = sPattern.replace(/\*/gi, ".*");  // replace *   with .*
  			sPattern = sPattern.replace(/:\.\*$/gi, ":\\d*"); // replace :.* with :\d* (only at the end)
  
  			if (sPattern.substr(sPattern.length - 1, 1) !== '$') {
  				sPattern = sPattern + '$'; // if not already there add $ at the end
  			}
  			if (sPattern.substr(0, 1) !== '^') {
  				sPattern = '^' + sPattern; // if not already there add ^ at the beginning
  			}
  
  			// sPattern looks like: ^.*:\/\/.*\.company\.corp:\d*$ or ^.*\.company\.corp$
  			var r = new RegExp(sPattern, 'i');
  			return r.test(sProbe);
  		}
  	};
  
  	FrameOptions._lockHandler = function(oEvent) {
  		oEvent.stopPropagation();
  		oEvent.preventDefault();
  	};
  
  	FrameOptions.prototype._createBlockLayer = function() {
  		if (document.readyState == "complete") {
  			var lockDiv = document.createElement("div");
  			lockDiv.style.position = "absolute";
  			lockDiv.style.top = "0px";
  			lockDiv.style.bottom = "0px";
  			lockDiv.style.left = "0px";
  			lockDiv.style.right = "0px";
  			lockDiv.style.opacity = "0";
  			lockDiv.style.backgroundColor = "white";
  			lockDiv.style.zIndex = 2147483647; // Max value of signed integer (32bit)
  			document.body.appendChild(lockDiv);
  			this._lockDiv = lockDiv;
  		}
  	};
  
  	FrameOptions.prototype._setCursor = function() {
  		if (this._lockDiv) {
  			this._lockDiv.style.cursor = this.sStatus == "denied" ? "not-allowed" : "wait";
  		}
  	};
  
  	FrameOptions.prototype._lock = function() {
  		var that = this;
  		if (this.bBlockEvents) {
  			for (var i = 0; i < FrameOptions._events.length; i++) {
  				document.addEventListener(FrameOptions._events[i], FrameOptions._lockHandler, true);
  			}
  		}
  		if (this.bShowBlockLayer) {
  			this._blockLayer = function() {
  				that._createBlockLayer();
  				that._setCursor();
  			};
  			if (document.readyState == "complete") {
  				this._blockLayer();
  			} else {
  				document.addEventListener("readystatechange", this._blockLayer);
  			}
  		}
  	};
  
  	FrameOptions.prototype._unlock = function() {
  		if (this.bBlockEvents) {
  			for (var i = 0; i < FrameOptions._events.length; i++) {
  				document.removeEventListener(FrameOptions._events[i], FrameOptions._lockHandler, true);
  			}
  		}
  		if (this.bShowBlockLayer) {
  			document.removeEventListener("readystatechange", this._blockLayer);
  			if (this._lockDiv) {
  				document.body.removeChild(this._lockDiv);
  				delete this._lockDiv;
  			}
  		}
  	};
  
  	FrameOptions.prototype._callback = function(bSuccess) {
  		this.sStatus = bSuccess ? "allowed" : "denied";
  		this._setCursor();
  		clearTimeout(this.iTimer);
  		if (typeof this.fnCallback === 'function') {
  			this.fnCallback.call(null, bSuccess);
  		}
  	};
  
  	FrameOptions.prototype._applyState = function(bIsRunnable, bIsParentUnlocked) {
  		if (bIsRunnable) {
  			this.bRunnable = true;
  		}
  		if (bIsParentUnlocked) {
  			this.bParentUnlocked = true;
  		}
  		if (!this.bRunnable || !this.bParentUnlocked) {
  			return;
  		}
  		this._unlock();
  		this._callback(true);
  		this._notifyChildFrames();
  		this.bUnlocked = true;
  	};
  
  	FrameOptions.prototype._applyTrusted = function(bTrusted) {
  		if (bTrusted) {
  			this._applyState(true, false);
  		} else {
  			this._callback(false);
  		}
  	};
  
  	FrameOptions.prototype._check = function() {
  		if (this.bRunnable) {
  			return;
  		}
  		var bTrusted = false;
  		if (this.bAllowSameOrigin && FrameOptions.__window.document.URL.indexOf(this.sParentOrigin) == 0) {
  			bTrusted = true;
  		} else if (this.mSettings.whitelist && this.mSettings.whitelist.length != 0) {
  			var sHostName = this.sParentOrigin.split('//')[1];
  			sHostName = sHostName.split(':')[0];
  			for (var i = 0; i < this.mSettings.whitelist.length; i++) {
  				var match = sHostName.indexOf(this.mSettings.whitelist[i]);
  				if (match != -1 && sHostName.substring(match) == this.mSettings.whitelist[i]) {
  					bTrusted = true;
  					break;
  				}
  			}
  		}
  		if (bTrusted) {
  			this._applyTrusted(bTrusted);
  		} else if (this.mSettings.whitelistService) {
  			var that = this;
  			var xmlhttp = new XMLHttpRequest();
  			var url = this.mSettings.whitelistService + '?parentOrigin=' + encodeURIComponent(this.sParentOrigin);
  			xmlhttp.onreadystatechange = function() {
  				if (xmlhttp.readyState == 4) {
  					that._handleXmlHttpResponse(xmlhttp);
  				}
  			};
  			xmlhttp.open('GET', url, true);
  			xmlhttp.setRequestHeader('Accept', 'application/json');
  			xmlhttp.send();
  		} else {
  			this._callback(false);
  		}
  	};
  
  	FrameOptions.prototype._handleXmlHttpResponse = function(xmlhttp) {
  		if (xmlhttp.status === 200) {
  			var bTrusted = false;
  			var sResponseText = xmlhttp.responseText;
  			var oRuleSet = JSON.parse(sResponseText);
  			if (oRuleSet.active == false) {
  				bTrusted = true;
  			} else if (this.match(this.sParentOrigin, oRuleSet.origin)) {
  				bTrusted = oRuleSet.framing;
  			}
  			this._applyTrusted(bTrusted);
  		} else {
  			this._callback(false);
  		}
  	};
  
  	FrameOptions.prototype._notifyChildFrames = function() {
  		for (var i = 0; i < this.aFPChilds.length; i++) {
  			this.aFPChilds[i].postMessage('SAPFrameProtection*parent-unlocked','*');
  		}
  	};
  
  	FrameOptions.prototype._handlePostMessage = function(oEvent) {
  		var oSource = oEvent.source,
  			sData = oEvent.data;
  
  		// For compatibility with previous version empty message from parent means parent-unlocked
  		// if (oSource === FrameOptions.__parent && sData == "") {
  		//	sData = "SAPFrameProtection*parent-unlocked";
  		// }
  
  		if (oSource === FrameOptions.__self || oSource == null ||
  			typeof sData !== "string" || sData.indexOf("SAPFrameProtection*") === -1) {
  			return;
  		}
  		if (oSource === FrameOptions.__parent) {
  			if (!this.sParentOrigin) {
  				this.sParentOrigin = oEvent.origin;
  				this._check();
  			}
  			if (sData == "SAPFrameProtection*parent-unlocked") {
  				this._applyState(false, true);
  			}
  		} else if (oSource.parent === FrameOptions.__self && sData == "SAPFrameProtection*require-origin" && this.bUnlocked) {
  			oSource.postMessage("SAPFrameProtection*parent-unlocked", "*");
  		} else {
  			oSource.postMessage("SAPFrameProtection*parent-origin", "*");
  			this.aFPChilds.push(oSource);
  		}
  	};
  
  	jQuery.sap.FrameOptions = FrameOptions;
  
  }());
  
  /**
   * Executes an 'eval' for its arguments in the global context (without closure variables).
   *
   * This is a synchronous replacement for <code>jQuery.globalEval</code> which in some
   * browsers (e.g. FireFox) behaves asynchronously.
   *
   * @type void
   * @public
   * @static
   * @SecSink {0|XSS} Parameter is evaluated
   */
  jQuery.sap.globalEval = function() {
  	/*eslint-disable no-eval */
  	eval(arguments[0]);
  	/*eslint-enable no-eval */
  };
  jQuery.sap.declare('sap-ui-core-lean');
  jQuery.sap.declare('sap.ui.thirdparty.jquery.jquery-1.11.1', false);
  jQuery.sap.declare('sap.ui.Device', false);
  jQuery.sap.declare('sap.ui.thirdparty.URI', false);
  jQuery.sap.declare('sap.ui.thirdparty.jqueryui.jquery-ui-position', false);
  jQuery.sap.declare('jquery.sap.promise', false);
  jQuery.sap.declare('jquery.sap.global', false);
  jQuery.sap.require("sap.ui.core.Core");
  // as this module contains the Core, we ensure that the Core has been booted
  sap.ui.getCore().boot && sap.ui.getCore().boot();
  