/*!
 * jQuery JavaScript Library v1.11.2
 * 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-12-17T15:27Z
 */

(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.2",

	// 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
		// adding 1 corrects loss of precision from parseFloat (#15100)
		return !jQuery.isArray( obj ) && (obj - parseFloat( obj ) + 1) >= 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 v2.2.0-pre
 * http://sizzlejs.com/
 *
 * Copyright 2008, 2014 jQuery Foundation, Inc. and other contributors
 * Released under the MIT license
 * http://jquery.org/license
 *
 * Date: 2014-12-16
 */
(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" + 1 * 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
	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 as it's faster than native
	// http://jsperf.com/thor-indexof-vs-for/5
	indexOf = function( list, elem ) {
		var i = 0,
			len = list.length;
		for ( ; i < len; i++ ) {
			if ( list[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
	rwhitespace = new RegExp( whitespace + "+", "g" ),
	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 );
	},

	// Used for iframes
	// See setDocument()
	// Removing the function wrapper causes a "Permission Denied"
	// error in IE
	unloadHandler = function() {
		setDocument();
	};

// 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 || [];
	nodeType = context.nodeType;

	if ( typeof selector !== "string" || !selector ||
		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {

		return results;
	}

	if ( !seed && documentIsHTML ) {

		// Try to shortcut find operations when possible (e.g., not under DocumentFragment)
		if ( nodeType !== 11 && (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 ) {
				push.apply( results, context.getElementsByClassName( m ) );
				return results;
			}
		}

		// QSA path
		if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
			nid = old = expando;
			newContext = context;
			newSelector = nodeType !== 1 && 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 !== "undefined" && 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, parent,
		doc = node ? node.ownerDocument || node : preferredDoc;

	// 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;
	parent = doc.defaultView;

	// 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", unloadHandler, false );
		} else if ( parent.attachEvent ) {
			parent.attachEvent( "onunload", unloadHandler );
		}
	}

	/* Support tests
	---------------------------------------------------------------------- */
	documentIsHTML = !isXML( doc );

	/* 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;
	});

	// Support: IE<9
	support.getElementsByClassName = rnative.test( doc.getElementsByClassName );

	// 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 !== "undefined" && 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 !== "undefined" && elem.getAttributeNode("id");
				return node && node.value === attrId;
			};
		};
	}

	// Tag
	Expr.find["TAG"] = support.getElementsByTagName ?
		function( tag, context ) {
			if ( typeof context.getElementsByTagName !== "undefined" ) {
				return context.getElementsByTagName( tag );

			// DocumentFragment nodes don't have gEBTN
			} else if ( support.qsa ) {
				return context.querySelectorAll( tag );
			}
		} :

		function( tag, context ) {
			var elem,
				tmp = [],
				i = 0,
				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
				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 ( 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
			docElem.appendChild( div ).innerHTML = "<a id='" + expando + "'></a>" +
				"<select id='" + expando + "-\f]' msallowcapture=''>" +
				"<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("[msallowcapture^='']").length ) {
				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
			}

			// Support: IE8
			// Boolean attributes and "value" are not treated correctly
			if ( !div.querySelectorAll("[selected]").length ) {
				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
			}

			// Support: Chrome<29, Android<4.2+, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.7+
			if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
				rbuggyQSA.push("~=");
			}

			// 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");
			}

			// Support: Safari 8+, iOS 8+
			// https://bugs.webkit.org/show_bug.cgi?id=136851
			// In-page `selector#id sibing-combinator selector` fails
			if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) {
				rbuggyQSA.push(".#.+[+~]");
			}
		});

		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( sortInput, a ) - indexOf( 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( sortInput, a ) - indexOf( 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 !== "undefined" && 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.replace( rwhitespace, " " ) + " " ).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( 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 );
					// Don't keep the element (issue #299)
					input[0] = null;
					return !results.pop();
				};
		}),

		"has": markFunction(function( selector ) {
			return function( elem ) {
				return Sizzle( selector, elem ).length > 0;
			};
		}),

		"contains": markFunction(function( text ) {
			text = text.replace( runescape, funescape );
			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( 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( checkContext, elem ) > -1;
		}, implicitRelative, true ),
		matchers = [ function( elem, context, xml ) {
			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
				(checkContext = context).nodeType ?
					matchContext( elem, context, xml ) :
					matchAnyContext( elem, context, xml ) );
			// Avoid hanging onto element (issue #299)
			checkContext = null;
			return ret;
		} ];

	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-35+
// 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+;/,
	rnoInnerhtml = /<(?:script|style|link)/i,
    // 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 ) {
		// Support: IE<=11+, Firefox<=30+ (#15098, #14150)
		// IE throws on elements created in popups
		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
		if ( elem.ownerDocument.defaultView.opener ) {
			return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
		}

		return window.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 );

			div.removeChild( contents );
		}

		// 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
		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
		fireGlobals = jQuery.event && 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
		});
	};
});


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)
// See https://support.microsoft.com/kb/2856746 for more info
if ( window.attachEvent ) {
	window.attachEvent( "onunload", 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;
};




// 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.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;

}));

/*!
* jQuery Migrate - v1.2.1 - 2013-05-08
* https://github.com/jquery/jquery-migrate
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
*/
(function (jQuery, window, undefined) {
    // See http://bugs.jquery.com/ticket/13335
    // "use strict";


    var warnedAbout = {};

    // List of warnings already given; public read only
    jQuery.migrateWarnings = [];

    // Set to true to prevent console output; migrateWarnings still maintained
    // jQuery.migrateMute = false;

    // Show a message on the console so devs know we're active
    if (!jQuery.migrateMute && window.console && window.console.log) {
        window.console.log("JQMIGRATE: Logging is active");
    }

    // Set to false to disable traces that appear with warnings
    if (jQuery.migrateTrace === undefined) {
        jQuery.migrateTrace = true;
    }

    // Forget any warnings we've already given; public
    jQuery.migrateReset = function () {
        warnedAbout = {};
        jQuery.migrateWarnings.length = 0;
    };

    function migrateWarn(msg) {
        var console = window.console;
        if (!warnedAbout[msg]) {
            warnedAbout[msg] = true;
            jQuery.migrateWarnings.push(msg);
            if (console && console.warn && !jQuery.migrateMute) {
                console.warn("JQMIGRATE: " + msg);
                if (jQuery.migrateTrace && console.trace) {
                    console.trace();
                }
            }
        }
    }

    function migrateWarnProp(obj, prop, value, msg) {
        if (Object.defineProperty) {
            // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
            // allow property to be overwritten in case some other plugin wants it
            try {
                Object.defineProperty(obj, prop, {
                    configurable: true,
                    enumerable: true,
                    get: function () {
                        migrateWarn(msg);
                        return value;
                    },
                    set: function (newValue) {
                        migrateWarn(msg);
                        value = newValue;
                    }
                });
                return;
            } catch (err) {
                // IE8 is a dope about Object.defineProperty, can't warn there
            }
        }

        // Non-ES5 (or broken) browser; just set the property
        jQuery._definePropertyBroken = true;
        obj[prop] = value;
    }

    if (document.compatMode === "BackCompat") {
        // jQuery has never supported or tested Quirks Mode
        migrateWarn("jQuery is not compatible with Quirks Mode");
    }


    var attrFn = jQuery("<input/>", { size: 1 }).attr("size") && jQuery.attrFn,
	oldAttr = jQuery.attr,
	valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
		function () { return null; },
	valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
		function () { return undefined; },
	rnoType = /^(?:input|button)$/i,
	rnoAttrNodeType = /^[238]$/,
	rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
	ruseDefault = /^(?:checked|selected)$/i;

    // jQuery.attrFn
    migrateWarnProp(jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated");

    jQuery.attr = function (elem, name, value, pass) {
        var lowerName = name.toLowerCase(),
		nType = elem && elem.nodeType;

        if (pass) {
            // Since pass is used internally, we only warn for new jQuery
            // versions where there isn't a pass arg in the formal params
            if (oldAttr.length < 4) {
                migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
            }
            if (elem && !rnoAttrNodeType.test(nType) &&
			(attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name]))) {
                return jQuery(elem)[name](value);
            }
        }

        // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
        // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
        if (name === "type" && value !== undefined && rnoType.test(elem.nodeName) && elem.parentNode) {
            migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
        }

        // Restore boolHook for boolean property/attribute synchronization
        if (!jQuery.attrHooks[lowerName] && rboolean.test(lowerName)) {
            jQuery.attrHooks[lowerName] = {
                get: function (elem, name) {
                    // Align boolean attributes with corresponding properties
                    // Fall back to attribute presence where some booleans are not supported
                    var attrNode,
					property = jQuery.prop(elem, name);
                    return property === true || typeof property !== "boolean" &&
					(attrNode = elem.getAttributeNode(name)) && attrNode.nodeValue !== false ?

					name.toLowerCase() :
					undefined;
                },
                set: function (elem, value, name) {
                    var propName;
                    if (value === false) {
                        // Remove boolean attributes when set to false
                        jQuery.removeAttr(elem, name);
                    } else {
                        // value is true since we know at this point it's type boolean and not false
                        // Set boolean attributes to the same name and set the DOM property
                        propName = jQuery.propFix[name] || name;
                        if (propName in elem) {
                            // Only set the IDL specifically if it already exists on the element
                            elem[propName] = true;
                        }

                        elem.setAttribute(name, name.toLowerCase());
                    }
                    return name;
                }
            };

            // Warn only for attributes that can remain distinct from their properties post-1.9
            if (ruseDefault.test(lowerName)) {
                migrateWarn("jQuery.fn.attr('" + lowerName + "') may use property instead of attribute");
            }
        }

        return oldAttr.call(jQuery, elem, name, value);
    };

    // attrHooks: value
    jQuery.attrHooks.value = {
        get: function (elem, name) {
            var nodeName = (elem.nodeName || "").toLowerCase();
            if (nodeName === "button") {
                return valueAttrGet.apply(this, arguments);
            }
            if (nodeName !== "input" && nodeName !== "option") {
                migrateWarn("jQuery.fn.attr('value') no longer gets properties");
            }
            return name in elem ?
			elem.value :
			null;
        },
        set: function (elem, value) {
            var nodeName = (elem.nodeName || "").toLowerCase();
            if (nodeName === "button") {
                return valueAttrSet.apply(this, arguments);
            }
            if (nodeName !== "input" && nodeName !== "option") {
                migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
            }
            // Does not return so that setAttribute is also used
            elem.value = value;
        }
    };


    var matched, browser,
	oldInit = jQuery.fn.init,
	oldParseJSON = jQuery.parseJSON,
    // Note: XSS check is done below after string is trimmed
	rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;

    // $(html) "looks like html" rule change
    jQuery.fn.init = function (selector, context, rootjQuery) {
        var match;

        if (selector && typeof selector === "string" && !jQuery.isPlainObject(context) &&
			(match = rquickExpr.exec(jQuery.trim(selector))) && match[0]) {
            // This is an HTML string according to the "old" rules; is it still?
            if (selector.charAt(0) !== "<") {
                migrateWarn("$(html) HTML strings must start with '<' character");
            }
            if (match[3]) {
                migrateWarn("$(html) HTML text after last tag is ignored");
            }
            // Consistently reject any HTML-like string starting with a hash (#9521)
            // Note that this may break jQuery 1.6.x code that otherwise would work.
            if (match[0].charAt(0) === "#") {
                migrateWarn("HTML string cannot start with a '#' character");
                jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
            }
            // Now process using loose rules; let pre-1.8 play too
            if (context && context.context) {
                // jQuery object as context; parseHTML expects a DOM object
                context = context.context;
            }
            if (jQuery.parseHTML) {
                return oldInit.call(this, jQuery.parseHTML(match[2], context, true),
					context, rootjQuery);
            }
        }
        return oldInit.apply(this, arguments);
    };
    jQuery.fn.init.prototype = jQuery.fn;

    // Let $.parseJSON(falsy_value) return null
    jQuery.parseJSON = function (json) {
        if (!json && json !== null) {
            migrateWarn("jQuery.parseJSON requires a valid JSON string");
            return null;
        }
        return oldParseJSON.apply(this, arguments);
    };

    jQuery.uaMatch = function (ua) {
        ua = ua.toLowerCase();

        var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
		/(webkit)[ \/]([\w.]+)/.exec(ua) ||
		/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
		/(msie) ([\w.]+)/.exec(ua) ||
		ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
		[];

        return {
            browser: match[1] || "",
            version: match[2] || "0"
        };
    };

    // Don't clobber any existing jQuery.browser in case it's different
    if (!jQuery.browser) {
        matched = jQuery.uaMatch(navigator.userAgent);
        browser = {};

        if (matched.browser) {
            browser[matched.browser] = true;
            browser.version = matched.version;
        }

        // Chrome is Webkit, but Webkit is also Safari.
        if (browser.chrome) {
            browser.webkit = true;
        } else if (browser.webkit) {
            browser.safari = true;
        }

        jQuery.browser = browser;
    }

    // Warn if the code tries to get jQuery.browser
    migrateWarnProp(jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated");

    jQuery.sub = function () {
        function jQuerySub(selector, context) {
            return new jQuerySub.fn.init(selector, context);
        }
        jQuery.extend(true, jQuerySub, this);
        jQuerySub.superclass = this;
        jQuerySub.fn = jQuerySub.prototype = this();
        jQuerySub.fn.constructor = jQuerySub;
        jQuerySub.sub = this.sub;
        jQuerySub.fn.init = function init(selector, context) {
            if (context && context instanceof jQuery && !(context instanceof jQuerySub)) {
                context = jQuerySub(context);
            }

            return jQuery.fn.init.call(this, selector, context, rootjQuerySub);
        };
        jQuerySub.fn.init.prototype = jQuerySub.fn;
        var rootjQuerySub = jQuerySub(document);
        migrateWarn("jQuery.sub() is deprecated");
        return jQuerySub;
    };


    // Ensure that $.ajax gets the new parseJSON defined in core.js
    jQuery.ajaxSetup({
        converters: {
            "text json": jQuery.parseJSON
        }
    });


    var oldFnData = jQuery.fn.data;

    jQuery.fn.data = function (name) {
        var ret, evt,
		elem = this[0];

        // Handles 1.7 which has this behavior and 1.8 which doesn't
        if (elem && name === "events" && arguments.length === 1) {
            ret = jQuery.data(elem, name);
            evt = jQuery._data(elem, name);
            if ((ret === undefined || ret === evt) && evt !== undefined) {
                migrateWarn("Use of jQuery.fn.data('events') is deprecated");
                return evt;
            }
        }
        return oldFnData.apply(this, arguments);
    };


    var rscriptType = /\/(java|ecma)script/i,
	oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;

    jQuery.fn.andSelf = function () {
        migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
        return oldSelf.apply(this, arguments);
    };

    // Since jQuery.clean is used internally on older versions, we only shim if it's missing
    if (!jQuery.clean) {
        jQuery.clean = function (elems, context, fragment, scripts) {
            // Set context per 1.8 logic
            context = context || document;
            context = !context.nodeType && context[0] || context;
            context = context.ownerDocument || context;

            migrateWarn("jQuery.clean() is deprecated");

            var i, elem, handleScript, jsTags,
			ret = [];

            jQuery.merge(ret, jQuery.buildFragment(elems, context).childNodes);

            // Complex logic lifted directly from jQuery 1.8
            if (fragment) {
                // Special handling of each script element
                handleScript = function (elem) {
                    // Check if we consider it executable
                    if (!elem.type || rscriptType.test(elem.type)) {
                        // Detach the script and store it in the scripts array (if provided) or the fragment
                        // Return truthy to indicate that it has been handled
                        return scripts ?
						scripts.push(elem.parentNode ? elem.parentNode.removeChild(elem) : elem) :
						fragment.appendChild(elem);
                    }
                };

                for (i = 0; (elem = ret[i]) != null; i++) {
                    // Check if we're done after handling an executable script
                    if (!(jQuery.nodeName(elem, "script") && handleScript(elem))) {
                        // Append to fragment and handle embedded scripts
                        fragment.appendChild(elem);
                        if (typeof elem.getElementsByTagName !== "undefined") {
                            // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
                            jsTags = jQuery.grep(jQuery.merge([], elem.getElementsByTagName("script")), handleScript);

                            // Splice the scripts into ret after their former ancestor and advance our index beyond them
                            ret.splice.apply(ret, [i + 1, 0].concat(jsTags));
                            i += jsTags.length;
                        }
                    }
                }
            }

            return ret;
        };
    }

    var eventAdd = jQuery.event.add,
	eventRemove = jQuery.event.remove,
	eventTrigger = jQuery.event.trigger,
	oldToggle = jQuery.fn.toggle,
	oldLive = jQuery.fn.live,
	oldDie = jQuery.fn.die,
	ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
	rajaxEvent = new RegExp("\\b(?:" + ajaxEvents + ")\\b"),
	rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
	hoverHack = function (events) {
	    if (typeof (events) !== "string" || jQuery.event.special.hover) {
	        return events;
	    }
	    if (rhoverHack.test(events)) {
	        migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
	    }
	    return events && events.replace(rhoverHack, "mouseenter$1 mouseleave$1");
	};

    // Event props removed in 1.9, put them back if needed; no practical way to warn them
    if (jQuery.event.props && jQuery.event.props[0] !== "attrChange") {
        jQuery.event.props.unshift("attrChange", "attrName", "relatedNode", "srcElement");
    }

    // Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
    if (jQuery.event.dispatch) {
        migrateWarnProp(jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated");
    }

    // Support for 'hover' pseudo-event and ajax event warnings
    jQuery.event.add = function (elem, types, handler, data, selector) {
        if (elem !== document && rajaxEvent.test(types)) {
            migrateWarn("AJAX events should be attached to document: " + types);
        }
        eventAdd.call(this, elem, hoverHack(types || ""), handler, data, selector);
    };
    jQuery.event.remove = function (elem, types, handler, selector, mappedTypes) {
        eventRemove.call(this, elem, hoverHack(types) || "", handler, selector, mappedTypes);
    };

    jQuery.fn.error = function () {
        var args = Array.prototype.slice.call(arguments, 0);
        migrateWarn("jQuery.fn.error() is deprecated");
        args.splice(0, 0, "error");
        if (arguments.length) {
            return this.bind.apply(this, args);
        }
        // error event should not bubble to window, although it does pre-1.7
        this.triggerHandler.apply(this, args);
        return this;
    };

    jQuery.fn.toggle = function (fn, fn2) {

        // Don't mess with animation or css toggles
        if (!jQuery.isFunction(fn) || !jQuery.isFunction(fn2)) {
            return oldToggle.apply(this, arguments);
        }
        migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");

        // Save reference to arguments for access in closure
        var args = arguments,
		guid = fn.guid || jQuery.guid++,
		i = 0,
		toggler = function (event) {
		    // Figure out which function to execute
		    var lastToggle = (jQuery._data(this, "lastToggle" + fn.guid) || 0) % i;
		    jQuery._data(this, "lastToggle" + fn.guid, lastToggle + 1);

		    // Make sure that clicks stop
		    event.preventDefault();

		    // and execute the function
		    return args[lastToggle].apply(this, arguments) || false;
		};

        // link all the functions, so any of them can unbind this click handler
        toggler.guid = guid;
        while (i < args.length) {
            args[i++].guid = guid;
        }

        return this.click(toggler);
    };

    jQuery.fn.live = function (types, data, fn) {
        migrateWarn("jQuery.fn.live() is deprecated");
        if (oldLive) {
            return oldLive.apply(this, arguments);
        }
        jQuery(this.context).on(types, this.selector, data, fn);
        return this;
    };

    jQuery.fn.die = function (types, fn) {
        migrateWarn("jQuery.fn.die() is deprecated");
        if (oldDie) {
            return oldDie.apply(this, arguments);
        }
        jQuery(this.context).off(types, this.selector || "**", fn);
        return this;
    };

    // Turn global events into document-triggered events
    jQuery.event.trigger = function (event, data, elem, onlyHandlers) {
        if (!elem && !rajaxEvent.test(event)) {
            migrateWarn("Global events are undocumented and deprecated");
        }
        return eventTrigger.call(this, event, data, elem || document, onlyHandlers);
    };
    jQuery.each(ajaxEvents.split("|"),
	function (_, name) {
	    jQuery.event.special[name] = {
	        setup: function () {
	            var elem = this;

	            // The document needs no shimming; must be !== for oldIE
	            if (elem !== document) {
	                jQuery.event.add(document, name + "." + jQuery.guid, function () {
	                    jQuery.event.trigger(name, null, elem, true);
	                });
	                jQuery._data(this, name, jQuery.guid++);
	            }
	            return false;
	        },
	        teardown: function () {
	            if (this !== document) {
	                jQuery.event.remove(document, name + "." + jQuery._data(this, name));
	            }
	            return false;
	        }
	    };
	}
);


})(jQuery, window);

// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
// This work is free. You can redistribute it and/or modify it
// under the terms of the WTFPL, Version 2
// For more information see LICENSE.txt or http://www.wtfpl.net/
//
// For more information, the home page:
// http://pieroxy.net/blog/pages/lz-string/testing.html
//
// LZ-based compression algorithm, version 1.4.4
var LZString = (function() {

// private property
var f = String.fromCharCode;
var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
var baseReverseDic = {};

function getBaseValue(alphabet, character) {
  if (!baseReverseDic[alphabet]) {
    baseReverseDic[alphabet] = {};
    for (var i=0 ; i<alphabet.length ; i++) {
      baseReverseDic[alphabet][alphabet.charAt(i)] = i;
    }
  }
  return baseReverseDic[alphabet][character];
}

var LZString = {
  compressToBase64 : function (input) {
    if (input == null) return "";
    var res = LZString._compress(input, 6, function(a){return keyStrBase64.charAt(a);});
    switch (res.length % 4) { // To produce valid Base64
    default: // When could this happen ?
    case 0 : return res;
    case 1 : return res+"===";
    case 2 : return res+"==";
    case 3 : return res+"=";
    }
  },

  decompressFromBase64 : function (input) {
    if (input == null) return "";
    if (input == "") return null;
    return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrBase64, input.charAt(index)); });
  },

  compressToUTF16 : function (input) {
    if (input == null) return "";
    return LZString._compress(input, 15, function(a){return f(a+32);}) + " ";
  },

  decompressFromUTF16: function (compressed) {
    if (compressed == null) return "";
    if (compressed == "") return null;
    return LZString._decompress(compressed.length, 16384, function(index) { return compressed.charCodeAt(index) - 32; });
  },

  //compress into uint8array (UCS-2 big endian format)
  compressToUint8Array: function (uncompressed) {
    var compressed = LZString.compress(uncompressed);
    var buf=new Uint8Array(compressed.length*2); // 2 bytes per character

    for (var i=0, TotalLen=compressed.length; i<TotalLen; i++) {
      var current_value = compressed.charCodeAt(i);
      buf[i*2] = current_value >>> 8;
      buf[i*2+1] = current_value % 256;
    }
    return buf;
  },

  //decompress from uint8array (UCS-2 big endian format)
  decompressFromUint8Array:function (compressed) {
    if (compressed===null || compressed===undefined){
        return LZString.decompress(compressed);
    } else {
        var buf=new Array(compressed.length/2); // 2 bytes per character
        for (var i=0, TotalLen=buf.length; i<TotalLen; i++) {
          buf[i]=compressed[i*2]*256+compressed[i*2+1];
        }

        var result = [];
        buf.forEach(function (c) {
          result.push(f(c));
        });
        return LZString.decompress(result.join(''));

    }

  },


  //compress into a string that is already URI encoded
  compressToEncodedURIComponent: function (input) {
    if (input == null) return "";
    return LZString._compress(input, 6, function(a){return keyStrUriSafe.charAt(a);});
  },

  //decompress from an output of compressToEncodedURIComponent
  decompressFromEncodedURIComponent:function (input) {
    if (input == null) return "";
    if (input == "") return null;
    input = input.replace(/ /g, "+");
    return LZString._decompress(input.length, 32, function(index) { return getBaseValue(keyStrUriSafe, input.charAt(index)); });
  },

  compress: function (uncompressed) {
    return LZString._compress(uncompressed, 16, function(a){return f(a);});
  },
  _compress: function (uncompressed, bitsPerChar, getCharFromInt) {
    if (uncompressed == null) return "";
    var i, value,
        context_dictionary= {},
        context_dictionaryToCreate= {},
        context_c="",
        context_wc="",
        context_w="",
        context_enlargeIn= 2, // Compensate for the first entry which should not count
        context_dictSize= 3,
        context_numBits= 2,
        context_data=[],
        context_data_val=0,
        context_data_position=0,
        ii;

    for (ii = 0; ii < uncompressed.length; ii += 1) {
      context_c = uncompressed.charAt(ii);
      if (!Object.prototype.hasOwnProperty.call(context_dictionary,context_c)) {
        context_dictionary[context_c] = context_dictSize++;
        context_dictionaryToCreate[context_c] = true;
      }

      context_wc = context_w + context_c;
      if (Object.prototype.hasOwnProperty.call(context_dictionary,context_wc)) {
        context_w = context_wc;
      } else {
        if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
          if (context_w.charCodeAt(0)<256) {
            for (i=0 ; i<context_numBits ; i++) {
              context_data_val = (context_data_val << 1);
              if (context_data_position == bitsPerChar-1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
            }
            value = context_w.charCodeAt(0);
            for (i=0 ; i<8 ; i++) {
              context_data_val = (context_data_val << 1) | (value&1);
              if (context_data_position == bitsPerChar-1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          } else {
            value = 1;
            for (i=0 ; i<context_numBits ; i++) {
              context_data_val = (context_data_val << 1) | value;
              if (context_data_position ==bitsPerChar-1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = 0;
            }
            value = context_w.charCodeAt(0);
            for (i=0 ; i<16 ; i++) {
              context_data_val = (context_data_val << 1) | (value&1);
              if (context_data_position == bitsPerChar-1) {
                context_data_position = 0;
                context_data.push(getCharFromInt(context_data_val));
                context_data_val = 0;
              } else {
                context_data_position++;
              }
              value = value >> 1;
            }
          }
          context_enlargeIn--;
          if (context_enlargeIn == 0) {
            context_enlargeIn = Math.pow(2, context_numBits);
            context_numBits++;
          }
          delete context_dictionaryToCreate[context_w];
        } else {
          value = context_dictionary[context_w];
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == bitsPerChar-1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }


        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        // Add wc to the dictionary.
        context_dictionary[context_wc] = context_dictSize++;
        context_w = String(context_c);
      }
    }

    // Output the code for w.
    if (context_w !== "") {
      if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
        if (context_w.charCodeAt(0)<256) {
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1);
            if (context_data_position == bitsPerChar-1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
          }
          value = context_w.charCodeAt(0);
          for (i=0 ; i<8 ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == bitsPerChar-1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        } else {
          value = 1;
          for (i=0 ; i<context_numBits ; i++) {
            context_data_val = (context_data_val << 1) | value;
            if (context_data_position == bitsPerChar-1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = 0;
          }
          value = context_w.charCodeAt(0);
          for (i=0 ; i<16 ; i++) {
            context_data_val = (context_data_val << 1) | (value&1);
            if (context_data_position == bitsPerChar-1) {
              context_data_position = 0;
              context_data.push(getCharFromInt(context_data_val));
              context_data_val = 0;
            } else {
              context_data_position++;
            }
            value = value >> 1;
          }
        }
        context_enlargeIn--;
        if (context_enlargeIn == 0) {
          context_enlargeIn = Math.pow(2, context_numBits);
          context_numBits++;
        }
        delete context_dictionaryToCreate[context_w];
      } else {
        value = context_dictionary[context_w];
        for (i=0 ; i<context_numBits ; i++) {
          context_data_val = (context_data_val << 1) | (value&1);
          if (context_data_position == bitsPerChar-1) {
            context_data_position = 0;
            context_data.push(getCharFromInt(context_data_val));
            context_data_val = 0;
          } else {
            context_data_position++;
          }
          value = value >> 1;
        }


      }
      context_enlargeIn--;
      if (context_enlargeIn == 0) {
        context_enlargeIn = Math.pow(2, context_numBits);
        context_numBits++;
      }
    }

    // Mark the end of the stream
    value = 2;
    for (i=0 ; i<context_numBits ; i++) {
      context_data_val = (context_data_val << 1) | (value&1);
      if (context_data_position == bitsPerChar-1) {
        context_data_position = 0;
        context_data.push(getCharFromInt(context_data_val));
        context_data_val = 0;
      } else {
        context_data_position++;
      }
      value = value >> 1;
    }

    // Flush the last char
    while (true) {
      context_data_val = (context_data_val << 1);
      if (context_data_position == bitsPerChar-1) {
        context_data.push(getCharFromInt(context_data_val));
        break;
      }
      else context_data_position++;
    }
    return context_data.join('');
  },

  decompress: function (compressed) {
    if (compressed == null) return "";
    if (compressed == "") return null;
    return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });
  },

  _decompress: function (length, resetValue, getNextValue) {
    var dictionary = [],
        next,
        enlargeIn = 4,
        dictSize = 4,
        numBits = 3,
        entry = "",
        result = [],
        i,
        w,
        bits, resb, maxpower, power,
        c,
        data = {val:getNextValue(0), position:resetValue, index:1};

    for (i = 0; i < 3; i += 1) {
      dictionary[i] = i;
    }

    bits = 0;
    maxpower = Math.pow(2,2);
    power=1;
    while (power!=maxpower) {
      resb = data.val & data.position;
      data.position >>= 1;
      if (data.position == 0) {
        data.position = resetValue;
        data.val = getNextValue(data.index++);
      }
      bits |= (resb>0 ? 1 : 0) * power;
      power <<= 1;
    }

    switch (next = bits) {
      case 0:
          bits = 0;
          maxpower = Math.pow(2,8);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = resetValue;
              data.val = getNextValue(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
        c = f(bits);
        break;
      case 1:
          bits = 0;
          maxpower = Math.pow(2,16);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = resetValue;
              data.val = getNextValue(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
        c = f(bits);
        break;
      case 2:
        return "";
    }
    dictionary[3] = c;
    w = c;
    result.push(c);
    while (true) {
      if (data.index > length) {
        return "";
      }

      bits = 0;
      maxpower = Math.pow(2,numBits);
      power=1;
      while (power!=maxpower) {
        resb = data.val & data.position;
        data.position >>= 1;
        if (data.position == 0) {
          data.position = resetValue;
          data.val = getNextValue(data.index++);
        }
        bits |= (resb>0 ? 1 : 0) * power;
        power <<= 1;
      }

      switch (c = bits) {
        case 0:
          bits = 0;
          maxpower = Math.pow(2,8);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = resetValue;
              data.val = getNextValue(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }

          dictionary[dictSize++] = f(bits);
          c = dictSize-1;
          enlargeIn--;
          break;
        case 1:
          bits = 0;
          maxpower = Math.pow(2,16);
          power=1;
          while (power!=maxpower) {
            resb = data.val & data.position;
            data.position >>= 1;
            if (data.position == 0) {
              data.position = resetValue;
              data.val = getNextValue(data.index++);
            }
            bits |= (resb>0 ? 1 : 0) * power;
            power <<= 1;
          }
          dictionary[dictSize++] = f(bits);
          c = dictSize-1;
          enlargeIn--;
          break;
        case 2:
          return result.join('');
      }

      if (enlargeIn == 0) {
        enlargeIn = Math.pow(2, numBits);
        numBits++;
      }

      if (dictionary[c]) {
        entry = dictionary[c];
      } else {
        if (c === dictSize) {
          entry = w + w.charAt(0);
        } else {
          return null;
        }
      }
      result.push(entry);

      // Add w+entry[0] to the dictionary.
      dictionary[dictSize++] = w + entry.charAt(0);
      enlargeIn--;

      w = entry;

      if (enlargeIn == 0) {
        enlargeIn = Math.pow(2, numBits);
        numBits++;
      }

    }
  }
};
  return LZString;
})();

if (typeof define === 'function' && define.amd) {
  define(function () { return LZString; });
} else if( typeof module !== 'undefined' && module != null ) {
  module.exports = LZString
}
//Not Used

(function($,undefined){var uuid=0,runiqueId=/^ui-id-\d+$/;$.ui=$.ui||{};$.extend($.ui,{version:"1.10.4",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}});$.fn.extend({focus:(function(orig){return function(delay,fn){return typeof delay==="number"?this.each(function(){var elem=this;setTimeout(function(){$(elem).focus();if(fn){fn.call(elem);}},delay);}):orig.apply(this,arguments);};})($.fn.focus),scrollParent:function(){var scrollParent;if(($.ui.ie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){scrollParent=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test($.css(this,"position"))&&(/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));}).eq(0);}else{scrollParent=this.parents().filter(function(){return(/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x"));}).eq(0);}
return(/fixed/).test(this.css("position"))||!scrollParent.length?$(document):scrollParent;},zIndex:function(zIndex){if(zIndex!==undefined){return this.css("zIndex",zIndex);}
if(this.length){var elem=$(this[0]),position,value;while(elem.length&&elem[0]!==document){position=elem.css("position");if(position==="absolute"||position==="relative"||position==="fixed"){value=parseInt(elem.css("zIndex"),10);if(!isNaN(value)&&value!==0){return value;}}
elem=elem.parent();}}
return 0;},uniqueId:function(){return this.each(function(){if(!this.id){this.id="ui-id-"+(++uuid);}});},removeUniqueId:function(){return this.each(function(){if(runiqueId.test(this.id)){$(this).removeAttr("id");}});}});function focusable(element,isTabIndexNotNaN){var map,mapName,img,nodeName=element.nodeName.toLowerCase();if("area"===nodeName){map=element.parentNode;mapName=map.name;if(!element.href||!mapName||map.nodeName.toLowerCase()!=="map"){return false;}
img=$("img[usemap=#"+mapName+"]")[0];return!!img&&visible(img);}
return(/input|select|textarea|button|object/.test(nodeName)?!element.disabled:"a"===nodeName?element.href||isTabIndexNotNaN:isTabIndexNotNaN)&&visible(element);}
function visible(element){return $.expr.filters.visible(element)&&!$(element).parents().addBack().filter(function(){return $.css(this,"visibility")==="hidden";}).length;}
$.extend($.expr[":"],{data:$.expr.createPseudo?$.expr.createPseudo(function(dataName){return function(elem){return!!$.data(elem,dataName);};}):function(elem,i,match){return!!$.data(elem,match[3]);},focusable:function(element){return focusable(element,!isNaN($.attr(element,"tabindex")));},tabbable:function(element){var tabIndex=$.attr(element,"tabindex"),isTabIndexNaN=isNaN(tabIndex);return(isTabIndexNaN||tabIndex>=0)&&focusable(element,!isTabIndexNaN);}});if(!$("<a>").outerWidth(1).jquery){$.each(["Width","Height"],function(i,name){var side=name==="Width"?["Left","Right"]:["Top","Bottom"],type=name.toLowerCase(),orig={innerWidth:$.fn.innerWidth,innerHeight:$.fn.innerHeight,outerWidth:$.fn.outerWidth,outerHeight:$.fn.outerHeight};function reduce(elem,size,border,margin){$.each(side,function(){size-=parseFloat($.css(elem,"padding"+this))||0;if(border){size-=parseFloat($.css(elem,"border"+this+"Width"))||0;}
if(margin){size-=parseFloat($.css(elem,"margin"+this))||0;}});return size;}
$.fn["inner"+name]=function(size){if(size===undefined){return orig["inner"+name].call(this);}
return this.each(function(){$(this).css(type,reduce(this,size)+"px");});};$.fn["outer"+name]=function(size,margin){if(typeof size!=="number"){return orig["outer"+name].call(this,size);}
return this.each(function(){$(this).css(type,reduce(this,size,true,margin)+"px");});};});}
if(!$.fn.addBack){$.fn.addBack=function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector));};}
if($("<a>").data("a-b","a").removeData("a-b").data("a-b")){$.fn.removeData=(function(removeData){return function(key){if(arguments.length){return removeData.call(this,$.camelCase(key));}else{return removeData.call(this);}};})($.fn.removeData);}
$.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());$.support.selectstart="onselectstart"in document.createElement("div");$.fn.extend({disableSelection:function(){return this.bind(($.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(event){event.preventDefault();});},enableSelection:function(){return this.unbind(".ui-disableSelection");}});$.extend($.ui,{plugin:{add:function(module,option,set){var i,proto=$.ui[module].prototype;for(i in set){proto.plugins[i]=proto.plugins[i]||[];proto.plugins[i].push([option,set[i]]);}},call:function(instance,name,args){var i,set=instance.plugins[name];if(!set||!instance.element[0].parentNode||instance.element[0].parentNode.nodeType===11){return;}
for(i=0;i<set.length;i++){if(instance.options[set[i][0]]){set[i][1].apply(instance.element,args);}}}},hasScroll:function(el,a){if($(el).css("overflow")==="hidden"){return false;}
var scroll=(a&&a==="left")?"scrollLeft":"scrollTop",has=false;if(el[scroll]>0){return true;}
el[scroll]=1;has=(el[scroll]>0);el[scroll]=0;return has;}});})(jQuery);(function($,undefined){var uuid=0,slice=Array.prototype.slice,_cleanData=$.cleanData;$.cleanData=function(elems){for(var i=0,elem;(elem=elems[i])!=null;i++){try{$(elem).triggerHandler("remove");}catch(e){}}
_cleanData(elems);};$.widget=function(name,base,prototype){var fullName,existingConstructor,constructor,basePrototype,proxiedPrototype={},namespace=name.split(".")[0];name=name.split(".")[1];fullName=namespace+"-"+name;if(!prototype){prototype=base;base=$.Widget;}
$.expr[":"][fullName.toLowerCase()]=function(elem){return!!$.data(elem,fullName);};$[namespace]=$[namespace]||{};existingConstructor=$[namespace][name];constructor=$[namespace][name]=function(options,element){if(!this._createWidget){return new constructor(options,element);}
if(arguments.length){this._createWidget(options,element);}};$.extend(constructor,existingConstructor,{version:prototype.version,_proto:$.extend({},prototype),_childConstructors:[]});basePrototype=new base();basePrototype.options=$.widget.extend({},basePrototype.options);$.each(prototype,function(prop,value){if(!$.isFunction(value)){proxiedPrototype[prop]=value;return;}
proxiedPrototype[prop]=(function(){var _super=function(){return base.prototype[prop].apply(this,arguments);},_superApply=function(args){return base.prototype[prop].apply(this,args);};return function(){var __super=this._super,__superApply=this._superApply,returnValue;this._super=_super;this._superApply=_superApply;returnValue=value.apply(this,arguments);this._super=__super;this._superApply=__superApply;return returnValue;};})();});constructor.prototype=$.widget.extend(basePrototype,{widgetEventPrefix:existingConstructor?(basePrototype.widgetEventPrefix||name):name},proxiedPrototype,{constructor:constructor,namespace:namespace,widgetName:name,widgetFullName:fullName});if(existingConstructor){$.each(existingConstructor._childConstructors,function(i,child){var childPrototype=child.prototype;$.widget(childPrototype.namespace+"."+childPrototype.widgetName,constructor,child._proto);});delete existingConstructor._childConstructors;}else{base._childConstructors.push(constructor);}
$.widget.bridge(name,constructor);};$.widget.extend=function(target){var input=slice.call(arguments,1),inputIndex=0,inputLength=input.length,key,value;for(;inputIndex<inputLength;inputIndex++){for(key in input[inputIndex]){value=input[inputIndex][key];if(input[inputIndex].hasOwnProperty(key)&&value!==undefined){if($.isPlainObject(value)){target[key]=$.isPlainObject(target[key])?$.widget.extend({},target[key],value):$.widget.extend({},value);}else{target[key]=value;}}}}
return target;};$.widget.bridge=function(name,object){var fullName=object.prototype.widgetFullName||name;$.fn[name]=function(options){var isMethodCall=typeof options==="string",args=slice.call(arguments,1),returnValue=this;options=!isMethodCall&&args.length?$.widget.extend.apply(null,[options].concat(args)):options;if(isMethodCall){this.each(function(){var methodValue,instance=$.data(this,fullName);if(!instance){return $.error("cannot call methods on "+name+" prior to initialization; "+"attempted to call method '"+options+"'");}
if(!$.isFunction(instance[options])||options.charAt(0)==="_"){return $.error("no such method '"+options+"' for "+name+" widget instance");}
methodValue=instance[options].apply(instance,args);if(methodValue!==instance&&methodValue!==undefined){returnValue=methodValue&&methodValue.jquery?returnValue.pushStack(methodValue.get()):methodValue;return false;}});}else{this.each(function(){var instance=$.data(this,fullName);if(instance){instance.option(options||{})._init();}else{$.data(this,fullName,new object(options,this));}});}
return returnValue;};};$.Widget=function(){};$.Widget._childConstructors=[];$.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:false,create:null},_createWidget:function(options,element){element=$(element||this.defaultElement||this)[0];this.element=$(element);this.uuid=uuid++;this.eventNamespace="."+this.widgetName+this.uuid;this.options=$.widget.extend({},this.options,this._getCreateOptions(),options);this.bindings=$();this.hoverable=$();this.focusable=$();if(element!==this){$.data(element,this.widgetFullName,this);this._on(true,this.element,{remove:function(event){if(event.target===element){this.destroy();}}});this.document=$(element.style?element.ownerDocument:element.document||element);this.window=$(this.document[0].defaultView||this.document[0].parentWindow);}
this._create();this._trigger("create",null,this._getCreateEventData());this._init();},_getCreateOptions:$.noop,_getCreateEventData:$.noop,_create:$.noop,_init:$.noop,destroy:function(){this._destroy();this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData($.camelCase(this.widgetFullName));this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled");this.bindings.unbind(this.eventNamespace);this.hoverable.removeClass("ui-state-hover");this.focusable.removeClass("ui-state-focus");},_destroy:$.noop,widget:function(){return this.element;},option:function(key,value){var options=key,parts,curOption,i;if(arguments.length===0){return $.widget.extend({},this.options);}
if(typeof key==="string"){options={};parts=key.split(".");key=parts.shift();if(parts.length){curOption=options[key]=$.widget.extend({},this.options[key]);for(i=0;i<parts.length-1;i++){curOption[parts[i]]=curOption[parts[i]]||{};curOption=curOption[parts[i]];}
key=parts.pop();if(arguments.length===1){return curOption[key]===undefined?null:curOption[key];}
curOption[key]=value;}else{if(arguments.length===1){return this.options[key]===undefined?null:this.options[key];}
options[key]=value;}}
this._setOptions(options);return this;},_setOptions:function(options){var key;for(key in options){this._setOption(key,options[key]);}
return this;},_setOption:function(key,value){this.options[key]=value;if(key==="disabled"){this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!value).attr("aria-disabled",value);this.hoverable.removeClass("ui-state-hover");this.focusable.removeClass("ui-state-focus");}
return this;},enable:function(){return this._setOption("disabled",false);},disable:function(){return this._setOption("disabled",true);},_on:function(suppressDisabledCheck,element,handlers){var delegateElement,instance=this;if(typeof suppressDisabledCheck!=="boolean"){handlers=element;element=suppressDisabledCheck;suppressDisabledCheck=false;}
if(!handlers){handlers=element;element=this.element;delegateElement=this.widget();}else{element=delegateElement=$(element);this.bindings=this.bindings.add(element);}
$.each(handlers,function(event,handler){function handlerProxy(){if(!suppressDisabledCheck&&(instance.options.disabled===true||$(this).hasClass("ui-state-disabled"))){return;}
return(typeof handler==="string"?instance[handler]:handler).apply(instance,arguments);}
if(typeof handler!=="string"){handlerProxy.guid=handler.guid=handler.guid||handlerProxy.guid||$.guid++;}
var match=event.match(/^(\w+)\s*(.*)$/),eventName=match[1]+instance.eventNamespace,selector=match[2];if(selector){delegateElement.delegate(selector,eventName,handlerProxy);}else{element.bind(eventName,handlerProxy);}});},_off:function(element,eventName){eventName=(eventName||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace;element.unbind(eventName).undelegate(eventName);},_delay:function(handler,delay){function handlerProxy(){return(typeof handler==="string"?instance[handler]:handler).apply(instance,arguments);}
var instance=this;return setTimeout(handlerProxy,delay||0);},_hoverable:function(element){this.hoverable=this.hoverable.add(element);this._on(element,{mouseenter:function(event){$(event.currentTarget).addClass("ui-state-hover");},mouseleave:function(event){$(event.currentTarget).removeClass("ui-state-hover");}});},_focusable:function(element){this.focusable=this.focusable.add(element);this._on(element,{focusin:function(event){$(event.currentTarget).addClass("ui-state-focus");},focusout:function(event){$(event.currentTarget).removeClass("ui-state-focus");}});},_trigger:function(type,event,data){var prop,orig,callback=this.options[type];data=data||{};event=$.Event(event);event.type=(type===this.widgetEventPrefix?type:this.widgetEventPrefix+type).toLowerCase();event.target=this.element[0];orig=event.originalEvent;if(orig){for(prop in orig){if(!(prop in event)){event[prop]=orig[prop];}}}
this.element.trigger(event,data);return!($.isFunction(callback)&&callback.apply(this.element[0],[event].concat(data))===false||event.isDefaultPrevented());}};$.each({show:"fadeIn",hide:"fadeOut"},function(method,defaultEffect){$.Widget.prototype["_"+method]=function(element,options,callback){if(typeof options==="string"){options={effect:options};}
var hasOptions,effectName=!options?method:options===true||typeof options==="number"?defaultEffect:options.effect||defaultEffect;options=options||{};if(typeof options==="number"){options={duration:options};}
hasOptions=!$.isEmptyObject(options);options.complete=callback;if(options.delay){element.delay(options.delay);}
if(hasOptions&&$.effects&&$.effects.effect[effectName]){element[method](options);}else if(effectName!==method&&element[effectName]){element[effectName](options.duration,options.easing,callback);}else{element.queue(function(next){$(this)[method]();if(callback){callback.call(element[0]);}
next();});}};});})(jQuery);(function($,undefined){var mouseHandled=false;$(document).mouseup(function(){mouseHandled=false;});$.widget("ui.mouse",{version:"1.10.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var that=this;this.element.bind("mousedown."+this.widgetName,function(event){return that._mouseDown(event);}).bind("click."+this.widgetName,function(event){if(true===$.data(event.target,that.widgetName+".preventClickEvent")){$.removeData(event.target,that.widgetName+".preventClickEvent");event.stopImmediatePropagation();return false;}});this.started=false;},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);if(this._mouseMoveDelegate){$(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);}},_mouseDown:function(event){if(mouseHandled){return;}
(this._mouseStarted&&this._mouseUp(event));this._mouseDownEvent=event;var that=this,btnIsLeft=(event.which===1),elIsCancel=(typeof this.options.cancel==="string"&&event.target.nodeName?$(event.target).closest(this.options.cancel).length:false);if(!btnIsLeft||elIsCancel||!this._mouseCapture(event)){return true;}
this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){that.mouseDelayMet=true;},this.options.delay);}
if(this._mouseDistanceMet(event)&&this._mouseDelayMet(event)){this._mouseStarted=(this._mouseStart(event)!==false);if(!this._mouseStarted){event.preventDefault();return true;}}
if(true===$.data(event.target,this.widgetName+".preventClickEvent")){$.removeData(event.target,this.widgetName+".preventClickEvent");}
this._mouseMoveDelegate=function(event){return that._mouseMove(event);};this._mouseUpDelegate=function(event){return that._mouseUp(event);};$(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);event.preventDefault();mouseHandled=true;return true;},_mouseMove:function(event){if($.ui.ie&&(!document.documentMode||document.documentMode<9)&&!event.button){return this._mouseUp(event);}
if(this._mouseStarted){this._mouseDrag(event);return event.preventDefault();}
if(this._mouseDistanceMet(event)&&this._mouseDelayMet(event)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,event)!==false);(this._mouseStarted?this._mouseDrag(event):this._mouseUp(event));}
return!this._mouseStarted;},_mouseUp:function(event){$(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;if(event.target===this._mouseDownEvent.target){$.data(event.target,this.widgetName+".preventClickEvent",true);}
this._mouseStop(event);}
return false;},_mouseDistanceMet:function(event){return(Math.max(Math.abs(this._mouseDownEvent.pageX-event.pageX),Math.abs(this._mouseDownEvent.pageY-event.pageY))>=this.options.distance);},_mouseDelayMet:function(){return this.mouseDelayMet;},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true;}});})(jQuery);(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);}
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){options.at="left top";}
targetWidth=dimensions.width;targetHeight=dimensions.height;targetOffset=dimensions.offset;basePosition=$.extend({},targetOffset);$.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";horizontalOffset=roffset.exec(pos[0]);verticalOffset=roffset.exec(pos[1]);offsets[this]=[horizontalOffset?horizontalOffset[0]:0,verticalOffset?verticalOffset[0]:0];options[this]=[rposition.exec(pos[0])[0],rposition.exec(pos[1])[0]];});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(!$.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){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;if(data.collisionWidth>outerWidth){if(overLeft>0&&overRight<=0){newOverRight=position.left+overLeft+data.collisionWidth-outerWidth-withinOffset;position.left+=overLeft-newOverRight;}else if(overRight>0&&overLeft<=0){position.left=withinOffset;}else{if(overLeft>overRight){position.left=withinOffset+outerWidth-data.collisionWidth;}else{position.left=withinOffset;}}}else if(overLeft>0){position.left+=overLeft;}else if(overRight>0){position.left-=overRight;}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;if(data.collisionHeight>outerHeight){if(overTop>0&&overBottom<=0){newOverBottom=position.top+overTop+data.collisionHeight-outerHeight-withinOffset;position.top+=overTop-newOverBottom;}else if(overBottom>0&&overTop<=0){position.top=withinOffset;}else{if(overTop>overBottom){position.top=withinOffset+outerHeight-data.collisionHeight;}else{position.top=withinOffset;}}}else if(overTop>0){position.top+=overTop;}else if(overBottom>0){position.top-=overBottom;}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);}}};(function(){var testElement,testElementParent,testElementStyle,offsetLeft,i,body=document.getElementsByTagName("body")[0],div=document.createElement("div");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));(function($,undefined){$.widget("ui.draggable",$.ui.mouse,{version:"1.10.4",widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false,drag:null,start:null,stop:null},_create:function(){if(this.options.helper==="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative";}
if(this.options.addClasses){this.element.addClass("ui-draggable");}
if(this.options.disabled){this.element.addClass("ui-draggable-disabled");}
this._mouseInit();},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();},_mouseCapture:function(event){var o=this.options;if(this.helper||o.disabled||$(event.target).closest(".ui-resizable-handle").length>0){return false;}
this.handle=this._getHandle(event);if(!this.handle){return false;}
$(o.iframeFix===true?"iframe":o.iframeFix).each(function(){$("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>").css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css($(this).offset()).appendTo("body");});return true;},_mouseStart:function(event){var o=this.options;this.helper=this._createHelper(event);this.helper.addClass("ui-draggable-dragging");this._cacheHelperProportions();if($.ui.ddmanager){$.ui.ddmanager.current=this;}
this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offsetParent=this.helper.offsetParent();this.offsetParentCssPosition=this.offsetParent.css("position");this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.offset.scroll=false;$.extend(this.offset,{click:{left:event.pageX-this.offset.left,top:event.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(event);this.originalPageX=event.pageX;this.originalPageY=event.pageY;(o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt));this._setContainment();if(this._trigger("start",event)===false){this._clear();return false;}
this._cacheHelperProportions();if($.ui.ddmanager&&!o.dropBehaviour){$.ui.ddmanager.prepareOffsets(this,event);}
this._mouseDrag(event,true);if($.ui.ddmanager){$.ui.ddmanager.dragStart(this,event);}
return true;},_mouseDrag:function(event,noPropagation){if(this.offsetParentCssPosition==="fixed"){this.offset.parent=this._getParentOffset();}
this.position=this._generatePosition(event);this.positionAbs=this._convertPositionTo("absolute");if(!noPropagation){var ui=this._uiHash();if(this._trigger("drag",event,ui)===false){this._mouseUp({});return false;}
this.position=ui.position;}
if(!this.options.axis||this.options.axis!=="y"){this.helper[0].style.left=this.position.left+"px";}
if(!this.options.axis||this.options.axis!=="x"){this.helper[0].style.top=this.position.top+"px";}
if($.ui.ddmanager){$.ui.ddmanager.drag(this,event);}
return false;},_mouseStop:function(event){var that=this,dropped=false;if($.ui.ddmanager&&!this.options.dropBehaviour){dropped=$.ui.ddmanager.drop(this,event);}
if(this.dropped){dropped=this.dropped;this.dropped=false;}
if(this.options.helper==="original"&&!$.contains(this.element[0].ownerDocument,this.element[0])){return false;}
if((this.options.revert==="invalid"&&!dropped)||(this.options.revert==="valid"&&dropped)||this.options.revert===true||($.isFunction(this.options.revert)&&this.options.revert.call(this.element,dropped))){$(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){if(that._trigger("stop",event)!==false){that._clear();}});}else{if(this._trigger("stop",event)!==false){this._clear();}}
return false;},_mouseUp:function(event){$("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this);});if($.ui.ddmanager){$.ui.ddmanager.dragStop(this,event);}
return $.ui.mouse.prototype._mouseUp.call(this,event);},cancel:function(){if(this.helper.is(".ui-draggable-dragging")){this._mouseUp({});}else{this._clear();}
return this;},_getHandle:function(event){return this.options.handle?!!$(event.target).closest(this.element.find(this.options.handle)).length:true;},_createHelper:function(event){var o=this.options,helper=$.isFunction(o.helper)?$(o.helper.apply(this.element[0],[event])):(o.helper==="clone"?this.element.clone().removeAttr("id"):this.element);if(!helper.parents("body").length){helper.appendTo((o.appendTo==="parent"?this.element[0].parentNode:o.appendTo));}
if(helper[0]!==this.element[0]&&!(/(fixed|absolute)/).test(helper.css("position"))){helper.css("position","absolute");}
return helper;},_adjustOffsetFromHelper:function(obj){if(typeof obj==="string"){obj=obj.split(" ");}
if($.isArray(obj)){obj={left:+obj[0],top:+obj[1]||0};}
if("left"in obj){this.offset.click.left=obj.left+this.margins.left;}
if("right"in obj){this.offset.click.left=this.helperProportions.width-obj.right+this.margins.left;}
if("top"in obj){this.offset.click.top=obj.top+this.margins.top;}
if("bottom"in obj){this.offset.click.top=this.helperProportions.height-obj.bottom+this.margins.top;}},_getParentOffset:function(){var po=this.offsetParent.offset();if(this.cssPosition==="absolute"&&this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0])){po.left+=this.scrollParent.scrollLeft();po.top+=this.scrollParent.scrollTop();}
if((this.offsetParent[0]===document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==="html"&&$.ui.ie)){po={top:0,left:0};}
return{top:po.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:po.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)};},_getRelativeOffset:function(){if(this.cssPosition==="relative"){var p=this.element.position();return{top:p.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:p.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()};}else{return{top:0,left:0};}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0),right:(parseInt(this.element.css("marginRight"),10)||0),bottom:(parseInt(this.element.css("marginBottom"),10)||0)};},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()};},_setContainment:function(){var over,c,ce,o=this.options;if(!o.containment){this.containment=null;return;}
if(o.containment==="window"){this.containment=[$(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,$(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,$(window).scrollLeft()+$(window).width()-this.helperProportions.width-this.margins.left,$(window).scrollTop()+($(window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];return;}
if(o.containment==="document"){this.containment=[0,0,$(document).width()-this.helperProportions.width-this.margins.left,($(document).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];return;}
if(o.containment.constructor===Array){this.containment=o.containment;return;}
if(o.containment==="parent"){o.containment=this.helper[0].parentNode;}
c=$(o.containment);ce=c[0];if(!ce){return;}
over=c.css("overflow")!=="hidden";this.containment=[(parseInt(c.css("borderLeftWidth"),10)||0)+(parseInt(c.css("paddingLeft"),10)||0),(parseInt(c.css("borderTopWidth"),10)||0)+(parseInt(c.css("paddingTop"),10)||0),(over?Math.max(ce.scrollWidth,ce.offsetWidth):ce.offsetWidth)-(parseInt(c.css("borderRightWidth"),10)||0)-(parseInt(c.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(over?Math.max(ce.scrollHeight,ce.offsetHeight):ce.offsetHeight)-(parseInt(c.css("borderBottomWidth"),10)||0)-(parseInt(c.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=c;},_convertPositionTo:function(d,pos){if(!pos){pos=this.position;}
var mod=d==="absolute"?1:-1,scroll=this.cssPosition==="absolute"&&!(this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent;if(!this.offset.scroll){this.offset.scroll={top:scroll.scrollTop(),left:scroll.scrollLeft()};}
return{top:(pos.top+
this.offset.relative.top*mod+
this.offset.parent.top*mod-
((this.cssPosition==="fixed"?-this.scrollParent.scrollTop():this.offset.scroll.top)*mod)),left:(pos.left+
this.offset.relative.left*mod+
this.offset.parent.left*mod-
((this.cssPosition==="fixed"?-this.scrollParent.scrollLeft():this.offset.scroll.left)*mod))};},_generatePosition:function(event){var containment,co,top,left,o=this.options,scroll=this.cssPosition==="absolute"&&!(this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,pageX=event.pageX,pageY=event.pageY;if(!this.offset.scroll){this.offset.scroll={top:scroll.scrollTop(),left:scroll.scrollLeft()};}
if(this.originalPosition){if(this.containment){if(this.relative_container){co=this.relative_container.offset();containment=[this.containment[0]+co.left,this.containment[1]+co.top,this.containment[2]+co.left,this.containment[3]+co.top];}
else{containment=this.containment;}
if(event.pageX-this.offset.click.left<containment[0]){pageX=containment[0]+this.offset.click.left;}
if(event.pageY-this.offset.click.top<containment[1]){pageY=containment[1]+this.offset.click.top;}
if(event.pageX-this.offset.click.left>containment[2]){pageX=containment[2]+this.offset.click.left;}
if(event.pageY-this.offset.click.top>containment[3]){pageY=containment[3]+this.offset.click.top;}}
if(o.grid){top=o.grid[1]?this.originalPageY+Math.round((pageY-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY;pageY=containment?((top-this.offset.click.top>=containment[1]||top-this.offset.click.top>containment[3])?top:((top-this.offset.click.top>=containment[1])?top-o.grid[1]:top+o.grid[1])):top;left=o.grid[0]?this.originalPageX+Math.round((pageX-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX;pageX=containment?((left-this.offset.click.left>=containment[0]||left-this.offset.click.left>containment[2])?left:((left-this.offset.click.left>=containment[0])?left-o.grid[0]:left+o.grid[0])):left;}}
return{top:(pageY-
this.offset.click.top-
this.offset.relative.top-
this.offset.parent.top+
(this.cssPosition==="fixed"?-this.scrollParent.scrollTop():this.offset.scroll.top)),left:(pageX-
this.offset.click.left-
this.offset.relative.left-
this.offset.parent.left+
(this.cssPosition==="fixed"?-this.scrollParent.scrollLeft():this.offset.scroll.left))};},_clear:function(){this.helper.removeClass("ui-draggable-dragging");if(this.helper[0]!==this.element[0]&&!this.cancelHelperRemoval){this.helper.remove();}
this.helper=null;this.cancelHelperRemoval=false;},_trigger:function(type,event,ui){ui=ui||this._uiHash();$.ui.plugin.call(this,type,[event,ui]);if(type==="drag"){this.positionAbs=this._convertPositionTo("absolute");}
return $.Widget.prototype._trigger.call(this,type,event,ui);},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs};}});$.ui.plugin.add("draggable","connectToSortable",{start:function(event,ui){var inst=$(this).data("ui-draggable"),o=inst.options,uiSortable=$.extend({},ui,{item:inst.element});inst.sortables=[];$(o.connectToSortable).each(function(){var sortable=$.data(this,"ui-sortable");if(sortable&&!sortable.options.disabled){inst.sortables.push({instance:sortable,shouldRevert:sortable.options.revert});sortable.refreshPositions();sortable._trigger("activate",event,uiSortable);}});},stop:function(event,ui){var inst=$(this).data("ui-draggable"),uiSortable=$.extend({},ui,{item:inst.element});$.each(inst.sortables,function(){if(this.instance.isOver){this.instance.isOver=0;inst.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert){this.instance.options.revert=this.shouldRevert;}
this.instance._mouseStop(event);this.instance.options.helper=this.instance.options._helper;if(inst.options.helper==="original"){this.instance.currentItem.css({top:"auto",left:"auto"});}}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",event,uiSortable);}});},drag:function(event,ui){var inst=$(this).data("ui-draggable"),that=this;$.each(inst.sortables,function(){var innermostIntersecting=false,thisSortable=this;this.instance.positionAbs=inst.positionAbs;this.instance.helperProportions=inst.helperProportions;this.instance.offset.click=inst.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){innermostIntersecting=true;$.each(inst.sortables,function(){this.instance.positionAbs=inst.positionAbs;this.instance.helperProportions=inst.helperProportions;this.instance.offset.click=inst.offset.click;if(this!==thisSortable&&this.instance._intersectsWith(this.instance.containerCache)&&$.contains(thisSortable.instance.element[0],this.instance.element[0])){innermostIntersecting=false;}
return innermostIntersecting;});}
if(innermostIntersecting){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=$(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return ui.helper[0];};event.target=this.instance.currentItem[0];this.instance._mouseCapture(event,true);this.instance._mouseStart(event,true,true);this.instance.offset.click.top=inst.offset.click.top;this.instance.offset.click.left=inst.offset.click.left;this.instance.offset.parent.left-=inst.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=inst.offset.parent.top-this.instance.offset.parent.top;inst._trigger("toSortable",event);inst.dropped=this.instance.element;inst.currentItem=inst.element;this.instance.fromOutside=inst;}
if(this.instance.currentItem){this.instance._mouseDrag(event);}}else{if(this.instance.isOver){this.instance.isOver=0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",event,this.instance._uiHash(this.instance));this.instance._mouseStop(event,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();if(this.instance.placeholder){this.instance.placeholder.remove();}
inst._trigger("fromSortable",event);inst.dropped=false;}}});}});$.ui.plugin.add("draggable","cursor",{start:function(){var t=$("body"),o=$(this).data("ui-draggable").options;if(t.css("cursor")){o._cursor=t.css("cursor");}
t.css("cursor",o.cursor);},stop:function(){var o=$(this).data("ui-draggable").options;if(o._cursor){$("body").css("cursor",o._cursor);}}});$.ui.plugin.add("draggable","opacity",{start:function(event,ui){var t=$(ui.helper),o=$(this).data("ui-draggable").options;if(t.css("opacity")){o._opacity=t.css("opacity");}
t.css("opacity",o.opacity);},stop:function(event,ui){var o=$(this).data("ui-draggable").options;if(o._opacity){$(ui.helper).css("opacity",o._opacity);}}});$.ui.plugin.add("draggable","scroll",{start:function(){var i=$(this).data("ui-draggable");if(i.scrollParent[0]!==document&&i.scrollParent[0].tagName!=="HTML"){i.overflowOffset=i.scrollParent.offset();}},drag:function(event){var i=$(this).data("ui-draggable"),o=i.options,scrolled=false;if(i.scrollParent[0]!==document&&i.scrollParent[0].tagName!=="HTML"){if(!o.axis||o.axis!=="x"){if((i.overflowOffset.top+i.scrollParent[0].offsetHeight)-event.pageY<o.scrollSensitivity){i.scrollParent[0].scrollTop=scrolled=i.scrollParent[0].scrollTop+o.scrollSpeed;}else if(event.pageY-i.overflowOffset.top<o.scrollSensitivity){i.scrollParent[0].scrollTop=scrolled=i.scrollParent[0].scrollTop-o.scrollSpeed;}}
if(!o.axis||o.axis!=="y"){if((i.overflowOffset.left+i.scrollParent[0].offsetWidth)-event.pageX<o.scrollSensitivity){i.scrollParent[0].scrollLeft=scrolled=i.scrollParent[0].scrollLeft+o.scrollSpeed;}else if(event.pageX-i.overflowOffset.left<o.scrollSensitivity){i.scrollParent[0].scrollLeft=scrolled=i.scrollParent[0].scrollLeft-o.scrollSpeed;}}}else{if(!o.axis||o.axis!=="x"){if(event.pageY-$(document).scrollTop()<o.scrollSensitivity){scrolled=$(document).scrollTop($(document).scrollTop()-o.scrollSpeed);}else if($(window).height()-(event.pageY-$(document).scrollTop())<o.scrollSensitivity){scrolled=$(document).scrollTop($(document).scrollTop()+o.scrollSpeed);}}
if(!o.axis||o.axis!=="y"){if(event.pageX-$(document).scrollLeft()<o.scrollSensitivity){scrolled=$(document).scrollLeft($(document).scrollLeft()-o.scrollSpeed);}else if($(window).width()-(event.pageX-$(document).scrollLeft())<o.scrollSensitivity){scrolled=$(document).scrollLeft($(document).scrollLeft()+o.scrollSpeed);}}}
if(scrolled!==false&&$.ui.ddmanager&&!o.dropBehaviour){$.ui.ddmanager.prepareOffsets(i,event);}}});$.ui.plugin.add("draggable","snap",{start:function(){var i=$(this).data("ui-draggable"),o=i.options;i.snapElements=[];$(o.snap.constructor!==String?(o.snap.items||":data(ui-draggable)"):o.snap).each(function(){var $t=$(this),$o=$t.offset();if(this!==i.element[0]){i.snapElements.push({item:this,width:$t.outerWidth(),height:$t.outerHeight(),top:$o.top,left:$o.left});}});},drag:function(event,ui){var ts,bs,ls,rs,l,r,t,b,i,first,inst=$(this).data("ui-draggable"),o=inst.options,d=o.snapTolerance,x1=ui.offset.left,x2=x1+inst.helperProportions.width,y1=ui.offset.top,y2=y1+inst.helperProportions.height;for(i=inst.snapElements.length-1;i>=0;i--){l=inst.snapElements[i].left;r=l+inst.snapElements[i].width;t=inst.snapElements[i].top;b=t+inst.snapElements[i].height;if(x2<l-d||x1>r+d||y2<t-d||y1>b+d||!$.contains(inst.snapElements[i].item.ownerDocument,inst.snapElements[i].item)){if(inst.snapElements[i].snapping){(inst.options.snap.release&&inst.options.snap.release.call(inst.element,event,$.extend(inst._uiHash(),{snapItem:inst.snapElements[i].item})));}
inst.snapElements[i].snapping=false;continue;}
if(o.snapMode!=="inner"){ts=Math.abs(t-y2)<=d;bs=Math.abs(b-y1)<=d;ls=Math.abs(l-x2)<=d;rs=Math.abs(r-x1)<=d;if(ts){ui.position.top=inst._convertPositionTo("relative",{top:t-inst.helperProportions.height,left:0}).top-inst.margins.top;}
if(bs){ui.position.top=inst._convertPositionTo("relative",{top:b,left:0}).top-inst.margins.top;}
if(ls){ui.position.left=inst._convertPositionTo("relative",{top:0,left:l-inst.helperProportions.width}).left-inst.margins.left;}
if(rs){ui.position.left=inst._convertPositionTo("relative",{top:0,left:r}).left-inst.margins.left;}}
first=(ts||bs||ls||rs);if(o.snapMode!=="outer"){ts=Math.abs(t-y1)<=d;bs=Math.abs(b-y2)<=d;ls=Math.abs(l-x1)<=d;rs=Math.abs(r-x2)<=d;if(ts){ui.position.top=inst._convertPositionTo("relative",{top:t,left:0}).top-inst.margins.top;}
if(bs){ui.position.top=inst._convertPositionTo("relative",{top:b-inst.helperProportions.height,left:0}).top-inst.margins.top;}
if(ls){ui.position.left=inst._convertPositionTo("relative",{top:0,left:l}).left-inst.margins.left;}
if(rs){ui.position.left=inst._convertPositionTo("relative",{top:0,left:r-inst.helperProportions.width}).left-inst.margins.left;}}
if(!inst.snapElements[i].snapping&&(ts||bs||ls||rs||first)){(inst.options.snap.snap&&inst.options.snap.snap.call(inst.element,event,$.extend(inst._uiHash(),{snapItem:inst.snapElements[i].item})));}
inst.snapElements[i].snapping=(ts||bs||ls||rs||first);}}});$.ui.plugin.add("draggable","stack",{start:function(){var min,o=this.data("ui-draggable").options,group=$.makeArray($(o.stack)).sort(function(a,b){return(parseInt($(a).css("zIndex"),10)||0)-(parseInt($(b).css("zIndex"),10)||0);});if(!group.length){return;}
min=parseInt($(group[0]).css("zIndex"),10)||0;$(group).each(function(i){$(this).css("zIndex",min+i);});this.css("zIndex",(min+group.length));}});$.ui.plugin.add("draggable","zIndex",{start:function(event,ui){var t=$(ui.helper),o=$(this).data("ui-draggable").options;if(t.css("zIndex")){o._zIndex=t.css("zIndex");}
t.css("zIndex",o.zIndex);},stop:function(event,ui){var o=$(this).data("ui-draggable").options;if(o._zIndex){$(ui.helper).css("zIndex",o._zIndex);}}});})(jQuery);(function($,undefined){function isOverAxis(x,reference,size){return(x>reference)&&(x<(reference+size));}
$.widget("ui.droppable",{version:"1.10.4",widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect",activate:null,deactivate:null,drop:null,out:null,over:null},_create:function(){var proportions,o=this.options,accept=o.accept;this.isover=false;this.isout=true;this.accept=$.isFunction(accept)?accept:function(d){return d.is(accept);};this.proportions=function(){if(arguments.length){proportions=arguments[0];}else{return proportions?proportions:proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};}};$.ui.ddmanager.droppables[o.scope]=$.ui.ddmanager.droppables[o.scope]||[];$.ui.ddmanager.droppables[o.scope].push(this);(o.addClasses&&this.element.addClass("ui-droppable"));},_destroy:function(){var i=0,drop=$.ui.ddmanager.droppables[this.options.scope];for(;i<drop.length;i++){if(drop[i]===this){drop.splice(i,1);}}
this.element.removeClass("ui-droppable ui-droppable-disabled");},_setOption:function(key,value){if(key==="accept"){this.accept=$.isFunction(value)?value:function(d){return d.is(value);};}
$.Widget.prototype._setOption.apply(this,arguments);},_activate:function(event){var draggable=$.ui.ddmanager.current;if(this.options.activeClass){this.element.addClass(this.options.activeClass);}
if(draggable){this._trigger("activate",event,this.ui(draggable));}},_deactivate:function(event){var draggable=$.ui.ddmanager.current;if(this.options.activeClass){this.element.removeClass(this.options.activeClass);}
if(draggable){this._trigger("deactivate",event,this.ui(draggable));}},_over:function(event){var draggable=$.ui.ddmanager.current;if(!draggable||(draggable.currentItem||draggable.element)[0]===this.element[0]){return;}
if(this.accept.call(this.element[0],(draggable.currentItem||draggable.element))){if(this.options.hoverClass){this.element.addClass(this.options.hoverClass);}
this._trigger("over",event,this.ui(draggable));}},_out:function(event){var draggable=$.ui.ddmanager.current;if(!draggable||(draggable.currentItem||draggable.element)[0]===this.element[0]){return;}
if(this.accept.call(this.element[0],(draggable.currentItem||draggable.element))){if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass);}
this._trigger("out",event,this.ui(draggable));}},_drop:function(event,custom){var draggable=custom||$.ui.ddmanager.current,childrenIntersection=false;if(!draggable||(draggable.currentItem||draggable.element)[0]===this.element[0]){return false;}
this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function(){var inst=$.data(this,"ui-droppable");if(inst.options.greedy&&!inst.options.disabled&&inst.options.scope===draggable.options.scope&&inst.accept.call(inst.element[0],(draggable.currentItem||draggable.element))&&$.ui.intersect(draggable,$.extend(inst,{offset:inst.element.offset()}),inst.options.tolerance)){childrenIntersection=true;return false;}});if(childrenIntersection){return false;}
if(this.accept.call(this.element[0],(draggable.currentItem||draggable.element))){if(this.options.activeClass){this.element.removeClass(this.options.activeClass);}
if(this.options.hoverClass){this.element.removeClass(this.options.hoverClass);}
this._trigger("drop",event,this.ui(draggable));return this.element;}
return false;},ui:function(c){return{draggable:(c.currentItem||c.element),helper:c.helper,position:c.position,offset:c.positionAbs};}});$.ui.intersect=function(draggable,droppable,toleranceMode){if(!droppable.offset){return false;}
var draggableLeft,draggableTop,x1=(draggable.positionAbs||draggable.position.absolute).left,y1=(draggable.positionAbs||draggable.position.absolute).top,x2=x1+draggable.helperProportions.width,y2=y1+draggable.helperProportions.height,l=droppable.offset.left,t=droppable.offset.top,r=l+droppable.proportions().width,b=t+droppable.proportions().height;switch(toleranceMode){case"fit":return(l<=x1&&x2<=r&&t<=y1&&y2<=b);case"intersect":return(l<x1+(draggable.helperProportions.width/2)&&x2-(draggable.helperProportions.width/2)<r&&t<y1+(draggable.helperProportions.height/2)&&y2-(draggable.helperProportions.height/2)<b);case"pointer":draggableLeft=((draggable.positionAbs||draggable.position.absolute).left+(draggable.clickOffset||draggable.offset.click).left);draggableTop=((draggable.positionAbs||draggable.position.absolute).top+(draggable.clickOffset||draggable.offset.click).top);return isOverAxis(draggableTop,t,droppable.proportions().height)&&isOverAxis(draggableLeft,l,droppable.proportions().width);case"touch":return((y1>=t&&y1<=b)||(y2>=t&&y2<=b)||(y1<t&&y2>b))&&((x1>=l&&x1<=r)||(x2>=l&&x2<=r)||(x1<l&&x2>r));default:return false;}};$.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,event){var i,j,m=$.ui.ddmanager.droppables[t.options.scope]||[],type=event?event.type:null,list=(t.currentItem||t.element).find(":data(ui-droppable)").addBack();droppablesLoop:for(i=0;i<m.length;i++){if(m[i].options.disabled||(t&&!m[i].accept.call(m[i].element[0],(t.currentItem||t.element)))){continue;}
for(j=0;j<list.length;j++){if(list[j]===m[i].element[0]){m[i].proportions().height=0;continue droppablesLoop;}}
m[i].visible=m[i].element.css("display")!=="none";if(!m[i].visible){continue;}
if(type==="mousedown"){m[i]._activate.call(m[i],event);}
m[i].offset=m[i].element.offset();m[i].proportions({width:m[i].element[0].offsetWidth,height:m[i].element[0].offsetHeight});}},drop:function(draggable,event){var dropped=false;$.each(($.ui.ddmanager.droppables[draggable.options.scope]||[]).slice(),function(){if(!this.options){return;}
if(!this.options.disabled&&this.visible&&$.ui.intersect(draggable,this,this.options.tolerance)){dropped=this._drop.call(this,event)||dropped;}
if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],(draggable.currentItem||draggable.element))){this.isout=true;this.isover=false;this._deactivate.call(this,event);}});return dropped;},dragStart:function(draggable,event){draggable.element.parentsUntil("body").bind("scroll.droppable",function(){if(!draggable.options.refreshPositions){$.ui.ddmanager.prepareOffsets(draggable,event);}});},drag:function(draggable,event){if(draggable.options.refreshPositions){$.ui.ddmanager.prepareOffsets(draggable,event);}
$.each($.ui.ddmanager.droppables[draggable.options.scope]||[],function(){if(this.options.disabled||this.greedyChild||!this.visible){return;}
var parentInstance,scope,parent,intersects=$.ui.intersect(draggable,this,this.options.tolerance),c=!intersects&&this.isover?"isout":(intersects&&!this.isover?"isover":null);if(!c){return;}
if(this.options.greedy){scope=this.options.scope;parent=this.element.parents(":data(ui-droppable)").filter(function(){return $.data(this,"ui-droppable").options.scope===scope;});if(parent.length){parentInstance=$.data(parent[0],"ui-droppable");parentInstance.greedyChild=(c==="isover");}}
if(parentInstance&&c==="isover"){parentInstance.isover=false;parentInstance.isout=true;parentInstance._out.call(parentInstance,event);}
this[c]=true;this[c==="isout"?"isover":"isout"]=false;this[c==="isover"?"_over":"_out"].call(this,event);if(parentInstance&&c==="isout"){parentInstance.isout=false;parentInstance.isover=true;parentInstance._over.call(parentInstance,event);}});},dragStop:function(draggable,event){draggable.element.parentsUntil("body").unbind("scroll.droppable");if(!draggable.options.refreshPositions){$.ui.ddmanager.prepareOffsets(draggable,event);}}};})(jQuery);(function($,undefined){function num(v){return parseInt(v,10)||0;}
function isNumber(value){return!isNaN(parseInt(value,10));}
$.widget("ui.resizable",$.ui.mouse,{version:"1.10.4",widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var n,i,handle,axis,hname,that=this,o=this.options;this.element.addClass("ui-resizable");$.extend(this,{_aspectRatio:!!(o.aspectRatio),aspectRatio:o.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:o.helper||o.ghost||o.animate?o.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){this.element.wrap($("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize();}
this.handles=o.handles||(!$(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor===String){if(this.handles==="all"){this.handles="n,e,s,w,se,sw,ne,nw";}
n=this.handles.split(",");this.handles={};for(i=0;i<n.length;i++){handle=$.trim(n[i]);hname="ui-resizable-"+handle;axis=$("<div class='ui-resizable-handle "+hname+"'></div>");axis.css({zIndex:o.zIndex});if("se"===handle){axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");}
this.handles[handle]=".ui-resizable-"+handle;this.element.append(axis);}}
this._renderAxis=function(target){var i,axis,padPos,padWrapper;target=target||this.element;for(i in this.handles){if(this.handles[i].constructor===String){this.handles[i]=$(this.handles[i],this.element).show();}
if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){axis=$(this.handles[i],this.element);padWrapper=/sw|ne|nw|se|n|s/.test(i)?axis.outerHeight():axis.outerWidth();padPos=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");target.css(padPos,padWrapper);this._proportionallyResize();}
if(!$(this.handles[i]).length){continue;}}};this._renderAxis(this.element);this._handles=$(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!that.resizing){if(this.className){axis=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);}
that.axis=axis&&axis[1]?axis[1]:"se";}});if(o.autoHide){this._handles.hide();$(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(o.disabled){return;}
$(this).removeClass("ui-resizable-autohide");that._handles.show();}).mouseleave(function(){if(o.disabled){return;}
if(!that.resizing){$(this).addClass("ui-resizable-autohide");that._handles.hide();}});}
this._mouseInit();},_destroy:function(){this._mouseDestroy();var wrapper,_destroy=function(exp){$(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();};if(this.elementIsWrapper){_destroy(this.element);wrapper=this.element;this.originalElement.css({position:wrapper.css("position"),width:wrapper.outerWidth(),height:wrapper.outerHeight(),top:wrapper.css("top"),left:wrapper.css("left")}).insertAfter(wrapper);wrapper.remove();}
this.originalElement.css("resize",this.originalResizeStyle);_destroy(this.originalElement);return this;},_mouseCapture:function(event){var i,handle,capture=false;for(i in this.handles){handle=$(this.handles[i])[0];if(handle===event.target||$.contains(handle,event.target)){capture=true;}}
return!this.options.disabled&&capture;},_mouseStart:function(event){var curleft,curtop,cursor,o=this.options,iniPos=this.element.position(),el=this.element;this.resizing=true;if((/absolute/).test(el.css("position"))){el.css({position:"absolute",top:el.css("top"),left:el.css("left")});}else if(el.is(".ui-draggable")){el.css({position:"absolute",top:iniPos.top,left:iniPos.left});}
this._renderProxy();curleft=num(this.helper.css("left"));curtop=num(this.helper.css("top"));if(o.containment){curleft+=$(o.containment).scrollLeft()||0;curtop+=$(o.containment).scrollTop()||0;}
this.offset=this.helper.offset();this.position={left:curleft,top:curtop};this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:el.width(),height:el.height()};this.originalSize=this._helper?{width:el.outerWidth(),height:el.outerHeight()}:{width:el.width(),height:el.height()};this.originalPosition={left:curleft,top:curtop};this.sizeDiff={width:el.outerWidth()-el.width(),height:el.outerHeight()-el.height()};this.originalMousePosition={left:event.pageX,top:event.pageY};this.aspectRatio=(typeof o.aspectRatio==="number")?o.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);cursor=$(".ui-resizable-"+this.axis).css("cursor");$("body").css("cursor",cursor==="auto"?this.axis+"-resize":cursor);el.addClass("ui-resizable-resizing");this._propagate("start",event);return true;},_mouseDrag:function(event){var data,el=this.helper,props={},smp=this.originalMousePosition,a=this.axis,prevTop=this.position.top,prevLeft=this.position.left,prevWidth=this.size.width,prevHeight=this.size.height,dx=(event.pageX-smp.left)||0,dy=(event.pageY-smp.top)||0,trigger=this._change[a];if(!trigger){return false;}
data=trigger.apply(this,[event,dx,dy]);this._updateVirtualBoundaries(event.shiftKey);if(this._aspectRatio||event.shiftKey){data=this._updateRatio(data,event);}
data=this._respectSize(data,event);this._updateCache(data);this._propagate("resize",event);if(this.position.top!==prevTop){props.top=this.position.top+"px";}
if(this.position.left!==prevLeft){props.left=this.position.left+"px";}
if(this.size.width!==prevWidth){props.width=this.size.width+"px";}
if(this.size.height!==prevHeight){props.height=this.size.height+"px";}
el.css(props);if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize();}
if(!$.isEmptyObject(props)){this._trigger("resize",event,this.ui());}
return false;},_mouseStop:function(event){this.resizing=false;var pr,ista,soffseth,soffsetw,s,left,top,o=this.options,that=this;if(this._helper){pr=this._proportionallyResizeElements;ista=pr.length&&(/textarea/i).test(pr[0].nodeName);soffseth=ista&&$.ui.hasScroll(pr[0],"left")?0:that.sizeDiff.height;soffsetw=ista?0:that.sizeDiff.width;s={width:(that.helper.width()-soffsetw),height:(that.helper.height()-soffseth)};left=(parseInt(that.element.css("left"),10)+(that.position.left-that.originalPosition.left))||null;top=(parseInt(that.element.css("top"),10)+(that.position.top-that.originalPosition.top))||null;if(!o.animate){this.element.css($.extend(s,{top:top,left:left}));}
that.helper.height(that.size.height);that.helper.width(that.size.width);if(this._helper&&!o.animate){this._proportionallyResize();}}
$("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",event);if(this._helper){this.helper.remove();}
return false;},_updateVirtualBoundaries:function(forceAspectRatio){var pMinWidth,pMaxWidth,pMinHeight,pMaxHeight,b,o=this.options;b={minWidth:isNumber(o.minWidth)?o.minWidth:0,maxWidth:isNumber(o.maxWidth)?o.maxWidth:Infinity,minHeight:isNumber(o.minHeight)?o.minHeight:0,maxHeight:isNumber(o.maxHeight)?o.maxHeight:Infinity};if(this._aspectRatio||forceAspectRatio){pMinWidth=b.minHeight*this.aspectRatio;pMinHeight=b.minWidth/this.aspectRatio;pMaxWidth=b.maxHeight*this.aspectRatio;pMaxHeight=b.maxWidth/this.aspectRatio;if(pMinWidth>b.minWidth){b.minWidth=pMinWidth;}
if(pMinHeight>b.minHeight){b.minHeight=pMinHeight;}
if(pMaxWidth<b.maxWidth){b.maxWidth=pMaxWidth;}
if(pMaxHeight<b.maxHeight){b.maxHeight=pMaxHeight;}}
this._vBoundaries=b;},_updateCache:function(data){this.offset=this.helper.offset();if(isNumber(data.left)){this.position.left=data.left;}
if(isNumber(data.top)){this.position.top=data.top;}
if(isNumber(data.height)){this.size.height=data.height;}
if(isNumber(data.width)){this.size.width=data.width;}},_updateRatio:function(data){var cpos=this.position,csize=this.size,a=this.axis;if(isNumber(data.height)){data.width=(data.height*this.aspectRatio);}else if(isNumber(data.width)){data.height=(data.width/this.aspectRatio);}
if(a==="sw"){data.left=cpos.left+(csize.width-data.width);data.top=null;}
if(a==="nw"){data.top=cpos.top+(csize.height-data.height);data.left=cpos.left+(csize.width-data.width);}
return data;},_respectSize:function(data){var o=this._vBoundaries,a=this.axis,ismaxw=isNumber(data.width)&&o.maxWidth&&(o.maxWidth<data.width),ismaxh=isNumber(data.height)&&o.maxHeight&&(o.maxHeight<data.height),isminw=isNumber(data.width)&&o.minWidth&&(o.minWidth>data.width),isminh=isNumber(data.height)&&o.minHeight&&(o.minHeight>data.height),dw=this.originalPosition.left+this.originalSize.width,dh=this.position.top+this.size.height,cw=/sw|nw|w/.test(a),ch=/nw|ne|n/.test(a);if(isminw){data.width=o.minWidth;}
if(isminh){data.height=o.minHeight;}
if(ismaxw){data.width=o.maxWidth;}
if(ismaxh){data.height=o.maxHeight;}
if(isminw&&cw){data.left=dw-o.minWidth;}
if(ismaxw&&cw){data.left=dw-o.maxWidth;}
if(isminh&&ch){data.top=dh-o.minHeight;}
if(ismaxh&&ch){data.top=dh-o.maxHeight;}
if(!data.width&&!data.height&&!data.left&&data.top){data.top=null;}else if(!data.width&&!data.height&&!data.top&&data.left){data.left=null;}
return data;},_proportionallyResize:function(){if(!this._proportionallyResizeElements.length){return;}
var i,j,borders,paddings,prel,element=this.helper||this.element;for(i=0;i<this._proportionallyResizeElements.length;i++){prel=this._proportionallyResizeElements[i];if(!this.borderDif){this.borderDif=[];borders=[prel.css("borderTopWidth"),prel.css("borderRightWidth"),prel.css("borderBottomWidth"),prel.css("borderLeftWidth")];paddings=[prel.css("paddingTop"),prel.css("paddingRight"),prel.css("paddingBottom"),prel.css("paddingLeft")];for(j=0;j<borders.length;j++){this.borderDif[j]=(parseInt(borders[j],10)||0)+(parseInt(paddings[j],10)||0);}}
prel.css({height:(element.height()-this.borderDif[0]-this.borderDif[2])||0,width:(element.width()-this.borderDif[1]-this.borderDif[3])||0});}},_renderProxy:function(){var el=this.element,o=this.options;this.elementOffset=el.offset();if(this._helper){this.helper=this.helper||$("<div style='overflow:hidden;'></div>");this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++o.zIndex});this.helper.appendTo("body").disableSelection();}else{this.helper=this.element;}},_change:{e:function(event,dx){return{width:this.originalSize.width+dx};},w:function(event,dx){var cs=this.originalSize,sp=this.originalPosition;return{left:sp.left+dx,width:cs.width-dx};},n:function(event,dx,dy){var cs=this.originalSize,sp=this.originalPosition;return{top:sp.top+dy,height:cs.height-dy};},s:function(event,dx,dy){return{height:this.originalSize.height+dy};},se:function(event,dx,dy){return $.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[event,dx,dy]));},sw:function(event,dx,dy){return $.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[event,dx,dy]));},ne:function(event,dx,dy){return $.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[event,dx,dy]));},nw:function(event,dx,dy){return $.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[event,dx,dy]));}},_propagate:function(n,event){$.ui.plugin.call(this,n,[event,this.ui()]);(n!=="resize"&&this._trigger(n,event,this.ui()));},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition};}});$.ui.plugin.add("resizable","animate",{stop:function(event){var that=$(this).data("ui-resizable"),o=that.options,pr=that._proportionallyResizeElements,ista=pr.length&&(/textarea/i).test(pr[0].nodeName),soffseth=ista&&$.ui.hasScroll(pr[0],"left")?0:that.sizeDiff.height,soffsetw=ista?0:that.sizeDiff.width,style={width:(that.size.width-soffsetw),height:(that.size.height-soffseth)},left=(parseInt(that.element.css("left"),10)+(that.position.left-that.originalPosition.left))||null,top=(parseInt(that.element.css("top"),10)+(that.position.top-that.originalPosition.top))||null;that.element.animate($.extend(style,top&&left?{top:top,left:left}:{}),{duration:o.animateDuration,easing:o.animateEasing,step:function(){var data={width:parseInt(that.element.css("width"),10),height:parseInt(that.element.css("height"),10),top:parseInt(that.element.css("top"),10),left:parseInt(that.element.css("left"),10)};if(pr&&pr.length){$(pr[0]).css({width:data.width,height:data.height});}
that._updateCache(data);that._propagate("resize",event);}});}});$.ui.plugin.add("resizable","containment",{start:function(){var element,p,co,ch,cw,width,height,that=$(this).data("ui-resizable"),o=that.options,el=that.element,oc=o.containment,ce=(oc instanceof $)?oc.get(0):(/parent/.test(oc))?el.parent().get(0):oc;if(!ce){return;}
that.containerElement=$(ce);if(/document/.test(oc)||oc===document){that.containerOffset={left:0,top:0};that.containerPosition={left:0,top:0};that.parentData={element:$(document),left:0,top:0,width:$(document).width(),height:$(document).height()||document.body.parentNode.scrollHeight};}
else{element=$(ce);p=[];$(["Top","Right","Left","Bottom"]).each(function(i,name){p[i]=num(element.css("padding"+name));});that.containerOffset=element.offset();that.containerPosition=element.position();that.containerSize={height:(element.innerHeight()-p[3]),width:(element.innerWidth()-p[1])};co=that.containerOffset;ch=that.containerSize.height;cw=that.containerSize.width;width=($.ui.hasScroll(ce,"left")?ce.scrollWidth:cw);height=($.ui.hasScroll(ce)?ce.scrollHeight:ch);that.parentData={element:ce,left:co.left,top:co.top,width:width,height:height};}},resize:function(event){var woset,hoset,isParent,isOffsetRelative,that=$(this).data("ui-resizable"),o=that.options,co=that.containerOffset,cp=that.position,pRatio=that._aspectRatio||event.shiftKey,cop={top:0,left:0},ce=that.containerElement;if(ce[0]!==document&&(/static/).test(ce.css("position"))){cop=co;}
if(cp.left<(that._helper?co.left:0)){that.size.width=that.size.width+(that._helper?(that.position.left-co.left):(that.position.left-cop.left));if(pRatio){that.size.height=that.size.width/that.aspectRatio;}
that.position.left=o.helper?co.left:0;}
if(cp.top<(that._helper?co.top:0)){that.size.height=that.size.height+(that._helper?(that.position.top-co.top):that.position.top);if(pRatio){that.size.width=that.size.height*that.aspectRatio;}
that.position.top=that._helper?co.top:0;}
that.offset.left=that.parentData.left+that.position.left;that.offset.top=that.parentData.top+that.position.top;woset=Math.abs((that._helper?that.offset.left-cop.left:(that.offset.left-cop.left))+that.sizeDiff.width);hoset=Math.abs((that._helper?that.offset.top-cop.top:(that.offset.top-co.top))+that.sizeDiff.height);isParent=that.containerElement.get(0)===that.element.parent().get(0);isOffsetRelative=/relative|absolute/.test(that.containerElement.css("position"));if(isParent&&isOffsetRelative){woset-=Math.abs(that.parentData.left);}
if(woset+that.size.width>=that.parentData.width){that.size.width=that.parentData.width-woset;if(pRatio){that.size.height=that.size.width/that.aspectRatio;}}
if(hoset+that.size.height>=that.parentData.height){that.size.height=that.parentData.height-hoset;if(pRatio){that.size.width=that.size.height*that.aspectRatio;}}},stop:function(){var that=$(this).data("ui-resizable"),o=that.options,co=that.containerOffset,cop=that.containerPosition,ce=that.containerElement,helper=$(that.helper),ho=helper.offset(),w=helper.outerWidth()-that.sizeDiff.width,h=helper.outerHeight()-that.sizeDiff.height;if(that._helper&&!o.animate&&(/relative/).test(ce.css("position"))){$(this).css({left:ho.left-cop.left-co.left,width:w,height:h});}
if(that._helper&&!o.animate&&(/static/).test(ce.css("position"))){$(this).css({left:ho.left-cop.left-co.left,width:w,height:h});}}});$.ui.plugin.add("resizable","alsoResize",{start:function(){var that=$(this).data("ui-resizable"),o=that.options,_store=function(exp){$(exp).each(function(){var el=$(this);el.data("ui-resizable-alsoresize",{width:parseInt(el.width(),10),height:parseInt(el.height(),10),left:parseInt(el.css("left"),10),top:parseInt(el.css("top"),10)});});};if(typeof(o.alsoResize)==="object"&&!o.alsoResize.parentNode){if(o.alsoResize.length){o.alsoResize=o.alsoResize[0];_store(o.alsoResize);}
else{$.each(o.alsoResize,function(exp){_store(exp);});}}else{_store(o.alsoResize);}},resize:function(event,ui){var that=$(this).data("ui-resizable"),o=that.options,os=that.originalSize,op=that.originalPosition,delta={height:(that.size.height-os.height)||0,width:(that.size.width-os.width)||0,top:(that.position.top-op.top)||0,left:(that.position.left-op.left)||0},_alsoResize=function(exp,c){$(exp).each(function(){var el=$(this),start=$(this).data("ui-resizable-alsoresize"),style={},css=c&&c.length?c:el.parents(ui.originalElement[0]).length?["width","height"]:["width","height","top","left"];$.each(css,function(i,prop){var sum=(start[prop]||0)+(delta[prop]||0);if(sum&&sum>=0){style[prop]=sum||null;}});el.css(style);});};if(typeof(o.alsoResize)==="object"&&!o.alsoResize.nodeType){$.each(o.alsoResize,function(exp,c){_alsoResize(exp,c);});}else{_alsoResize(o.alsoResize);}},stop:function(){$(this).removeData("resizable-alsoresize");}});$.ui.plugin.add("resizable","ghost",{start:function(){var that=$(this).data("ui-resizable"),o=that.options,cs=that.size;that.ghost=that.originalElement.clone();that.ghost.css({opacity:0.25,display:"block",position:"relative",height:cs.height,width:cs.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof o.ghost==="string"?o.ghost:"");that.ghost.appendTo(that.helper);},resize:function(){var that=$(this).data("ui-resizable");if(that.ghost){that.ghost.css({position:"relative",height:that.size.height,width:that.size.width});}},stop:function(){var that=$(this).data("ui-resizable");if(that.ghost&&that.helper){that.helper.get(0).removeChild(that.ghost.get(0));}}});$.ui.plugin.add("resizable","grid",{resize:function(){var that=$(this).data("ui-resizable"),o=that.options,cs=that.size,os=that.originalSize,op=that.originalPosition,a=that.axis,grid=typeof o.grid==="number"?[o.grid,o.grid]:o.grid,gridX=(grid[0]||1),gridY=(grid[1]||1),ox=Math.round((cs.width-os.width)/gridX)*gridX,oy=Math.round((cs.height-os.height)/gridY)*gridY,newWidth=os.width+ox,newHeight=os.height+oy,isMaxWidth=o.maxWidth&&(o.maxWidth<newWidth),isMaxHeight=o.maxHeight&&(o.maxHeight<newHeight),isMinWidth=o.minWidth&&(o.minWidth>newWidth),isMinHeight=o.minHeight&&(o.minHeight>newHeight);o.grid=grid;if(isMinWidth){newWidth=newWidth+gridX;}
if(isMinHeight){newHeight=newHeight+gridY;}
if(isMaxWidth){newWidth=newWidth-gridX;}
if(isMaxHeight){newHeight=newHeight-gridY;}
if(/^(se|s|e)$/.test(a)){that.size.width=newWidth;that.size.height=newHeight;}else if(/^(ne)$/.test(a)){that.size.width=newWidth;that.size.height=newHeight;that.position.top=op.top-oy;}else if(/^(sw)$/.test(a)){that.size.width=newWidth;that.size.height=newHeight;that.position.left=op.left-ox;}else{if(newHeight-gridY>0){that.size.height=newHeight;that.position.top=op.top-oy;}else{that.size.height=gridY;that.position.top=op.top+os.height-gridY;}
if(newWidth-gridX>0){that.size.width=newWidth;that.position.left=op.left-ox;}else{that.size.width=gridX;that.position.left=op.left+os.width-gridX;}}}});})(jQuery);(function($,undefined){$.widget("ui.selectable",$.ui.mouse,{version:"1.10.4",options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch",selected:null,selecting:null,start:null,stop:null,unselected:null,unselecting:null},_create:function(){var selectees,that=this;this.element.addClass("ui-selectable");this.dragged=false;this.refresh=function(){selectees=$(that.options.filter,that.element[0]);selectees.addClass("ui-selectee");selectees.each(function(){var $this=$(this),pos=$this.offset();$.data(this,"selectable-item",{element:this,$element:$this,left:pos.left,top:pos.top,right:pos.left+$this.outerWidth(),bottom:pos.top+$this.outerHeight(),startselected:false,selected:$this.hasClass("ui-selected"),selecting:$this.hasClass("ui-selecting"),unselecting:$this.hasClass("ui-unselecting")});});};this.refresh();this.selectees=selectees.addClass("ui-selectee");this._mouseInit();this.helper=$("<div class='ui-selectable-helper'></div>");},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled");this._mouseDestroy();},_mouseStart:function(event){var that=this,options=this.options;this.opos=[event.pageX,event.pageY];if(this.options.disabled){return;}
this.selectees=$(options.filter,this.element[0]);this._trigger("start",event);$(options.appendTo).append(this.helper);this.helper.css({"left":event.pageX,"top":event.pageY,"width":0,"height":0});if(options.autoRefresh){this.refresh();}
this.selectees.filter(".ui-selected").each(function(){var selectee=$.data(this,"selectable-item");selectee.startselected=true;if(!event.metaKey&&!event.ctrlKey){selectee.$element.removeClass("ui-selected");selectee.selected=false;selectee.$element.addClass("ui-unselecting");selectee.unselecting=true;that._trigger("unselecting",event,{unselecting:selectee.element});}});$(event.target).parents().addBack().each(function(){var doSelect,selectee=$.data(this,"selectable-item");if(selectee){doSelect=(!event.metaKey&&!event.ctrlKey)||!selectee.$element.hasClass("ui-selected");selectee.$element.removeClass(doSelect?"ui-unselecting":"ui-selected").addClass(doSelect?"ui-selecting":"ui-unselecting");selectee.unselecting=!doSelect;selectee.selecting=doSelect;selectee.selected=doSelect;if(doSelect){that._trigger("selecting",event,{selecting:selectee.element});}else{that._trigger("unselecting",event,{unselecting:selectee.element});}
return false;}});},_mouseDrag:function(event){this.dragged=true;if(this.options.disabled){return;}
var tmp,that=this,options=this.options,x1=this.opos[0],y1=this.opos[1],x2=event.pageX,y2=event.pageY;if(x1>x2){tmp=x2;x2=x1;x1=tmp;}
if(y1>y2){tmp=y2;y2=y1;y1=tmp;}
this.helper.css({left:x1,top:y1,width:x2-x1,height:y2-y1});this.selectees.each(function(){var selectee=$.data(this,"selectable-item"),hit=false;if(!selectee||selectee.element===that.element[0]){return;}
if(options.tolerance==="touch"){hit=(!(selectee.left>x2||selectee.right<x1||selectee.top>y2||selectee.bottom<y1));}else if(options.tolerance==="fit"){hit=(selectee.left>x1&&selectee.right<x2&&selectee.top>y1&&selectee.bottom<y2);}
if(hit){if(selectee.selected){selectee.$element.removeClass("ui-selected");selectee.selected=false;}
if(selectee.unselecting){selectee.$element.removeClass("ui-unselecting");selectee.unselecting=false;}
if(!selectee.selecting){selectee.$element.addClass("ui-selecting");selectee.selecting=true;that._trigger("selecting",event,{selecting:selectee.element});}}else{if(selectee.selecting){if((event.metaKey||event.ctrlKey)&&selectee.startselected){selectee.$element.removeClass("ui-selecting");selectee.selecting=false;selectee.$element.addClass("ui-selected");selectee.selected=true;}else{selectee.$element.removeClass("ui-selecting");selectee.selecting=false;if(selectee.startselected){selectee.$element.addClass("ui-unselecting");selectee.unselecting=true;}
that._trigger("unselecting",event,{unselecting:selectee.element});}}
if(selectee.selected){if(!event.metaKey&&!event.ctrlKey&&!selectee.startselected){selectee.$element.removeClass("ui-selected");selectee.selected=false;selectee.$element.addClass("ui-unselecting");selectee.unselecting=true;that._trigger("unselecting",event,{unselecting:selectee.element});}}}});return false;},_mouseStop:function(event){var that=this;this.dragged=false;$(".ui-unselecting",this.element[0]).each(function(){var selectee=$.data(this,"selectable-item");selectee.$element.removeClass("ui-unselecting");selectee.unselecting=false;selectee.startselected=false;that._trigger("unselected",event,{unselected:selectee.element});});$(".ui-selecting",this.element[0]).each(function(){var selectee=$.data(this,"selectable-item");selectee.$element.removeClass("ui-selecting").addClass("ui-selected");selectee.selecting=false;selectee.selected=true;selectee.startselected=true;that._trigger("selected",event,{selected:selectee.element});});this._trigger("stop",event);this.helper.remove();return false;}});})(jQuery);(function($,undefined){function isOverAxis(x,reference,size){return(x>reference)&&(x<(reference+size));}
function isFloating(item){return(/left|right/).test(item.css("float"))||(/inline|table-cell/).test(item.css("display"));}
$.widget("ui.sortable",$.ui.mouse,{version:"1.10.4",widgetEventPrefix:"sort",ready:false,options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_create:function(){var o=this.options;this.containerCache={};this.element.addClass("ui-sortable");this.refresh();this.floating=this.items.length?o.axis==="x"||isFloating(this.items[0].item):false;this.offset=this.element.offset();this._mouseInit();this.ready=true;},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled");this._mouseDestroy();for(var i=this.items.length-1;i>=0;i--){this.items[i].item.removeData(this.widgetName+"-item");}
return this;},_setOption:function(key,value){if(key==="disabled"){this.options[key]=value;this.widget().toggleClass("ui-sortable-disabled",!!value);}else{$.Widget.prototype._setOption.apply(this,arguments);}},_mouseCapture:function(event,overrideHandle){var currentItem=null,validHandle=false,that=this;if(this.reverting){return false;}
if(this.options.disabled||this.options.type==="static"){return false;}
this._refreshItems(event);$(event.target).parents().each(function(){if($.data(this,that.widgetName+"-item")===that){currentItem=$(this);return false;}});if($.data(event.target,that.widgetName+"-item")===that){currentItem=$(event.target);}
if(!currentItem){return false;}
if(this.options.handle&&!overrideHandle){$(this.options.handle,currentItem).find("*").addBack().each(function(){if(this===event.target){validHandle=true;}});if(!validHandle){return false;}}
this.currentItem=currentItem;this._removeCurrentsFromItems();return true;},_mouseStart:function(event,overrideHandle,noActivation){var i,body,o=this.options;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(event);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};$.extend(this.offset,{click:{left:event.pageX-this.offset.left,top:event.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");this.originalPosition=this._generatePosition(event);this.originalPageX=event.pageX;this.originalPageY=event.pageY;(o.cursorAt&&this._adjustOffsetFromHelper(o.cursorAt));this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!==this.currentItem[0]){this.currentItem.hide();}
this._createPlaceholder();if(o.containment){this._setContainment();}
if(o.cursor&&o.cursor!=="auto"){body=this.document.find("body");this.storedCursor=body.css("cursor");body.css("cursor",o.cursor);this.storedStylesheet=$("<style>*{ cursor: "+o.cursor+" !important; }</style>").appendTo(body);}
if(o.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity");}
this.helper.css("opacity",o.opacity);}
if(o.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex");}
this.helper.css("zIndex",o.zIndex);}
if(this.scrollParent[0]!==document&&this.scrollParent[0].tagName!=="HTML"){this.overflowOffset=this.scrollParent.offset();}
this._trigger("start",event,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions();}
if(!noActivation){for(i=this.containers.length-1;i>=0;i--){this.containers[i]._trigger("activate",event,this._uiHash(this));}}
if($.ui.ddmanager){$.ui.ddmanager.current=this;}
if($.ui.ddmanager&&!o.dropBehaviour){$.ui.ddmanager.prepareOffsets(this,event);}
this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(event);return true;},_mouseDrag:function(event){var i,item,itemElement,intersection,o=this.options,scrolled=false;this.position=this._generatePosition(event);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs;}
if(this.options.scroll){if(this.scrollParent[0]!==document&&this.scrollParent[0].tagName!=="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-event.pageY<o.scrollSensitivity){this.scrollParent[0].scrollTop=scrolled=this.scrollParent[0].scrollTop+o.scrollSpeed;}else if(event.pageY-this.overflowOffset.top<o.scrollSensitivity){this.scrollParent[0].scrollTop=scrolled=this.scrollParent[0].scrollTop-o.scrollSpeed;}
if((this.overflowOffset.left+this.scrollParent[0].offsetWidth)-event.pageX<o.scrollSensitivity){this.scrollParent[0].scrollLeft=scrolled=this.scrollParent[0].scrollLeft+o.scrollSpeed;}else if(event.pageX-this.overflowOffset.left<o.scrollSensitivity){this.scrollParent[0].scrollLeft=scrolled=this.scrollParent[0].scrollLeft-o.scrollSpeed;}}else{if(event.pageY-$(document).scrollTop()<o.scrollSensitivity){scrolled=$(document).scrollTop($(document).scrollTop()-o.scrollSpeed);}else if($(window).height()-(event.pageY-$(document).scrollTop())<o.scrollSensitivity){scrolled=$(document).scrollTop($(document).scrollTop()+o.scrollSpeed);}
if(event.pageX-$(document).scrollLeft()<o.scrollSensitivity){scrolled=$(document).scrollLeft($(document).scrollLeft()-o.scrollSpeed);}else if($(window).width()-(event.pageX-$(document).scrollLeft())<o.scrollSensitivity){scrolled=$(document).scrollLeft($(document).scrollLeft()+o.scrollSpeed);}}
if(scrolled!==false&&$.ui.ddmanager&&!o.dropBehaviour){$.ui.ddmanager.prepareOffsets(this,event);}}
this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!=="y"){this.helper[0].style.left=this.position.left+"px";}
if(!this.options.axis||this.options.axis!=="x"){this.helper[0].style.top=this.position.top+"px";}
for(i=this.items.length-1;i>=0;i--){item=this.items[i];itemElement=item.item[0];intersection=this._intersectsWithPointer(item);if(!intersection){continue;}
if(item.instance!==this.currentContainer){continue;}
if(itemElement!==this.currentItem[0]&&this.placeholder[intersection===1?"next":"prev"]()[0]!==itemElement&&!$.contains(this.placeholder[0],itemElement)&&(this.options.type==="semi-dynamic"?!$.contains(this.element[0],itemElement):true)){this.direction=intersection===1?"down":"up";if(this.options.tolerance==="pointer"||this._intersectsWithSides(item)){this._rearrange(event,item);}else{break;}
this._trigger("change",event,this._uiHash());break;}}
this._contactContainers(event);if($.ui.ddmanager){$.ui.ddmanager.drag(this,event);}
this._trigger("sort",event,this._uiHash());this.lastPositionAbs=this.positionAbs;return false;},_mouseStop:function(event,noPropagation){if(!event){return;}
if($.ui.ddmanager&&!this.options.dropBehaviour){$.ui.ddmanager.drop(this,event);}
if(this.options.revert){var that=this,cur=this.placeholder.offset(),axis=this.options.axis,animation={};if(!axis||axis==="x"){animation.left=cur.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollLeft);}
if(!axis||axis==="y"){animation.top=cur.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]===document.body?0:this.offsetParent[0].scrollTop);}
this.reverting=true;$(this.helper).animate(animation,parseInt(this.options.revert,10)||500,function(){that._clear(event);});}else{this._clear(event,noPropagation);}
return false;},cancel:function(){if(this.dragging){this._mouseUp({target:null});if(this.options.helper==="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");}else{this.currentItem.show();}
for(var i=this.containers.length-1;i>=0;i--){this.containers[i]._trigger("deactivate",null,this._uiHash(this));if(this.containers[i].containerCache.over){this.containers[i]._trigger("out",null,this._uiHash(this));this.containers[i].containerCache.over=0;}}}
if(this.placeholder){if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0]);}
if(this.options.helper!=="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove();}
$.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){$(this.domPosition.prev).after(this.currentItem);}else{$(this.domPosition.parent).prepend(this.currentItem);}}
return this;},serialize:function(o){var items=this._getItemsAsjQuery(o&&o.connected),str=[];o=o||{};$(items).each(function(){var res=($(o.item||this).attr(o.attribute||"id")||"").match(o.expression||(/(.+)[\-=_](.+)/));if(res){str.push((o.key||res[1]+"[]")+"="+(o.key&&o.expression?res[1]:res[2]));}});if(!str.length&&o.key){str.push(o.key+"=");}
return str.join("&");},toArray:function(o){var items=this._getItemsAsjQuery(o&&o.connected),ret=[];o=o||{};items.each(function(){ret.push($(o.item||this).attr(o.attribute||"id")||"");});return ret;},_intersectsWith:function(item){var x1=this.positionAbs.left,x2=x1+this.helperProportions.width,y1=this.positionAbs.top,y2=y1+this.helperProportions.height,l=item.left,r=l+item.width,t=item.top,b=t+item.height,dyClick=this.offset.click.top,dxClick=this.offset.click.left,isOverElementHeight=(this.options.axis==="x")||((y1+dyClick)>t&&(y1+dyClick)<b),isOverElementWidth=(this.options.axis==="y")||((x1+dxClick)>l&&(x1+dxClick)<r),isOverElement=isOverElementHeight&&isOverElementWidth;if(this.options.tolerance==="pointer"||this.options.forcePointerForContainers||(this.options.tolerance!=="pointer"&&this.helperProportions[this.floating?"width":"height"]>item[this.floating?"width":"height"])){return isOverElement;}else{return(l<x1+(this.helperProportions.width/2)&&x2-(this.helperProportions.width/2)<r&&t<y1+(this.helperProportions.height/2)&&y2-(this.helperProportions.height/2)<b);}},_intersectsWithPointer:function(item){var isOverElementHeight=(this.options.axis==="x")||isOverAxis(this.positionAbs.top+this.offset.click.top,item.top,item.height),isOverElementWidth=(this.options.axis==="y")||isOverAxis(this.positionAbs.left+this.offset.click.left,item.left,item.width),isOverElement=isOverElementHeight&&isOverElementWidth,verticalDirection=this._getDragVerticalDirection(),horizontalDirection=this._getDragHorizontalDirection();if(!isOverElement){return false;}
return this.floating?(((horizontalDirection&&horizontalDirection==="right")||verticalDirection==="down")?2:1):(verticalDirection&&(verticalDirection==="down"?2:1));},_intersectsWithSides:function(item){var isOverBottomHalf=isOverAxis(this.positionAbs.top+this.offset.click.top,item.top+(item.height/2),item.height),isOverRightHalf=isOverAxis(this.positionAbs.left+this.offset.click.left,item.left+(item.width/2),item.width),verticalDirection=this._getDragVerticalDirection(),horizontalDirection=this._getDragHorizontalDirection();if(this.floating&&horizontalDirection){return((horizontalDirection==="right"&&isOverRightHalf)||(horizontalDirection==="left"&&!isOverRightHalf));}else{return verticalDirection&&((verticalDirection==="down"&&isOverBottomHalf)||(verticalDirection==="up"&&!isOverBottomHalf));}},_getDragVerticalDirection:function(){var delta=this.positionAbs.top-this.lastPositionAbs.top;return delta!==0&&(delta>0?"down":"up");},_getDragHorizontalDirection:function(){var delta=this.positionAbs.left-this.lastPositionAbs.left;return delta!==0&&(delta>0?"right":"left");},refresh:function(event){this._refreshItems(event);this.refreshPositions();return this;},_connectWith:function(){var options=this.options;return options.connectWith.constructor===String?[options.connectWith]:options.connectWith;},_getItemsAsjQuery:function(connected){var i,j,cur,inst,items=[],queries=[],connectWith=this._connectWith();if(connectWith&&connected){for(i=connectWith.length-1;i>=0;i--){cur=$(connectWith[i]);for(j=cur.length-1;j>=0;j--){inst=$.data(cur[j],this.widgetFullName);if(inst&&inst!==this&&!inst.options.disabled){queries.push([$.isFunction(inst.options.items)?inst.options.items.call(inst.element):$(inst.options.items,inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),inst]);}}}}
queries.push([$.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):$(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);function addItems(){items.push(this);}
for(i=queries.length-1;i>=0;i--){queries[i][0].each(addItems);}
return $(items);},_removeCurrentsFromItems:function(){var list=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=$.grep(this.items,function(item){for(var j=0;j<list.length;j++){if(list[j]===item.item[0]){return false;}}
return true;});},_refreshItems:function(event){this.items=[];this.containers=[this];var i,j,cur,inst,targetData,_queries,item,queriesLength,items=this.items,queries=[[$.isFunction(this.options.items)?this.options.items.call(this.element[0],event,{item:this.currentItem}):$(this.options.items,this.element),this]],connectWith=this._connectWith();if(connectWith&&this.ready){for(i=connectWith.length-1;i>=0;i--){cur=$(connectWith[i]);for(j=cur.length-1;j>=0;j--){inst=$.data(cur[j],this.widgetFullName);if(inst&&inst!==this&&!inst.options.disabled){queries.push([$.isFunction(inst.options.items)?inst.options.items.call(inst.element[0],event,{item:this.currentItem}):$(inst.options.items,inst.element),inst]);this.containers.push(inst);}}}}
for(i=queries.length-1;i>=0;i--){targetData=queries[i][1];_queries=queries[i][0];for(j=0,queriesLength=_queries.length;j<queriesLength;j++){item=$(_queries[j]);item.data(this.widgetName+"-item",targetData);items.push({item:item,instance:targetData,width:0,height:0,left:0,top:0});}}},refreshPositions:function(fast){if(this.offsetParent&&this.helper){this.offset.parent=this._getParentOffset();}
var i,item,t,p;for(i=this.items.length-1;i>=0;i--){item=this.items[i];if(item.instance!==this.currentContainer&&this.currentContainer&&item.item[0]!==this.currentItem[0]){continue;}
t=this.options.toleranceElement?$(this.options.toleranceElement,item.item):item.item;if(!fast){item.width=t.outerWidth();item.height=t.outerHeight();}
p=t.offset();item.left=p.left;item.top=p.top;}
if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this);}else{for(i=this.containers.length-1;i>=0;i--){p=this.containers[i].element.offset();this.containers[i].containerCache.left=p.left;this.containers[i].containerCache.top=p.top;this.containers[i].containerCache.width=this.containers[i].element.outerWidth();this.containers[i].containerCache.height=this.containers[i].element.outerHeight();}}
return this;},_createPlaceholder:function(that){that=that||this;var className,o=that.options;if(!o.placeholder||o.placeholder.constructor===String){className=o.placeholder;o.placeholder={element:function(){var nodeName=that.currentItem[0].nodeName.toLowerCase(),element=$("<"+nodeName+">",that.document[0]).addClass(className||that.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper");if(nodeName==="tr"){that.currentItem.children().each(function(){$("<td>&#160;</td>",that.document[0]).attr("colspan",$(this).attr("colspan")||1).appendTo(element);});}else if(nodeName==="img"){element.attr("src",that.currentItem.attr("src"));}
if(!className){element.css("visibility","hidden");}
return element;},update:function(container,p){if(className&&!o.forcePlaceholderSize){return;}
if(!p.height()){p.height(that.currentItem.innerHeight()-parseInt(that.currentItem.css("paddingTop")||0,10)-parseInt(that.currentItem.css("paddingBottom")||0,10));}
if(!p.width()){p.width(that.currentItem.innerWidth()-parseInt(that.currentItem.css("paddingLeft")||0,10)-parseInt(that.currentItem.css("paddingRight")||0,10));}}};}
that.placeholder=$(o.placeholder.element.call(that.element,that.currentItem));that.currentItem.after(that.placeholder);o.placeholder.update(that,that.placeholder);},_contactContainers:function(event){var i,j,dist,itemWithLeastDistance,posProperty,sizeProperty,base,cur,nearBottom,floating,innermostContainer=null,innermostIndex=null;for(i=this.containers.length-1;i>=0;i--){if($.contains(this.currentItem[0],this.containers[i].element[0])){continue;}
if(this._intersectsWith(this.containers[i].containerCache)){if(innermostContainer&&$.contains(this.containers[i].element[0],innermostContainer.element[0])){continue;}
innermostContainer=this.containers[i];innermostIndex=i;}else{if(this.containers[i].containerCache.over){this.containers[i]._trigger("out",event,this._uiHash(this));this.containers[i].containerCache.over=0;}}}
if(!innermostContainer){return;}
if(this.containers.length===1){if(!this.containers[innermostIndex].containerCache.over){this.containers[innermostIndex]._trigger("over",event,this._uiHash(this));this.containers[innermostIndex].containerCache.over=1;}}else{dist=10000;itemWithLeastDistance=null;floating=innermostContainer.floating||isFloating(this.currentItem);posProperty=floating?"left":"top";sizeProperty=floating?"width":"height";base=this.positionAbs[posProperty]+this.offset.click[posProperty];for(j=this.items.length-1;j>=0;j--){if(!$.contains(this.containers[innermostIndex].element[0],this.items[j].item[0])){continue;}
if(this.items[j].item[0]===this.currentItem[0]){continue;}
if(floating&&!isOverAxis(this.positionAbs.top+this.offset.click.top,this.items[j].top,this.items[j].height)){continue;}
cur=this.items[j].item.offset()[posProperty];nearBottom=false;if(Math.abs(cur-base)>Math.abs(cur+this.items[j][sizeProperty]-base)){nearBottom=true;cur+=this.items[j][sizeProperty];}
if(Math.abs(cur-base)<dist){dist=Math.abs(cur-base);itemWithLeastDistance=this.items[j];this.direction=nearBottom?"up":"down";}}
if(!itemWithLeastDistance&&!this.options.dropOnEmpty){return;}
if(this.currentContainer===this.containers[innermostIndex]){return;}
itemWithLeastDistance?this._rearrange(event,itemWithLeastDistance,null,true):this._rearrange(event,null,this.containers[innermostIndex].element,true);this._trigger("change",event,this._uiHash());this.containers[innermostIndex]._trigger("change",event,this._uiHash(this));this.currentContainer=this.containers[innermostIndex];this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[innermostIndex]._trigger("over",event,this._uiHash(this));this.containers[innermostIndex].containerCache.over=1;}},_createHelper:function(event){var o=this.options,helper=$.isFunction(o.helper)?$(o.helper.apply(this.element[0],[event,this.currentItem])):(o.helper==="clone"?this.currentItem.clone():this.currentItem);if(!helper.parents("body").length){$(o.appendTo!=="parent"?o.appendTo:this.currentItem[0].parentNode)[0].appendChild(helper[0]);}
if(helper[0]===this.currentItem[0]){this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};}
if(!helper[0].style.width||o.forceHelperSize){helper.width(this.currentItem.width());}
if(!helper[0].style.height||o.forceHelperSize){helper.height(this.currentItem.height());}
return helper;},_adjustOffsetFromHelper:function(obj){if(typeof obj==="string"){obj=obj.split(" ");}
if($.isArray(obj)){obj={left:+obj[0],top:+obj[1]||0};}
if("left"in obj){this.offset.click.left=obj.left+this.margins.left;}
if("right"in obj){this.offset.click.left=this.helperProportions.width-obj.right+this.margins.left;}
if("top"in obj){this.offset.click.top=obj.top+this.margins.top;}
if("bottom"in obj){this.offset.click.top=this.helperProportions.height-obj.bottom+this.margins.top;}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var po=this.offsetParent.offset();if(this.cssPosition==="absolute"&&this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0])){po.left+=this.scrollParent.scrollLeft();po.top+=this.scrollParent.scrollTop();}
if(this.offsetParent[0]===document.body||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()==="html"&&$.ui.ie)){po={top:0,left:0};}
return{top:po.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:po.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)};},_getRelativeOffset:function(){if(this.cssPosition==="relative"){var p=this.currentItem.position();return{top:p.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:p.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()};}else{return{top:0,left:0};}},_cacheMargins:function(){this.margins={left:(parseInt(this.currentItem.css("marginLeft"),10)||0),top:(parseInt(this.currentItem.css("marginTop"),10)||0)};},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()};},_setContainment:function(){var ce,co,over,o=this.options;if(o.containment==="parent"){o.containment=this.helper[0].parentNode;}
if(o.containment==="document"||o.containment==="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,$(o.containment==="document"?document:window).width()-this.helperProportions.width-this.margins.left,($(o.containment==="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];}
if(!(/^(document|window|parent)$/).test(o.containment)){ce=$(o.containment)[0];co=$(o.containment).offset();over=($(ce).css("overflow")!=="hidden");this.containment=[co.left+(parseInt($(ce).css("borderLeftWidth"),10)||0)+(parseInt($(ce).css("paddingLeft"),10)||0)-this.margins.left,co.top+(parseInt($(ce).css("borderTopWidth"),10)||0)+(parseInt($(ce).css("paddingTop"),10)||0)-this.margins.top,co.left+(over?Math.max(ce.scrollWidth,ce.offsetWidth):ce.offsetWidth)-(parseInt($(ce).css("borderLeftWidth"),10)||0)-(parseInt($(ce).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,co.top+(over?Math.max(ce.scrollHeight,ce.offsetHeight):ce.offsetHeight)-(parseInt($(ce).css("borderTopWidth"),10)||0)-(parseInt($(ce).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top];}},_convertPositionTo:function(d,pos){if(!pos){pos=this.position;}
var mod=d==="absolute"?1:-1,scroll=this.cssPosition==="absolute"&&!(this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,scrollIsRootNode=(/(html|body)/i).test(scroll[0].tagName);return{top:(pos.top+
this.offset.relative.top*mod+
this.offset.parent.top*mod-
((this.cssPosition==="fixed"?-this.scrollParent.scrollTop():(scrollIsRootNode?0:scroll.scrollTop()))*mod)),left:(pos.left+
this.offset.relative.left*mod+
this.offset.parent.left*mod-
((this.cssPosition==="fixed"?-this.scrollParent.scrollLeft():scrollIsRootNode?0:scroll.scrollLeft())*mod))};},_generatePosition:function(event){var top,left,o=this.options,pageX=event.pageX,pageY=event.pageY,scroll=this.cssPosition==="absolute"&&!(this.scrollParent[0]!==document&&$.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,scrollIsRootNode=(/(html|body)/i).test(scroll[0].tagName);if(this.cssPosition==="relative"&&!(this.scrollParent[0]!==document&&this.scrollParent[0]!==this.offsetParent[0])){this.offset.relative=this._getRelativeOffset();}
if(this.originalPosition){if(this.containment){if(event.pageX-this.offset.click.left<this.containment[0]){pageX=this.containment[0]+this.offset.click.left;}
if(event.pageY-this.offset.click.top<this.containment[1]){pageY=this.containment[1]+this.offset.click.top;}
if(event.pageX-this.offset.click.left>this.containment[2]){pageX=this.containment[2]+this.offset.click.left;}
if(event.pageY-this.offset.click.top>this.containment[3]){pageY=this.containment[3]+this.offset.click.top;}}
if(o.grid){top=this.originalPageY+Math.round((pageY-this.originalPageY)/o.grid[1])*o.grid[1];pageY=this.containment?((top-this.offset.click.top>=this.containment[1]&&top-this.offset.click.top<=this.containment[3])?top:((top-this.offset.click.top>=this.containment[1])?top-o.grid[1]:top+o.grid[1])):top;left=this.originalPageX+Math.round((pageX-this.originalPageX)/o.grid[0])*o.grid[0];pageX=this.containment?((left-this.offset.click.left>=this.containment[0]&&left-this.offset.click.left<=this.containment[2])?left:((left-this.offset.click.left>=this.containment[0])?left-o.grid[0]:left+o.grid[0])):left;}}
return{top:(pageY-
this.offset.click.top-
this.offset.relative.top-
this.offset.parent.top+
((this.cssPosition==="fixed"?-this.scrollParent.scrollTop():(scrollIsRootNode?0:scroll.scrollTop())))),left:(pageX-
this.offset.click.left-
this.offset.relative.left-
this.offset.parent.left+
((this.cssPosition==="fixed"?-this.scrollParent.scrollLeft():scrollIsRootNode?0:scroll.scrollLeft())))};},_rearrange:function(event,i,a,hardRefresh){a?a[0].appendChild(this.placeholder[0]):i.item[0].parentNode.insertBefore(this.placeholder[0],(this.direction==="down"?i.item[0]:i.item[0].nextSibling));this.counter=this.counter?++this.counter:1;var counter=this.counter;this._delay(function(){if(counter===this.counter){this.refreshPositions(!hardRefresh);}});},_clear:function(event,noPropagation){this.reverting=false;var i,delayedTriggers=[];if(!this._noFinalSort&&this.currentItem.parent().length){this.placeholder.before(this.currentItem);}
this._noFinalSort=null;if(this.helper[0]===this.currentItem[0]){for(i in this._storedCSS){if(this._storedCSS[i]==="auto"||this._storedCSS[i]==="static"){this._storedCSS[i]="";}}
this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");}else{this.currentItem.show();}
if(this.fromOutside&&!noPropagation){delayedTriggers.push(function(event){this._trigger("receive",event,this._uiHash(this.fromOutside));});}
if((this.fromOutside||this.domPosition.prev!==this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!==this.currentItem.parent()[0])&&!noPropagation){delayedTriggers.push(function(event){this._trigger("update",event,this._uiHash());});}
if(this!==this.currentContainer){if(!noPropagation){delayedTriggers.push(function(event){this._trigger("remove",event,this._uiHash());});delayedTriggers.push((function(c){return function(event){c._trigger("receive",event,this._uiHash(this));};}).call(this,this.currentContainer));delayedTriggers.push((function(c){return function(event){c._trigger("update",event,this._uiHash(this));};}).call(this,this.currentContainer));}}
function delayEvent(type,instance,container){return function(event){container._trigger(type,event,instance._uiHash(instance));};}
for(i=this.containers.length-1;i>=0;i--){if(!noPropagation){delayedTriggers.push(delayEvent("deactivate",this,this.containers[i]));}
if(this.containers[i].containerCache.over){delayedTriggers.push(delayEvent("out",this,this.containers[i]));this.containers[i].containerCache.over=0;}}
if(this.storedCursor){this.document.find("body").css("cursor",this.storedCursor);this.storedStylesheet.remove();}
if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity);}
if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex==="auto"?"":this._storedZIndex);}
this.dragging=false;if(this.cancelHelperRemoval){if(!noPropagation){this._trigger("beforeStop",event,this._uiHash());for(i=0;i<delayedTriggers.length;i++){delayedTriggers[i].call(this,event);}
this._trigger("stop",event,this._uiHash());}
this.fromOutside=false;return false;}
if(!noPropagation){this._trigger("beforeStop",event,this._uiHash());}
this.placeholder[0].parentNode.removeChild(this.placeholder[0]);if(this.helper[0]!==this.currentItem[0]){this.helper.remove();}
this.helper=null;if(!noPropagation){for(i=0;i<delayedTriggers.length;i++){delayedTriggers[i].call(this,event);}
this._trigger("stop",event,this._uiHash());}
this.fromOutside=false;return true;},_trigger:function(){if($.Widget.prototype._trigger.apply(this,arguments)===false){this.cancel();}},_uiHash:function(_inst){var inst=_inst||this;return{helper:inst.helper,placeholder:inst.placeholder||$([]),position:inst.position,originalPosition:inst.originalPosition,offset:inst.positionAbs,item:inst.currentItem,sender:_inst?_inst.element:null};}});})(jQuery);(function($,undefined){var uid=0,hideProps={},showProps={};hideProps.height=hideProps.paddingTop=hideProps.paddingBottom=hideProps.borderTopWidth=hideProps.borderBottomWidth="hide";showProps.height=showProps.paddingTop=showProps.paddingBottom=showProps.borderTopWidth=showProps.borderBottomWidth="show";$.widget("ui.accordion",{version:"1.10.4",options:{active:0,animate:{},collapsible:false,event:"click",header:"> li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var options=this.options;this.prevShow=this.prevHide=$();this.element.addClass("ui-accordion ui-widget ui-helper-reset").attr("role","tablist");if(!options.collapsible&&(options.active===false||options.active==null)){options.active=0;}
this._processPanels();if(options.active<0){options.active+=this.headers.length;}
this._refresh();},_getCreateEventData:function(){return{header:this.active,panel:!this.active.length?$():this.active.next(),content:!this.active.length?$():this.active.next()};},_createIcons:function(){var icons=this.options.icons;if(icons){$("<span>").addClass("ui-accordion-header-icon ui-icon "+icons.header).prependTo(this.headers);this.active.children(".ui-accordion-header-icon").removeClass(icons.header).addClass(icons.activeHeader);this.headers.addClass("ui-accordion-icons");}},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove();},_destroy:function(){var contents;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){if(/^ui-accordion/.test(this.id)){this.removeAttribute("id");}});this._destroyIcons();contents=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){if(/^ui-accordion/.test(this.id)){this.removeAttribute("id");}});if(this.options.heightStyle!=="content"){contents.css("height","");}},_setOption:function(key,value){if(key==="active"){this._activate(value);return;}
if(key==="event"){if(this.options.event){this._off(this.headers,this.options.event);}
this._setupEvents(value);}
this._super(key,value);if(key==="collapsible"&&!value&&this.options.active===false){this._activate(0);}
if(key==="icons"){this._destroyIcons();if(value){this._createIcons();}}
if(key==="disabled"){this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!value);}},_keydown:function(event){if(event.altKey||event.ctrlKey){return;}
var keyCode=$.ui.keyCode,length=this.headers.length,currentIndex=this.headers.index(event.target),toFocus=false;switch(event.keyCode){case keyCode.RIGHT:case keyCode.DOWN:toFocus=this.headers[(currentIndex+1)%length];break;case keyCode.LEFT:case keyCode.UP:toFocus=this.headers[(currentIndex-1+length)%length];break;case keyCode.SPACE:case keyCode.ENTER:this._eventHandler(event);break;case keyCode.HOME:toFocus=this.headers[0];break;case keyCode.END:toFocus=this.headers[length-1];break;}
if(toFocus){$(event.target).attr("tabIndex",-1);$(toFocus).attr("tabIndex",0);toFocus.focus();event.preventDefault();}},_panelKeyDown:function(event){if(event.keyCode===$.ui.keyCode.UP&&event.ctrlKey){$(event.currentTarget).prev().focus();}},refresh:function(){var options=this.options;this._processPanels();if((options.active===false&&options.collapsible===true)||!this.headers.length){options.active=false;this.active=$();}else if(options.active===false){this._activate(0);}else if(this.active.length&&!$.contains(this.element[0],this.active[0])){if(this.headers.length===this.headers.find(".ui-state-disabled").length){options.active=false;this.active=$();}else{this._activate(Math.max(0,options.active-1));}}else{options.active=this.headers.index(this.active);}
this._destroyIcons();this._refresh();},_processPanels:function(){this.headers=this.element.find(this.options.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all");this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").filter(":not(.ui-accordion-content-active)").hide();},_refresh:function(){var maxHeight,options=this.options,heightStyle=options.heightStyle,parent=this.element.parent(),accordionId=this.accordionId="ui-accordion-"+
(this.element.attr("id")||++uid);this.active=this._findActive(options.active).addClass("ui-accordion-header-active ui-state-active ui-corner-top").removeClass("ui-corner-all");this.active.next().addClass("ui-accordion-content-active").show();this.headers.attr("role","tab").each(function(i){var header=$(this),headerId=header.attr("id"),panel=header.next(),panelId=panel.attr("id");if(!headerId){headerId=accordionId+"-header-"+i;header.attr("id",headerId);}
if(!panelId){panelId=accordionId+"-panel-"+i;panel.attr("id",panelId);}
header.attr("aria-controls",panelId);panel.attr("aria-labelledby",headerId);}).next().attr("role","tabpanel");this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex",0);}else{this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"});}
this._createIcons();this._setupEvents(options.event);if(heightStyle==="fill"){maxHeight=parent.height();this.element.siblings(":visible").each(function(){var elem=$(this),position=elem.css("position");if(position==="absolute"||position==="fixed"){return;}
maxHeight-=elem.outerHeight(true);});this.headers.each(function(){maxHeight-=$(this).outerHeight(true);});this.headers.next().each(function(){$(this).height(Math.max(0,maxHeight-
$(this).innerHeight()+$(this).height()));}).css("overflow","auto");}else if(heightStyle==="auto"){maxHeight=0;this.headers.next().each(function(){maxHeight=Math.max(maxHeight,$(this).css("height","").height());}).height(maxHeight);}},_activate:function(index){var active=this._findActive(index)[0];if(active===this.active[0]){return;}
active=active||this.active[0];this._eventHandler({target:active,currentTarget:active,preventDefault:$.noop});},_findActive:function(selector){return typeof selector==="number"?this.headers.eq(selector):$();},_setupEvents:function(event){var events={keydown:"_keydown"};if(event){$.each(event.split(" "),function(index,eventName){events[eventName]="_eventHandler";});}
this._off(this.headers.add(this.headers.next()));this._on(this.headers,events);this._on(this.headers.next(),{keydown:"_panelKeyDown"});this._hoverable(this.headers);this._focusable(this.headers);},_eventHandler:function(event){var options=this.options,active=this.active,clicked=$(event.currentTarget),clickedIsActive=clicked[0]===active[0],collapsing=clickedIsActive&&options.collapsible,toShow=collapsing?$():clicked.next(),toHide=active.next(),eventData={oldHeader:active,oldPanel:toHide,newHeader:collapsing?$():clicked,newPanel:toShow};event.preventDefault();if((clickedIsActive&&!options.collapsible)||(this._trigger("beforeActivate",event,eventData)===false)){return;}
options.active=collapsing?false:this.headers.index(clicked);this.active=clickedIsActive?$():clicked;this._toggle(eventData);active.removeClass("ui-accordion-header-active ui-state-active");if(options.icons){active.children(".ui-accordion-header-icon").removeClass(options.icons.activeHeader).addClass(options.icons.header);}
if(!clickedIsActive){clicked.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top");if(options.icons){clicked.children(".ui-accordion-header-icon").removeClass(options.icons.header).addClass(options.icons.activeHeader);}
clicked.next().addClass("ui-accordion-content-active");}},_toggle:function(data){var toShow=data.newPanel,toHide=this.prevShow.length?this.prevShow:data.oldPanel;this.prevShow.add(this.prevHide).stop(true,true);this.prevShow=toShow;this.prevHide=toHide;if(this.options.animate){this._animate(toShow,toHide,data);}else{toHide.hide();toShow.show();this._toggleComplete(data);}
toHide.attr({"aria-hidden":"true"});toHide.prev().attr("aria-selected","false");if(toShow.length&&toHide.length){toHide.prev().attr({"tabIndex":-1,"aria-expanded":"false"});}else if(toShow.length){this.headers.filter(function(){return $(this).attr("tabIndex")===0;}).attr("tabIndex",-1);}
toShow.attr("aria-hidden","false").prev().attr({"aria-selected":"true",tabIndex:0,"aria-expanded":"true"});},_animate:function(toShow,toHide,data){var total,easing,duration,that=this,adjust=0,down=toShow.length&&(!toHide.length||(toShow.index()<toHide.index())),animate=this.options.animate||{},options=down&&animate.down||animate,complete=function(){that._toggleComplete(data);};if(typeof options==="number"){duration=options;}
if(typeof options==="string"){easing=options;}
easing=easing||options.easing||animate.easing;duration=duration||options.duration||animate.duration;if(!toHide.length){return toShow.animate(showProps,duration,easing,complete);}
if(!toShow.length){return toHide.animate(hideProps,duration,easing,complete);}
total=toShow.show().outerHeight();toHide.animate(hideProps,{duration:duration,easing:easing,step:function(now,fx){fx.now=Math.round(now);}});toShow.hide().animate(showProps,{duration:duration,easing:easing,complete:complete,step:function(now,fx){fx.now=Math.round(now);if(fx.prop!=="height"){adjust+=fx.now;}else if(that.options.heightStyle!=="content"){fx.now=Math.round(total-toHide.outerHeight()-adjust);adjust=0;}}});},_toggleComplete:function(data){var toHide=data.oldPanel;toHide.removeClass("ui-accordion-content-active").prev().removeClass("ui-corner-top").addClass("ui-corner-all");if(toHide.length){toHide.parent()[0].className=toHide.parent()[0].className;}
this._trigger("activate",null,data);}});})(jQuery);(function($,undefined){$.widget("ui.autocomplete",{version:"1.10.4",defaultElement:"<input>",options:{appendTo:null,autoFocus:false,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"flip"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,_create:function(){var suppressKeyPress,suppressKeyPressRepeat,suppressInput,nodeName=this.element[0].nodeName.toLowerCase(),isTextarea=nodeName==="textarea",isInput=nodeName==="input";this.isMultiLine=isTextarea?true:isInput?false:this.element.prop("isContentEditable");this.valueMethod=this.element[isTextarea||isInput?"val":"text"];this.isNewMenu=true;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off");this._on(this.element,{keydown:function(event){if(this.element.prop("readOnly")){suppressKeyPress=true;suppressInput=true;suppressKeyPressRepeat=true;return;}
suppressKeyPress=false;suppressInput=false;suppressKeyPressRepeat=false;var keyCode=$.ui.keyCode;switch(event.keyCode){case keyCode.PAGE_UP:suppressKeyPress=true;this._move("previousPage",event);break;case keyCode.PAGE_DOWN:suppressKeyPress=true;this._move("nextPage",event);break;case keyCode.UP:suppressKeyPress=true;this._keyEvent("previous",event);break;case keyCode.DOWN:suppressKeyPress=true;this._keyEvent("next",event);break;case keyCode.ENTER:case keyCode.NUMPAD_ENTER:if(this.menu.active){suppressKeyPress=true;event.preventDefault();this.menu.select(event);}
break;case keyCode.TAB:if(this.menu.active){this.menu.select(event);}
break;case keyCode.ESCAPE:if(this.menu.element.is(":visible")){this._value(this.term);this.close(event);event.preventDefault();}
break;default:suppressKeyPressRepeat=true;this._searchTimeout(event);break;}},keypress:function(event){if(suppressKeyPress){suppressKeyPress=false;if(!this.isMultiLine||this.menu.element.is(":visible")){event.preventDefault();}
return;}
if(suppressKeyPressRepeat){return;}
var keyCode=$.ui.keyCode;switch(event.keyCode){case keyCode.PAGE_UP:this._move("previousPage",event);break;case keyCode.PAGE_DOWN:this._move("nextPage",event);break;case keyCode.UP:this._keyEvent("previous",event);break;case keyCode.DOWN:this._keyEvent("next",event);break;}},input:function(event){if(suppressInput){suppressInput=false;event.preventDefault();return;}
this._searchTimeout(event);},focus:function(){this.selectedItem=null;this.previous=this._value();},blur:function(event){if(this.cancelBlur){delete this.cancelBlur;return;}
clearTimeout(this.searching);this.close(event);this._change(event);}});this._initSource();this.menu=$("<ul>").addClass("ui-autocomplete ui-front").appendTo(this._appendTo()).menu({role:null}).hide().data("ui-menu");this._on(this.menu.element,{mousedown:function(event){event.preventDefault();this.cancelBlur=true;this._delay(function(){delete this.cancelBlur;});var menuElement=this.menu.element[0];if(!$(event.target).closest(".ui-menu-item").length){this._delay(function(){var that=this;this.document.one("mousedown",function(event){if(event.target!==that.element[0]&&event.target!==menuElement&&!$.contains(menuElement,event.target)){that.close();}});});}},menufocus:function(event,ui){if(this.isNewMenu){this.isNewMenu=false;if(event.originalEvent&&/^mouse/.test(event.originalEvent.type)){this.menu.blur();this.document.one("mousemove",function(){$(event.target).trigger(event.originalEvent);});return;}}
var item=ui.item.data("ui-autocomplete-item");if(false!==this._trigger("focus",event,{item:item})){if(event.originalEvent&&/^key/.test(event.originalEvent.type)){this._value(item.value);}}else{this.liveRegion.text(item.value);}},menuselect:function(event,ui){var item=ui.item.data("ui-autocomplete-item"),previous=this.previous;if(this.element[0]!==this.document[0].activeElement){this.element.focus();this.previous=previous;this._delay(function(){this.previous=previous;this.selectedItem=item;});}
if(false!==this._trigger("select",event,{item:item})){this._value(item.value);}
this.term=this._value();this.close(event);this.selectedItem=item;}});this.liveRegion=$("<span>",{role:"status","aria-live":"polite"}).addClass("ui-helper-hidden-accessible").insertBefore(this.element);this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete");}});},_destroy:function(){clearTimeout(this.searching);this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete");this.menu.element.remove();this.liveRegion.remove();},_setOption:function(key,value){this._super(key,value);if(key==="source"){this._initSource();}
if(key==="appendTo"){this.menu.element.appendTo(this._appendTo());}
if(key==="disabled"&&value&&this.xhr){this.xhr.abort();}},_appendTo:function(){var element=this.options.appendTo;if(element){element=element.jquery||element.nodeType?$(element):this.document.find(element).eq(0);}
if(!element){element=this.element.closest(".ui-front");}
if(!element.length){element=this.document[0].body;}
return element;},_initSource:function(){var array,url,that=this;if($.isArray(this.options.source)){array=this.options.source;this.source=function(request,response){response($.ui.autocomplete.filter(array,request.term));};}else if(typeof this.options.source==="string"){url=this.options.source;this.source=function(request,response){if(that.xhr){that.xhr.abort();}
that.xhr=$.ajax({url:url,data:request,dataType:"json",success:function(data){response(data);},error:function(){response([]);}});};}else{this.source=this.options.source;}},_searchTimeout:function(event){clearTimeout(this.searching);this.searching=this._delay(function(){if(this.term!==this._value()){this.selectedItem=null;this.search(null,event);}},this.options.delay);},search:function(value,event){value=value!=null?value:this._value();this.term=this._value();if(value.length<this.options.minLength){return this.close(event);}
if(this._trigger("search",event)===false){return;}
return this._search(value);},_search:function(value){this.pending++;this.element.addClass("ui-autocomplete-loading");this.cancelSearch=false;this.source({term:value},this._response());},_response:function(){var index=++this.requestIndex;return $.proxy(function(content){if(index===this.requestIndex){this.__response(content);}
this.pending--;if(!this.pending){this.element.removeClass("ui-autocomplete-loading");}},this);},__response:function(content){if(content){content=this._normalize(content);}
this._trigger("response",null,{content:content});if(!this.options.disabled&&content&&content.length&&!this.cancelSearch){this._suggest(content);this._trigger("open");}else{this._close();}},close:function(event){this.cancelSearch=true;this._close(event);},_close:function(event){if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.blur();this.isNewMenu=true;this._trigger("close",event);}},_change:function(event){if(this.previous!==this._value()){this._trigger("change",event,{item:this.selectedItem});}},_normalize:function(items){if(items.length&&items[0].label&&items[0].value){return items;}
return $.map(items,function(item){if(typeof item==="string"){return{label:item,value:item};}
return $.extend({label:item.label||item.value,value:item.value||item.label},item);});},_suggest:function(items){var ul=this.menu.element.empty();this._renderMenu(ul,items);this.isNewMenu=true;this.menu.refresh();ul.show();this._resizeMenu();ul.position($.extend({of:this.element},this.options.position));if(this.options.autoFocus){this.menu.next();}},_resizeMenu:function(){var ul=this.menu.element;ul.outerWidth(Math.max(ul.width("").outerWidth()+1,this.element.outerWidth()));},_renderMenu:function(ul,items){var that=this;$.each(items,function(index,item){that._renderItemData(ul,item);});},_renderItemData:function(ul,item){return this._renderItem(ul,item).data("ui-autocomplete-item",item);},_renderItem:function(ul,item){return $("<li>").append($("<a>").text(item.label)).appendTo(ul);},_move:function(direction,event){if(!this.menu.element.is(":visible")){this.search(null,event);return;}
if(this.menu.isFirstItem()&&/^previous/.test(direction)||this.menu.isLastItem()&&/^next/.test(direction)){this._value(this.term);this.menu.blur();return;}
this.menu[direction](event);},widget:function(){return this.menu.element;},_value:function(){return this.valueMethod.apply(this.element,arguments);},_keyEvent:function(keyEvent,event){if(!this.isMultiLine||this.menu.element.is(":visible")){this._move(keyEvent,event);event.preventDefault();}}});$.extend($.ui.autocomplete,{escapeRegex:function(value){return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");},filter:function(array,term){var matcher=new RegExp($.ui.autocomplete.escapeRegex(term),"i");return $.grep(array,function(value){return matcher.test(value.label||value.value||value);});}});$.widget("ui.autocomplete",$.ui.autocomplete,{options:{messages:{noResults:"No search results.",results:function(amount){return amount+(amount>1?" results are":" result is")+" available, use up and down arrow keys to navigate.";}}},__response:function(content){var message;this._superApply(arguments);if(this.options.disabled||this.cancelSearch){return;}
if(content&&content.length){message=this.options.messages.results(content.length);}else{message=this.options.messages.noResults;}
this.liveRegion.text(message);}});}(jQuery));(function($,undefined){var lastActive,baseClasses="ui-button ui-widget ui-state-default ui-corner-all",typeClasses="ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",formResetHandler=function(){var form=$(this);setTimeout(function(){form.find(":ui-button").button("refresh");},1);},radioGroup=function(radio){var name=radio.name,form=radio.form,radios=$([]);if(name){name=name.replace(/'/g,"\\'");if(form){radios=$(form).find("[name='"+name+"']");}else{radios=$("[name='"+name+"']",radio.ownerDocument).filter(function(){return!this.form;});}}
return radios;};$.widget("ui.button",{version:"1.10.4",defaultElement:"<button>",options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset"+this.eventNamespace).bind("reset"+this.eventNamespace,formResetHandler);if(typeof this.options.disabled!=="boolean"){this.options.disabled=!!this.element.prop("disabled");}else{this.element.prop("disabled",this.options.disabled);}
this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var that=this,options=this.options,toggleButton=this.type==="checkbox"||this.type==="radio",activeClass=!toggleButton?"ui-state-active":"";if(options.label===null){options.label=(this.type==="input"?this.buttonElement.val():this.buttonElement.html());}
this._hoverable(this.buttonElement);this.buttonElement.addClass(baseClasses).attr("role","button").bind("mouseenter"+this.eventNamespace,function(){if(options.disabled){return;}
if(this===lastActive){$(this).addClass("ui-state-active");}}).bind("mouseleave"+this.eventNamespace,function(){if(options.disabled){return;}
$(this).removeClass(activeClass);}).bind("click"+this.eventNamespace,function(event){if(options.disabled){event.preventDefault();event.stopImmediatePropagation();}});this._on({focus:function(){this.buttonElement.addClass("ui-state-focus");},blur:function(){this.buttonElement.removeClass("ui-state-focus");}});if(toggleButton){this.element.bind("change"+this.eventNamespace,function(){that.refresh();});}
if(this.type==="checkbox"){this.buttonElement.bind("click"+this.eventNamespace,function(){if(options.disabled){return false;}});}else if(this.type==="radio"){this.buttonElement.bind("click"+this.eventNamespace,function(){if(options.disabled){return false;}
$(this).addClass("ui-state-active");that.buttonElement.attr("aria-pressed","true");var radio=that.element[0];radioGroup(radio).not(radio).map(function(){return $(this).button("widget")[0];}).removeClass("ui-state-active").attr("aria-pressed","false");});}else{this.buttonElement.bind("mousedown"+this.eventNamespace,function(){if(options.disabled){return false;}
$(this).addClass("ui-state-active");lastActive=this;that.document.one("mouseup",function(){lastActive=null;});}).bind("mouseup"+this.eventNamespace,function(){if(options.disabled){return false;}
$(this).removeClass("ui-state-active");}).bind("keydown"+this.eventNamespace,function(event){if(options.disabled){return false;}
if(event.keyCode===$.ui.keyCode.SPACE||event.keyCode===$.ui.keyCode.ENTER){$(this).addClass("ui-state-active");}}).bind("keyup"+this.eventNamespace+" blur"+this.eventNamespace,function(){$(this).removeClass("ui-state-active");});if(this.buttonElement.is("a")){this.buttonElement.keyup(function(event){if(event.keyCode===$.ui.keyCode.SPACE){$(this).click();}});}}
this._setOption("disabled",options.disabled);this._resetButton();},_determineButtonType:function(){var ancestor,labelSelector,checked;if(this.element.is("[type=checkbox]")){this.type="checkbox";}else if(this.element.is("[type=radio]")){this.type="radio";}else if(this.element.is("input")){this.type="input";}else{this.type="button";}
if(this.type==="checkbox"||this.type==="radio"){ancestor=this.element.parents().last();labelSelector="label[for='"+this.element.attr("id")+"']";this.buttonElement=ancestor.find(labelSelector);if(!this.buttonElement.length){ancestor=ancestor.length?ancestor.siblings():this.element.siblings();this.buttonElement=ancestor.filter(labelSelector);if(!this.buttonElement.length){this.buttonElement=ancestor.find(labelSelector);}}
this.element.addClass("ui-helper-hidden-accessible");checked=this.element.is(":checked");if(checked){this.buttonElement.addClass("ui-state-active");}
this.buttonElement.prop("aria-pressed",checked);}else{this.buttonElement=this.element;}},widget:function(){return this.buttonElement;},_destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass(baseClasses+" ui-state-active "+typeClasses).removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());if(!this.hasTitle){this.buttonElement.removeAttr("title");}},_setOption:function(key,value){this._super(key,value);if(key==="disabled"){this.element.prop("disabled",!!value);if(value){this.buttonElement.removeClass("ui-state-focus");}
return;}
this._resetButton();},refresh:function(){var isDisabled=this.element.is("input, button")?this.element.is(":disabled"):this.element.hasClass("ui-button-disabled");if(isDisabled!==this.options.disabled){this._setOption("disabled",isDisabled);}
if(this.type==="radio"){radioGroup(this.element[0]).each(function(){if($(this).is(":checked")){$(this).button("widget").addClass("ui-state-active").attr("aria-pressed","true");}else{$(this).button("widget").removeClass("ui-state-active").attr("aria-pressed","false");}});}else if(this.type==="checkbox"){if(this.element.is(":checked")){this.buttonElement.addClass("ui-state-active").attr("aria-pressed","true");}else{this.buttonElement.removeClass("ui-state-active").attr("aria-pressed","false");}}},_resetButton:function(){if(this.type==="input"){if(this.options.label){this.element.val(this.options.label);}
return;}
var buttonElement=this.buttonElement.removeClass(typeClasses),buttonText=$("<span></span>",this.document[0]).addClass("ui-button-text").html(this.options.label).appendTo(buttonElement.empty()).text(),icons=this.options.icons,multipleIcons=icons.primary&&icons.secondary,buttonClasses=[];if(icons.primary||icons.secondary){if(this.options.text){buttonClasses.push("ui-button-text-icon"+(multipleIcons?"s":(icons.primary?"-primary":"-secondary")));}
if(icons.primary){buttonElement.prepend("<span class='ui-button-icon-primary ui-icon "+icons.primary+"'></span>");}
if(icons.secondary){buttonElement.append("<span class='ui-button-icon-secondary ui-icon "+icons.secondary+"'></span>");}
if(!this.options.text){buttonClasses.push(multipleIcons?"ui-button-icons-only":"ui-button-icon-only");if(!this.hasTitle){buttonElement.attr("title",$.trim(buttonText));}}}else{buttonClasses.push("ui-button-text-only");}
buttonElement.addClass(buttonClasses.join(" "));}});$.widget("ui.buttonset",{version:"1.10.4",options:{items:"button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"},_create:function(){this.element.addClass("ui-buttonset");},_init:function(){this.refresh();},_setOption:function(key,value){if(key==="disabled"){this.buttons.button("option",key,value);}
this._super(key,value);},refresh:function(){var rtl=this.element.css("direction")==="rtl";this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return $(this).button("widget")[0];}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass(rtl?"ui-corner-right":"ui-corner-left").end().filter(":last").addClass(rtl?"ui-corner-left":"ui-corner-right").end().end();},_destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return $(this).button("widget")[0];}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");}});}(jQuery));(function($,undefined){$.extend($.ui,{datepicker:{version:"1.10.4"}});var PROP_NAME="datepicker",instActive;function Datepicker(){this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._datepickerShowing=false;this._inDialog=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass="ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false,disabled:false};$.extend(this._defaults,this.regional[""]);this.dpDiv=bindHover($("<div id='"+this._mainDivId+"' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));}
$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,_widgetDatepicker:function(){return this.dpDiv;},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this;},_attachDatepicker:function(target,settings){var nodeName,inline,inst;nodeName=target.nodeName.toLowerCase();inline=(nodeName==="div"||nodeName==="span");if(!target.id){this.uuid+=1;target.id="dp"+this.uuid;}
inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{});if(nodeName==="input"){this._connectDatepicker(target,inst);}else if(inline){this._inlineDatepicker(target,inst);}},_newInst:function(target,inline){var id=target[0].id.replace(/([^A-Za-z0-9_\-])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:bindHover($("<div class='"+this._inlineClass+" ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return;}
this._attachments(input,inst);input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp);this._autoSize(inst);$.data(target,PROP_NAME,inst);if(inst.settings.disabled){this._disableDatepicker(target);}},_attachments:function(input,inst){var showOn,buttonText,buttonImage,appendText=this._get(inst,"appendText"),isRTL=this._get(inst,"isRTL");if(inst.append){inst.append.remove();}
if(appendText){inst.append=$("<span class='"+this._appendClass+"'>"+appendText+"</span>");input[isRTL?"before":"after"](inst.append);}
input.unbind("focus",this._showDatepicker);if(inst.trigger){inst.trigger.remove();}
showOn=this._get(inst,"showOn");if(showOn==="focus"||showOn==="both"){input.focus(this._showDatepicker);}
if(showOn==="button"||showOn==="both"){buttonText=this._get(inst,"buttonText");buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$("<button type='button'></button>").addClass(this._triggerClass).html(!buttonImage?buttonText:$("<img/>").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput===input[0]){$.datepicker._hideDatepicker();}else if($.datepicker._datepickerShowing&&$.datepicker._lastInput!==input[0]){$.datepicker._hideDatepicker();$.datepicker._showDatepicker(input[0]);}else{$.datepicker._showDatepicker(input[0]);}
return false;});}},_autoSize:function(inst){if(this._get(inst,"autoSize")&&!inst.inline){var findMax,max,maxI,i,date=new Date(2009,12-1,20),dateFormat=this._get(inst,"dateFormat");if(dateFormat.match(/[DM]/)){findMax=function(names){max=0;maxI=0;for(i=0;i<names.length;i++){if(names[i].length>max){max=names[i].length;maxI=i;}}
return maxI;};date.setMonth(findMax(this._get(inst,(dateFormat.match(/MM/)?"monthNames":"monthNamesShort"))));date.setDate(findMax(this._get(inst,(dateFormat.match(/DD/)?"dayNames":"dayNamesShort")))+20-date.getDay());}
inst.input.attr("size",this._formatDate(inst,date).length);}},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return;}
divSpan.addClass(this.markerClassName).append(inst.dpDiv);$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst),true);this._updateDatepicker(inst);this._updateAlternate(inst);if(inst.settings.disabled){this._disableDatepicker(target);}
inst.dpDiv.css("display","block");},_dialogDatepicker:function(input,date,onSelect,settings,pos){var id,browserWidth,browserHeight,scrollX,scrollY,inst=this._dialogInst;if(!inst){this.uuid+=1;id="dp"+this.uuid;this._dialogInput=$("<input type='text' id='"+id+"' style='position: absolute; top: -100px; width: 0px;'/>");this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst);}
extendRemove(inst.settings,settings||{});date=(date&&date.constructor===Date?this._formatDate(inst,date):date);this._dialogInput.val(date);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){browserWidth=document.documentElement.clientWidth;browserHeight=document.documentElement.clientHeight;scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY];}
this._dialogInput.css("left",(this._pos[0]+20)+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv);}
$.data(this._dialogInput[0],PROP_NAME,inst);return this;},_destroyDatepicker:function(target){var nodeName,$target=$(target),inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName==="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp);}else if(nodeName==="div"||nodeName==="span"){$target.removeClass(this.markerClassName).empty();}},_enableDatepicker:function(target){var nodeName,inline,$target=$(target),inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
nodeName=target.nodeName.toLowerCase();if(nodeName==="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false;}).end().filter("img").css({opacity:"1.0",cursor:""});}else if(nodeName==="div"||nodeName==="span"){inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled");inline.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",false);}
this._disabledInputs=$.map(this._disabledInputs,function(value){return(value===target?null:value);});},_disableDatepicker:function(target){var nodeName,inline,$target=$(target),inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
nodeName=target.nodeName.toLowerCase();if(nodeName==="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true;}).end().filter("img").css({opacity:"0.5",cursor:"default"});}else if(nodeName==="div"||nodeName==="span"){inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled");inline.find("select.ui-datepicker-month, select.ui-datepicker-year").prop("disabled",true);}
this._disabledInputs=$.map(this._disabledInputs,function(value){return(value===target?null:value);});this._disabledInputs[this._disabledInputs.length]=target;},_isDisabledDatepicker:function(target){if(!target){return false;}
for(var i=0;i<this._disabledInputs.length;i++){if(this._disabledInputs[i]===target){return true;}}
return false;},_getInst:function(target){try{return $.data(target,PROP_NAME);}
catch(err){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(target,name,value){var settings,date,minDate,maxDate,inst=this._getInst(target);if(arguments.length===2&&typeof name==="string"){return(name==="defaults"?$.extend({},$.datepicker._defaults):(inst?(name==="all"?$.extend({},inst.settings):this._get(inst,name)):null));}
settings=name||{};if(typeof name==="string"){settings={};settings[name]=value;}
if(inst){if(this._curInst===inst){this._hideDatepicker();}
date=this._getDateDatepicker(target,true);minDate=this._getMinMaxDate(inst,"min");maxDate=this._getMinMaxDate(inst,"max");extendRemove(inst.settings,settings);if(minDate!==null&&settings.dateFormat!==undefined&&settings.minDate===undefined){inst.settings.minDate=this._formatDate(inst,minDate);}
if(maxDate!==null&&settings.dateFormat!==undefined&&settings.maxDate===undefined){inst.settings.maxDate=this._formatDate(inst,maxDate);}
if("disabled"in settings){if(settings.disabled){this._disableDatepicker(target);}else{this._enableDatepicker(target);}}
this._attachments($(target),inst);this._autoSize(inst);this._setDate(inst,date);this._updateAlternate(inst);this._updateDatepicker(inst);}},_changeDatepicker:function(target,name,value){this._optionDatepicker(target,name,value);},_refreshDatepicker:function(target){var inst=this._getInst(target);if(inst){this._updateDatepicker(inst);}},_setDateDatepicker:function(target,date){var inst=this._getInst(target);if(inst){this._setDate(inst,date);this._updateDatepicker(inst);this._updateAlternate(inst);}},_getDateDatepicker:function(target,noDefault){var inst=this._getInst(target);if(inst&&!inst.inline){this._setDateFromField(inst,noDefault);}
return(inst?this._getDate(inst):null);},_doKeyDown:function(event){var onSelect,dateStr,sel,inst=$.datepicker._getInst(event.target),handled=true,isRTL=inst.dpDiv.is(".ui-datepicker-rtl");inst._keyEvent=true;if($.datepicker._datepickerShowing){switch(event.keyCode){case 9:$.datepicker._hideDatepicker();handled=false;break;case 13:sel=$("td."+$.datepicker._dayOverClass+":not(."+
$.datepicker._currentClass+")",inst.dpDiv);if(sel[0]){$.datepicker._selectDay(event.target,inst.selectedMonth,inst.selectedYear,sel[0]);}
onSelect=$.datepicker._get(inst,"onSelect");if(onSelect){dateStr=$.datepicker._formatDate(inst);onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst]);}else{$.datepicker._hideDatepicker();}
return false;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M");break;case 34:$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M");break;case 35:if(event.ctrlKey||event.metaKey){$.datepicker._clearDate(event.target);}
handled=event.ctrlKey||event.metaKey;break;case 36:if(event.ctrlKey||event.metaKey){$.datepicker._gotoToday(event.target);}
handled=event.ctrlKey||event.metaKey;break;case 37:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?+1:-1),"D");}
handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?-$.datepicker._get(inst,"stepBigMonths"):-$.datepicker._get(inst,"stepMonths")),"M");}
break;case 38:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,-7,"D");}
handled=event.ctrlKey||event.metaKey;break;case 39:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,(isRTL?-1:+1),"D");}
handled=event.ctrlKey||event.metaKey;if(event.originalEvent.altKey){$.datepicker._adjustDate(event.target,(event.ctrlKey?+$.datepicker._get(inst,"stepBigMonths"):+$.datepicker._get(inst,"stepMonths")),"M");}
break;case 40:if(event.ctrlKey||event.metaKey){$.datepicker._adjustDate(event.target,+7,"D");}
handled=event.ctrlKey||event.metaKey;break;default:handled=false;}}else if(event.keyCode===36&&event.ctrlKey){$.datepicker._showDatepicker(this);}else{handled=false;}
if(handled){event.preventDefault();event.stopPropagation();}},_doKeyPress:function(event){var chars,chr,inst=$.datepicker._getInst(event.target);if($.datepicker._get(inst,"constrainInput")){chars=$.datepicker._possibleChars($.datepicker._get(inst,"dateFormat"));chr=String.fromCharCode(event.charCode==null?event.keyCode:event.charCode);return event.ctrlKey||event.metaKey||(chr<" "||!chars||chars.indexOf(chr)>-1);}},_doKeyUp:function(event){var date,inst=$.datepicker._getInst(event.target);if(inst.input.val()!==inst.lastVal){try{date=$.datepicker.parseDate($.datepicker._get(inst,"dateFormat"),(inst.input?inst.input.val():null),$.datepicker._getFormatConfig(inst));if(date){$.datepicker._setDateFromField(inst);$.datepicker._updateAlternate(inst);$.datepicker._updateDatepicker(inst);}}
catch(err){}}
return true;},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!=="input"){input=$("input",input.parentNode)[0];}
if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput===input){return;}
var inst,beforeShow,beforeShowSettings,isFixed,offset,showAnim,duration;inst=$.datepicker._getInst(input);if($.datepicker._curInst&&$.datepicker._curInst!==inst){$.datepicker._curInst.dpDiv.stop(true,true);if(inst&&$.datepicker._datepickerShowing){$.datepicker._hideDatepicker($.datepicker._curInst.input[0]);}}
beforeShow=$.datepicker._get(inst,"beforeShow");beforeShowSettings=beforeShow?beforeShow.apply(input,[input,inst]):{};if(beforeShowSettings===false){return;}
extendRemove(inst.settings,beforeShowSettings);inst.lastVal=null;$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value="";}
if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight;}
isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")==="fixed";return!isFixed;});offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.dpDiv.empty();inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){showAnim=$.datepicker._get(inst,"showAnim");duration=$.datepicker._get(inst,"duration");inst.dpDiv.zIndex($(input).zIndex()+1);$.datepicker._datepickerShowing=true;if($.effects&&$.effects.effect[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration);}else{inst.dpDiv[showAnim||"show"](showAnim?duration:null);}
if($.datepicker._shouldFocusInput(inst)){inst.input.focus();}
$.datepicker._curInst=inst;}},_updateDatepicker:function(inst){this.maxRows=4;instActive=inst;inst.dpDiv.empty().append(this._generateHTML(inst));this._attachHandlers(inst);inst.dpDiv.find("."+this._dayOverClass+" a").mouseover();var origyearshtml,numMonths=this._getNumberOfMonths(inst),cols=numMonths[1],width=17;inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em");}
inst.dpDiv[(numMonths[0]!==1||numMonths[1]!==1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst===$.datepicker._curInst&&$.datepicker._datepickerShowing&&$.datepicker._shouldFocusInput(inst)){inst.input.focus();}
if(inst.yearshtml){origyearshtml=inst.yearshtml;setTimeout(function(){if(origyearshtml===inst.yearshtml&&inst.yearshtml){inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);}
origyearshtml=inst.yearshtml=null;},0);}},_shouldFocusInput:function(inst){return inst.input&&inst.input.is(":visible")&&!inst.input.is(":disabled")&&!inst.input.is(":focus");},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth(),dpHeight=inst.dpDiv.outerHeight(),inputWidth=inst.input?inst.input.outerWidth():0,inputHeight=inst.input?inst.input.outerHeight():0,viewWidth=document.documentElement.clientWidth+(isFixed?0:$(document).scrollLeft()),viewHeight=document.documentElement.clientHeight+(isFixed?0:$(document).scrollTop());offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left===inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top===(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=Math.min(offset.left,(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0);offset.top-=Math.min(offset.top,(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(dpHeight+inputHeight):0);return offset;},_findPos:function(obj){var position,inst=this._getInst(obj),isRTL=this._get(inst,"isRTL");while(obj&&(obj.type==="hidden"||obj.nodeType!==1||$.expr.filters.hidden(obj))){obj=obj[isRTL?"previousSibling":"nextSibling"];}
position=$(obj).offset();return[position.left,position.top];},_hideDatepicker:function(input){var showAnim,duration,postProcess,onClose,inst=this._curInst;if(!inst||(input&&inst!==$.data(input,PROP_NAME))){return;}
if(this._datepickerShowing){showAnim=this._get(inst,"showAnim");duration=this._get(inst,"duration");postProcess=function(){$.datepicker._tidyDialog(inst);};if($.effects&&($.effects.effect[showAnim]||$.effects[showAnim])){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess);}else{inst.dpDiv[(showAnim==="slideDown"?"slideUp":(showAnim==="fadeIn"?"fadeOut":"hide"))]((showAnim?duration:null),postProcess);}
if(!showAnim){postProcess();}
this._datepickerShowing=false;onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst]);}
this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv);}}
this._inDialog=false;}},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");},_checkExternalClick:function(event){if(!$.datepicker._curInst){return;}
var $target=$(event.target),inst=$.datepicker._getInst($target[0]);if((($target[0].id!==$.datepicker._mainDivId&&$target.parents("#"+$.datepicker._mainDivId).length===0&&!$target.hasClass($.datepicker.markerClassName)&&!$target.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)))||($target.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!==inst)){$.datepicker._hideDatepicker();}},_adjustDate:function(id,offset,period){var target=$(id),inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return;}
this._adjustInstDate(inst,offset+
(period==="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst);},_gotoToday:function(id){var date,target=$(id),inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear;}else{date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();}
this._notifyChange(inst);this._adjustDate(target);},_selectMonthYear:function(id,select,period){var target=$(id),inst=this._getInst(target[0]);inst["selected"+(period==="M"?"Month":"Year")]=inst["draw"+(period==="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target);},_selectDay:function(id,month,year,td){var inst,target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return;}
inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));},_clearDate:function(id){var target=$(id);this._selectDate(target,"");},_selectDate:function(id,dateStr){var onSelect,target=$(id),inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr);}
this._updateAlternate(inst);onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst]);}else if(inst.input){inst.input.trigger("change");}
if(inst.inline){this._updateDatepicker(inst);}else{this._hideDatepicker();this._lastInput=inst.input[0];if(typeof(inst.input[0])!=="object"){inst.input.focus();}
this._lastInput=null;}},_updateAlternate:function(inst){var altFormat,date,dateStr,altField=this._get(inst,"altField");if(altField){altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr);});}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""];},iso8601Week:function(date){var time,checkDate=new Date(date.getTime());checkDate.setDate(checkDate.getDate()+4-(checkDate.getDay()||7));time=checkDate.getTime();checkDate.setMonth(0);checkDate.setDate(1);return Math.floor(Math.round((time-checkDate)/86400000)/7)+1;},parseDate:function(format,value,settings){if(format==null||value==null){throw"Invalid arguments";}
value=(typeof value==="object"?value.toString():value+"");if(value===""){return null;}
var iFormat,dim,extra,iValue=0,shortYearCutoffTemp=(settings?settings.shortYearCutoff:null)||this._defaults.shortYearCutoff,shortYearCutoff=(typeof shortYearCutoffTemp!=="string"?shortYearCutoffTemp:new Date().getFullYear()%100+parseInt(shortYearCutoffTemp,10)),dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort,dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames,monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort,monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames,year=-1,month=-1,day=-1,doy=-1,literal=false,date,lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)===match);if(matches){iFormat++;}
return matches;},getNumber=function(match){var isDoubled=lookAhead(match),size=(match==="@"?14:(match==="!"?20:(match==="y"&&isDoubled?4:(match==="o"?3:2)))),digits=new RegExp("^\\d{1,"+size+"}"),num=value.substring(iValue).match(digits);if(!num){throw"Missing number at position "+iValue;}
iValue+=num[0].length;return parseInt(num[0],10);},getName=function(match,shortNames,longNames){var index=-1,names=$.map(lookAhead(match)?longNames:shortNames,function(v,k){return[[k,v]];}).sort(function(a,b){return-(a[1].length-b[1].length);});$.each(names,function(i,pair){var name=pair[1];if(value.substr(iValue,name.length).toLowerCase()===name.toLowerCase()){index=pair[0];iValue+=name.length;return false;}});if(index!==-1){return index+1;}else{throw"Unknown name at position "+iValue;}},checkLiteral=function(){if(value.charAt(iValue)!==format.charAt(iFormat)){throw"Unexpected literal at position "+iValue;}
iValue++;};for(iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)==="'"&&!lookAhead("'")){literal=false;}else{checkLiteral();}}else{switch(format.charAt(iFormat)){case"d":day=getNumber("d");break;case"D":getName("D",dayNamesShort,dayNames);break;case"o":doy=getNumber("o");break;case"m":month=getNumber("m");break;case"M":month=getName("M",monthNamesShort,monthNames);break;case"y":year=getNumber("y");break;case"@":date=new Date(getNumber("@"));year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"!":date=new Date((getNumber("!")-this._ticksTo1970)/10000);year=date.getFullYear();month=date.getMonth()+1;day=date.getDate();break;case"'":if(lookAhead("'")){checkLiteral();}else{literal=true;}
break;default:checkLiteral();}}}
if(iValue<value.length){extra=value.substr(iValue);if(!/^\s+/.test(extra)){throw"Extra/unparsed characters found in date: "+extra;}}
if(year===-1){year=new Date().getFullYear();}else if(year<100){year+=new Date().getFullYear()-new Date().getFullYear()%100+
(year<=shortYearCutoff?0:-100);}
if(doy>-1){month=1;day=doy;do{dim=this._getDaysInMonth(year,month-1);if(day<=dim){break;}
month++;day-=dim;}while(true);}
date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!==year||date.getMonth()+1!==month||date.getDate()!==day){throw"Invalid date";}
return date;},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(((1970-1)*365+Math.floor(1970/4)-Math.floor(1970/100)+
Math.floor(1970/400))*24*60*60*10000000),formatDate:function(format,date,settings){if(!date){return"";}
var iFormat,dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort,dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames,monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort,monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames,lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)===match);if(matches){iFormat++;}
return matches;},formatNumber=function(match,value,len){var num=""+value;if(lookAhead(match)){while(num.length<len){num="0"+num;}}
return num;},formatName=function(match,value,shortNames,longNames){return(lookAhead(match)?longNames[value]:shortNames[value]);},output="",literal=false;if(date){for(iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)==="'"&&!lookAhead("'")){literal=false;}else{output+=format.charAt(iFormat);}}else{switch(format.charAt(iFormat)){case"d":output+=formatNumber("d",date.getDate(),2);break;case"D":output+=formatName("D",date.getDay(),dayNamesShort,dayNames);break;case"o":output+=formatNumber("o",Math.round((new Date(date.getFullYear(),date.getMonth(),date.getDate()).getTime()-new Date(date.getFullYear(),0,0).getTime())/86400000),3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"!":output+=date.getTime()*10000+this._ticksTo1970;break;case"'":if(lookAhead("'")){output+="'";}else{literal=true;}
break;default:output+=format.charAt(iFormat);}}}}
return output;},_possibleChars:function(format){var iFormat,chars="",literal=false,lookAhead=function(match){var matches=(iFormat+1<format.length&&format.charAt(iFormat+1)===match);if(matches){iFormat++;}
return matches;};for(iFormat=0;iFormat<format.length;iFormat++){if(literal){if(format.charAt(iFormat)==="'"&&!lookAhead("'")){literal=false;}else{chars+=format.charAt(iFormat);}}else{switch(format.charAt(iFormat)){case"d":case"m":case"y":case"@":chars+="0123456789";break;case"D":case"M":return null;case"'":if(lookAhead("'")){chars+="'";}else{literal=true;}
break;default:chars+=format.charAt(iFormat);}}}
return chars;},_get:function(inst,name){return inst.settings[name]!==undefined?inst.settings[name]:this._defaults[name];},_setDateFromField:function(inst,noDefault){if(inst.input.val()===inst.lastVal){return;}
var dateFormat=this._get(inst,"dateFormat"),dates=inst.lastVal=inst.input?inst.input.val():null,defaultDate=this._getDefaultDate(inst),date=defaultDate,settings=this._getFormatConfig(inst);try{date=this.parseDate(dateFormat,dates,settings)||defaultDate;}catch(event){dates=(noDefault?"":dates);}
inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();inst.currentDay=(dates?date.getDate():0);inst.currentMonth=(dates?date.getMonth():0);inst.currentYear=(dates?date.getFullYear():0);this._adjustInstDate(inst);},_getDefaultDate:function(inst){return this._restrictMinMax(inst,this._determineDate(inst,this._get(inst,"defaultDate"),new Date()));},_determineDate:function(inst,date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date;},offsetString=function(offset){try{return $.datepicker.parseDate($.datepicker._get(inst,"dateFormat"),offset,$.datepicker._getFormatConfig(inst));}
catch(e){}
var date=(offset.toLowerCase().match(/^c/)?$.datepicker._getDate(inst):null)||new Date(),year=date.getFullYear(),month=date.getMonth(),day=date.getDate(),pattern=/([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,$.datepicker._getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,$.datepicker._getDaysInMonth(year,month));break;}
matches=pattern.exec(offset);}
return new Date(year,month,day);},newDate=(date==null||date===""?defaultDate:(typeof date==="string"?offsetString(date):(typeof date==="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):new Date(date.getTime()))));newDate=(newDate&&newDate.toString()==="Invalid Date"?defaultDate:newDate);if(newDate){newDate.setHours(0);newDate.setMinutes(0);newDate.setSeconds(0);newDate.setMilliseconds(0);}
return this._daylightSavingAdjust(newDate);},_daylightSavingAdjust:function(date){if(!date){return null;}
date.setHours(date.getHours()>12?date.getHours()+2:0);return date;},_setDate:function(inst,date,noChange){var clear=!date,origMonth=inst.selectedMonth,origYear=inst.selectedYear,newDate=this._restrictMinMax(inst,this._determineDate(inst,date,new Date()));inst.selectedDay=inst.currentDay=newDate.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=newDate.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=newDate.getFullYear();if((origMonth!==inst.selectedMonth||origYear!==inst.selectedYear)&&!noChange){this._notifyChange(inst);}
this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst));}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()==="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate;},_attachHandlers:function(inst){var stepMonths=this._get(inst,"stepMonths"),id="#"+inst.id.replace(/\\\\/g,"\\");inst.dpDiv.find("[data-handler]").map(function(){var handler={prev:function(){$.datepicker._adjustDate(id,-stepMonths,"M");},next:function(){$.datepicker._adjustDate(id,+stepMonths,"M");},hide:function(){$.datepicker._hideDatepicker();},today:function(){$.datepicker._gotoToday(id);},selectDay:function(){$.datepicker._selectDay(id,+this.getAttribute("data-month"),+this.getAttribute("data-year"),this);return false;},selectMonth:function(){$.datepicker._selectMonthYear(id,this,"M");return false;},selectYear:function(){$.datepicker._selectMonthYear(id,this,"Y");return false;}};$(this).bind(this.getAttribute("data-event"),handler[this.getAttribute("data-handler")]);});},_generateHTML:function(inst){var maxDraw,prevText,prev,nextText,next,currentText,gotoDate,controls,buttonPanel,firstDay,showWeek,dayNames,dayNamesMin,monthNames,monthNamesShort,beforeShowDay,showOtherMonths,selectOtherMonths,defaultDate,html,dow,row,group,col,selectedDate,cornerClass,calender,thead,day,daysInMonth,leadDays,curRows,numRows,printDate,dRow,tbody,daySettings,otherMonth,unselectable,tempDate=new Date(),today=this._daylightSavingAdjust(new Date(tempDate.getFullYear(),tempDate.getMonth(),tempDate.getDate())),isRTL=this._get(inst,"isRTL"),showButtonPanel=this._get(inst,"showButtonPanel"),hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext"),navigationAsDateFormat=this._get(inst,"navigationAsDateFormat"),numMonths=this._getNumberOfMonths(inst),showCurrentAtPos=this._get(inst,"showCurrentAtPos"),stepMonths=this._get(inst,"stepMonths"),isMultiMonth=(numMonths[0]!==1||numMonths[1]!==1),currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay))),minDate=this._getMinMaxDate(inst,"min"),maxDate=this._getMinMaxDate(inst,"max"),drawMonth=inst.drawMonth-showCurrentAtPos,drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--;}
if(maxDate){maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-(numMonths[0]*numMonths[1])+1,maxDate.getDate()));maxDraw=(minDate&&maxDraw<minDate?minDate:maxDraw);while(this._daylightSavingAdjust(new Date(drawYear,drawMonth,1))>maxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--;}}}
inst.drawMonth=drawMonth;inst.drawYear=drawYear;prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'"+" title='"+prevText+"'><span class='ui-icon ui-icon-circle-triangle-"+(isRTL?"e":"w")+"'>"+prevText+"</span></a>":(hideIfNoPrevNext?"":"<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+prevText+"'><span class='ui-icon ui-icon-circle-triangle-"+(isRTL?"e":"w")+"'>"+prevText+"</span></a>"));nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'"+" title='"+nextText+"'><span class='ui-icon ui-icon-circle-triangle-"+(isRTL?"w":"e")+"'>"+nextText+"</span></a>":(hideIfNoPrevNext?"":"<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+nextText+"'><span class='ui-icon ui-icon-circle-triangle-"+(isRTL?"w":"e")+"'>"+nextText+"</span></a>"));currentText=this._get(inst,"currentText");gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));controls=(!inst.inline?"<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>"+
this._get(inst,"closeText")+"</button>":"");buttonPanel=(showButtonPanel)?"<div class='ui-datepicker-buttonpane ui-widget-content'>"+(isRTL?controls:"")+
(this._isInRange(inst,gotoDate)?"<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'"+">"+currentText+"</button>":"")+(isRTL?"":controls)+"</div>":"";firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);showWeek=this._get(inst,"showWeek");dayNames=this._get(inst,"dayNames");dayNamesMin=this._get(inst,"dayNamesMin");monthNames=this._get(inst,"monthNames");monthNamesShort=this._get(inst,"monthNamesShort");beforeShowDay=this._get(inst,"beforeShowDay");showOtherMonths=this._get(inst,"showOtherMonths");selectOtherMonths=this._get(inst,"selectOtherMonths");defaultDate=this._getDefaultDate(inst);html="";dow;for(row=0;row<numMonths[0];row++){group="";this.maxRows=4;for(col=0;col<numMonths[1];col++){selectedDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,inst.selectedDay));cornerClass=" ui-corner-all";calender="";if(isMultiMonth){calender+="<div class='ui-datepicker-group";if(numMonths[1]>1){switch(col){case 0:calender+=" ui-datepicker-group-first";cornerClass=" ui-corner-"+(isRTL?"right":"left");break;case numMonths[1]-1:calender+=" ui-datepicker-group-last";cornerClass=" ui-corner-"+(isRTL?"left":"right");break;default:calender+=" ui-datepicker-group-middle";cornerClass="";break;}}
calender+="'>";}
calender+="<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix"+cornerClass+"'>"+
(/all|left/.test(cornerClass)&&row===0?(isRTL?next:prev):"")+
(/all|right/.test(cornerClass)&&row===0?(isRTL?prev:next):"")+
this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,row>0||col>0,monthNames,monthNamesShort)+"</div><table class='ui-datepicker-calendar'><thead>"+"<tr>";thead=(showWeek?"<th class='ui-datepicker-week-col'>"+this._get(inst,"weekHeader")+"</th>":"");for(dow=0;dow<7;dow++){day=(dow+firstDay)%7;thead+="<th"+((dow+firstDay+6)%7>=5?" class='ui-datepicker-week-end'":"")+">"+"<span title='"+dayNames[day]+"'>"+dayNamesMin[day]+"</span></th>";}
calender+=thead+"</tr></thead><tbody>";daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear===inst.selectedYear&&drawMonth===inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth);}
leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;curRows=Math.ceil((leadDays+daysInMonth)/7);numRows=(isMultiMonth?this.maxRows>curRows?this.maxRows:curRows:curRows);this.maxRows=numRows;printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(dRow=0;dRow<numRows;dRow++){calender+="<tr>";tbody=(!showWeek?"":"<td class='ui-datepicker-week-col'>"+
this._get(inst,"calculateWeek")(printDate)+"</td>");for(dow=0;dow<7;dow++){daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);otherMonth=(printDate.getMonth()!==drawMonth);unselectable=(otherMonth&&!selectOtherMonths)||!daySettings[0]||(minDate&&printDate<minDate)||(maxDate&&printDate>maxDate);tbody+="<td class='"+
((dow+firstDay+6)%7>=5?" ui-datepicker-week-end":"")+
(otherMonth?" ui-datepicker-other-month":"")+
((printDate.getTime()===selectedDate.getTime()&&drawMonth===inst.selectedMonth&&inst._keyEvent)||(defaultDate.getTime()===printDate.getTime()&&defaultDate.getTime()===selectedDate.getTime())?" "+this._dayOverClass:"")+
(unselectable?" "+this._unselectableClass+" ui-state-disabled":"")+
(otherMonth&&!showOtherMonths?"":" "+daySettings[1]+
(printDate.getTime()===currentDate.getTime()?" "+this._currentClass:"")+
(printDate.getTime()===today.getTime()?" ui-datepicker-today":""))+"'"+
((!otherMonth||showOtherMonths)&&daySettings[2]?" title='"+daySettings[2].replace(/'/g,"&#39;")+"'":"")+
(unselectable?"":" data-handler='selectDay' data-event='click' data-month='"+printDate.getMonth()+"' data-year='"+printDate.getFullYear()+"'")+">"+
(otherMonth&&!showOtherMonths?"&#xa0;":(unselectable?"<span class='ui-state-default'>"+printDate.getDate()+"</span>":"<a class='ui-state-default"+
(printDate.getTime()===today.getTime()?" ui-state-highlight":"")+
(printDate.getTime()===currentDate.getTime()?" ui-state-active":"")+
(otherMonth?" ui-priority-secondary":"")+"' href='#'>"+printDate.getDate()+"</a>"))+"</td>";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate);}
calender+=tbody+"</tr>";}
drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++;}
calender+="</tbody></table>"+(isMultiMonth?"</div>"+
((numMonths[0]>0&&col===numMonths[1]-1)?"<div class='ui-datepicker-row-break'></div>":""):"");group+=calender;}
html+=group;}
html+=buttonPanel;inst._keyEvent=false;return html;},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,secondary,monthNames,monthNamesShort){var inMinYear,inMaxYear,month,years,thisYear,determineYear,year,endYear,changeMonth=this._get(inst,"changeMonth"),changeYear=this._get(inst,"changeYear"),showMonthAfterYear=this._get(inst,"showMonthAfterYear"),html="<div class='ui-datepicker-title'>",monthHtml="";if(secondary||!changeMonth){monthHtml+="<span class='ui-datepicker-month'>"+monthNames[drawMonth]+"</span>";}else{inMinYear=(minDate&&minDate.getFullYear()===drawYear);inMaxYear=(maxDate&&maxDate.getFullYear()===drawYear);monthHtml+="<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";for(month=0;month<12;month++){if((!inMinYear||month>=minDate.getMonth())&&(!inMaxYear||month<=maxDate.getMonth())){monthHtml+="<option value='"+month+"'"+
(month===drawMonth?" selected='selected'":"")+">"+monthNamesShort[month]+"</option>";}}
monthHtml+="</select>";}
if(!showMonthAfterYear){html+=monthHtml+(secondary||!(changeMonth&&changeYear)?"&#xa0;":"");}
if(!inst.yearshtml){inst.yearshtml="";if(secondary||!changeYear){html+="<span class='ui-datepicker-year'>"+drawYear+"</span>";}else{years=this._get(inst,"yearRange").split(":");thisYear=new Date().getFullYear();determineYear=function(value){var year=(value.match(/c[+\-].*/)?drawYear+parseInt(value.substring(1),10):(value.match(/[+\-].*/)?thisYear+parseInt(value,10):parseInt(value,10)));return(isNaN(year)?thisYear:year);};year=determineYear(years[0]);endYear=Math.max(year,determineYear(years[1]||""));year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);inst.yearshtml+="<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";for(;year<=endYear;year++){inst.yearshtml+="<option value='"+year+"'"+
(year===drawYear?" selected='selected'":"")+">"+year+"</option>";}
inst.yearshtml+="</select>";html+=inst.yearshtml;inst.yearshtml=null;}}
html+=this._get(inst,"yearSuffix");if(showMonthAfterYear){html+=(secondary||!(changeMonth&&changeYear)?"&#xa0;":"")+monthHtml;}
html+="</div>";return html;},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period==="Y"?offset:0),month=inst.drawMonth+(period==="M"?offset:0),day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period==="D"?offset:0),date=this._restrictMinMax(inst,this._daylightSavingAdjust(new Date(year,month,day)));inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period==="M"||period==="Y"){this._notifyChange(inst);}},_restrictMinMax:function(inst,date){var minDate=this._getMinMaxDate(inst,"min"),maxDate=this._getMinMaxDate(inst,"max"),newDate=(minDate&&date<minDate?minDate:date);return(maxDate&&newDate>maxDate?maxDate:newDate);},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst]);}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths==="number"?[1,numMonths]:numMonths));},_getMinMaxDate:function(inst,minMax){return this._determineDate(inst,this._get(inst,minMax+"Date"),null);},_getDaysInMonth:function(year,month){return 32-this._daylightSavingAdjust(new Date(year,month,32)).getDate();},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay();},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst),date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[0]*numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()));}
return this._isInRange(inst,date);},_isInRange:function(inst,date){var yearSplit,currentYear,minDate=this._getMinMaxDate(inst,"min"),maxDate=this._getMinMaxDate(inst,"max"),minYear=null,maxYear=null,years=this._get(inst,"yearRange");if(years){yearSplit=years.split(":");currentYear=new Date().getFullYear();minYear=parseInt(yearSplit[0],10);maxYear=parseInt(yearSplit[1],10);if(yearSplit[0].match(/[+\-].*/)){minYear+=currentYear;}
if(yearSplit[1].match(/[+\-].*/)){maxYear+=currentYear;}}
return((!minDate||date.getTime()>=minDate.getTime())&&(!maxDate||date.getTime()<=maxDate.getTime())&&(!minYear||date.getFullYear()>=minYear)&&(!maxYear||date.getFullYear()<=maxYear));},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!=="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")};},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear;}
var date=(day?(typeof day==="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst));}});function bindHover(dpDiv){var selector="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return dpDiv.delegate(selector,"mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!==-1){$(this).removeClass("ui-datepicker-prev-hover");}
if(this.className.indexOf("ui-datepicker-next")!==-1){$(this).removeClass("ui-datepicker-next-hover");}}).delegate(selector,"mouseover",function(){if(!$.datepicker._isDisabledDatepicker(instActive.inline?dpDiv.parent()[0]:instActive.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!==-1){$(this).addClass("ui-datepicker-prev-hover");}
if(this.className.indexOf("ui-datepicker-next")!==-1){$(this).addClass("ui-datepicker-next-hover");}}});}
function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null){target[name]=props[name];}}
return target;}
$.fn.datepicker=function(options){if(!this.length){return this;}
if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick);$.datepicker.initialized=true;}
if($("#"+$.datepicker._mainDivId).length===0){$("body").append($.datepicker.dpDiv);}
var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options==="string"&&(options==="isDisabled"||options==="getDate"||options==="widget")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs));}
if(options==="option"&&arguments.length===2&&typeof arguments[1]==="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs));}
return this.each(function(){typeof options==="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options);});};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.10.4";})(jQuery);(function($,undefined){var sizeRelatedOptions={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},resizableRelatedOptions={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};$.widget("ui.dialog",{version:"1.10.4",options:{appendTo:"body",autoOpen:true,buttons:[],closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:null,maxWidth:null,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(pos){var topOffset=$(this).css(pos).offset().top;if(topOffset<0){$(this).css("top",pos.top-topOffset);}}},resizable:true,show:null,title:null,width:300,beforeClose:null,close:null,drag:null,dragStart:null,dragStop:null,focus:null,open:null,resize:null,resizeStart:null,resizeStop:null},_create:function(){this.originalCss={display:this.element[0].style.display,width:this.element[0].style.width,minHeight:this.element[0].style.minHeight,maxHeight:this.element[0].style.maxHeight,height:this.element[0].style.height};this.originalPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)};this.originalTitle=this.element.attr("title");this.options.title=this.options.title||this.originalTitle;this._createWrapper();this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(this.uiDialog);this._createTitlebar();this._createButtonPane();if(this.options.draggable&&$.fn.draggable){this._makeDraggable();}
if(this.options.resizable&&$.fn.resizable){this._makeResizable();}
this._isOpen=false;},_init:function(){if(this.options.autoOpen){this.open();}},_appendTo:function(){var element=this.options.appendTo;if(element&&(element.jquery||element.nodeType)){return $(element);}
return this.document.find(element||"body").eq(0);},_destroy:function(){var next,originalPosition=this.originalPosition;this._destroyOverlay();this.element.removeUniqueId().removeClass("ui-dialog-content ui-widget-content").css(this.originalCss).detach();this.uiDialog.stop(true,true).remove();if(this.originalTitle){this.element.attr("title",this.originalTitle);}
next=originalPosition.parent.children().eq(originalPosition.index);if(next.length&&next[0]!==this.element[0]){next.before(this.element);}else{originalPosition.parent.append(this.element);}},widget:function(){return this.uiDialog;},disable:$.noop,enable:$.noop,close:function(event){var activeElement,that=this;if(!this._isOpen||this._trigger("beforeClose",event)===false){return;}
this._isOpen=false;this._destroyOverlay();if(!this.opener.filter(":focusable").focus().length){try{activeElement=this.document[0].activeElement;if(activeElement&&activeElement.nodeName.toLowerCase()!=="body"){$(activeElement).blur();}}catch(error){}}
this._hide(this.uiDialog,this.options.hide,function(){that._trigger("close",event);});},isOpen:function(){return this._isOpen;},moveToTop:function(){this._moveToTop();},_moveToTop:function(event,silent){var moved=!!this.uiDialog.nextAll(":visible").insertBefore(this.uiDialog).length;if(moved&&!silent){this._trigger("focus",event);}
return moved;},open:function(){var that=this;if(this._isOpen){if(this._moveToTop()){this._focusTabbable();}
return;}
this._isOpen=true;this.opener=$(this.document[0].activeElement);this._size();this._position();this._createOverlay();this._moveToTop(null,true);this._show(this.uiDialog,this.options.show,function(){that._focusTabbable();that._trigger("focus");});this._trigger("open");},_focusTabbable:function(){var hasFocus=this.element.find("[autofocus]");if(!hasFocus.length){hasFocus=this.element.find(":tabbable");}
if(!hasFocus.length){hasFocus=this.uiDialogButtonPane.find(":tabbable");}
if(!hasFocus.length){hasFocus=this.uiDialogTitlebarClose.filter(":tabbable");}
if(!hasFocus.length){hasFocus=this.uiDialog;}
hasFocus.eq(0).focus();},_keepFocus:function(event){function checkFocus(){var activeElement=this.document[0].activeElement,isActive=this.uiDialog[0]===activeElement||$.contains(this.uiDialog[0],activeElement);if(!isActive){this._focusTabbable();}}
event.preventDefault();checkFocus.call(this);this._delay(checkFocus);},_createWrapper:function(){this.uiDialog=$("<div>").addClass("ui-dialog ui-widget ui-widget-content ui-corner-all ui-front "+
this.options.dialogClass).hide().attr({tabIndex:-1,role:"dialog"}).appendTo(this._appendTo());this._on(this.uiDialog,{keydown:function(event){if(this.options.closeOnEscape&&!event.isDefaultPrevented()&&event.keyCode&&event.keyCode===$.ui.keyCode.ESCAPE){event.preventDefault();this.close(event);return;}
if(event.keyCode!==$.ui.keyCode.TAB){return;}
var tabbables=this.uiDialog.find(":tabbable"),first=tabbables.filter(":first"),last=tabbables.filter(":last");if((event.target===last[0]||event.target===this.uiDialog[0])&&!event.shiftKey){first.focus(1);event.preventDefault();}else if((event.target===first[0]||event.target===this.uiDialog[0])&&event.shiftKey){last.focus(1);event.preventDefault();}},mousedown:function(event){if(this._moveToTop(event)){this._focusTabbable();}}});if(!this.element.find("[aria-describedby]").length){this.uiDialog.attr({"aria-describedby":this.element.uniqueId().attr("id")});}},_createTitlebar:function(){var uiDialogTitle;this.uiDialogTitlebar=$("<div>").addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(this.uiDialog);this._on(this.uiDialogTitlebar,{mousedown:function(event){if(!$(event.target).closest(".ui-dialog-titlebar-close")){this.uiDialog.focus();}}});this.uiDialogTitlebarClose=$("<button type='button'></button>").button({label:this.options.closeText,icons:{primary:"ui-icon-closethick"},text:false}).addClass("ui-dialog-titlebar-close").appendTo(this.uiDialogTitlebar);this._on(this.uiDialogTitlebarClose,{click:function(event){event.preventDefault();this.close(event);}});uiDialogTitle=$("<span>").uniqueId().addClass("ui-dialog-title").prependTo(this.uiDialogTitlebar);this._title(uiDialogTitle);this.uiDialog.attr({"aria-labelledby":uiDialogTitle.attr("id")});},_title:function(title){if(!this.options.title){title.html("&#160;");}
title.text(this.options.title);},_createButtonPane:function(){this.uiDialogButtonPane=$("<div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiButtonSet=$("<div>").addClass("ui-dialog-buttonset").appendTo(this.uiDialogButtonPane);this._createButtons();},_createButtons:function(){var that=this,buttons=this.options.buttons;this.uiDialogButtonPane.remove();this.uiButtonSet.empty();if($.isEmptyObject(buttons)||($.isArray(buttons)&&!buttons.length)){this.uiDialog.removeClass("ui-dialog-buttons");return;}
$.each(buttons,function(name,props){var click,buttonOptions;props=$.isFunction(props)?{click:props,text:name}:props;props=$.extend({type:"button"},props);click=props.click;props.click=function(){click.apply(that.element[0],arguments);};buttonOptions={icons:props.icons,text:props.showText};delete props.icons;delete props.showText;$("<button></button>",props).button(buttonOptions).appendTo(that.uiButtonSet);});this.uiDialog.addClass("ui-dialog-buttons");this.uiDialogButtonPane.appendTo(this.uiDialog);},_makeDraggable:function(){var that=this,options=this.options;function filteredUi(ui){return{position:ui.position,offset:ui.offset};}
this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(event,ui){$(this).addClass("ui-dialog-dragging");that._blockFrames();that._trigger("dragStart",event,filteredUi(ui));},drag:function(event,ui){that._trigger("drag",event,filteredUi(ui));},stop:function(event,ui){options.position=[ui.position.left-that.document.scrollLeft(),ui.position.top-that.document.scrollTop()];$(this).removeClass("ui-dialog-dragging");that._unblockFrames();that._trigger("dragStop",event,filteredUi(ui));}});},_makeResizable:function(){var that=this,options=this.options,handles=options.resizable,position=this.uiDialog.css("position"),resizeHandles=typeof handles==="string"?handles:"n,e,s,w,se,sw,ne,nw";function filteredUi(ui){return{originalPosition:ui.originalPosition,originalSize:ui.originalSize,position:ui.position,size:ui.size};}
this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:options.maxWidth,maxHeight:options.maxHeight,minWidth:options.minWidth,minHeight:this._minHeight(),handles:resizeHandles,start:function(event,ui){$(this).addClass("ui-dialog-resizing");that._blockFrames();that._trigger("resizeStart",event,filteredUi(ui));},resize:function(event,ui){that._trigger("resize",event,filteredUi(ui));},stop:function(event,ui){options.height=$(this).height();options.width=$(this).width();$(this).removeClass("ui-dialog-resizing");that._unblockFrames();that._trigger("resizeStop",event,filteredUi(ui));}}).css("position",position);},_minHeight:function(){var options=this.options;return options.height==="auto"?options.minHeight:Math.min(options.minHeight,options.height);},_position:function(){var isVisible=this.uiDialog.is(":visible");if(!isVisible){this.uiDialog.show();}
this.uiDialog.position(this.options.position);if(!isVisible){this.uiDialog.hide();}},_setOptions:function(options){var that=this,resize=false,resizableOptions={};$.each(options,function(key,value){that._setOption(key,value);if(key in sizeRelatedOptions){resize=true;}
if(key in resizableRelatedOptions){resizableOptions[key]=value;}});if(resize){this._size();this._position();}
if(this.uiDialog.is(":data(ui-resizable)")){this.uiDialog.resizable("option",resizableOptions);}},_setOption:function(key,value){var isDraggable,isResizable,uiDialog=this.uiDialog;if(key==="dialogClass"){uiDialog.removeClass(this.options.dialogClass).addClass(value);}
if(key==="disabled"){return;}
this._super(key,value);if(key==="appendTo"){this.uiDialog.appendTo(this._appendTo());}
if(key==="buttons"){this._createButtons();}
if(key==="closeText"){this.uiDialogTitlebarClose.button({label:""+value});}
if(key==="draggable"){isDraggable=uiDialog.is(":data(ui-draggable)");if(isDraggable&&!value){uiDialog.draggable("destroy");}
if(!isDraggable&&value){this._makeDraggable();}}
if(key==="position"){this._position();}
if(key==="resizable"){isResizable=uiDialog.is(":data(ui-resizable)");if(isResizable&&!value){uiDialog.resizable("destroy");}
if(isResizable&&typeof value==="string"){uiDialog.resizable("option","handles",value);}
if(!isResizable&&value!==false){this._makeResizable();}}
if(key==="title"){this._title(this.uiDialogTitlebar.find(".ui-dialog-title"));}},_size:function(){var nonContentHeight,minContentHeight,maxContentHeight,options=this.options;this.element.show().css({width:"auto",minHeight:0,maxHeight:"none",height:0});if(options.minWidth>options.width){options.width=options.minWidth;}
nonContentHeight=this.uiDialog.css({height:"auto",width:options.width}).outerHeight();minContentHeight=Math.max(0,options.minHeight-nonContentHeight);maxContentHeight=typeof options.maxHeight==="number"?Math.max(0,options.maxHeight-nonContentHeight):"none";if(options.height==="auto"){this.element.css({minHeight:minContentHeight,maxHeight:maxContentHeight,height:"auto"});}else{this.element.height(Math.max(0,options.height-nonContentHeight));}
if(this.uiDialog.is(":data(ui-resizable)")){this.uiDialog.resizable("option","minHeight",this._minHeight());}},_blockFrames:function(){this.iframeBlocks=this.document.find("iframe").map(function(){var iframe=$(this);return $("<div>").css({position:"absolute",width:iframe.outerWidth(),height:iframe.outerHeight()}).appendTo(iframe.parent()).offset(iframe.offset())[0];});},_unblockFrames:function(){if(this.iframeBlocks){this.iframeBlocks.remove();delete this.iframeBlocks;}},_allowInteraction:function(event){if($(event.target).closest(".ui-dialog").length){return true;}
return!!$(event.target).closest(".ui-datepicker").length;},_createOverlay:function(){if(!this.options.modal){return;}
var that=this,widgetFullName=this.widgetFullName;if(!$.ui.dialog.overlayInstances){this._delay(function(){if($.ui.dialog.overlayInstances){this.document.bind("focusin.dialog",function(event){if(!that._allowInteraction(event)){event.preventDefault();$(".ui-dialog:visible:last .ui-dialog-content").data(widgetFullName)._focusTabbable();}});}});}
this.overlay=$("<div>").addClass("ui-widget-overlay ui-front").appendTo(this._appendTo());this._on(this.overlay,{mousedown:"_keepFocus"});$.ui.dialog.overlayInstances++;},_destroyOverlay:function(){if(!this.options.modal){return;}
if(this.overlay){$.ui.dialog.overlayInstances--;if(!$.ui.dialog.overlayInstances){this.document.unbind("focusin.dialog");}
this.overlay.remove();this.overlay=null;}}});$.ui.dialog.overlayInstances=0;if($.uiBackCompat!==false){$.widget("ui.dialog",$.ui.dialog,{_position:function(){var position=this.options.position,myAt=[],offset=[0,0],isVisible;if(position){if(typeof position==="string"||(typeof position==="object"&&"0"in position)){myAt=position.split?position.split(" "):[position[0],position[1]];if(myAt.length===1){myAt[1]=myAt[0];}
$.each(["left","top"],function(i,offsetPosition){if(+myAt[i]===myAt[i]){offset[i]=myAt[i];myAt[i]=offsetPosition;}});position={my:myAt[0]+(offset[0]<0?offset[0]:"+"+offset[0])+" "+
myAt[1]+(offset[1]<0?offset[1]:"+"+offset[1]),at:myAt.join(" ")};}
position=$.extend({},$.ui.dialog.prototype.options.position,position);}else{position=$.ui.dialog.prototype.options.position;}
isVisible=this.uiDialog.is(":visible");if(!isVisible){this.uiDialog.show();}
this.uiDialog.position(position);if(!isVisible){this.uiDialog.hide();}}});}}(jQuery));(function($,undefined){$.widget("ui.menu",{version:"1.10.4",defaultElement:"<ul>",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element;this.mouseHandled=false;this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,$.proxy(function(event){if(this.options.disabled){event.preventDefault();}},this));if(this.options.disabled){this.element.addClass("ui-state-disabled").attr("aria-disabled","true");}
this._on({"mousedown .ui-menu-item > a":function(event){event.preventDefault();},"click .ui-state-disabled > a":function(event){event.preventDefault();},"click .ui-menu-item:has(a)":function(event){var target=$(event.target).closest(".ui-menu-item");if(!this.mouseHandled&&target.not(".ui-state-disabled").length){this.select(event);if(!event.isPropagationStopped()){this.mouseHandled=true;}
if(target.has(".ui-menu").length){this.expand(event);}else if(!this.element.is(":focus")&&$(this.document[0].activeElement).closest(".ui-menu").length){this.element.trigger("focus",[true]);if(this.active&&this.active.parents(".ui-menu").length===1){clearTimeout(this.timer);}}}},"mouseenter .ui-menu-item":function(event){var target=$(event.currentTarget);target.siblings().children(".ui-state-active").removeClass("ui-state-active");this.focus(event,target);},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(event,keepActiveItem){var item=this.active||this.element.children(".ui-menu-item").eq(0);if(!keepActiveItem){this.focus(event,item);}},blur:function(event){this._delay(function(){if(!$.contains(this.element[0],this.document[0].activeElement)){this.collapseAll(event);}});},keydown:"_keydown"});this.refresh();this._on(this.document,{click:function(event){if(!$(event.target).closest(".ui-menu").length){this.collapseAll(event);}
this.mouseHandled=false;}});},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show();this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var elem=$(this);if(elem.data("ui-menu-submenu-carat")){elem.remove();}});this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content");},_keydown:function(event){var match,prev,character,skip,regex,preventDefault=true;function escape(value){return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&");}
switch(event.keyCode){case $.ui.keyCode.PAGE_UP:this.previousPage(event);break;case $.ui.keyCode.PAGE_DOWN:this.nextPage(event);break;case $.ui.keyCode.HOME:this._move("first","first",event);break;case $.ui.keyCode.END:this._move("last","last",event);break;case $.ui.keyCode.UP:this.previous(event);break;case $.ui.keyCode.DOWN:this.next(event);break;case $.ui.keyCode.LEFT:this.collapse(event);break;case $.ui.keyCode.RIGHT:if(this.active&&!this.active.is(".ui-state-disabled")){this.expand(event);}
break;case $.ui.keyCode.ENTER:case $.ui.keyCode.SPACE:this._activate(event);break;case $.ui.keyCode.ESCAPE:this.collapse(event);break;default:preventDefault=false;prev=this.previousFilter||"";character=String.fromCharCode(event.keyCode);skip=false;clearTimeout(this.filterTimer);if(character===prev){skip=true;}else{character=prev+character;}
regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});match=skip&&match.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):match;if(!match.length){character=String.fromCharCode(event.keyCode);regex=new RegExp("^"+escape(character),"i");match=this.activeMenu.children(".ui-menu-item").filter(function(){return regex.test($(this).children("a").text());});}
if(match.length){this.focus(event,match);if(match.length>1){this.previousFilter=character;this.filterTimer=this._delay(function(){delete this.previousFilter;},1000);}else{delete this.previousFilter;}}else{delete this.previousFilter;}}
if(preventDefault){event.preventDefault();}},_activate:function(event){if(!this.active.is(".ui-state-disabled")){if(this.active.children("a[aria-haspopup='true']").length){this.expand(event);}else{this.select(event);}}},refresh:function(){var menus,icon=this.options.icons.submenu,submenus=this.element.find(this.options.menus);this.element.toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length);submenus.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var menu=$(this),item=menu.prev("a"),submenuCarat=$("<span>").addClass("ui-menu-icon ui-icon "+icon).data("ui-menu-submenu-carat",true);item.attr("aria-haspopup","true").prepend(submenuCarat);menu.attr("aria-labelledby",item.attr("id"));});menus=submenus.add(this.element);menus.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()});menus.children(":not(.ui-menu-item)").each(function(){var item=$(this);if(!/[^\-\u2014\u2013\s]/.test(item.text())){item.addClass("ui-widget-content ui-menu-divider");}});menus.children(".ui-state-disabled").attr("aria-disabled","true");if(this.active&&!$.contains(this.element[0],this.active[0])){this.blur();}},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role];},_setOption:function(key,value){if(key==="icons"){this.element.find(".ui-menu-icon").removeClass(this.options.icons.submenu).addClass(value.submenu);}
this._super(key,value);},focus:function(event,item){var nested,focused;this.blur(event,event&&event.type==="focus");this._scrollIntoView(item);this.active=item.first();focused=this.active.children("a").addClass("ui-state-focus");if(this.options.role){this.element.attr("aria-activedescendant",focused.attr("id"));}
this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active");if(event&&event.type==="keydown"){this._close();}else{this.timer=this._delay(function(){this._close();},this.delay);}
nested=item.children(".ui-menu");if(nested.length&&event&&(/^mouse/.test(event.type))){this._startOpening(nested);}
this.activeMenu=item.parent();this._trigger("focus",event,{item:item});},_scrollIntoView:function(item){var borderTop,paddingTop,offset,scroll,elementHeight,itemHeight;if(this._hasScroll()){borderTop=parseFloat($.css(this.activeMenu[0],"borderTopWidth"))||0;paddingTop=parseFloat($.css(this.activeMenu[0],"paddingTop"))||0;offset=item.offset().top-this.activeMenu.offset().top-borderTop-paddingTop;scroll=this.activeMenu.scrollTop();elementHeight=this.activeMenu.height();itemHeight=item.height();if(offset<0){this.activeMenu.scrollTop(scroll+offset);}else if(offset+itemHeight>elementHeight){this.activeMenu.scrollTop(scroll+offset-elementHeight+itemHeight);}}},blur:function(event,fromFocus){if(!fromFocus){clearTimeout(this.timer);}
if(!this.active){return;}
this.active.children("a").removeClass("ui-state-focus");this.active=null;this._trigger("blur",event,{item:this.active});},_startOpening:function(submenu){clearTimeout(this.timer);if(submenu.attr("aria-hidden")!=="true"){return;}
this.timer=this._delay(function(){this._close();this._open(submenu);},this.delay);},_open:function(submenu){var position=$.extend({of:this.active},this.options.position);clearTimeout(this.timer);this.element.find(".ui-menu").not(submenu.parents(".ui-menu")).hide().attr("aria-hidden","true");submenu.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(position);},collapseAll:function(event,all){clearTimeout(this.timer);this.timer=this._delay(function(){var currentMenu=all?this.element:$(event&&event.target).closest(this.element.find(".ui-menu"));if(!currentMenu.length){currentMenu=this.element;}
this._close(currentMenu);this.blur(event);this.activeMenu=currentMenu;},this.delay);},_close:function(startMenu){if(!startMenu){startMenu=this.active?this.active.parent():this.element;}
startMenu.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active");},collapse:function(event){var newItem=this.active&&this.active.parent().closest(".ui-menu-item",this.element);if(newItem&&newItem.length){this._close();this.focus(event,newItem);}},expand:function(event){var newItem=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();if(newItem&&newItem.length){this._open(newItem.parent());this._delay(function(){this.focus(event,newItem);});}},next:function(event){this._move("next","first",event);},previous:function(event){this._move("prev","last",event);},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length;},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length;},_move:function(direction,filter,event){var next;if(this.active){if(direction==="first"||direction==="last"){next=this.active
[direction==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1);}else{next=this.active
[direction+"All"](".ui-menu-item").eq(0);}}
if(!next||!next.length||!this.active){next=this.activeMenu.children(".ui-menu-item")[filter]();}
this.focus(event,next);},nextPage:function(event){var item,base,height;if(!this.active){this.next(event);return;}
if(this.isLastItem()){return;}
if(this._hasScroll()){base=this.active.offset().top;height=this.element.height();this.active.nextAll(".ui-menu-item").each(function(){item=$(this);return item.offset().top-base-height<0;});this.focus(event,item);}else{this.focus(event,this.activeMenu.children(".ui-menu-item")
[!this.active?"first":"last"]());}},previousPage:function(event){var item,base,height;if(!this.active){this.next(event);return;}
if(this.isFirstItem()){return;}
if(this._hasScroll()){base=this.active.offset().top;height=this.element.height();this.active.prevAll(".ui-menu-item").each(function(){item=$(this);return item.offset().top-base+height>0;});this.focus(event,item);}else{this.focus(event,this.activeMenu.children(".ui-menu-item").first());}},_hasScroll:function(){return this.element.outerHeight()<this.element.prop("scrollHeight");},select:function(event){this.active=this.active||$(event.target).closest(".ui-menu-item");var ui={item:this.active};if(!this.active.has(".ui-menu").length){this.collapseAll(event,true);}
this._trigger("select",event,ui);}});}(jQuery));(function($,undefined){$.widget("ui.progressbar",{version:"1.10.4",options:{max:100,value:0,change:null,complete:null},min:0,_create:function(){this.oldValue=this.options.value=this._constrainedValue();this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min});this.valueDiv=$("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this._refreshValue();},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");this.valueDiv.remove();},value:function(newValue){if(newValue===undefined){return this.options.value;}
this.options.value=this._constrainedValue(newValue);this._refreshValue();},_constrainedValue:function(newValue){if(newValue===undefined){newValue=this.options.value;}
this.indeterminate=newValue===false;if(typeof newValue!=="number"){newValue=0;}
return this.indeterminate?false:Math.min(this.options.max,Math.max(this.min,newValue));},_setOptions:function(options){var value=options.value;delete options.value;this._super(options);this.options.value=this._constrainedValue(value);this._refreshValue();},_setOption:function(key,value){if(key==="max"){value=Math.max(this.min,value);}
this._super(key,value);},_percentage:function(){return this.indeterminate?100:100*(this.options.value-this.min)/(this.options.max-this.min);},_refreshValue:function(){var value=this.options.value,percentage=this._percentage();this.valueDiv.toggle(this.indeterminate||value>this.min).toggleClass("ui-corner-right",value===this.options.max).width(percentage.toFixed(0)+"%");this.element.toggleClass("ui-progressbar-indeterminate",this.indeterminate);if(this.indeterminate){this.element.removeAttr("aria-valuenow");if(!this.overlayDiv){this.overlayDiv=$("<div class='ui-progressbar-overlay'></div>").appendTo(this.valueDiv);}}else{this.element.attr({"aria-valuemax":this.options.max,"aria-valuenow":value});if(this.overlayDiv){this.overlayDiv.remove();this.overlayDiv=null;}}
if(this.oldValue!==value){this.oldValue=value;this._trigger("change");}
if(value===this.options.max){this._trigger("complete");}}});})(jQuery);(function($,undefined){var numPages=5;$.widget("ui.slider",$.ui.mouse,{version:"1.10.4",widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null,change:null,slide:null,start:null,stop:null},_create:function(){this._keySliding=false;this._mouseSliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider"+" ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all");this._refresh();this._setOption("disabled",this.options.disabled);this._animateOff=false;},_refresh:function(){this._createRange();this._createHandles();this._setupEvents();this._refreshValue();},_createHandles:function(){var i,handleCount,options=this.options,existingHandles=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),handle="<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",handles=[];handleCount=(options.values&&options.values.length)||1;if(existingHandles.length>handleCount){existingHandles.slice(handleCount).remove();existingHandles=existingHandles.slice(0,handleCount);}
for(i=existingHandles.length;i<handleCount;i++){handles.push(handle);}
this.handles=existingHandles.add($(handles.join("")).appendTo(this.element));this.handle=this.handles.eq(0);this.handles.each(function(i){$(this).data("ui-slider-handle-index",i);});},_createRange:function(){var options=this.options,classes="";if(options.range){if(options.range===true){if(!options.values){options.values=[this._valueMin(),this._valueMin()];}else if(options.values.length&&options.values.length!==2){options.values=[options.values[0],options.values[0]];}else if($.isArray(options.values)){options.values=options.values.slice(0);}}
if(!this.range||!this.range.length){this.range=$("<div></div>").appendTo(this.element);classes="ui-slider-range"+" ui-widget-header ui-corner-all";}else{this.range.removeClass("ui-slider-range-min ui-slider-range-max").css({"left":"","bottom":""});}
this.range.addClass(classes+
((options.range==="min"||options.range==="max")?" ui-slider-range-"+options.range:""));}else{if(this.range){this.range.remove();}
this.range=null;}},_setupEvents:function(){var elements=this.handles.add(this.range).filter("a");this._off(elements);this._on(elements,this._handleEvents);this._hoverable(elements);this._focusable(elements);},_destroy:function(){this.handles.remove();if(this.range){this.range.remove();}
this.element.removeClass("ui-slider"+" ui-slider-horizontal"+" ui-slider-vertical"+" ui-widget"+" ui-widget-content"+" ui-corner-all");this._mouseDestroy();},_mouseCapture:function(event){var position,normValue,distance,closestHandle,index,allowed,offset,mouseOverHandle,that=this,o=this.options;if(o.disabled){return false;}
this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();position={x:event.pageX,y:event.pageY};normValue=this._normValueFromMouse(position);distance=this._valueMax()-this._valueMin()+1;this.handles.each(function(i){var thisDistance=Math.abs(normValue-that.values(i));if((distance>thisDistance)||(distance===thisDistance&&(i===that._lastChangedValue||that.values(i)===o.min))){distance=thisDistance;closestHandle=$(this);index=i;}});allowed=this._start(event,index);if(allowed===false){return false;}
this._mouseSliding=true;this._handleIndex=index;closestHandle.addClass("ui-state-active").focus();offset=closestHandle.offset();mouseOverHandle=!$(event.target).parents().addBack().is(".ui-slider-handle");this._clickOffset=mouseOverHandle?{left:0,top:0}:{left:event.pageX-offset.left-(closestHandle.width()/2),top:event.pageY-offset.top-
(closestHandle.height()/2)-
(parseInt(closestHandle.css("borderTopWidth"),10)||0)-
(parseInt(closestHandle.css("borderBottomWidth"),10)||0)+
(parseInt(closestHandle.css("marginTop"),10)||0)};if(!this.handles.hasClass("ui-state-hover")){this._slide(event,index,normValue);}
this._animateOff=true;return true;},_mouseStart:function(){return true;},_mouseDrag:function(event){var position={x:event.pageX,y:event.pageY},normValue=this._normValueFromMouse(position);this._slide(event,this._handleIndex,normValue);return false;},_mouseStop:function(event){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(event,this._handleIndex);this._change(event,this._handleIndex);this._handleIndex=null;this._clickOffset=null;this._animateOff=false;return false;},_detectOrientation:function(){this.orientation=(this.options.orientation==="vertical")?"vertical":"horizontal";},_normValueFromMouse:function(position){var pixelTotal,pixelMouse,percentMouse,valueTotal,valueMouse;if(this.orientation==="horizontal"){pixelTotal=this.elementSize.width;pixelMouse=position.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0);}else{pixelTotal=this.elementSize.height;pixelMouse=position.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0);}
percentMouse=(pixelMouse/pixelTotal);if(percentMouse>1){percentMouse=1;}
if(percentMouse<0){percentMouse=0;}
if(this.orientation==="vertical"){percentMouse=1-percentMouse;}
valueTotal=this._valueMax()-this._valueMin();valueMouse=this._valueMin()+percentMouse*valueTotal;return this._trimAlignValue(valueMouse);},_start:function(event,index){var uiHash={handle:this.handles[index],value:this.value()};if(this.options.values&&this.options.values.length){uiHash.value=this.values(index);uiHash.values=this.values();}
return this._trigger("start",event,uiHash);},_slide:function(event,index,newVal){var otherVal,newValues,allowed;if(this.options.values&&this.options.values.length){otherVal=this.values(index?0:1);if((this.options.values.length===2&&this.options.range===true)&&((index===0&&newVal>otherVal)||(index===1&&newVal<otherVal))){newVal=otherVal;}
if(newVal!==this.values(index)){newValues=this.values();newValues[index]=newVal;allowed=this._trigger("slide",event,{handle:this.handles[index],value:newVal,values:newValues});otherVal=this.values(index?0:1);if(allowed!==false){this.values(index,newVal);}}}else{if(newVal!==this.value()){allowed=this._trigger("slide",event,{handle:this.handles[index],value:newVal});if(allowed!==false){this.value(newVal);}}}},_stop:function(event,index){var uiHash={handle:this.handles[index],value:this.value()};if(this.options.values&&this.options.values.length){uiHash.value=this.values(index);uiHash.values=this.values();}
this._trigger("stop",event,uiHash);},_change:function(event,index){if(!this._keySliding&&!this._mouseSliding){var uiHash={handle:this.handles[index],value:this.value()};if(this.options.values&&this.options.values.length){uiHash.value=this.values(index);uiHash.values=this.values();}
this._lastChangedValue=index;this._trigger("change",event,uiHash);}},value:function(newValue){if(arguments.length){this.options.value=this._trimAlignValue(newValue);this._refreshValue();this._change(null,0);return;}
return this._value();},values:function(index,newValue){var vals,newValues,i;if(arguments.length>1){this.options.values[index]=this._trimAlignValue(newValue);this._refreshValue();this._change(null,index);return;}
if(arguments.length){if($.isArray(arguments[0])){vals=this.options.values;newValues=arguments[0];for(i=0;i<vals.length;i+=1){vals[i]=this._trimAlignValue(newValues[i]);this._change(null,i);}
this._refreshValue();}else{if(this.options.values&&this.options.values.length){return this._values(index);}else{return this.value();}}}else{return this._values();}},_setOption:function(key,value){var i,valsLength=0;if(key==="range"&&this.options.range===true){if(value==="min"){this.options.value=this._values(0);this.options.values=null;}else if(value==="max"){this.options.value=this._values(this.options.values.length-1);this.options.values=null;}}
if($.isArray(this.options.values)){valsLength=this.options.values.length;}
$.Widget.prototype._setOption.apply(this,arguments);switch(key){case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case"value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case"values":this._animateOff=true;this._refreshValue();for(i=0;i<valsLength;i+=1){this._change(null,i);}
this._animateOff=false;break;case"min":case"max":this._animateOff=true;this._refreshValue();this._animateOff=false;break;case"range":this._animateOff=true;this._refresh();this._animateOff=false;break;}},_value:function(){var val=this.options.value;val=this._trimAlignValue(val);return val;},_values:function(index){var val,vals,i;if(arguments.length){val=this.options.values[index];val=this._trimAlignValue(val);return val;}else if(this.options.values&&this.options.values.length){vals=this.options.values.slice();for(i=0;i<vals.length;i+=1){vals[i]=this._trimAlignValue(vals[i]);}
return vals;}else{return[];}},_trimAlignValue:function(val){if(val<=this._valueMin()){return this._valueMin();}
if(val>=this._valueMax()){return this._valueMax();}
var step=(this.options.step>0)?this.options.step:1,valModStep=(val-this._valueMin())%step,alignValue=val-valModStep;if(Math.abs(valModStep)*2>=step){alignValue+=(valModStep>0)?step:(-step);}
return parseFloat(alignValue.toFixed(5));},_valueMin:function(){return this.options.min;},_valueMax:function(){return this.options.max;},_refreshValue:function(){var lastValPercent,valPercent,value,valueMin,valueMax,oRange=this.options.range,o=this.options,that=this,animate=(!this._animateOff)?o.animate:false,_set={};if(this.options.values&&this.options.values.length){this.handles.each(function(i){valPercent=(that.values(i)-that._valueMin())/(that._valueMax()-that._valueMin())*100;_set[that.orientation==="horizontal"?"left":"bottom"]=valPercent+"%";$(this).stop(1,1)[animate?"animate":"css"](_set,o.animate);if(that.options.range===true){if(that.orientation==="horizontal"){if(i===0){that.range.stop(1,1)[animate?"animate":"css"]({left:valPercent+"%"},o.animate);}
if(i===1){that.range[animate?"animate":"css"]({width:(valPercent-lastValPercent)+"%"},{queue:false,duration:o.animate});}}else{if(i===0){that.range.stop(1,1)[animate?"animate":"css"]({bottom:(valPercent)+"%"},o.animate);}
if(i===1){that.range[animate?"animate":"css"]({height:(valPercent-lastValPercent)+"%"},{queue:false,duration:o.animate});}}}
lastValPercent=valPercent;});}else{value=this.value();valueMin=this._valueMin();valueMax=this._valueMax();valPercent=(valueMax!==valueMin)?(value-valueMin)/(valueMax-valueMin)*100:0;_set[this.orientation==="horizontal"?"left":"bottom"]=valPercent+"%";this.handle.stop(1,1)[animate?"animate":"css"](_set,o.animate);if(oRange==="min"&&this.orientation==="horizontal"){this.range.stop(1,1)[animate?"animate":"css"]({width:valPercent+"%"},o.animate);}
if(oRange==="max"&&this.orientation==="horizontal"){this.range[animate?"animate":"css"]({width:(100-valPercent)+"%"},{queue:false,duration:o.animate});}
if(oRange==="min"&&this.orientation==="vertical"){this.range.stop(1,1)[animate?"animate":"css"]({height:valPercent+"%"},o.animate);}
if(oRange==="max"&&this.orientation==="vertical"){this.range[animate?"animate":"css"]({height:(100-valPercent)+"%"},{queue:false,duration:o.animate});}}},_handleEvents:{keydown:function(event){var allowed,curVal,newVal,step,index=$(event.target).data("ui-slider-handle-index");switch(event.keyCode){case $.ui.keyCode.HOME:case $.ui.keyCode.END:case $.ui.keyCode.PAGE_UP:case $.ui.keyCode.PAGE_DOWN:case $.ui.keyCode.UP:case $.ui.keyCode.RIGHT:case $.ui.keyCode.DOWN:case $.ui.keyCode.LEFT:event.preventDefault();if(!this._keySliding){this._keySliding=true;$(event.target).addClass("ui-state-active");allowed=this._start(event,index);if(allowed===false){return;}}
break;}
step=this.options.step;if(this.options.values&&this.options.values.length){curVal=newVal=this.values(index);}else{curVal=newVal=this.value();}
switch(event.keyCode){case $.ui.keyCode.HOME:newVal=this._valueMin();break;case $.ui.keyCode.END:newVal=this._valueMax();break;case $.ui.keyCode.PAGE_UP:newVal=this._trimAlignValue(curVal+((this._valueMax()-this._valueMin())/numPages));break;case $.ui.keyCode.PAGE_DOWN:newVal=this._trimAlignValue(curVal-((this._valueMax()-this._valueMin())/numPages));break;case $.ui.keyCode.UP:case $.ui.keyCode.RIGHT:if(curVal===this._valueMax()){return;}
newVal=this._trimAlignValue(curVal+step);break;case $.ui.keyCode.DOWN:case $.ui.keyCode.LEFT:if(curVal===this._valueMin()){return;}
newVal=this._trimAlignValue(curVal-step);break;}
this._slide(event,index,newVal);},click:function(event){event.preventDefault();},keyup:function(event){var index=$(event.target).data("ui-slider-handle-index");if(this._keySliding){this._keySliding=false;this._stop(event,index);this._change(event,index);$(event.target).removeClass("ui-state-active");}}}});}(jQuery));(function($){function modifier(fn){return function(){var previous=this.element.val();fn.apply(this,arguments);this._refresh();if(previous!==this.element.val()){this._trigger("change");}};}
$.widget("ui.spinner",{version:"1.10.4",defaultElement:"<input>",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:true,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max);this._setOption("min",this.options.min);this._setOption("step",this.options.step);if(this.value()!==""){this._value(this.element.val(),true);}
this._draw();this._on(this._events);this._refresh();this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete");}});},_getCreateOptions:function(){var options={},element=this.element;$.each(["min","max","step"],function(i,option){var value=element.attr(option);if(value!==undefined&&value.length){options[option]=value;}});return options;},_events:{keydown:function(event){if(this._start(event)&&this._keydown(event)){event.preventDefault();}},keyup:"_stop",focus:function(){this.previous=this.element.val();},blur:function(event){if(this.cancelBlur){delete this.cancelBlur;return;}
this._stop();this._refresh();if(this.previous!==this.element.val()){this._trigger("change",event);}},mousewheel:function(event,delta){if(!delta){return;}
if(!this.spinning&&!this._start(event)){return false;}
this._spin((delta>0?1:-1)*this.options.step,event);clearTimeout(this.mousewheelTimer);this.mousewheelTimer=this._delay(function(){if(this.spinning){this._stop(event);}},100);event.preventDefault();},"mousedown .ui-spinner-button":function(event){var previous;previous=this.element[0]===this.document[0].activeElement?this.previous:this.element.val();function checkFocus(){var isActive=this.element[0]===this.document[0].activeElement;if(!isActive){this.element.focus();this.previous=previous;this._delay(function(){this.previous=previous;});}}
event.preventDefault();checkFocus.call(this);this.cancelBlur=true;this._delay(function(){delete this.cancelBlur;checkFocus.call(this);});if(this._start(event)===false){return;}
this._repeat(null,$(event.currentTarget).hasClass("ui-spinner-up")?1:-1,event);},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(event){if(!$(event.currentTarget).hasClass("ui-state-active")){return;}
if(this._start(event)===false){return false;}
this._repeat(null,$(event.currentTarget).hasClass("ui-spinner-up")?1:-1,event);},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var uiSpinner=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton");this.buttons=uiSpinner.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all");if(this.buttons.height()>Math.ceil(uiSpinner.height()*0.5)&&uiSpinner.height()>0){uiSpinner.height(uiSpinner.height());}
if(this.options.disabled){this.disable();}},_keydown:function(event){var options=this.options,keyCode=$.ui.keyCode;switch(event.keyCode){case keyCode.UP:this._repeat(null,1,event);return true;case keyCode.DOWN:this._repeat(null,-1,event);return true;case keyCode.PAGE_UP:this._repeat(null,options.page,event);return true;case keyCode.PAGE_DOWN:this._repeat(null,-options.page,event);return true;}
return false;},_uiSpinnerHtml:function(){return"<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";},_buttonHtml:function(){return""+"<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>"+"<span class='ui-icon "+this.options.icons.up+"'>&#9650;</span>"+"</a>"+"<a class='ui-spinner-button ui-spinner-down ui-corner-br'>"+"<span class='ui-icon "+this.options.icons.down+"'>&#9660;</span>"+"</a>";},_start:function(event){if(!this.spinning&&this._trigger("start",event)===false){return false;}
if(!this.counter){this.counter=1;}
this.spinning=true;return true;},_repeat:function(i,steps,event){i=i||500;clearTimeout(this.timer);this.timer=this._delay(function(){this._repeat(40,steps,event);},i);this._spin(steps*this.options.step,event);},_spin:function(step,event){var value=this.value()||0;if(!this.counter){this.counter=1;}
value=this._adjustValue(value+step*this._increment(this.counter));if(!this.spinning||this._trigger("spin",event,{value:value})!==false){this._value(value);this.counter++;}},_increment:function(i){var incremental=this.options.incremental;if(incremental){return $.isFunction(incremental)?incremental(i):Math.floor(i*i*i/50000-i*i/500+17*i/200+1);}
return 1;},_precision:function(){var precision=this._precisionOf(this.options.step);if(this.options.min!==null){precision=Math.max(precision,this._precisionOf(this.options.min));}
return precision;},_precisionOf:function(num){var str=num.toString(),decimal=str.indexOf(".");return decimal===-1?0:str.length-decimal-1;},_adjustValue:function(value){var base,aboveMin,options=this.options;base=options.min!==null?options.min:0;aboveMin=value-base;aboveMin=Math.round(aboveMin/options.step)*options.step;value=base+aboveMin;value=parseFloat(value.toFixed(this._precision()));if(options.max!==null&&value>options.max){return options.max;}
if(options.min!==null&&value<options.min){return options.min;}
return value;},_stop:function(event){if(!this.spinning){return;}
clearTimeout(this.timer);clearTimeout(this.mousewheelTimer);this.counter=0;this.spinning=false;this._trigger("stop",event);},_setOption:function(key,value){if(key==="culture"||key==="numberFormat"){var prevValue=this._parse(this.element.val());this.options[key]=value;this.element.val(this._format(prevValue));return;}
if(key==="max"||key==="min"||key==="step"){if(typeof value==="string"){value=this._parse(value);}}
if(key==="icons"){this.buttons.first().find(".ui-icon").removeClass(this.options.icons.up).addClass(value.up);this.buttons.last().find(".ui-icon").removeClass(this.options.icons.down).addClass(value.down);}
this._super(key,value);if(key==="disabled"){if(value){this.element.prop("disabled",true);this.buttons.button("disable");}else{this.element.prop("disabled",false);this.buttons.button("enable");}}},_setOptions:modifier(function(options){this._super(options);this._value(this.element.val());}),_parse:function(val){if(typeof val==="string"&&val!==""){val=window.Globalize&&this.options.numberFormat?Globalize.parseFloat(val,10,this.options.culture):+val;}
return val===""||isNaN(val)?null:val;},_format:function(value){if(value===""){return"";}
return window.Globalize&&this.options.numberFormat?Globalize.format(value,this.options.numberFormat,this.options.culture):value;},_refresh:function(){this.element.attr({"aria-valuemin":this.options.min,"aria-valuemax":this.options.max,"aria-valuenow":this._parse(this.element.val())});},_value:function(value,allowAny){var parsed;if(value!==""){parsed=this._parse(value);if(parsed!==null){if(!allowAny){parsed=this._adjustValue(parsed);}
value=this._format(parsed);}}
this.element.val(value);this._refresh();},_destroy:function(){this.element.removeClass("ui-spinner-input").prop("disabled",false).removeAttr("autocomplete").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");this.uiSpinner.replaceWith(this.element);},stepUp:modifier(function(steps){this._stepUp(steps);}),_stepUp:function(steps){if(this._start()){this._spin((steps||1)*this.options.step);this._stop();}},stepDown:modifier(function(steps){this._stepDown(steps);}),_stepDown:function(steps){if(this._start()){this._spin((steps||1)*-this.options.step);this._stop();}},pageUp:modifier(function(pages){this._stepUp((pages||1)*this.options.page);}),pageDown:modifier(function(pages){this._stepDown((pages||1)*this.options.page);}),value:function(newVal){if(!arguments.length){return this._parse(this.element.val());}
modifier(this._value).call(this,newVal);},widget:function(){return this.uiSpinner;}});}(jQuery));(function($,undefined){var tabId=0,rhash=/#.*$/;function getNextTabId(){return++tabId;}
function isLocal(anchor){anchor=anchor.cloneNode(false);return anchor.hash.length>1&&decodeURIComponent(anchor.href.replace(rhash,""))===decodeURIComponent(location.href.replace(rhash,""));}
$.widget("ui.tabs",{version:"1.10.4",delay:300,options:{active:null,collapsible:false,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var that=this,options=this.options;this.running=false;this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",options.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(event){if($(this).is(".ui-state-disabled")){event.preventDefault();}}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){if($(this).closest("li").is(".ui-state-disabled")){this.blur();}});this._processTabs();options.active=this._initialActive();if($.isArray(options.disabled)){options.disabled=$.unique(options.disabled.concat($.map(this.tabs.filter(".ui-state-disabled"),function(li){return that.tabs.index(li);}))).sort();}
if(this.options.active!==false&&this.anchors.length){this.active=this._findActive(options.active);}else{this.active=$();}
this._refresh();if(this.active.length){this.load(options.active);}},_initialActive:function(){var active=this.options.active,collapsible=this.options.collapsible,locationHash=location.hash.substring(1);if(active===null){if(locationHash){this.tabs.each(function(i,tab){if($(tab).attr("aria-controls")===locationHash){active=i;return false;}});}
if(active===null){active=this.tabs.index(this.tabs.filter(".ui-tabs-active"));}
if(active===null||active===-1){active=this.tabs.length?0:false;}}
if(active!==false){active=this.tabs.index(this.tabs.eq(active));if(active===-1){active=collapsible?false:0;}}
if(!collapsible&&active===false&&this.anchors.length){active=0;}
return active;},_getCreateEventData:function(){return{tab:this.active,panel:!this.active.length?$():this._getPanelForTab(this.active)};},_tabKeydown:function(event){var focusedTab=$(this.document[0].activeElement).closest("li"),selectedIndex=this.tabs.index(focusedTab),goingForward=true;if(this._handlePageNav(event)){return;}
switch(event.keyCode){case $.ui.keyCode.RIGHT:case $.ui.keyCode.DOWN:selectedIndex++;break;case $.ui.keyCode.UP:case $.ui.keyCode.LEFT:goingForward=false;selectedIndex--;break;case $.ui.keyCode.END:selectedIndex=this.anchors.length-1;break;case $.ui.keyCode.HOME:selectedIndex=0;break;case $.ui.keyCode.SPACE:event.preventDefault();clearTimeout(this.activating);this._activate(selectedIndex);return;case $.ui.keyCode.ENTER:event.preventDefault();clearTimeout(this.activating);this._activate(selectedIndex===this.options.active?false:selectedIndex);return;default:return;}
event.preventDefault();clearTimeout(this.activating);selectedIndex=this._focusNextTab(selectedIndex,goingForward);if(!event.ctrlKey){focusedTab.attr("aria-selected","false");this.tabs.eq(selectedIndex).attr("aria-selected","true");this.activating=this._delay(function(){this.option("active",selectedIndex);},this.delay);}},_panelKeydown:function(event){if(this._handlePageNav(event)){return;}
if(event.ctrlKey&&event.keyCode===$.ui.keyCode.UP){event.preventDefault();this.active.focus();}},_handlePageNav:function(event){if(event.altKey&&event.keyCode===$.ui.keyCode.PAGE_UP){this._activate(this._focusNextTab(this.options.active-1,false));return true;}
if(event.altKey&&event.keyCode===$.ui.keyCode.PAGE_DOWN){this._activate(this._focusNextTab(this.options.active+1,true));return true;}},_findNextTab:function(index,goingForward){var lastTabIndex=this.tabs.length-1;function constrain(){if(index>lastTabIndex){index=0;}
if(index<0){index=lastTabIndex;}
return index;}
while($.inArray(constrain(),this.options.disabled)!==-1){index=goingForward?index+1:index-1;}
return index;},_focusNextTab:function(index,goingForward){index=this._findNextTab(index,goingForward);this.tabs.eq(index).focus();return index;},_setOption:function(key,value){if(key==="active"){this._activate(value);return;}
if(key==="disabled"){this._setupDisabled(value);return;}
this._super(key,value);if(key==="collapsible"){this.element.toggleClass("ui-tabs-collapsible",value);if(!value&&this.options.active===false){this._activate(0);}}
if(key==="event"){this._setupEvents(value);}
if(key==="heightStyle"){this._setupHeightStyle(value);}},_tabId:function(tab){return tab.attr("aria-controls")||"ui-tabs-"+getNextTabId();},_sanitizeSelector:function(hash){return hash?hash.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):"";},refresh:function(){var options=this.options,lis=this.tablist.children(":has(a[href])");options.disabled=$.map(lis.filter(".ui-state-disabled"),function(tab){return lis.index(tab);});this._processTabs();if(options.active===false||!this.anchors.length){options.active=false;this.active=$();}else if(this.active.length&&!$.contains(this.tablist[0],this.active[0])){if(this.tabs.length===options.disabled.length){options.active=false;this.active=$();}else{this._activate(this._findNextTab(Math.max(0,options.active-1),false));}}else{options.active=this.tabs.index(this.active);}
this._refresh();},_refresh:function(){this._setupDisabled(this.options.disabled);this._setupEvents(this.options.event);this._setupHeightStyle(this.options.heightStyle);this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1});this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"});if(!this.active.length){this.tabs.eq(0).attr("tabIndex",0);}else{this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0});this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"});}},_processTabs:function(){var that=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist");this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1});this.anchors=this.tabs.map(function(){return $("a",this)[0];}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1});this.panels=$();this.anchors.each(function(i,anchor){var selector,panel,panelId,anchorId=$(anchor).uniqueId().attr("id"),tab=$(anchor).closest("li"),originalAriaControls=tab.attr("aria-controls");if(isLocal(anchor)){selector=anchor.hash;panel=that.element.find(that._sanitizeSelector(selector));}else{panelId=that._tabId(tab);selector="#"+panelId;panel=that.element.find(selector);if(!panel.length){panel=that._createPanel(panelId);panel.insertAfter(that.panels[i-1]||that.tablist);}
panel.attr("aria-live","polite");}
if(panel.length){that.panels=that.panels.add(panel);}
if(originalAriaControls){tab.data("ui-tabs-aria-controls",originalAriaControls);}
tab.attr({"aria-controls":selector.substring(1),"aria-labelledby":anchorId});panel.attr("aria-labelledby",anchorId);});this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel");},_getList:function(){return this.tablist||this.element.find("ol,ul").eq(0);},_createPanel:function(id){return $("<div>").attr("id",id).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",true);},_setupDisabled:function(disabled){if($.isArray(disabled)){if(!disabled.length){disabled=false;}else if(disabled.length===this.anchors.length){disabled=true;}}
for(var i=0,li;(li=this.tabs[i]);i++){if(disabled===true||$.inArray(i,disabled)!==-1){$(li).addClass("ui-state-disabled").attr("aria-disabled","true");}else{$(li).removeClass("ui-state-disabled").removeAttr("aria-disabled");}}
this.options.disabled=disabled;},_setupEvents:function(event){var events={click:function(event){event.preventDefault();}};if(event){$.each(event.split(" "),function(index,eventName){events[eventName]="_eventHandler";});}
this._off(this.anchors.add(this.tabs).add(this.panels));this._on(this.anchors,events);this._on(this.tabs,{keydown:"_tabKeydown"});this._on(this.panels,{keydown:"_panelKeydown"});this._focusable(this.tabs);this._hoverable(this.tabs);},_setupHeightStyle:function(heightStyle){var maxHeight,parent=this.element.parent();if(heightStyle==="fill"){maxHeight=parent.height();maxHeight-=this.element.outerHeight()-this.element.height();this.element.siblings(":visible").each(function(){var elem=$(this),position=elem.css("position");if(position==="absolute"||position==="fixed"){return;}
maxHeight-=elem.outerHeight(true);});this.element.children().not(this.panels).each(function(){maxHeight-=$(this).outerHeight(true);});this.panels.each(function(){$(this).height(Math.max(0,maxHeight-
$(this).innerHeight()+$(this).height()));}).css("overflow","auto");}else if(heightStyle==="auto"){maxHeight=0;this.panels.each(function(){maxHeight=Math.max(maxHeight,$(this).height("").height());}).height(maxHeight);}},_eventHandler:function(event){var options=this.options,active=this.active,anchor=$(event.currentTarget),tab=anchor.closest("li"),clickedIsActive=tab[0]===active[0],collapsing=clickedIsActive&&options.collapsible,toShow=collapsing?$():this._getPanelForTab(tab),toHide=!active.length?$():this._getPanelForTab(active),eventData={oldTab:active,oldPanel:toHide,newTab:collapsing?$():tab,newPanel:toShow};event.preventDefault();if(tab.hasClass("ui-state-disabled")||tab.hasClass("ui-tabs-loading")||this.running||(clickedIsActive&&!options.collapsible)||(this._trigger("beforeActivate",event,eventData)===false)){return;}
options.active=collapsing?false:this.tabs.index(tab);this.active=clickedIsActive?$():tab;if(this.xhr){this.xhr.abort();}
if(!toHide.length&&!toShow.length){$.error("jQuery UI Tabs: Mismatching fragment identifier.");}
if(toShow.length){this.load(this.tabs.index(tab),event);}
this._toggle(event,eventData);},_toggle:function(event,eventData){var that=this,toShow=eventData.newPanel,toHide=eventData.oldPanel;this.running=true;function complete(){that.running=false;that._trigger("activate",event,eventData);}
function show(){eventData.newTab.closest("li").addClass("ui-tabs-active ui-state-active");if(toShow.length&&that.options.show){that._show(toShow,that.options.show,complete);}else{toShow.show();complete();}}
if(toHide.length&&this.options.hide){this._hide(toHide,this.options.hide,function(){eventData.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");show();});}else{eventData.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active");toHide.hide();show();}
toHide.attr({"aria-expanded":"false","aria-hidden":"true"});eventData.oldTab.attr("aria-selected","false");if(toShow.length&&toHide.length){eventData.oldTab.attr("tabIndex",-1);}else if(toShow.length){this.tabs.filter(function(){return $(this).attr("tabIndex")===0;}).attr("tabIndex",-1);}
toShow.attr({"aria-expanded":"true","aria-hidden":"false"});eventData.newTab.attr({"aria-selected":"true",tabIndex:0});},_activate:function(index){var anchor,active=this._findActive(index);if(active[0]===this.active[0]){return;}
if(!active.length){active=this.active;}
anchor=active.find(".ui-tabs-anchor")[0];this._eventHandler({target:anchor,currentTarget:anchor,preventDefault:$.noop});},_findActive:function(index){return index===false?$():this.tabs.eq(index);},_getIndex:function(index){if(typeof index==="string"){index=this.anchors.index(this.anchors.filter("[href$='"+index+"']"));}
return index;},_destroy:function(){if(this.xhr){this.xhr.abort();}
this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible");this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role");this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeUniqueId();this.tabs.add(this.panels).each(function(){if($.data(this,"ui-tabs-destroy")){$(this).remove();}else{$(this).removeClass("ui-state-default ui-state-active ui-state-disabled "+"ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role");}});this.tabs.each(function(){var li=$(this),prev=li.data("ui-tabs-aria-controls");if(prev){li.attr("aria-controls",prev).removeData("ui-tabs-aria-controls");}else{li.removeAttr("aria-controls");}});this.panels.show();if(this.options.heightStyle!=="content"){this.panels.css("height","");}},enable:function(index){var disabled=this.options.disabled;if(disabled===false){return;}
if(index===undefined){disabled=false;}else{index=this._getIndex(index);if($.isArray(disabled)){disabled=$.map(disabled,function(num){return num!==index?num:null;});}else{disabled=$.map(this.tabs,function(li,num){return num!==index?num:null;});}}
this._setupDisabled(disabled);},disable:function(index){var disabled=this.options.disabled;if(disabled===true){return;}
if(index===undefined){disabled=true;}else{index=this._getIndex(index);if($.inArray(index,disabled)!==-1){return;}
if($.isArray(disabled)){disabled=$.merge([index],disabled).sort();}else{disabled=[index];}}
this._setupDisabled(disabled);},load:function(index,event){index=this._getIndex(index);var that=this,tab=this.tabs.eq(index),anchor=tab.find(".ui-tabs-anchor"),panel=this._getPanelForTab(tab),eventData={tab:tab,panel:panel};if(isLocal(anchor[0])){return;}
this.xhr=$.ajax(this._ajaxSettings(anchor,event,eventData));if(this.xhr&&this.xhr.statusText!=="canceled"){tab.addClass("ui-tabs-loading");panel.attr("aria-busy","true");this.xhr.success(function(response){setTimeout(function(){panel.html(response);that._trigger("load",event,eventData);},1);}).complete(function(jqXHR,status){setTimeout(function(){if(status==="abort"){that.panels.stop(false,true);}
tab.removeClass("ui-tabs-loading");panel.removeAttr("aria-busy");if(jqXHR===that.xhr){delete that.xhr;}},1);});}},_ajaxSettings:function(anchor,event,eventData){var that=this;return{url:anchor.attr("href"),beforeSend:function(jqXHR,settings){return that._trigger("beforeLoad",event,$.extend({jqXHR:jqXHR,ajaxSettings:settings},eventData));}};},_getPanelForTab:function(tab){var id=$(tab).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+id));}});})(jQuery);(function($){var increments=0;function addDescribedBy(elem,id){var describedby=(elem.attr("aria-describedby")||"").split(/\s+/);describedby.push(id);elem.data("ui-tooltip-id",id).attr("aria-describedby",$.trim(describedby.join(" ")));}
function removeDescribedBy(elem){var id=elem.data("ui-tooltip-id"),describedby=(elem.attr("aria-describedby")||"").split(/\s+/),index=$.inArray(id,describedby);if(index!==-1){describedby.splice(index,1);}
elem.removeData("ui-tooltip-id");describedby=$.trim(describedby.join(" "));if(describedby){elem.attr("aria-describedby",describedby);}else{elem.removeAttr("aria-describedby");}}
$.widget("ui.tooltip",{version:"1.10.4",options:{content:function(){var title=$(this).attr("title")||"";return $("<a>").text(title).html();},hide:true,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:true,tooltipClass:null,track:false,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"});this.tooltips={};this.parents={};if(this.options.disabled){this._disable();}},_setOption:function(key,value){var that=this;if(key==="disabled"){this[value?"_disable":"_enable"]();this.options[key]=value;return;}
this._super(key,value);if(key==="content"){$.each(this.tooltips,function(id,element){that._updateContent(element);});}},_disable:function(){var that=this;$.each(this.tooltips,function(id,element){var event=$.Event("blur");event.target=event.currentTarget=element[0];that.close(event,true);});this.element.find(this.options.items).addBack().each(function(){var element=$(this);if(element.is("[title]")){element.data("ui-tooltip-title",element.attr("title")).attr("title","");}});},_enable:function(){this.element.find(this.options.items).addBack().each(function(){var element=$(this);if(element.data("ui-tooltip-title")){element.attr("title",element.data("ui-tooltip-title"));}});},open:function(event){var that=this,target=$(event?event.target:this.element).closest(this.options.items);if(!target.length||target.data("ui-tooltip-id")){return;}
if(target.attr("title")){target.data("ui-tooltip-title",target.attr("title"));}
target.data("ui-tooltip-open",true);if(event&&event.type==="mouseover"){target.parents().each(function(){var parent=$(this),blurEvent;if(parent.data("ui-tooltip-open")){blurEvent=$.Event("blur");blurEvent.target=blurEvent.currentTarget=this;that.close(blurEvent,true);}
if(parent.attr("title")){parent.uniqueId();that.parents[this.id]={element:this,title:parent.attr("title")};parent.attr("title","");}});}
this._updateContent(target,event);},_updateContent:function(target,event){var content,contentOption=this.options.content,that=this,eventType=event?event.type:null;if(typeof contentOption==="string"){return this._open(event,target,contentOption);}
content=contentOption.call(target[0],function(response){if(!target.data("ui-tooltip-open")){return;}
that._delay(function(){if(event){event.type=eventType;}
this._open(event,target,response);});});if(content){this._open(event,target,content);}},_open:function(event,target,content){var tooltip,events,delayedShow,positionOption=$.extend({},this.options.position);if(!content){return;}
tooltip=this._find(target);if(tooltip.length){tooltip.find(".ui-tooltip-content").html(content);return;}
if(target.is("[title]")){if(event&&event.type==="mouseover"){target.attr("title","");}else{target.removeAttr("title");}}
tooltip=this._tooltip(target);addDescribedBy(target,tooltip.attr("id"));tooltip.find(".ui-tooltip-content").html(content);function position(event){positionOption.of=event;if(tooltip.is(":hidden")){return;}
tooltip.position(positionOption);}
if(this.options.track&&event&&/^mouse/.test(event.type)){this._on(this.document,{mousemove:position});position(event);}else{tooltip.position($.extend({of:target},this.options.position));}
tooltip.hide();this._show(tooltip,this.options.show);if(this.options.show&&this.options.show.delay){delayedShow=this.delayedShow=setInterval(function(){if(tooltip.is(":visible")){position(positionOption.of);clearInterval(delayedShow);}},$.fx.interval);}
this._trigger("open",event,{tooltip:tooltip});events={keyup:function(event){if(event.keyCode===$.ui.keyCode.ESCAPE){var fakeEvent=$.Event(event);fakeEvent.currentTarget=target[0];this.close(fakeEvent,true);}},remove:function(){this._removeTooltip(tooltip);}};if(!event||event.type==="mouseover"){events.mouseleave="close";}
if(!event||event.type==="focusin"){events.focusout="close";}
this._on(true,target,events);},close:function(event){var that=this,target=$(event?event.currentTarget:this.element),tooltip=this._find(target);if(this.closing){return;}
clearInterval(this.delayedShow);if(target.data("ui-tooltip-title")){target.attr("title",target.data("ui-tooltip-title"));}
removeDescribedBy(target);tooltip.stop(true);this._hide(tooltip,this.options.hide,function(){that._removeTooltip($(this));});target.removeData("ui-tooltip-open");this._off(target,"mouseleave focusout keyup");if(target[0]!==this.element[0]){this._off(target,"remove");}
this._off(this.document,"mousemove");if(event&&event.type==="mouseleave"){$.each(this.parents,function(id,parent){$(parent.element).attr("title",parent.title);delete that.parents[id];});}
this.closing=true;this._trigger("close",event,{tooltip:tooltip});this.closing=false;},_tooltip:function(element){var id="ui-tooltip-"+increments++,tooltip=$("<div>").attr({id:id,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+
(this.options.tooltipClass||""));$("<div>").addClass("ui-tooltip-content").appendTo(tooltip);tooltip.appendTo(this.document[0].body);this.tooltips[id]=element;return tooltip;},_find:function(target){var id=target.data("ui-tooltip-id");return id?$("#"+id):$();},_removeTooltip:function(tooltip){tooltip.remove();delete this.tooltips[tooltip.attr("id")];},_destroy:function(){var that=this;$.each(this.tooltips,function(id,element){var event=$.Event("blur");event.target=event.currentTarget=element[0];that.close(event,true);$("#"+id).remove();if(element.data("ui-tooltip-title")){element.attr("title",element.data("ui-tooltip-title"));element.removeData("ui-tooltip-title");}});}});}(jQuery));(function($,undefined){var dataSpace="ui-effects-";$.effects={effect:{}};(function(jQuery,undefined){var stepHooks="backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",rplusequals=/^([\-+])=\s*(\d+\.?\d*)/,stringParsers=[{re:/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(execResult){return[execResult[1],execResult[2],execResult[3],execResult[4]];}},{re:/rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,parse:function(execResult){return[execResult[1]*2.55,execResult[2]*2.55,execResult[3]*2.55,execResult[4]];}},{re:/#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,parse:function(execResult){return[parseInt(execResult[1],16),parseInt(execResult[2],16),parseInt(execResult[3],16)];}},{re:/#([a-f0-9])([a-f0-9])([a-f0-9])/,parse:function(execResult){return[parseInt(execResult[1]+execResult[1],16),parseInt(execResult[2]+execResult[2],16),parseInt(execResult[3]+execResult[3],16)];}},{re:/hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,space:"hsla",parse:function(execResult){return[execResult[1],execResult[2]/100,execResult[3]/100,execResult[4]];}}],color=jQuery.Color=function(color,green,blue,alpha){return new jQuery.Color.fn.parse(color,green,blue,alpha);},spaces={rgba:{props:{red:{idx:0,type:"byte"},green:{idx:1,type:"byte"},blue:{idx:2,type:"byte"}}},hsla:{props:{hue:{idx:0,type:"degrees"},saturation:{idx:1,type:"percent"},lightness:{idx:2,type:"percent"}}}},propTypes={"byte":{floor:true,max:255},"percent":{max:1},"degrees":{mod:360,floor:true}},support=color.support={},supportElem=jQuery("<p>")[0],colors,each=jQuery.each;supportElem.style.cssText="background-color:rgba(1,1,1,.5)";support.rgba=supportElem.style.backgroundColor.indexOf("rgba")>-1;each(spaces,function(spaceName,space){space.cache="_"+spaceName;space.props.alpha={idx:3,type:"percent",def:1};});function clamp(value,prop,allowEmpty){var type=propTypes[prop.type]||{};if(value==null){return(allowEmpty||!prop.def)?null:prop.def;}
value=type.floor?~~value:parseFloat(value);if(isNaN(value)){return prop.def;}
if(type.mod){return(value+type.mod)%type.mod;}
return 0>value?0:type.max<value?type.max:value;}
function stringParse(string){var inst=color(),rgba=inst._rgba=[];string=string.toLowerCase();each(stringParsers,function(i,parser){var parsed,match=parser.re.exec(string),values=match&&parser.parse(match),spaceName=parser.space||"rgba";if(values){parsed=inst[spaceName](values);inst[spaces[spaceName].cache]=parsed[spaces[spaceName].cache];rgba=inst._rgba=parsed._rgba;return false;}});if(rgba.length){if(rgba.join()==="0,0,0,0"){jQuery.extend(rgba,colors.transparent);}
return inst;}
return colors[string];}
color.fn=jQuery.extend(color.prototype,{parse:function(red,green,blue,alpha){if(red===undefined){this._rgba=[null,null,null,null];return this;}
if(red.jquery||red.nodeType){red=jQuery(red).css(green);green=undefined;}
var inst=this,type=jQuery.type(red),rgba=this._rgba=[];if(green!==undefined){red=[red,green,blue,alpha];type="array";}
if(type==="string"){return this.parse(stringParse(red)||colors._default);}
if(type==="array"){each(spaces.rgba.props,function(key,prop){rgba[prop.idx]=clamp(red[prop.idx],prop);});return this;}
if(type==="object"){if(red instanceof color){each(spaces,function(spaceName,space){if(red[space.cache]){inst[space.cache]=red[space.cache].slice();}});}else{each(spaces,function(spaceName,space){var cache=space.cache;each(space.props,function(key,prop){if(!inst[cache]&&space.to){if(key==="alpha"||red[key]==null){return;}
inst[cache]=space.to(inst._rgba);}
inst[cache][prop.idx]=clamp(red[key],prop,true);});if(inst[cache]&&jQuery.inArray(null,inst[cache].slice(0,3))<0){inst[cache][3]=1;if(space.from){inst._rgba=space.from(inst[cache]);}}});}
return this;}},is:function(compare){var is=color(compare),same=true,inst=this;each(spaces,function(_,space){var localCache,isCache=is[space.cache];if(isCache){localCache=inst[space.cache]||space.to&&space.to(inst._rgba)||[];each(space.props,function(_,prop){if(isCache[prop.idx]!=null){same=(isCache[prop.idx]===localCache[prop.idx]);return same;}});}
return same;});return same;},_space:function(){var used=[],inst=this;each(spaces,function(spaceName,space){if(inst[space.cache]){used.push(spaceName);}});return used.pop();},transition:function(other,distance){var end=color(other),spaceName=end._space(),space=spaces[spaceName],startColor=this.alpha()===0?color("transparent"):this,start=startColor[space.cache]||space.to(startColor._rgba),result=start.slice();end=end[space.cache];each(space.props,function(key,prop){var index=prop.idx,startValue=start[index],endValue=end[index],type=propTypes[prop.type]||{};if(endValue===null){return;}
if(startValue===null){result[index]=endValue;}else{if(type.mod){if(endValue-startValue>type.mod/2){startValue+=type.mod;}else if(startValue-endValue>type.mod/2){startValue-=type.mod;}}
result[index]=clamp((endValue-startValue)*distance+startValue,prop);}});return this[spaceName](result);},blend:function(opaque){if(this._rgba[3]===1){return this;}
var rgb=this._rgba.slice(),a=rgb.pop(),blend=color(opaque)._rgba;return color(jQuery.map(rgb,function(v,i){return(1-a)*blend[i]+a*v;}));},toRgbaString:function(){var prefix="rgba(",rgba=jQuery.map(this._rgba,function(v,i){return v==null?(i>2?1:0):v;});if(rgba[3]===1){rgba.pop();prefix="rgb(";}
return prefix+rgba.join()+")";},toHslaString:function(){var prefix="hsla(",hsla=jQuery.map(this.hsla(),function(v,i){if(v==null){v=i>2?1:0;}
if(i&&i<3){v=Math.round(v*100)+"%";}
return v;});if(hsla[3]===1){hsla.pop();prefix="hsl(";}
return prefix+hsla.join()+")";},toHexString:function(includeAlpha){var rgba=this._rgba.slice(),alpha=rgba.pop();if(includeAlpha){rgba.push(~~(alpha*255));}
return"#"+jQuery.map(rgba,function(v){v=(v||0).toString(16);return v.length===1?"0"+v:v;}).join("");},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString();}});color.fn.parse.prototype=color.fn;function hue2rgb(p,q,h){h=(h+1)%1;if(h*6<1){return p+(q-p)*h*6;}
if(h*2<1){return q;}
if(h*3<2){return p+(q-p)*((2/3)-h)*6;}
return p;}
spaces.hsla.to=function(rgba){if(rgba[0]==null||rgba[1]==null||rgba[2]==null){return[null,null,null,rgba[3]];}
var r=rgba[0]/255,g=rgba[1]/255,b=rgba[2]/255,a=rgba[3],max=Math.max(r,g,b),min=Math.min(r,g,b),diff=max-min,add=max+min,l=add*0.5,h,s;if(min===max){h=0;}else if(r===max){h=(60*(g-b)/diff)+360;}else if(g===max){h=(60*(b-r)/diff)+120;}else{h=(60*(r-g)/diff)+240;}
if(diff===0){s=0;}else if(l<=0.5){s=diff/add;}else{s=diff/(2-add);}
return[Math.round(h)%360,s,l,a==null?1:a];};spaces.hsla.from=function(hsla){if(hsla[0]==null||hsla[1]==null||hsla[2]==null){return[null,null,null,hsla[3]];}
var h=hsla[0]/360,s=hsla[1],l=hsla[2],a=hsla[3],q=l<=0.5?l*(1+s):l+s-l*s,p=2*l-q;return[Math.round(hue2rgb(p,q,h+(1/3))*255),Math.round(hue2rgb(p,q,h)*255),Math.round(hue2rgb(p,q,h-(1/3))*255),a];};each(spaces,function(spaceName,space){var props=space.props,cache=space.cache,to=space.to,from=space.from;color.fn[spaceName]=function(value){if(to&&!this[cache]){this[cache]=to(this._rgba);}
if(value===undefined){return this[cache].slice();}
var ret,type=jQuery.type(value),arr=(type==="array"||type==="object")?value:arguments,local=this[cache].slice();each(props,function(key,prop){var val=arr[type==="object"?key:prop.idx];if(val==null){val=local[prop.idx];}
local[prop.idx]=clamp(val,prop);});if(from){ret=color(from(local));ret[cache]=local;return ret;}else{return color(local);}};each(props,function(key,prop){if(color.fn[key]){return;}
color.fn[key]=function(value){var vtype=jQuery.type(value),fn=(key==="alpha"?(this._hsla?"hsla":"rgba"):spaceName),local=this[fn](),cur=local[prop.idx],match;if(vtype==="undefined"){return cur;}
if(vtype==="function"){value=value.call(this,cur);vtype=jQuery.type(value);}
if(value==null&&prop.empty){return this;}
if(vtype==="string"){match=rplusequals.exec(value);if(match){value=cur+parseFloat(match[2])*(match[1]==="+"?1:-1);}}
local[prop.idx]=value;return this[fn](local);};});});color.hook=function(hook){var hooks=hook.split(" ");each(hooks,function(i,hook){jQuery.cssHooks[hook]={set:function(elem,value){var parsed,curElem,backgroundColor="";if(value!=="transparent"&&(jQuery.type(value)!=="string"||(parsed=stringParse(value)))){value=color(parsed||value);if(!support.rgba&&value._rgba[3]!==1){curElem=hook==="backgroundColor"?elem.parentNode:elem;while((backgroundColor===""||backgroundColor==="transparent")&&curElem&&curElem.style){try{backgroundColor=jQuery.css(curElem,"backgroundColor");curElem=curElem.parentNode;}catch(e){}}
value=value.blend(backgroundColor&&backgroundColor!=="transparent"?backgroundColor:"_default");}
value=value.toRgbaString();}
try{elem.style[hook]=value;}catch(e){}}};jQuery.fx.step[hook]=function(fx){if(!fx.colorInit){fx.start=color(fx.elem,hook);fx.end=color(fx.end);fx.colorInit=true;}
jQuery.cssHooks[hook].set(fx.elem,fx.start.transition(fx.end,fx.pos));};});};color.hook(stepHooks);jQuery.cssHooks.borderColor={expand:function(value){var expanded={};each(["Top","Right","Bottom","Left"],function(i,part){expanded["border"+part+"Color"]=value;});return expanded;}};colors=jQuery.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"};})(jQuery);(function(){var classAnimationActions=["add","remove","toggle"],shorthandStyles={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};$.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(_,prop){$.fx.step[prop]=function(fx){if(fx.end!=="none"&&!fx.setAttr||fx.pos===1&&!fx.setAttr){jQuery.style(fx.elem,prop,fx.end);fx.setAttr=true;}};});function getElementStyles(elem){var key,len,style=elem.ownerDocument.defaultView?elem.ownerDocument.defaultView.getComputedStyle(elem,null):elem.currentStyle,styles={};if(style&&style.length&&style[0]&&style[style[0]]){len=style.length;while(len--){key=style[len];if(typeof style[key]==="string"){styles[$.camelCase(key)]=style[key];}}}else{for(key in style){if(typeof style[key]==="string"){styles[key]=style[key];}}}
return styles;}
function styleDifference(oldStyle,newStyle){var diff={},name,value;for(name in newStyle){value=newStyle[name];if(oldStyle[name]!==value){if(!shorthandStyles[name]){if($.fx.step[name]||!isNaN(parseFloat(value))){diff[name]=value;}}}}
return diff;}
if(!$.fn.addBack){$.fn.addBack=function(selector){return this.add(selector==null?this.prevObject:this.prevObject.filter(selector));};}
$.effects.animateClass=function(value,duration,easing,callback){var o=$.speed(duration,easing,callback);return this.queue(function(){var animated=$(this),baseClass=animated.attr("class")||"",applyClassChange,allAnimations=o.children?animated.find("*").addBack():animated;allAnimations=allAnimations.map(function(){var el=$(this);return{el:el,start:getElementStyles(this)};});applyClassChange=function(){$.each(classAnimationActions,function(i,action){if(value[action]){animated[action+"Class"](value[action]);}});};applyClassChange();allAnimations=allAnimations.map(function(){this.end=getElementStyles(this.el[0]);this.diff=styleDifference(this.start,this.end);return this;});animated.attr("class",baseClass);allAnimations=allAnimations.map(function(){var styleInfo=this,dfd=$.Deferred(),opts=$.extend({},o,{queue:false,complete:function(){dfd.resolve(styleInfo);}});this.el.animate(this.diff,opts);return dfd.promise();});$.when.apply($,allAnimations.get()).done(function(){applyClassChange();$.each(arguments,function(){var el=this.el;$.each(this.diff,function(key){el.css(key,"");});});o.complete.call(animated[0]);});});};$.fn.extend({addClass:(function(orig){return function(classNames,speed,easing,callback){return speed?$.effects.animateClass.call(this,{add:classNames},speed,easing,callback):orig.apply(this,arguments);};})($.fn.addClass),removeClass:(function(orig){return function(classNames,speed,easing,callback){return arguments.length>1?$.effects.animateClass.call(this,{remove:classNames},speed,easing,callback):orig.apply(this,arguments);};})($.fn.removeClass),toggleClass:(function(orig){return function(classNames,force,speed,easing,callback){if(typeof force==="boolean"||force===undefined){if(!speed){return orig.apply(this,arguments);}else{return $.effects.animateClass.call(this,(force?{add:classNames}:{remove:classNames}),speed,easing,callback);}}else{return $.effects.animateClass.call(this,{toggle:classNames},force,speed,easing);}};})($.fn.toggleClass),switchClass:function(remove,add,speed,easing,callback){return $.effects.animateClass.call(this,{add:add,remove:remove},speed,easing,callback);}});})();(function(){$.extend($.effects,{version:"1.10.4",save:function(element,set){for(var i=0;i<set.length;i++){if(set[i]!==null){element.data(dataSpace+set[i],element[0].style[set[i]]);}}},restore:function(element,set){var val,i;for(i=0;i<set.length;i++){if(set[i]!==null){val=element.data(dataSpace+set[i]);if(val===undefined){val="";}
element.css(set[i],val);}}},setMode:function(el,mode){if(mode==="toggle"){mode=el.is(":hidden")?"show":"hide";}
return mode;},getBaseline:function(origin,original){var y,x;switch(origin[0]){case"top":y=0;break;case"middle":y=0.5;break;case"bottom":y=1;break;default:y=origin[0]/original.height;}
switch(origin[1]){case"left":x=0;break;case"center":x=0.5;break;case"right":x=1;break;default:x=origin[1]/original.width;}
return{x:x,y:y};},createWrapper:function(element){if(element.parent().is(".ui-effects-wrapper")){return element.parent();}
var props={width:element.outerWidth(true),height:element.outerHeight(true),"float":element.css("float")},wrapper=$("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),size={width:element.width(),height:element.height()},active=document.activeElement;try{active.id;}catch(e){active=document.body;}
element.wrap(wrapper);if(element[0]===active||$.contains(element[0],active)){$(active).focus();}
wrapper=element.parent();if(element.css("position")==="static"){wrapper.css({position:"relative"});element.css({position:"relative"});}else{$.extend(props,{position:element.css("position"),zIndex:element.css("z-index")});$.each(["top","left","bottom","right"],function(i,pos){props[pos]=element.css(pos);if(isNaN(parseInt(props[pos],10))){props[pos]="auto";}});element.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"});}
element.css(size);return wrapper.css(props).show();},removeWrapper:function(element){var active=document.activeElement;if(element.parent().is(".ui-effects-wrapper")){element.parent().replaceWith(element);if(element[0]===active||$.contains(element[0],active)){$(active).focus();}}
return element;},setTransition:function(element,list,factor,value){value=value||{};$.each(list,function(i,x){var unit=element.cssUnit(x);if(unit[0]>0){value[x]=unit[0]*factor+unit[1];}});return value;}});function _normalizeArguments(effect,options,speed,callback){if($.isPlainObject(effect)){options=effect;effect=effect.effect;}
effect={effect:effect};if(options==null){options={};}
if($.isFunction(options)){callback=options;speed=null;options={};}
if(typeof options==="number"||$.fx.speeds[options]){callback=speed;speed=options;options={};}
if($.isFunction(speed)){callback=speed;speed=null;}
if(options){$.extend(effect,options);}
speed=speed||options.duration;effect.duration=$.fx.off?0:typeof speed==="number"?speed:speed in $.fx.speeds?$.fx.speeds[speed]:$.fx.speeds._default;effect.complete=callback||options.complete;return effect;}
function standardAnimationOption(option){if(!option||typeof option==="number"||$.fx.speeds[option]){return true;}
if(typeof option==="string"&&!$.effects.effect[option]){return true;}
if($.isFunction(option)){return true;}
if(typeof option==="object"&&!option.effect){return true;}
return false;}
$.fn.extend({effect:function(){var args=_normalizeArguments.apply(this,arguments),mode=args.mode,queue=args.queue,effectMethod=$.effects.effect[args.effect];if($.fx.off||!effectMethod){if(mode){return this[mode](args.duration,args.complete);}else{return this.each(function(){if(args.complete){args.complete.call(this);}});}}
function run(next){var elem=$(this),complete=args.complete,mode=args.mode;function done(){if($.isFunction(complete)){complete.call(elem[0]);}
if($.isFunction(next)){next();}}
if(elem.is(":hidden")?mode==="hide":mode==="show"){elem[mode]();done();}else{effectMethod.call(elem[0],args,done);}}
return queue===false?this.each(run):this.queue(queue||"fx",run);},show:(function(orig){return function(option){if(standardAnimationOption(option)){return orig.apply(this,arguments);}else{var args=_normalizeArguments.apply(this,arguments);args.mode="show";return this.effect.call(this,args);}};})($.fn.show),hide:(function(orig){return function(option){if(standardAnimationOption(option)){return orig.apply(this,arguments);}else{var args=_normalizeArguments.apply(this,arguments);args.mode="hide";return this.effect.call(this,args);}};})($.fn.hide),toggle:(function(orig){return function(option){if(standardAnimationOption(option)||typeof option==="boolean"){return orig.apply(this,arguments);}else{var args=_normalizeArguments.apply(this,arguments);args.mode="toggle";return this.effect.call(this,args);}};})($.fn.toggle),cssUnit:function(key){var style=this.css(key),val=[];$.each(["em","px","%","pt"],function(i,unit){if(style.indexOf(unit)>0){val=[parseFloat(style),unit];}});return val;}});})();(function(){var baseEasings={};$.each(["Quad","Cubic","Quart","Quint","Expo"],function(i,name){baseEasings[name]=function(p){return Math.pow(p,i+2);};});$.extend(baseEasings,{Sine:function(p){return 1-Math.cos(p*Math.PI/2);},Circ:function(p){return 1-Math.sqrt(1-p*p);},Elastic:function(p){return p===0||p===1?p:-Math.pow(2,8*(p-1))*Math.sin(((p-1)*80-7.5)*Math.PI/15);},Back:function(p){return p*p*(3*p-2);},Bounce:function(p){var pow2,bounce=4;while(p<((pow2=Math.pow(2,--bounce))-1)/11){}
return 1/Math.pow(4,3-bounce)-7.5625*Math.pow((pow2*3-2)/22-p,2);}});$.each(baseEasings,function(name,easeIn){$.easing["easeIn"+name]=easeIn;$.easing["easeOut"+name]=function(p){return 1-easeIn(1-p);};$.easing["easeInOut"+name]=function(p){return p<0.5?easeIn(p*2)/2:1-easeIn(p*-2+2)/2;};});})();})(jQuery);(function($,undefined){var rvertical=/up|down|vertical/,rpositivemotion=/up|left|vertical|horizontal/;$.effects.effect.blind=function(o,done){var el=$(this),props=["position","top","bottom","left","right","height","width"],mode=$.effects.setMode(el,o.mode||"hide"),direction=o.direction||"up",vertical=rvertical.test(direction),ref=vertical?"height":"width",ref2=vertical?"top":"left",motion=rpositivemotion.test(direction),animation={},show=mode==="show",wrapper,distance,margin;if(el.parent().is(".ui-effects-wrapper")){$.effects.save(el.parent(),props);}else{$.effects.save(el,props);}
el.show();wrapper=$.effects.createWrapper(el).css({overflow:"hidden"});distance=wrapper[ref]();margin=parseFloat(wrapper.css(ref2))||0;animation[ref]=show?distance:0;if(!motion){el.css(vertical?"bottom":"right",0).css(vertical?"top":"left","auto").css({position:"absolute"});animation[ref2]=show?margin:distance+margin;}
if(show){wrapper.css(ref,0);if(!motion){wrapper.css(ref2,margin+distance);}}
wrapper.animate(animation,{duration:o.duration,easing:o.easing,queue:false,complete:function(){if(mode==="hide"){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();}});};})(jQuery);(function($,undefined){$.effects.effect.bounce=function(o,done){var el=$(this),props=["position","top","bottom","left","right","height","width"],mode=$.effects.setMode(el,o.mode||"effect"),hide=mode==="hide",show=mode==="show",direction=o.direction||"up",distance=o.distance,times=o.times||5,anims=times*2+(show||hide?1:0),speed=o.duration/anims,easing=o.easing,ref=(direction==="up"||direction==="down")?"top":"left",motion=(direction==="up"||direction==="left"),i,upAnim,downAnim,queue=el.queue(),queuelen=queue.length;if(show||hide){props.push("opacity");}
$.effects.save(el,props);el.show();$.effects.createWrapper(el);if(!distance){distance=el[ref==="top"?"outerHeight":"outerWidth"]()/3;}
if(show){downAnim={opacity:1};downAnim[ref]=0;el.css("opacity",0).css(ref,motion?-distance*2:distance*2).animate(downAnim,speed,easing);}
if(hide){distance=distance/Math.pow(2,times-1);}
downAnim={};downAnim[ref]=0;for(i=0;i<times;i++){upAnim={};upAnim[ref]=(motion?"-=":"+=")+distance;el.animate(upAnim,speed,easing).animate(downAnim,speed,easing);distance=hide?distance*2:distance/2;}
if(hide){upAnim={opacity:0};upAnim[ref]=(motion?"-=":"+=")+distance;el.animate(upAnim,speed,easing);}
el.queue(function(){if(hide){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();});if(queuelen>1){queue.splice.apply(queue,[1,0].concat(queue.splice(queuelen,anims+1)));}
el.dequeue();};})(jQuery);(function($,undefined){$.effects.effect.clip=function(o,done){var el=$(this),props=["position","top","bottom","left","right","height","width"],mode=$.effects.setMode(el,o.mode||"hide"),show=mode==="show",direction=o.direction||"vertical",vert=direction==="vertical",size=vert?"height":"width",position=vert?"top":"left",animation={},wrapper,animate,distance;$.effects.save(el,props);el.show();wrapper=$.effects.createWrapper(el).css({overflow:"hidden"});animate=(el[0].tagName==="IMG")?wrapper:el;distance=animate[size]();if(show){animate.css(size,0);animate.css(position,distance/2);}
animation[size]=show?distance:0;animation[position]=show?0:distance/2;animate.animate(animation,{queue:false,duration:o.duration,easing:o.easing,complete:function(){if(!show){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();}});};})(jQuery);(function($,undefined){$.effects.effect.drop=function(o,done){var el=$(this),props=["position","top","bottom","left","right","opacity","height","width"],mode=$.effects.setMode(el,o.mode||"hide"),show=mode==="show",direction=o.direction||"left",ref=(direction==="up"||direction==="down")?"top":"left",motion=(direction==="up"||direction==="left")?"pos":"neg",animation={opacity:show?1:0},distance;$.effects.save(el,props);el.show();$.effects.createWrapper(el);distance=o.distance||el[ref==="top"?"outerHeight":"outerWidth"](true)/2;if(show){el.css("opacity",0).css(ref,motion==="pos"?-distance:distance);}
animation[ref]=(show?(motion==="pos"?"+=":"-="):(motion==="pos"?"-=":"+="))+
distance;el.animate(animation,{queue:false,duration:o.duration,easing:o.easing,complete:function(){if(mode==="hide"){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();}});};})(jQuery);(function($,undefined){$.effects.effect.explode=function(o,done){var rows=o.pieces?Math.round(Math.sqrt(o.pieces)):3,cells=rows,el=$(this),mode=$.effects.setMode(el,o.mode||"hide"),show=mode==="show",offset=el.show().css("visibility","hidden").offset(),width=Math.ceil(el.outerWidth()/cells),height=Math.ceil(el.outerHeight()/rows),pieces=[],i,j,left,top,mx,my;function childComplete(){pieces.push(this);if(pieces.length===rows*cells){animComplete();}}
for(i=0;i<rows;i++){top=offset.top+i*height;my=i-(rows-1)/2;for(j=0;j<cells;j++){left=offset.left+j*width;mx=j-(cells-1)/2;el.clone().appendTo("body").wrap("<div></div>").css({position:"absolute",visibility:"visible",left:-j*width,top:-i*height}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:width,height:height,left:left+(show?mx*width:0),top:top+(show?my*height:0),opacity:show?0:1}).animate({left:left+(show?0:mx*width),top:top+(show?0:my*height),opacity:show?1:0},o.duration||500,o.easing,childComplete);}}
function animComplete(){el.css({visibility:"visible"});$(pieces).remove();if(!show){el.hide();}
done();}};})(jQuery);(function($,undefined){$.effects.effect.fade=function(o,done){var el=$(this),mode=$.effects.setMode(el,o.mode||"toggle");el.animate({opacity:mode},{queue:false,duration:o.duration,easing:o.easing,complete:done});};})(jQuery);(function($,undefined){$.effects.effect.fold=function(o,done){var el=$(this),props=["position","top","bottom","left","right","height","width"],mode=$.effects.setMode(el,o.mode||"hide"),show=mode==="show",hide=mode==="hide",size=o.size||15,percent=/([0-9]+)%/.exec(size),horizFirst=!!o.horizFirst,widthFirst=show!==horizFirst,ref=widthFirst?["width","height"]:["height","width"],duration=o.duration/2,wrapper,distance,animation1={},animation2={};$.effects.save(el,props);el.show();wrapper=$.effects.createWrapper(el).css({overflow:"hidden"});distance=widthFirst?[wrapper.width(),wrapper.height()]:[wrapper.height(),wrapper.width()];if(percent){size=parseInt(percent[1],10)/100*distance[hide?0:1];}
if(show){wrapper.css(horizFirst?{height:0,width:size}:{height:size,width:0});}
animation1[ref[0]]=show?distance[0]:size;animation2[ref[1]]=show?distance[1]:0;wrapper.animate(animation1,duration,o.easing).animate(animation2,duration,o.easing,function(){if(hide){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();});};})(jQuery);(function($,undefined){$.effects.effect.highlight=function(o,done){var elem=$(this),props=["backgroundImage","backgroundColor","opacity"],mode=$.effects.setMode(elem,o.mode||"show"),animation={backgroundColor:elem.css("backgroundColor")};if(mode==="hide"){animation.opacity=0;}
$.effects.save(elem,props);elem.show().css({backgroundImage:"none",backgroundColor:o.color||"#ffff99"}).animate(animation,{queue:false,duration:o.duration,easing:o.easing,complete:function(){if(mode==="hide"){elem.hide();}
$.effects.restore(elem,props);done();}});};})(jQuery);(function($,undefined){$.effects.effect.pulsate=function(o,done){var elem=$(this),mode=$.effects.setMode(elem,o.mode||"show"),show=mode==="show",hide=mode==="hide",showhide=(show||mode==="hide"),anims=((o.times||5)*2)+(showhide?1:0),duration=o.duration/anims,animateTo=0,queue=elem.queue(),queuelen=queue.length,i;if(show||!elem.is(":visible")){elem.css("opacity",0).show();animateTo=1;}
for(i=1;i<anims;i++){elem.animate({opacity:animateTo},duration,o.easing);animateTo=1-animateTo;}
elem.animate({opacity:animateTo},duration,o.easing);elem.queue(function(){if(hide){elem.hide();}
done();});if(queuelen>1){queue.splice.apply(queue,[1,0].concat(queue.splice(queuelen,anims+1)));}
elem.dequeue();};})(jQuery);(function($,undefined){$.effects.effect.puff=function(o,done){var elem=$(this),mode=$.effects.setMode(elem,o.mode||"hide"),hide=mode==="hide",percent=parseInt(o.percent,10)||150,factor=percent/100,original={height:elem.height(),width:elem.width(),outerHeight:elem.outerHeight(),outerWidth:elem.outerWidth()};$.extend(o,{effect:"scale",queue:false,fade:true,mode:mode,complete:done,percent:hide?percent:100,from:hide?original:{height:original.height*factor,width:original.width*factor,outerHeight:original.outerHeight*factor,outerWidth:original.outerWidth*factor}});elem.effect(o);};$.effects.effect.scale=function(o,done){var el=$(this),options=$.extend(true,{},o),mode=$.effects.setMode(el,o.mode||"effect"),percent=parseInt(o.percent,10)||(parseInt(o.percent,10)===0?0:(mode==="hide"?0:100)),direction=o.direction||"both",origin=o.origin,original={height:el.height(),width:el.width(),outerHeight:el.outerHeight(),outerWidth:el.outerWidth()},factor={y:direction!=="horizontal"?(percent/100):1,x:direction!=="vertical"?(percent/100):1};options.effect="size";options.queue=false;options.complete=done;if(mode!=="effect"){options.origin=origin||["middle","center"];options.restore=true;}
options.from=o.from||(mode==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:original);options.to={height:original.height*factor.y,width:original.width*factor.x,outerHeight:original.outerHeight*factor.y,outerWidth:original.outerWidth*factor.x};if(options.fade){if(mode==="show"){options.from.opacity=0;options.to.opacity=1;}
if(mode==="hide"){options.from.opacity=1;options.to.opacity=0;}}
el.effect(options);};$.effects.effect.size=function(o,done){var original,baseline,factor,el=$(this),props0=["position","top","bottom","left","right","width","height","overflow","opacity"],props1=["position","top","bottom","left","right","overflow","opacity"],props2=["width","height","overflow"],cProps=["fontSize"],vProps=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],hProps=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],mode=$.effects.setMode(el,o.mode||"effect"),restore=o.restore||mode!=="effect",scale=o.scale||"both",origin=o.origin||["middle","center"],position=el.css("position"),props=restore?props0:props1,zero={height:0,width:0,outerHeight:0,outerWidth:0};if(mode==="show"){el.show();}
original={height:el.height(),width:el.width(),outerHeight:el.outerHeight(),outerWidth:el.outerWidth()};if(o.mode==="toggle"&&mode==="show"){el.from=o.to||zero;el.to=o.from||original;}else{el.from=o.from||(mode==="show"?zero:original);el.to=o.to||(mode==="hide"?zero:original);}
factor={from:{y:el.from.height/original.height,x:el.from.width/original.width},to:{y:el.to.height/original.height,x:el.to.width/original.width}};if(scale==="box"||scale==="both"){if(factor.from.y!==factor.to.y){props=props.concat(vProps);el.from=$.effects.setTransition(el,vProps,factor.from.y,el.from);el.to=$.effects.setTransition(el,vProps,factor.to.y,el.to);}
if(factor.from.x!==factor.to.x){props=props.concat(hProps);el.from=$.effects.setTransition(el,hProps,factor.from.x,el.from);el.to=$.effects.setTransition(el,hProps,factor.to.x,el.to);}}
if(scale==="content"||scale==="both"){if(factor.from.y!==factor.to.y){props=props.concat(cProps).concat(props2);el.from=$.effects.setTransition(el,cProps,factor.from.y,el.from);el.to=$.effects.setTransition(el,cProps,factor.to.y,el.to);}}
$.effects.save(el,props);el.show();$.effects.createWrapper(el);el.css("overflow","hidden").css(el.from);if(origin){baseline=$.effects.getBaseline(origin,original);el.from.top=(original.outerHeight-el.outerHeight())*baseline.y;el.from.left=(original.outerWidth-el.outerWidth())*baseline.x;el.to.top=(original.outerHeight-el.to.outerHeight)*baseline.y;el.to.left=(original.outerWidth-el.to.outerWidth)*baseline.x;}
el.css(el.from);if(scale==="content"||scale==="both"){vProps=vProps.concat(["marginTop","marginBottom"]).concat(cProps);hProps=hProps.concat(["marginLeft","marginRight"]);props2=props0.concat(vProps).concat(hProps);el.find("*[width]").each(function(){var child=$(this),c_original={height:child.height(),width:child.width(),outerHeight:child.outerHeight(),outerWidth:child.outerWidth()};if(restore){$.effects.save(child,props2);}
child.from={height:c_original.height*factor.from.y,width:c_original.width*factor.from.x,outerHeight:c_original.outerHeight*factor.from.y,outerWidth:c_original.outerWidth*factor.from.x};child.to={height:c_original.height*factor.to.y,width:c_original.width*factor.to.x,outerHeight:c_original.height*factor.to.y,outerWidth:c_original.width*factor.to.x};if(factor.from.y!==factor.to.y){child.from=$.effects.setTransition(child,vProps,factor.from.y,child.from);child.to=$.effects.setTransition(child,vProps,factor.to.y,child.to);}
if(factor.from.x!==factor.to.x){child.from=$.effects.setTransition(child,hProps,factor.from.x,child.from);child.to=$.effects.setTransition(child,hProps,factor.to.x,child.to);}
child.css(child.from);child.animate(child.to,o.duration,o.easing,function(){if(restore){$.effects.restore(child,props2);}});});}
el.animate(el.to,{queue:false,duration:o.duration,easing:o.easing,complete:function(){if(el.to.opacity===0){el.css("opacity",el.from.opacity);}
if(mode==="hide"){el.hide();}
$.effects.restore(el,props);if(!restore){if(position==="static"){el.css({position:"relative",top:el.to.top,left:el.to.left});}else{$.each(["top","left"],function(idx,pos){el.css(pos,function(_,str){var val=parseInt(str,10),toRef=idx?el.to.left:el.to.top;if(str==="auto"){return toRef+"px";}
return val+toRef+"px";});});}}
$.effects.removeWrapper(el);done();}});};})(jQuery);(function($,undefined){$.effects.effect.shake=function(o,done){var el=$(this),props=["position","top","bottom","left","right","height","width"],mode=$.effects.setMode(el,o.mode||"effect"),direction=o.direction||"left",distance=o.distance||20,times=o.times||3,anims=times*2+1,speed=Math.round(o.duration/anims),ref=(direction==="up"||direction==="down")?"top":"left",positiveMotion=(direction==="up"||direction==="left"),animation={},animation1={},animation2={},i,queue=el.queue(),queuelen=queue.length;$.effects.save(el,props);el.show();$.effects.createWrapper(el);animation[ref]=(positiveMotion?"-=":"+=")+distance;animation1[ref]=(positiveMotion?"+=":"-=")+distance*2;animation2[ref]=(positiveMotion?"-=":"+=")+distance*2;el.animate(animation,speed,o.easing);for(i=1;i<times;i++){el.animate(animation1,speed,o.easing).animate(animation2,speed,o.easing);}
el.animate(animation1,speed,o.easing).animate(animation,speed/2,o.easing).queue(function(){if(mode==="hide"){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();});if(queuelen>1){queue.splice.apply(queue,[1,0].concat(queue.splice(queuelen,anims+1)));}
el.dequeue();};})(jQuery);(function($,undefined){$.effects.effect.slide=function(o,done){var el=$(this),props=["position","top","bottom","left","right","width","height"],mode=$.effects.setMode(el,o.mode||"show"),show=mode==="show",direction=o.direction||"left",ref=(direction==="up"||direction==="down")?"top":"left",positiveMotion=(direction==="up"||direction==="left"),distance,animation={};$.effects.save(el,props);el.show();distance=o.distance||el[ref==="top"?"outerHeight":"outerWidth"](true);$.effects.createWrapper(el).css({overflow:"hidden"});if(show){el.css(ref,positiveMotion?(isNaN(distance)?"-"+distance:-distance):distance);}
animation[ref]=(show?(positiveMotion?"+=":"-="):(positiveMotion?"-=":"+="))+
distance;el.animate(animation,{queue:false,duration:o.duration,easing:o.easing,complete:function(){if(mode==="hide"){el.hide();}
$.effects.restore(el,props);$.effects.removeWrapper(el);done();}});};})(jQuery);(function($,undefined){$.effects.effect.transfer=function(o,done){var elem=$(this),target=$(o.to),targetFixed=target.css("position")==="fixed",body=$("body"),fixTop=targetFixed?body.scrollTop():0,fixLeft=targetFixed?body.scrollLeft():0,endPosition=target.offset(),animation={top:endPosition.top-fixTop,left:endPosition.left-fixLeft,height:target.innerHeight(),width:target.innerWidth()},startPosition=elem.offset(),transfer=$("<div class='ui-effects-transfer'></div>").appendTo(document.body).addClass(o.className).css({top:startPosition.top-fixTop,left:startPosition.left-fixLeft,height:elem.innerHeight(),width:elem.innerWidth(),position:targetFixed?"fixed":"absolute"}).animate(animation,o.duration,o.easing,function(){transfer.remove();done();});};})(jQuery);

(function($){$.widget("ui.multiselect",{options:{sortable:true,searchable:true,doubleClickable:true,animated:'fast',show:'slideDown',hide:'slideUp',dividerLocation:0.6,availableFirst:false,nodeComparator:function(node1,node2){var text1=node1.text(),text2=node2.text();return text1==text2?0:(text1<text2?-1:1);}},_create:function(){this.element.hide();this.id=this.element.attr("id");this.container=$('<div class="ui-multiselect ui-helper-clearfix ui-widget"></div>').insertAfter(this.element);this.count=0;this.selectedContainer=$('<div class="selected"></div>').appendTo(this.container);this.availableContainer=$('<div class="available"></div>')[this.options.availableFirst?'prependTo':'appendTo'](this.container);this.selectedActions=$('<div class="actions ui-widget-header ui-helper-clearfix"><span class="count">0 '+$.ui.multiselect.locale.itemsCount+'</span><a href="#" class="remove-all">'+$.ui.multiselect.locale.removeAll+'</a></div>').appendTo(this.selectedContainer);this.availableActions=$('<div class="actions ui-widget-header ui-helper-clearfix"><input type="text" class="search empty ui-widget-content ui-corner-all"/><a href="#" class="add-all">'+$.ui.multiselect.locale.addAll+'</a></div>').appendTo(this.availableContainer);this.selectedList=$('<ul class="selected connected-list"><li class="ui-helper-hidden-accessible"></li></ul>').bind('selectstart',function(){return false;}).appendTo(this.selectedContainer);this.availableList=$('<ul class="available connected-list"><li class="ui-helper-hidden-accessible"></li></ul>').bind('selectstart',function(){return false;}).appendTo(this.availableContainer);var that=this;this.container.width("100%");this.selectedContainer.width("50%");this.availableContainer.width("49%");this.selectedList.height(Math.max(this.element.height()-this.selectedActions.height(),1));this.availableList.height(Math.max(this.element.height()-this.availableActions.height(),1));if(!this.options.animated){this.options.show='show';this.options.hide='hide';}
this._populateLists(this.element.find('option'));if(this.options.sortable){this.selectedList.sortable({placeholder:'ui-state-highlight',axis:'y',update:function(event,ui){that.selectedList.find('li').each(function(){if($(this).data('optionLink'))
$(this).data('optionLink').remove().appendTo(that.element);});},receive:function(event,ui){ui.item.data('optionLink').attr('selected',true);that.count+=1;that._updateCount();that.selectedList.children('.ui-draggable').each(function(){$(this).removeClass('ui-draggable');$(this).data('optionLink',ui.item.data('optionLink'));$(this).data('idx',ui.item.data('idx'));that._applyItemState($(this),true);});setTimeout(function(){ui.item.remove();},1);}});}
if(this.options.searchable){this._registerSearchEvents(this.availableContainer.find('input.search'));}else{$('.search').hide();}
this.container.find(".remove-all").click(function(e){$handleclick(e);that._populateLists(that.element.find('option').removeAttr('selected'));return false;});this.container.find(".add-all").click(function(e){$handleclick(e);var options=that.element.find('option').not(":selected");if(that.availableList.children('li:hidden').length>1){that.availableList.children('li').each(function(i){if($(this).is(":visible"))$(options[i-1]).attr('selected','selected');});}else{options.attr('selected','selected');}
that._populateLists(that.element.find('option'));return false;});},destroy:function(){this.element.show();this.container.remove();$.Widget.prototype.destroy.apply(this,arguments);},_populateLists:function(options){this.selectedList.children('.ui-element').remove();this.availableList.children('.ui-element').remove();this.count=0;var that=this;var items=$(options.map(function(i){var item=that._getOptionNode(this).appendTo(this.selected?that.selectedList:that.availableList).show();if(this.selected)that.count+=1;that._applyItemState(item,this.selected);item.data('idx',i);return item[0];}));this._updateCount();that._filter.apply(this.availableContainer.find('input.search'),[that.availableList]);},_updateCount:function(){this.element.trigger('change');this.selectedContainer.find('span.count').text(this.count+" "+$.ui.multiselect.locale.itemsCount);},_getOptionNode:function(option){option=$(option);var description=(option.attr("description")?decodeURI(option.attr("description")):option.text());var node=$('<li class="ui-state-default ui-element" title="'+option.text()+'" style="overflow-y: hidden;"><span class="ui-icon"/>'+description+'<a href="#" class="action"><span class="ui-corner-all ui-icon"/></a></li>').hide();node.data('optionLink',option);return node;},_cloneWithData:function(clonee){var clone=clonee.clone(false,false);clone.data('optionLink',clonee.data('optionLink'));clone.data('idx',clonee.data('idx'));return clone;},_setSelected:function(item,selected){item.data('optionLink').attr('selected',selected);if(selected){var selectedItem=this._cloneWithData(item);item[this.options.hide](this.options.animated,function(){$(this).remove();});selectedItem.appendTo(this.selectedList).hide()[this.options.show](this.options.animated);this._applyItemState(selectedItem,true);return selectedItem;}else{var items=this.availableList.find('li'),comparator=this.options.nodeComparator;var succ=null,i=item.data('idx'),direction=comparator(item,$(items[i]));if(direction){while(i>=0&&i<items.length){direction>0?i++:i--;if(direction!=comparator(item,$(items[i]))){succ=items[direction>0?i:i+1];break;}}}else{succ=items[i];}
var availableItem=this._cloneWithData(item);succ?availableItem.insertBefore($(succ)):availableItem.appendTo(this.availableList);item[this.options.hide](this.options.animated,function(){$(this).remove();});availableItem.hide()[this.options.show](this.options.animated);this._applyItemState(availableItem,false);return availableItem;}},_applyItemState:function(item,selected){if(selected){if(this.options.sortable)
item.children('span').addClass('ui-icon-arrowthick-2-n-s').removeClass('ui-helper-hidden').addClass('ui-icon');else
item.children('span').removeClass('ui-icon-arrowthick-2-n-s').addClass('ui-helper-hidden').removeClass('ui-icon');item.find('a.action span').addClass('ui-icon-minus').removeClass('ui-icon-plus');this._registerRemoveEvents(item.find('a.action'));}else{item.children('span').removeClass('ui-icon-arrowthick-2-n-s').addClass('ui-helper-hidden').removeClass('ui-icon');item.find('a.action span').addClass('ui-icon-plus').removeClass('ui-icon-minus');this._registerAddEvents(item.find('a.action'));}
this._registerDoubleClickEvents(item);this._registerHoverEvents(item);},_filter:function(list){var input=$(this);var rows=list.children('li'),cache=rows.map(function(){return $(this).text().toLowerCase();});var term=$.trim(input.val().toLowerCase()),scores=[];if(!term){rows.show();}else{rows.hide();cache.each(function(i){if(this.indexOf(term)>-1){scores.push(i);}});$.each(scores,function(){$(rows[this]).show();});}},_registerDoubleClickEvents:function(elements){if(!this.options.doubleClickable)return;elements.dblclick(function(ev){if($(ev.target).closest('.action').length===0){elements.find('a.action').click();}});},_registerHoverEvents:function(elements){elements.removeClass('ui-state-hover');elements.mouseover(function(){$(this).addClass('ui-state-hover');});elements.mouseout(function(){$(this).removeClass('ui-state-hover');});},_registerAddEvents:function(elements){var that=this;elements.click(function(e){$handleclick(e);var item=that._setSelected($(this).parent(),true);that.count+=1;that._updateCount();return false;});if(this.options.sortable){elements.each(function(){$(this).parent().draggable({connectToSortable:that.selectedList,helper:function(){var selectedItem=that._cloneWithData($(this)).width($(this).width()-50);selectedItem.width($(this).width());return selectedItem;},appendTo:that.container,containment:that.container,revert:'invalid'});});}},_registerRemoveEvents:function(elements){var that=this;elements.click(function(e){$handleclick(e);that._setSelected($(this).parent(),false);that.count-=1;that._updateCount();return false;});},_registerSearchEvents:function(input){var that=this;input.focus(function(){$(this).addClass('ui-state-active');}).blur(function(){$(this).removeClass('ui-state-active');}).keypress(function(e){if(e.keyCode==13)
return false;}).keyup(function(){that._filter.apply(this,[that.availableList]);});}});$.extend($.ui.multiselect,{locale:{addAll:'Add all',removeAll:'Remove all',itemsCount:'items selected'}});})(jQuery);
!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery-ui/menu"],a):a(jQuery)}(function(a){"use strict";var b="onselectstart"in document.createElement("div"),c=a.ui.menu.version.match(/^(\d)\.(\d+)/),d={major:parseInt(c[1],10),minor:parseInt(c[2],10)},e=d.major<2&&d.minor<11;a.widget("moogle.contextmenu",{version:"@VERSION",options:{addClass:"ui-contextmenu",autoTrigger:!0,delegate:null,hide:{effect:"fadeOut",duration:"fast"},ignoreParentSelect:!0,menu:null,position:null,preventContextMenuForPopup:!1,preventSelect:!1,show:{effect:"slideDown",duration:"fast"},taphold:!1,uiMenuOptions:{},beforeOpen:a.noop,blur:a.noop,close:a.noop,create:a.noop,createMenu:a.noop,focus:a.noop,open:a.noop,select:a.noop},_create:function(){var c,d,e,f=this.options;if(this.$headStyle=null,this.$menu=null,this.menuIsTemp=!1,this.currentTarget=null,f.preventSelect){e=(a(this.element).is(document)?a("body"):this.element).uniqueId().attr("id"),c="#"+e+" "+f.delegate+" { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }",this.$headStyle=a("<style class='moogle-contextmenu-style' />").prop("type","text/css").appendTo("head");try{this.$headStyle.html(c)}catch(g){this.$headStyle[0].styleSheet.cssText=c}
b&&this.element.delegate(f.delegate,"selectstart"+this.eventNamespace,function(a){a.preventDefault()})}
this._createUiMenu(f.menu),d="contextmenu"+this.eventNamespace,f.taphold&&(d+=" taphold"+this.eventNamespace),this.element.delegate(f.delegate,d,a.proxy(this._openMenu,this))},_destroy:function(){this.element.undelegate(this.eventNamespace),this._createUiMenu(null),this.$headStyle&&(this.$headStyle.remove(),this.$headStyle=null)},_createUiMenu:function(b){var c,d=this.options;this.isOpen()&&(c=this.currentTarget,this._closeMenu(!0),this.currentTarget=c),this.menuIsTemp?this.$menu.remove():this.$menu&&this.$menu.menu("destroy").removeClass(this.options.addClass).hide(),this.$menu=null,this.menuIsTemp=!1,b&&(a.isArray(b)?(this.$menu=a.moogle.contextmenu.createMenuMarkup(b),this.menuIsTemp=!0):this.$menu="string"==typeof b?a(b):b,this.$menu.hide().addClass(d.addClass).menu(a.extend(!0,{},d.uiMenuOptions,{blur:a.proxy(d.blur,this),create:a.proxy(d.createMenu,this),focus:a.proxy(d.focus,this),select:a.proxy(function(b,c){var e,f=a.moogle.contextmenu.isMenu(c.item),g=c.item.data("actionHandler");c.cmd=c.item.attr("data-command"),c.target=a(this.currentTarget),f&&d.ignoreParentSelect||(e=this._trigger.call(this,"select",b,c),g&&(e=g.call(this,b,c)),e!==!1&&this._closeMenu.call(this),b.preventDefault())},this)})))},_openMenu:function(b,c){var d,e,f=this.options,g=f.position,h=this,i=!!b.isTrigger,j={menu:this.$menu,target:a(b.target),extraData:b.extraData,originalEvent:b,result:null};if(f.autoTrigger||i){if(b.preventDefault(),this.currentTarget=b.target,!c){if(d=this._trigger("beforeOpen",b,j),e=j.result&&a.isFunction(j.result.promise)?j.result:null,j.result=null,d===!1)return this.currentTarget=null,!1;if(e)return e.done(function(){h._openMenu(b,!0)}),this.currentTarget=null,!1;j.menu=this.$menu}
a(document).bind("keydown"+this.eventNamespace,function(b){b.which===a.ui.keyCode.ESCAPE&&h._closeMenu()}).bind("mousedown"+this.eventNamespace+" touchstart"+this.eventNamespace,function(b){a(b.target).closest(".ui-menu-item").length||h._closeMenu()}),a.isFunction(g)&&(g=g(b,j)),g=a.extend({my:"left top",at:"left bottom",of:void 0===b.pageX?b.target:b,collision:"fit"},g);if(this.$menu)
this.$menu.show().css({position:"absolute",left:0,top:0}).position(g).hide(),f.preventContextMenuForPopup&&this.$menu.bind("contextmenu"+this.eventNamespace,function(a){a.preventDefault()}),this._show(this.$menu,this.options.show,function(){h._trigger.call(h,"open",b,j)})}},_closeMenu:function(b){var c=this,d=b?!1:this.options.hide;a(document).unbind("mousedown"+this.eventNamespace).unbind("touchstart"+this.eventNamespace).unbind("keydown"+this.eventNamespace),c.currentTarget=null,this.$menu?(this.$menu.unbind("contextmenu"+this.eventNamespace),this._hide(this.$menu,d,function(){c._trigger("close")})):c._trigger("close")
this._destroy();},_setOption:function(b,c){switch(b){case"menu":this.replaceMenu(c)}
a.Widget.prototype._setOption.apply(this,arguments)},_getMenuEntry:function(a){return this.$menu.find("li[data-command="+a+"]")},close:function(){this.isOpen()&&this._closeMenu()},enableEntry:function(a,b){this._getMenuEntry(a).toggleClass("ui-state-disabled",b===!1)},getMenu:function(){return this.$menu},isOpen:function(){return!!this.$menu&&!!this.currentTarget},open:function(a,b){b=b||{};var c=jQuery.Event("contextmenu",{target:a.get(0),extraData:b});return this.element.trigger(c)},replaceMenu:function(a){this._createUiMenu(a)},setEntry:function(b,c){var d,e=this._getMenuEntry(b);"string"==typeof c?a.moogle.contextmenu.updateTitle(e,c):(e.empty(),c.cmd=c.cmd||b,a.moogle.contextmenu.createEntryMarkup(c,e),a.isArray(c.children)&&(d=a("<ul/>").appendTo(e),a.moogle.contextmenu.createMenuMarkup(c.children,d)),this.getMenu().menu("refresh"))},showEntry:function(a,b){this._getMenuEntry(a).toggle(b!==!1)}}),a.extend(a.moogle.contextmenu,{createEntryMarkup:function(b,c){var d=null;/[^\-\u2014\u2013\s]/.test(b.title)?(e?(c.attr("data-command",b.cmd),d=a("<a/>",{html:""+b.title,href:"#"}).appendTo(c),b.uiIcon&&d.append(a("<span class='ui-icon' />").addClass(b.uiIcon))):(c.attr("data-command",b.cmd).html(""+b.title),a.isFunction(b.action)&&c.data("actionHandler",b.action),b.uiIcon&&c.append(a("<span class='ui-icon' />").addClass(b.uiIcon))),a.isFunction(b.action)&&c.data("actionHandler",b.action),b.disabled&&c.addClass("ui-state-disabled"),b.addClass&&c.addClass(b.addClass),a.isPlainObject(b.data)&&c.data(b.data)):c.text(b.title)},createMenuMarkup:function(b,c){var d,e,f,g;for(null==c&&(c=a("<ul class='ui-helper-hidden' />").appendTo("body")),d=0;d<b.length;d++)e=b[d],g=a("<li style='width: 220px' />").appendTo(c),a.moogle.contextmenu.createEntryMarkup(e,g),a.isArray(e.children)&&(f=a("<ul/>").appendTo(g),a.moogle.contextmenu.createMenuMarkup(e.children,f));return c},isMenu:function(a){return e?a.has(">a[aria-haspopup='true']").length>0:a.is("[aria-haspopup='true']")},replaceFirstTextNodeChild:function(a,b){a.contents().filter(function(){return 3===this.nodeType}).first().replaceWith(b)},updateTitle:function(b,c){e?a.moogle.contextmenu.replaceFirstTextNodeChild(a("a",b),c):a.moogle.contextmenu.replaceFirstTextNodeChild(b,c)}})});

(function($){'use strict';var default_options={i18n:{en:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],dayOfWeek:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]}},value:'',lang:'en',format:'d/m/Y h:i A',formatTime:'h:i A',formatDate:'d/m/Y',startDate:false,step:60,monthChangeSpinner:true,closeOnDateSelect:false,closeOnTimeSelect:false,closeOnWithoutClick:true,closeOnInputClick:true,timepicker:true,datepicker:true,weeks:false,defaultTime:false,defaultDate:false,minDate:false,maxDate:false,minTime:false,maxTime:false,allowTimes:[],opened:false,initTime:true,inline:false,theme:'',onSelectDate:function(){},onSelectTime:function(){},onChangeMonth:function(){},onChangeYear:function(){},onChangeDateTime:function(){},onShow:function(){},onClose:function(){},onGenerate:function(){},withoutCopyright:true,inverseButton:false,hours12:false,next:'xdsoft_next',prev:'xdsoft_prev',dayOfWeekStart:0,parentID:'body',timeHeightInTimePicker:25,timepickerScrollbar:true,todayButton:true,prevButton:true,nextButton:true,defaultSelect:true,scrollMonth:true,scrollTime:true,scrollInput:true,lazyInit:false,mask:false,validateOnBlur:false,allowBlank:true,yearStart:1950,yearEnd:2050,monthStart:0,monthEnd:11,style:'',id:'',fixed:false,roundTime:'round',className:'',weekends:[],disabledDates:[],yearOffset:0,beforeShowDay:null,enterLikeTab:true,showApplyButton:false};if(!Array.prototype.indexOf){Array.prototype.indexOf=function(obj,start){var i,j;for(i=(start||0),j=this.length;i<j;i+=1){if(this[i]===obj){return i;}}
return-1;};}
Date.prototype.countDaysInMonth=function(){return new Date(this.getFullYear(),this.getMonth()+1,0).getDate();};$.fn.xdsoftScroller=function(percent){return this.each(function(){var timeboxparent=$(this),pointerEventToXY=function(e){var out={x:0,y:0},touch;if(e.type==='touchstart'||e.type==='touchmove'||e.type==='touchend'||e.type==='touchcancel'){touch=e.originalEvent.touches[0]||e.originalEvent.changedTouches[0];out.x=touch.clientX;out.y=touch.clientY;}else if(e.type==='mousedown'||e.type==='mouseup'||e.type==='mousemove'||e.type==='mouseover'||e.type==='mouseout'||e.type==='mouseenter'||e.type==='mouseleave'){out.x=e.clientX;out.y=e.clientY;}
return out;},move=0,timebox,parentHeight,height,scrollbar,scroller,maximumOffset=100,start=false,startY=0,startTop=0,h1=0,touchStart=false,startTopScroll=0,calcOffset=function(){};if(percent==='hide'){timeboxparent.find('.xdsoft_scrollbar').hide();return;}
if(!$(this).hasClass('xdsoft_scroller_box')){timebox=timeboxparent.children().eq(0);parentHeight=timeboxparent[0].clientHeight;height=timebox[0].offsetHeight;scrollbar=$('<div class="xdsoft_scrollbar"></div>');scroller=$('<div class="xdsoft_scroller"></div>');scrollbar.append(scroller);timeboxparent.addClass('xdsoft_scroller_box').append(scrollbar);calcOffset=function calcOffset(event){var offset=pointerEventToXY(event).y-startY+startTopScroll;if(offset<0){offset=0;}
if(offset+scroller[0].offsetHeight>h1){offset=h1-scroller[0].offsetHeight;}
timeboxparent.trigger('scroll_element.xdsoft_scroller',[maximumOffset?offset/maximumOffset:0]);};scroller.on('touchstart.xdsoft_scroller mousedown.xdsoft_scroller',function(event){if(!parentHeight){timeboxparent.trigger('resize_scroll.xdsoft_scroller',[percent]);}
startY=pointerEventToXY(event).y;startTopScroll=parseInt(scroller.css('margin-top'),10);h1=scrollbar[0].offsetHeight;if(event.type==='mousedown'){if(document){$(document.body).addClass('xdsoft_noselect');}
$([document.body,window]).on('mouseup.xdsoft_scroller',function arguments_callee(){$([document.body,window]).off('mouseup.xdsoft_scroller',arguments_callee).off('mousemove.xdsoft_scroller',calcOffset).removeClass('xdsoft_noselect');});$(document.body).on('mousemove.xdsoft_scroller',calcOffset);}else{touchStart=true;event.stopPropagation();event.preventDefault();}}).on('touchmove',function(event){if(touchStart){event.preventDefault();calcOffset(event);}}).on('touchend touchcancel',function(event){touchStart=false;startTopScroll=0;});timeboxparent.on('scroll_element.xdsoft_scroller',function(event,percentage){if(!parentHeight){timeboxparent.trigger('resize_scroll.xdsoft_scroller',[percentage,true]);}
percentage=percentage>1?1:(percentage<0||isNaN(percentage))?0:percentage;scroller.css('margin-top',maximumOffset*percentage);setTimeout(function(){timebox.css('marginTop',-parseInt((timebox[0].offsetHeight-parentHeight)*percentage,10));},10);}).on('resize_scroll.xdsoft_scroller',function(event,percentage,noTriggerScroll){var percent,sh;parentHeight=timeboxparent[0].clientHeight;height=timebox[0].offsetHeight;percent=parentHeight/height;sh=percent*scrollbar[0].offsetHeight;if(percent>1){scroller.hide();}else{scroller.show();scroller.css('height',parseInt(sh>10?sh:10,10));maximumOffset=scrollbar[0].offsetHeight-scroller[0].offsetHeight;if(noTriggerScroll!==true){timeboxparent.trigger('scroll_element.xdsoft_scroller',[percentage||Math.abs(parseInt(timebox.css('marginTop'),10))/(height-parentHeight)]);}}});timeboxparent.on('mousewheel',function(event){var top=Math.abs(parseInt(timebox.css('marginTop'),10));top=top-(event.deltaY*20);if(top<0){top=0;}
timeboxparent.trigger('scroll_element.xdsoft_scroller',[top/(height-parentHeight)]);event.stopPropagation();return false;});timeboxparent.on('touchstart',function(event){start=pointerEventToXY(event);startTop=Math.abs(parseInt(timebox.css('marginTop'),10));});timeboxparent.on('touchmove',function(event){if(start){event.preventDefault();var coord=pointerEventToXY(event);timeboxparent.trigger('scroll_element.xdsoft_scroller',[(startTop-(coord.y-start.y))/(height-parentHeight)]);}});timeboxparent.on('touchend touchcancel',function(event){start=false;startTop=0;});}
timeboxparent.trigger('resize_scroll.xdsoft_scroller',[percent]);});};$.fn.datetimepicker=function(opt){var KEY0=48,KEY9=57,_KEY0=96,_KEY9=105,CTRLKEY=17,DEL=46,ENTER=13,ESC=27,BACKSPACE=8,ARROWLEFT=37,ARROWUP=38,ARROWRIGHT=39,ARROWDOWN=40,TAB=9,F5=116,AKEY=65,CKEY=67,VKEY=86,ZKEY=90,YKEY=89,ctrlDown=false,options=($.isPlainObject(opt)||!opt)?$.extend(true,{},default_options,opt):$.extend(true,{},default_options),lazyInitTimer=0,createDateTimePicker,destroyDateTimePicker,lazyInit=function(input){input.on('open.xdsoft mousedown.xdsoft',function initOnActionCallback(event){if(input.is(':disabled')||input.data('xdsoft_datetimepicker')){return;}
clearTimeout(lazyInitTimer);lazyInitTimer=setTimeout(function(){if(!input.data('xdsoft_datetimepicker')){createDateTimePicker(input);}
input.off('open.xdsoft mousedown.xdsoft',initOnActionCallback).trigger('open.xdsoft');},100);});};createDateTimePicker=function(input){var datetimepicker=$('<div '+(options.id?'id="'+options.id+'"':'')+' '+(options.style?'style="'+options.style+'"':'')+' class="xdsoft_datetimepicker xdsoft_'+options.theme+' xdsoft_noselect '+(options.weeks?' xdsoft_showweeks':'')+options.className+'"></div>'),xdsoft_copyright=$('<div class="xdsoft_copyright"><a target="_blank" href="http://xdsoft.net/jqplugins/datetimepicker/">xdsoft.net</a></div>'),datepicker=$('<div class="xdsoft_datepicker active"></div>'),mounth_picker=$('<div class="xdsoft_mounthpicker"><button type="button" class="xdsoft_prev"></button><button type="button" class="xdsoft_today_button"></button>'+'<div class="xdsoft_label xdsoft_month"><span></span><i></i></div>'+'<div class="xdsoft_label xdsoft_year"><span></span><i></i></div>'+'<button type="button" class="xdsoft_next"></button></div>'),calendar=$('<div class="xdsoft_calendar"></div>'),timepicker=$('<div class="xdsoft_timepicker active"><button type="button" class="xdsoft_prev"></button><div class="xdsoft_time_box"></div><button type="button" class="xdsoft_next"></button></div>'),timeboxparent=timepicker.find('.xdsoft_time_box').eq(0),timebox=$('<div class="xdsoft_time_variant"></div>'),applyButton=$('<button class="xdsoft_save_selected blue-gradient-button">Save Selected</button>'),monthselect=$('<div class="xdsoft_select xdsoft_monthselect"><div></div></div>'),yearselect=$('<div class="xdsoft_select xdsoft_yearselect"><div></div></div>'),triggerAfterOpen=false,XDSoft_datetime,xchangeTimer,timerclick,current_time_index,setPos,timer=0,timer1=0,_xdsoft_datetime;mounth_picker.find('.xdsoft_month span').after(monthselect);mounth_picker.find('.xdsoft_year span').after(yearselect);mounth_picker.find('.xdsoft_month,.xdsoft_year').on('mousedown.xdsoft',function(event){var select=$(this).find('.xdsoft_select').eq(0),val=0,top=0,visible=select.is(':visible'),items,i;mounth_picker.find('.xdsoft_select').hide();if(_xdsoft_datetime.currentTime){val=_xdsoft_datetime.currentTime[$(this).hasClass('xdsoft_month')?'getMonth':'getFullYear']();}
select[visible?'hide':'show']();for(items=select.find('div.xdsoft_option'),i=0;i<items.length;i+=1){if(items.eq(i).data('value')===val){break;}else{top+=items[0].offsetHeight;}}
select.xdsoftScroller(top/(select.children()[0].offsetHeight-(select[0].clientHeight)));event.stopPropagation();return false;});mounth_picker.find('.xdsoft_select').xdsoftScroller().on('mousedown.xdsoft',function(event){event.stopPropagation();event.preventDefault();}).on('mousedown.xdsoft','.xdsoft_option',function(event){if(_xdsoft_datetime.currentTime===undefined||_xdsoft_datetime.currentTime===null){_xdsoft_datetime.currentTime=_xdsoft_datetime.now();}
var year=_xdsoft_datetime.currentTime.getFullYear();if(_xdsoft_datetime&&_xdsoft_datetime.currentTime){_xdsoft_datetime.currentTime[$(this).parent().parent().hasClass('xdsoft_monthselect')?'setMonth':'setFullYear']($(this).data('value'));}
$(this).parent().parent().hide();datetimepicker.trigger('xchange.xdsoft');if(options.onChangeMonth&&$.isFunction(options.onChangeMonth)){options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}
if(year!==_xdsoft_datetime.currentTime.getFullYear()&&$.isFunction(options.onChangeYear)){options.onChangeYear.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}});datetimepicker.setOptions=function(_options){options=$.extend(true,{},options,_options);if(_options.allowTimes&&$.isArray(_options.allowTimes)&&_options.allowTimes.length){options.allowTimes=$.extend(true,[],_options.allowTimes);}
if(_options.weekends&&$.isArray(_options.weekends)&&_options.weekends.length){options.weekends=$.extend(true,[],_options.weekends);}
if(_options.disabledDates&&$.isArray(_options.disabledDates)&&_options.disabledDates.length){options.disabledDates=$.extend(true,[],_options.disabledDates);}
if((options.open||options.opened)&&(!options.inline)){input.trigger('open.xdsoft');}
if(options.inline){triggerAfterOpen=true;datetimepicker.addClass('xdsoft_inline');input.after(datetimepicker).hide();}
if(options.inverseButton){options.next='xdsoft_prev';options.prev='xdsoft_next';}
if(options.datepicker){datepicker.addClass('active');}else{datepicker.removeClass('active');}
if(options.timepicker){timepicker.addClass('active');}else{timepicker.removeClass('active');}
if(options.value){_xdsoft_datetime.setCurrentTime(options.value);if(input&&input.val){input.val(_xdsoft_datetime.str);}}
if(isNaN(options.dayOfWeekStart)){options.dayOfWeekStart=0;}else{options.dayOfWeekStart=parseInt(options.dayOfWeekStart,10)%7;}
if(!options.timepickerScrollbar){timeboxparent.xdsoftScroller('hide');}
if(options.minDate&&/^-(.*)$/.test(options.minDate)){options.minDate=_xdsoft_datetime.strToDateTime(options.minDate).dateFormat(options.formatDate);}
if(options.maxDate&&/^\+(.*)$/.test(options.maxDate)){options.maxDate=_xdsoft_datetime.strToDateTime(options.maxDate).dateFormat(options.formatDate);}
applyButton.toggle(options.showApplyButton);mounth_picker.find('.xdsoft_today_button').css('visibility',!options.todayButton?'hidden':'visible');mounth_picker.find('.'+options.prev).css('visibility',!options.prevButton?'hidden':'visible');mounth_picker.find('.'+options.next).css('visibility',!options.nextButton?'hidden':'visible');if(options.mask){var e,getCaretPos=function(input){try{if(document.selection&&document.selection.createRange){var range=document.selection.createRange();return range.getBookmark().charCodeAt(2)-2;}
if(input.setSelectionRange){return input.selectionStart;}}catch(e){return 0;}},setCaretPos=function(node,pos){node=(typeof node==="string"||node instanceof String)?document.getElementById(node):node;if(!node){return false;}
if(node.createTextRange){var textRange=node.createTextRange();textRange.collapse(true);textRange.moveEnd('character',pos);textRange.moveStart('character',pos);textRange.select();return true;}
if(node.setSelectionRange){node.setSelectionRange(pos,pos);return true;}
return false;},isValidValue=function(mask,value){var reg=mask.replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g,'\\$1').replace(/_/g,'{digit+}').replace(/([0-9]{1})/g,'{digit$1}').replace(/\{digit([0-9]{1})\}/g,'[0-$1_]{1}').replace(/\{digit[\+]\}/g,'[0-9_]{1}');return(new RegExp(reg)).test(value);};input.off('keydown.xdsoft');if(options.mask===true){options.mask=options.format.replace(/Y/g,'9999').replace(/F/g,'9999').replace(/m/g,'19').replace(/d/g,'39').replace(/H/g,'29').replace(/i/g,'59').replace(/s/g,'59');}
if($.type(options.mask)==='string'){if(!isValidValue(options.mask,input.val())){input.val(options.mask.replace(/[0-9]/g,'_'));}
input.on('keydown.xdsoft',function(event){var val=this.value,key=event.which,pos,digit;if(((key>=KEY0&&key<=KEY9)||(key>=_KEY0&&key<=_KEY9))||(key===BACKSPACE||key===DEL)){pos=getCaretPos(this);digit=(key!==BACKSPACE&&key!==DEL)?String.fromCharCode((_KEY0<=key&&key<=_KEY9)?key-KEY0:key):'_';if((key===BACKSPACE||key===DEL)&&pos){pos-=1;digit='_';}
while(/[^0-9_]/.test(options.mask.substr(pos,1))&&pos<options.mask.length&&pos>0){pos+=(key===BACKSPACE||key===DEL)?-1:1;}
val=val.substr(0,pos)+digit+val.substr(pos+1);if($.trim(val)===''){val=options.mask.replace(/[0-9]/g,'_');}else{if(pos===options.mask.length){event.preventDefault();return false;}}
pos+=(key===BACKSPACE||key===DEL)?0:1;while(/[^0-9_]/.test(options.mask.substr(pos,1))&&pos<options.mask.length&&pos>0){pos+=(key===BACKSPACE||key===DEL)?-1:1;}
if(isValidValue(options.mask,val)){this.value=val;setCaretPos(this,pos);}else if($.trim(val)===''){this.value=options.mask.replace(/[0-9]/g,'_');}else{input.trigger('error_input.xdsoft');}}else{if(([AKEY,CKEY,VKEY,ZKEY,YKEY].indexOf(key)!==-1&&ctrlDown)||[ESC,ARROWUP,ARROWDOWN,ARROWLEFT,ARROWRIGHT,F5,CTRLKEY,TAB,ENTER].indexOf(key)!==-1){return true;}}
event.preventDefault();return false;});}}
if(options.validateOnBlur){input.off('blur.xdsoft').on('blur.xdsoft',function(){if(options.allowBlank&&!$.trim($(this).val()).length){$(this).val(null);datetimepicker.data('xdsoft_datetime').empty();}else if(!Date.parseDate($(this).val(),options.format)){var splittedHours=+([$(this).val()[0],$(this).val()[1]].join('')),splittedMinutes=+([$(this).val()[2],$(this).val()[3]].join(''));if(!options.datepicker&&options.timepicker&&splittedHours>=0&&splittedHours<24&&splittedMinutes>=0&&splittedMinutes<60){$(this).val([splittedHours,splittedMinutes].map(function(item){return item>9?item:'0'+item}).join(':'));}else{$(this).val((_xdsoft_datetime.now()).dateFormat(options.format));}
datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val());}else{datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val());}
datetimepicker.trigger('changedatetime.xdsoft');});}
options.dayOfWeekStartPrev=(options.dayOfWeekStart===0)?6:options.dayOfWeekStart-1;datetimepicker.trigger('xchange.xdsoft').trigger('afterOpen.xdsoft');};datetimepicker.data('options',options).on('mousedown.xdsoft',function(event){event.stopPropagation();event.preventDefault();yearselect.hide();monthselect.hide();return false;});timeboxparent.append(timebox);timeboxparent.xdsoftScroller();datetimepicker.on('afterOpen.xdsoft',function(){timeboxparent.xdsoftScroller();});datetimepicker.append(datepicker).append(timepicker);if(options.withoutCopyright!==true){datetimepicker.append(xdsoft_copyright);}
datepicker.append(mounth_picker).append(calendar).append(applyButton);$(options.parentID).append(datetimepicker);XDSoft_datetime=function(){var _this=this;_this.now=function(norecursion){var d=new Date(),date,time;if(!norecursion&&options.defaultDate){date=_this.strToDate(options.defaultDate);d.setFullYear(date.getFullYear());d.setMonth(date.getMonth());d.setDate(date.getDate());}
if(options.yearOffset){d.setFullYear(d.getFullYear()+options.yearOffset);}
if(!norecursion&&options.defaultTime){time=_this.strtotime(options.defaultTime);d.setHours(time.getHours());d.setMinutes(time.getMinutes());}
return d;};_this.isValidDate=function(d){if(Object.prototype.toString.call(d)!=="[object Date]"){return false;}
return!isNaN(d.getTime());};_this.setCurrentTime=function(dTime){_this.currentTime=(typeof dTime==='string')?_this.strToDateTime(dTime):_this.isValidDate(dTime)?dTime:_this.now();datetimepicker.trigger('xchange.xdsoft');};_this.empty=function(){_this.currentTime=null;};_this.getCurrentTime=function(dTime){return _this.currentTime;};_this.nextMonth=function(){if(_this.currentTime===undefined||_this.currentTime===null){_this.currentTime=_this.now();}
var month=_this.currentTime.getMonth()+1,year;if(month===12){_this.currentTime.setFullYear(_this.currentTime.getFullYear()+1);month=0;}
year=_this.currentTime.getFullYear();_this.currentTime.setDate(Math.min(new Date(_this.currentTime.getFullYear(),month+1,0).getDate(),_this.currentTime.getDate()));_this.currentTime.setMonth(month);if(options.onChangeMonth&&$.isFunction(options.onChangeMonth)){options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}
if(year!==_this.currentTime.getFullYear()&&$.isFunction(options.onChangeYear)){options.onChangeYear.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}
datetimepicker.trigger('xchange.xdsoft');return month;};_this.prevMonth=function(){if(_this.currentTime===undefined||_this.currentTime===null){_this.currentTime=_this.now();}
var month=_this.currentTime.getMonth()-1;if(month===-1){_this.currentTime.setFullYear(_this.currentTime.getFullYear()-1);month=11;}
_this.currentTime.setDate(Math.min(new Date(_this.currentTime.getFullYear(),month+1,0).getDate(),_this.currentTime.getDate()));_this.currentTime.setMonth(month);if(options.onChangeMonth&&$.isFunction(options.onChangeMonth)){options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}
datetimepicker.trigger('xchange.xdsoft');return month;};_this.getWeekOfYear=function(datetime){var onejan=new Date(datetime.getFullYear(),0,1);return Math.ceil((((datetime-onejan)/86400000)+onejan.getDay()+1)/7);};_this.strToDateTime=function(sDateTime){var tmpDate=[],timeOffset,currentTime;if(sDateTime&&sDateTime instanceof Date&&_this.isValidDate(sDateTime)){return sDateTime;}
tmpDate=/^(\+|\-)(.*)$/.exec(sDateTime);if(tmpDate){tmpDate[2]=Date.parseDate(tmpDate[2],options.formatDate);}
if(tmpDate&&tmpDate[2]){timeOffset=tmpDate[2].getTime()-(tmpDate[2].getTimezoneOffset())*60000;currentTime=new Date((_xdsoft_datetime.now()).getTime()+parseInt(tmpDate[1]+'1',10)*timeOffset);}else{currentTime=sDateTime?Date.parseDate(sDateTime,options.format):_this.now();}
if(!_this.isValidDate(currentTime)){currentTime=_this.now();}
return currentTime;};_this.strToDate=function(sDate){if(sDate&&sDate instanceof Date&&_this.isValidDate(sDate)){return sDate;}
var currentTime=sDate?Date.parseDate(sDate,options.formatDate):_this.now(true);if(!_this.isValidDate(currentTime)){currentTime=_this.now(true);}
return currentTime;};_this.strtotime=function(sTime){if(sTime&&sTime instanceof Date&&_this.isValidDate(sTime)){return sTime;}
var currentTime=sTime?Date.parseDate(sTime,options.formatTime):_this.now(true);if(!_this.isValidDate(currentTime)){currentTime=_this.now(true);}
return currentTime;};_this.str=function(){return _this.currentTime.dateFormat(options.format);};_this.currentTime=this.now();};_xdsoft_datetime=new XDSoft_datetime();applyButton.on('click',function(e){e.preventDefault();datetimepicker.data('changed',true);_xdsoft_datetime.setCurrentTime(getCurrentValue());input.val(_xdsoft_datetime.str());datetimepicker.trigger('close.xdsoft');});mounth_picker.find('.xdsoft_today_button').on('mousedown.xdsoft',function(){datetimepicker.data('changed',true);_xdsoft_datetime.setCurrentTime(0);datetimepicker.trigger('afterOpen.xdsoft');}).on('dblclick.xdsoft',function(){input.val(_xdsoft_datetime.str());datetimepicker.trigger('close.xdsoft');});mounth_picker.find('.xdsoft_prev,.xdsoft_next').on('mousedown.xdsoft',function(){var $this=$(this),timer=0,stop=false;(function arguments_callee1(v){if($this.hasClass(options.next)){_xdsoft_datetime.nextMonth();}else if($this.hasClass(options.prev)){_xdsoft_datetime.prevMonth();}
if(options.monthChangeSpinner){if(!stop){timer=setTimeout(arguments_callee1,v||100);}}}(500));$([document.body,window]).on('mouseup.xdsoft',function arguments_callee2(){clearTimeout(timer);stop=true;$([document.body,window]).off('mouseup.xdsoft',arguments_callee2);});});timepicker.find('.xdsoft_prev,.xdsoft_next').on('mousedown.xdsoft',function(){var $this=$(this),timer=0,stop=false,period=110;(function arguments_callee4(v){var pheight=timeboxparent[0].clientHeight,height=timebox[0].offsetHeight,top=Math.abs(parseInt(timebox.css('marginTop'),10));if($this.hasClass(options.next)&&(height-pheight)-options.timeHeightInTimePicker>=top){timebox.css('marginTop','-'+(top+options.timeHeightInTimePicker)+'px');}else if($this.hasClass(options.prev)&&top-options.timeHeightInTimePicker>=0){timebox.css('marginTop','-'+(top-options.timeHeightInTimePicker)+'px');}
timeboxparent.trigger('scroll_element.xdsoft_scroller',[Math.abs(parseInt(timebox.css('marginTop'),10)/(height-pheight))]);period=(period>10)?10:period-10;if(!stop){timer=setTimeout(arguments_callee4,v||period);}}(500));$([document.body,window]).on('mouseup.xdsoft',function arguments_callee5(){clearTimeout(timer);stop=true;$([document.body,window]).off('mouseup.xdsoft',arguments_callee5);});});xchangeTimer=0;datetimepicker.on('xchange.xdsoft',function(event){clearTimeout(xchangeTimer);xchangeTimer=setTimeout(function(){if(_xdsoft_datetime.currentTime===undefined||_xdsoft_datetime.currentTime===null){_xdsoft_datetime.currentTime=_xdsoft_datetime.now();}
var table='',start=new Date(_xdsoft_datetime.currentTime.getFullYear(),_xdsoft_datetime.currentTime.getMonth(),1,12,0,0),i=0,j,today=_xdsoft_datetime.now(),maxDate=false,minDate=false,d,y,m,w,classes=[],customDateSettings,newRow=true,time='',h='',line_time;while(start.getDay()!==options.dayOfWeekStart){start.setDate(start.getDate()-1);}
table+='<table><thead><tr>';if(options.weeks){table+='<th></th>';}
for(j=0;j<7;j+=1){table+='<th>'+options.i18n[options.lang].dayOfWeek[(j+options.dayOfWeekStart)%7]+'</th>';}
table+='</tr></thead>';table+='<tbody>';if(options.maxDate!==false){maxDate=_xdsoft_datetime.strToDate(options.maxDate);maxDate=new Date(maxDate.getFullYear(),maxDate.getMonth(),maxDate.getDate(),23,59,59,999);}
if(options.minDate!==false){minDate=_xdsoft_datetime.strToDate(options.minDate);minDate=new Date(minDate.getFullYear(),minDate.getMonth(),minDate.getDate());}
while(i<_xdsoft_datetime.currentTime.countDaysInMonth()||start.getDay()!==options.dayOfWeekStart||_xdsoft_datetime.currentTime.getMonth()===start.getMonth()){classes=[];i+=1;d=start.getDate();y=start.getFullYear();m=start.getMonth();w=_xdsoft_datetime.getWeekOfYear(start);classes.push('xdsoft_date');if(options.beforeShowDay&&$.isFunction(options.beforeShowDay.call)){customDateSettings=options.beforeShowDay.call(datetimepicker,start);}else{customDateSettings=null;}
if((maxDate!==false&&start>maxDate)||(minDate!==false&&start<minDate)||(customDateSettings&&customDateSettings[0]===false)){classes.push('xdsoft_disabled');}else if(options.disabledDates.indexOf(start.dateFormat(options.formatDate))!==-1){classes.push('xdsoft_disabled');}
if(customDateSettings&&customDateSettings[1]!==""){classes.push(customDateSettings[1]);}
if(_xdsoft_datetime.currentTime.getMonth()!==m){classes.push('xdsoft_other_month');}
if((options.defaultSelect||datetimepicker.data('changed'))&&_xdsoft_datetime.currentTime.dateFormat(options.formatDate)===start.dateFormat(options.formatDate)){classes.push('xdsoft_current');}
if(today.dateFormat(options.formatDate)===start.dateFormat(options.formatDate)){classes.push('xdsoft_today');}
if(start.getDay()===0||start.getDay()===6||~options.weekends.indexOf(start.dateFormat(options.formatDate))){classes.push('xdsoft_weekend');}
if(options.beforeShowDay&&$.isFunction(options.beforeShowDay)){classes.push(options.beforeShowDay(start));}
if(newRow){table+='<tr>';newRow=false;if(options.weeks){table+='<th>'+w+'</th>';}}
table+='<td data-date="'+d+'" data-month="'+m+'" data-year="'+y+'"'+' class="xdsoft_date xdsoft_day_of_week'+start.getDay()+' '+classes.join(' ')+'">'+'<div>'+d+'</div>'+'</td>';if(start.getDay()===options.dayOfWeekStartPrev){table+='</tr>';newRow=true;}
start.setDate(d+1);}
table+='</tbody></table>';calendar.html(table);mounth_picker.find('.xdsoft_label span').eq(0).text(options.i18n[options.lang].months[_xdsoft_datetime.currentTime.getMonth()]);mounth_picker.find('.xdsoft_label span').eq(1).text(_xdsoft_datetime.currentTime.getFullYear());time='';h='';m='';line_time=function line_time(h,m){var now=_xdsoft_datetime.now();now.setHours(h);h=parseInt(now.getHours(),10);now.setMinutes(m);m=parseInt(now.getMinutes(),10);var optionDateTime=new Date(_xdsoft_datetime.currentTime);optionDateTime.setHours(h);optionDateTime.setMinutes(m);classes=[];if((options.minDateTime!==false&&options.minDateTime>optionDateTime)||(options.maxTime!==false&&_xdsoft_datetime.strtotime(options.maxTime).getTime()<now.getTime())||(options.minTime!==false&&_xdsoft_datetime.strtotime(options.minTime).getTime()>now.getTime())){classes.push('xdsoft_disabled');}
var current_time=new Date(_xdsoft_datetime.currentTime);current_time.setHours(parseInt(_xdsoft_datetime.currentTime.getHours(),10));current_time.setMinutes(Math[options.roundTime](_xdsoft_datetime.currentTime.getMinutes()/options.step)*options.step);if((options.initTime||options.defaultSelect||datetimepicker.data('changed'))&&current_time.getHours()===parseInt(h,10)&&(options.step>59||current_time.getMinutes()===parseInt(m,10))){if(options.defaultSelect||datetimepicker.data('changed')){classes.push('xdsoft_current');}else if(options.initTime){classes.push('xdsoft_init_time');}}
if(parseInt(today.getHours(),10)===parseInt(h,10)&&parseInt(today.getMinutes(),10)===parseInt(m,10)){classes.push('xdsoft_today');}
time+='<div class="xdsoft_time '+classes.join(' ')+'" data-hour="'+h+'" data-minute="'+m+'">'+now.dateFormat(options.formatTime)+'</div>';};if(!options.allowTimes||!$.isArray(options.allowTimes)||!options.allowTimes.length){for(i=0,j=0;i<(options.hours12?12:24);i+=1){for(j=0;j<60;j+=options.step){h=(i<10?'0':'')+i;m=(j<10?'0':'')+j;line_time(h,m);}}}else{for(i=0;i<options.allowTimes.length;i+=1){h=_xdsoft_datetime.strtotime(options.allowTimes[i]).getHours();m=_xdsoft_datetime.strtotime(options.allowTimes[i]).getMinutes();line_time(h,m);}}
timebox.html(time);opt='';i=0;for(i=parseInt(options.yearStart,10)+options.yearOffset;i<=parseInt(options.yearEnd,10)+options.yearOffset;i+=1){opt+='<div class="xdsoft_option '+(_xdsoft_datetime.currentTime.getFullYear()===i?'xdsoft_current':'')+'" data-value="'+i+'">'+i+'</div>';}
yearselect.children().eq(0).html(opt);for(i=parseInt(options.monthStart),opt='';i<=parseInt(options.monthEnd);i+=1){opt+='<div class="xdsoft_option '+(_xdsoft_datetime.currentTime.getMonth()===i?'xdsoft_current':'')+'" data-value="'+i+'">'+options.i18n[options.lang].months[i]+'</div>';}
monthselect.children().eq(0).html(opt);$(datetimepicker).trigger('generate.xdsoft');},10);event.stopPropagation();}).on('afterOpen.xdsoft',function(){if(options.timepicker){var classType,pheight,height,top;if(timebox.find('.xdsoft_current').length){classType='.xdsoft_current';}else if(timebox.find('.xdsoft_init_time').length){classType='.xdsoft_init_time';}
if(classType){pheight=timeboxparent[0].clientHeight;height=timebox[0].offsetHeight;top=timebox.find(classType).index()*options.timeHeightInTimePicker+1;if((height-pheight)<top){top=height-pheight;}
timeboxparent.trigger('scroll_element.xdsoft_scroller',[parseInt(top,10)/(height-pheight)]);}else{timeboxparent.trigger('scroll_element.xdsoft_scroller',[0]);}}});timerclick=0;calendar.on('click.xdsoft','td',function(xdevent){xdevent.stopPropagation();timerclick+=1;var $this=$(this),currentTime=_xdsoft_datetime.currentTime;if(currentTime===undefined||currentTime===null){_xdsoft_datetime.currentTime=_xdsoft_datetime.now();currentTime=_xdsoft_datetime.currentTime;}
if($this.hasClass('xdsoft_disabled')){return false;}
currentTime.setDate(1);currentTime.setFullYear($this.data('year'));currentTime.setMonth($this.data('month'));currentTime.setDate($this.data('date'));datetimepicker.trigger('select.xdsoft',[currentTime]);input.val(_xdsoft_datetime.str());if((timerclick>1||(options.closeOnDateSelect===true||(options.closeOnDateSelect===0&&!options.timepicker)))&&!options.inline){datetimepicker.trigger('close.xdsoft');}
if(options.onSelectDate&&$.isFunction(options.onSelectDate)){options.onSelectDate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'),xdevent);}
datetimepicker.data('changed',true);datetimepicker.trigger('xchange.xdsoft');datetimepicker.trigger('changedatetime.xdsoft');setTimeout(function(){timerclick=0;},200);});timebox.on('click.xdsoft','div',function(xdevent){xdevent.stopPropagation();var $this=$(this),currentTime=_xdsoft_datetime.currentTime;if(currentTime===undefined||currentTime===null){_xdsoft_datetime.currentTime=_xdsoft_datetime.now();currentTime=_xdsoft_datetime.currentTime;}
if($this.hasClass('xdsoft_disabled')){return false;}
currentTime.setHours($this.data('hour'));currentTime.setMinutes($this.data('minute'));datetimepicker.trigger('select.xdsoft',[currentTime]);datetimepicker.data('input').val(_xdsoft_datetime.str());if(options.inline!==true&&options.closeOnTimeSelect===true){datetimepicker.trigger('close.xdsoft');}
if(options.onSelectTime&&$.isFunction(options.onSelectTime)){options.onSelectTime.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'),xdevent);}
datetimepicker.data('changed',true);datetimepicker.trigger('xchange.xdsoft');datetimepicker.trigger('changedatetime.xdsoft');});datepicker.on('mousewheel.xdsoft',function(event){if(!options.scrollMonth){return true;}
if(event.deltaY<0){_xdsoft_datetime.nextMonth();}else{_xdsoft_datetime.prevMonth();}
return false;});input.on('mousewheel.xdsoft',function(event){if(!options.scrollInput){return true;}
if(!options.datepicker&&options.timepicker){current_time_index=timebox.find('.xdsoft_current').length?timebox.find('.xdsoft_current').eq(0).index():0;if(current_time_index+event.deltaY>=0&&current_time_index+event.deltaY<timebox.children().length){current_time_index+=event.deltaY;}
if(timebox.children().eq(current_time_index).length){timebox.children().eq(current_time_index).trigger('mousedown');}
return false;}
if(options.datepicker&&!options.timepicker){datepicker.trigger(event,[event.deltaY,event.deltaX,event.deltaY]);if(input.val){input.val(_xdsoft_datetime.str());}
datetimepicker.trigger('changedatetime.xdsoft');return false;}});datetimepicker.on('changedatetime.xdsoft',function(event){if(options.onChangeDateTime&&$.isFunction(options.onChangeDateTime)){var $input=datetimepicker.data('input');options.onChangeDateTime.call(datetimepicker,_xdsoft_datetime.currentTime,$input,event);delete options.value;$input.trigger('change');}}).on('generate.xdsoft',function(){if(options.onGenerate&&$.isFunction(options.onGenerate)){options.onGenerate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));}
if(triggerAfterOpen){datetimepicker.trigger('afterOpen.xdsoft');triggerAfterOpen=false;}}).on('click.xdsoft',function(xdevent){xdevent.stopPropagation();});current_time_index=0;setPos=function(){var offset=datetimepicker.data('input').offset(),top=offset.top+datetimepicker.data('input')[0].offsetHeight-1,left=offset.left,position="absolute";if(options.fixed){top-=$(window).scrollTop();left-=$(window).scrollLeft();position="fixed";}else{if(top+datetimepicker[0].offsetHeight>$(window).height()+$(window).scrollTop()){top=offset.top-datetimepicker[0].offsetHeight+1;}
if(top<0){top=0;}
if(left+datetimepicker[0].offsetWidth>$(window).width()){left=$(window).width()-datetimepicker[0].offsetWidth;}}
datetimepicker.css({left:left,top:top,position:position});};datetimepicker.on('open.xdsoft',function(event){var onShow=true;if(options.onShow&&$.isFunction(options.onShow)){onShow=options.onShow.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'),event);}
if(onShow!==false){datetimepicker.show();setPos();$(window).off('resize.xdsoft',setPos).on('resize.xdsoft',setPos);if(options.closeOnWithoutClick){$([document.body,window]).on('mousedown.xdsoft',function arguments_callee6(){datetimepicker.trigger('close.xdsoft');$([document.body,window]).off('mousedown.xdsoft',arguments_callee6);});}}}).on('close.xdsoft',function(event){var onClose=true;mounth_picker.find('.xdsoft_month,.xdsoft_year').find('.xdsoft_select').hide();if(options.onClose&&$.isFunction(options.onClose)){onClose=options.onClose.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'),event);}
if(onClose!==false&&!options.opened&&!options.inline){datetimepicker.hide();}
event.stopPropagation();}).on('toggle.xdsoft',function(event){if(datetimepicker.is(':visible')){datetimepicker.trigger('close.xdsoft');}else{datetimepicker.trigger('open.xdsoft');}}).data('input',input);timer=0;timer1=0;datetimepicker.data('xdsoft_datetime',_xdsoft_datetime);datetimepicker.setOptions(options);function getCurrentValue(){var ct=false,time;if(options.startDate){ct=_xdsoft_datetime.strToDate(options.startDate);}else{ct=options.value||((input&&input.val&&input.val())?input.val():'');if(ct){ct=_xdsoft_datetime.strToDateTime(ct);}else if(options.defaultDate){ct=_xdsoft_datetime.strToDate(options.defaultDate);if(options.defaultTime){time=_xdsoft_datetime.strtotime(options.defaultTime);ct.setHours(time.getHours());ct.setMinutes(time.getMinutes());}}}
if(ct&&_xdsoft_datetime.isValidDate(ct)){datetimepicker.data('changed',true);}else{ct='';}
return ct||0;}
_xdsoft_datetime.setCurrentTime(getCurrentValue());input.data('xdsoft_datetimepicker',datetimepicker).on('open.xdsoft mousedown.xdsoft',function(event){if(input.is(':disabled')||(input.data('xdsoft_datetimepicker').is(':visible')&&options.closeOnInputClick)){return;}
clearTimeout(timer);timer=setTimeout(function(){if(input.is(':disabled')){return;}
triggerAfterOpen=true;_xdsoft_datetime.setCurrentTime(getCurrentValue());datetimepicker.trigger('open.xdsoft');},100);}).on('keydown.xdsoft',function(event){var val=this.value,elementSelector,key=event.which;if([ENTER].indexOf(key)!==-1&&options.enterLikeTab){elementSelector=$("input:visible,textarea:visible");datetimepicker.trigger('close.xdsoft');elementSelector.eq(elementSelector.index(this)+1).focus();return false;}
if([TAB].indexOf(key)!==-1){datetimepicker.trigger('close.xdsoft');return true;}});};destroyDateTimePicker=function(input){var datetimepicker=input.data('xdsoft_datetimepicker');if(datetimepicker){datetimepicker.data('xdsoft_datetime',null);datetimepicker.remove();input.data('xdsoft_datetimepicker',null).off('.xdsoft');$(window).off('resize.xdsoft');$([window,document.body]).off('mousedown.xdsoft');if(input.unmousewheel){input.unmousewheel();}}};$(document).off('keydown.xdsoftctrl keyup.xdsoftctrl').on('keydown.xdsoftctrl',function(e){if(e.keyCode===CTRLKEY){ctrlDown=true;}}).on('keyup.xdsoftctrl',function(e){if(e.keyCode===CTRLKEY){ctrlDown=false;}});return this.each(function(){var datetimepicker=$(this).data('xdsoft_datetimepicker');if(datetimepicker){if($.type(opt)==='string'){switch(opt){case'show':$(this).select().focus();datetimepicker.trigger('open.xdsoft');break;case'hide':datetimepicker.trigger('close.xdsoft');break;case'toggle':datetimepicker.trigger('toggle.xdsoft');break;case'destroy':destroyDateTimePicker($(this));break;case'reset':this.value=this.defaultValue;if(!this.value||!datetimepicker.data('xdsoft_datetime').isValidDate(Date.parseDate(this.value,options.format))){datetimepicker.data('changed',false);}
datetimepicker.data('xdsoft_datetime').setCurrentTime(this.value);break;case'validate':var $input=datetimepicker.data('input');$input.trigger('blur.xdsoft');break;}}else{datetimepicker.setOptions(opt);}
return 0;}
if($.type(opt)!=='string'){if(!options.lazyInit||options.open||options.inline){createDateTimePicker($(this));}else{lazyInit($(this));}}});};$.fn.datetimepicker.defaults=default_options;}(jQuery));(function(){!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.12",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b),d=c["offsetParent"in a.fn?"offsetParent":"parent"]();return d.length||(d=a("body")),parseInt(d.css("fontSize"),10)||parseInt(c.css("fontSize"),10)||16},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});Date.parseFunctions={count:0};Date.parseRegexes=[];Date.formatFunctions={count:0};Date.prototype.dateFormat=function(b){if(b=="unixtime"){return parseInt(this.getTime()/1000);}if(Date.formatFunctions[b]==null){Date.createNewFormat(b);}var a=Date.formatFunctions[b];return this[a]();};Date.createNewFormat=function(format){var funcName="format"+Date.formatFunctions.count++;Date.formatFunctions[format]=funcName;var codePrefix="Date.prototype."+funcName+" = function() {return ";var code="";var special=false;var ch="";for(var i=0;i<format.length;++i){ch=format.charAt(i);if(!special&&ch=="\\"){special=true;}else{if(special){special=false;code+="'"+String.escape(ch)+"' + ";}else{code+=Date.getFormatCode(ch);}}}if(code.length==0){code="\"\"";}else{code=code.substring(0,code.length-3);}eval(codePrefix+code+";}");};Date.getFormatCode=function(a){switch(a){case"d":return"String.leftPad(this.getDate(), 2, '0') + ";case"D":return"Date.dayNames[this.getDay()].substring(0, 3) + ";case"j":return"this.getDate() + ";case"l":return"Date.dayNames[this.getDay()] + ";case"S":return"this.getSuffix() + ";case"w":return"this.getDay() + ";case"z":return"this.getDayOfYear() + ";case"W":return"this.getWeekOfYear() + ";case"F":return"Date.monthNames[this.getMonth()] + ";case"m":return"String.leftPad(this.getMonth() + 1, 2, '0') + ";case"M":return"Date.monthNames[this.getMonth()].substring(0, 3) + ";case"n":return"(this.getMonth() + 1) + ";case"t":return"this.getDaysInMonth() + ";case"L":return"(this.isLeapYear() ? 1 : 0) + ";case"Y":return"this.getFullYear() + ";case"y":return"('' + this.getFullYear()).substring(2, 4) + ";case"a":return"(this.getHours() < 12 ? 'am' : 'pm') + ";case"A":return"(this.getHours() < 12 ? 'AM' : 'PM') + ";case"g":return"((this.getHours() %12) ? this.getHours() % 12 : 12) + ";case"G":return"this.getHours() + ";case"h":return"String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";case"H":return"String.leftPad(this.getHours(), 2, '0') + ";case"i":return"String.leftPad(this.getMinutes(), 2, '0') + ";case"s":return"String.leftPad(this.getSeconds(), 2, '0') + ";case"O":return"this.getGMTOffset() + ";case"T":return"this.getTimezone() + ";case"Z":return"(this.getTimezoneOffset() * -60) + ";default:return"'"+String.escape(a)+"' + ";}};Date.parseDate=function(a,c){if(c=="unixtime"){return new Date(!isNaN(parseInt(a))?parseInt(a)*1000:0);}if(Date.parseFunctions[c]==null){Date.createParser(c);}var b=Date.parseFunctions[c];return Date[b](a);};Date.createParser=function(format){var funcName="parse"+Date.parseFunctions.count++;var regexNum=Date.parseRegexes.length;var currentGroup=1;Date.parseFunctions[format]=funcName;var code="Date."+funcName+" = function(input) {\nvar y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, z = -1;\nvar d = new Date();\ny = d.getFullYear();\nm = d.getMonth();\nd = d.getDate();\nvar results = input.match(Date.parseRegexes["+regexNum+"]);\nif (results && results.length > 0) {";var regex="";var special=false;var ch="";for(var i=0;i<format.length;++i){ch=format.charAt(i);if(!special&&ch=="\\"){special=true;}else{if(special){special=false;regex+=String.escape(ch);}else{obj=Date.formatCodeToRegex(ch,currentGroup);currentGroup+=obj.g;regex+=obj.s;if(obj.g&&obj.c){code+=obj.c;}}}}code+="if (y > 0 && z > 0){\nvar doyDate = new Date(y,0);\ndoyDate.setDate(z);\nm = doyDate.getMonth();\nd = doyDate.getDate();\n}";code+="if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n{return new Date(y, m, d, h, i, s);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n{return new Date(y, m, d, h, i);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0)\n{return new Date(y, m, d, h);}\nelse if (y > 0 && m >= 0 && d > 0)\n{return new Date(y, m, d);}\nelse if (y > 0 && m >= 0)\n{return new Date(y, m);}\nelse if (y > 0)\n{return new Date(y);}\n}return null;}";Date.parseRegexes[regexNum]=new RegExp("^"+regex+"$",'i');eval(code);};Date.formatCodeToRegex=function(b,a){switch(b){case"D":return{g:0,c:null,s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};case"j":case"d":return{g:1,c:"d = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"l":return{g:0,c:null,s:"(?:"+Date.dayNames.join("|")+")"};case"S":return{g:0,c:null,s:"(?:st|nd|rd|th)"};case"w":return{g:0,c:null,s:"\\d"};case"z":return{g:1,c:"z = parseInt(results["+a+"], 10);\n",s:"(\\d{1,3})"};case"W":return{g:0,c:null,s:"(?:\\d{2})"};case"F":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"].substring(0, 3)], 10);\n",s:"("+Date.monthNames.join("|")+")"};case"M":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"]], 10);\n",s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};case"n":case"m":return{g:1,c:"m = parseInt(results["+a+"], 10) - 1;\n",s:"(\\d{1,2})"};case"t":return{g:0,c:null,s:"\\d{1,2}"};case"L":return{g:0,c:null,s:"(?:1|0)"};case"Y":return{g:1,c:"y = parseInt(results["+a+"], 10);\n",s:"(\\d{4})"};case"y":return{g:1,c:"var ty = parseInt(results["+a+"], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",s:"(\\d{1,2})"};case"a":return{g:1,c:"if (results["+a+"] == 'am') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(am|pm)"};case"A":return{g:1,c:"if (results["+a+"] == 'AM') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(AM|PM)"};case"g":case"G":case"h":case"H":return{g:1,c:"h = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"i":return{g:1,c:"i = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"s":return{g:1,c:"s = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"O":return{g:0,c:null,s:"[+-]\\d{4}"};case"T":return{g:0,c:null,s:"[A-Z]{3}"};case"Z":return{g:0,c:null,s:"[+-]\\d{1,5}"};default:return{g:0,c:null,s:String.escape(b)};}};Date.prototype.getTimezone=function(){return this.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3");};Date.prototype.getGMTOffset=function(){return(this.getTimezoneOffset()>0?"-":"+")+String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset())/60),2,"0")+String.leftPad(Math.abs(this.getTimezoneOffset())%60,2,"0");};Date.prototype.getDayOfYear=function(){var a=0;Date.daysInMonth[1]=this.isLeapYear()?29:28;for(var b=0;b<this.getMonth();++b){a+=Date.daysInMonth[b];}return a+this.getDate();};Date.prototype.getWeekOfYear=function(){var b=this.getDayOfYear()+(4-this.getDay());var a=new Date(this.getFullYear(),0,1);var c=(7-a.getDay()+4);return String.leftPad(Math.ceil((b-c)/7)+1,2,"0");};Date.prototype.isLeapYear=function(){var a=this.getFullYear();return((a&3)==0&&(a%100||(a%400==0&&a)));};Date.prototype.getFirstDayOfMonth=function(){var a=(this.getDay()-(this.getDate()-1))%7;return(a<0)?(a+7):a;};Date.prototype.getLastDayOfMonth=function(){var a=(this.getDay()+(Date.daysInMonth[this.getMonth()]-this.getDate()))%7;return(a<0)?(a+7):a;};Date.prototype.getDaysInMonth=function(){Date.daysInMonth[1]=this.isLeapYear()?29:28;return Date.daysInMonth[this.getMonth()];};Date.prototype.getSuffix=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};String.escape=function(a){return a.replace(/('|\\)/g,"\\$1");};String.leftPad=function(d,b,c){var a=new String(d);if(c==null){c=" ";}while(a.length<b){a=c+a;}return a;};Date.daysInMonth=[31,28,31,30,31,30,31,31,30,31,30,31];Date.monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];Date.dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];Date.y2kYear=50;Date.monthNumbers={Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11};Date.patterns={ISO8601LongPattern:"Y-m-d H:i:s",ISO8601ShortPattern:"Y-m-d",ShortDatePattern:"n/j/Y",LongDatePattern:"l, F d, Y",FullDateTimePattern:"l, F d, Y g:i:s A",MonthDayPattern:"F d",ShortTimePattern:"g:i A",LongTimePattern:"g:i:s A",SortableDateTimePattern:"Y-m-d\\TH:i:s",UniversalSortableDateTimePattern:"Y-m-d H:i:sO",YearMonthPattern:"F, Y"};}());

(function(jQuery,undefined){var timer;function Timer(fn,fd){var self=this,clock;function update(){self.frameCount++;fn.call(self);}
this.frameDuration=fd||25;this.frameCount=-1;this.start=function(){update();clock=setInterval(update,this.frameDuration);};this.stop=function(){clearInterval(clock);clock=null;};}
function callHandler(){var fn=jQuery.event.special.frame.handler,event=jQuery.Event("frame"),array=this.array,l=array.length;event.frameCount=this.frameCount;while(l--){fn.call(array[l],event);}}
if(!jQuery.event.special.frame){jQuery.event.special.frame={setup:function(data,namespaces){if(timer){timer.array.push(this);}
else{timer=new Timer(callHandler,data&&data.frameDuration);timer.array=[this];var t=setTimeout(function(){timer.start();clearTimeout(t);t=null;},0);}
return;},teardown:function(namespaces){var array=timer.array,l=array.length;while(l--){if(array[l]===this){array.splice(l,1);break;}}
if(array.length===0){timer.stop();timer=undefined;}
return;},handler:function(event){jQuery.event.handle.apply(this,arguments);}};}})(jQuery);

$.widget('custom.mcautocomplete',$.ui.autocomplete,{_create:function(){this._super();this.widget().menu("option","items","> :not(.ui-widget-header)");},_renderMenu:function(ul,items){var self=this,thead;ul.css("z-index",30002);if(this.options.menu)
ul.css("overflow","hidden").css("height","auto");if(this.options.showHeader&&!this.options.menu){table=$('<div class="ui-widget-header" style="width:100%; padding-top: 0.3em; padding-bottom: 0.3em;"></div>');$.each(this.options.columns,function(index,item){table.append('<span style="padding:0 4px;float:left;width:'+item.width+';">'+item.name+'</span>');});this.options.drilldown=Default(this.options.drilldown,"");if(this.options.drilldown!=""||this.options.allowdelete){if(this.options.drilldown==""){table.append('<span style="padding:0 4px;float:left;width:15px;max-width:15px;"></span>');}else{var dd=$('<span class="ui-state-default" style="padding:0 4px;float:left;width:15px;background-color:transparent;border:0px;color:white;cursor:pointer;"><small>edit</small></span>');dd.on('click',function(){Application.App.LoadPage(self.options.drilldown,self.options.drilldownview);}).mouseover(function(){$(this).removeClass("ui-state-default");}).mouseout(function(){$(this).addClass("ui-state-default");});table.append(dd);}}
table.append('<div style="clear: both;"></div>');ul.append(table);}
var currentCategory="";$.each(items,function(index,item){if(item.BoldField&&item.BoldField!=""){if(item.BoldField!=currentCategory){ul.append("<li class='ui-autocomplete-category'>"+item.BoldField+"</li>");currentCategory=item.BoldField;}}
self._renderItem(ul,item);});},_renderItem:function(ul,item){var t='',result='';$.each(this.options.columns,function(index,column){t+='<span style="padding:0 4px;float:left;height:15px;overflow:hidden;width:'+column.width+';max-width:'+column.width+';">'+item[column.valueField?column.valueField:index]+'</span>'});if(this.options.drilldown!=""||this.options.allowdelete){if(this.options.allowdelete){if(item.BlankRow==false)
t+='<span id="del'+item.UID+'" style="padding:0 4px;float:left;height:15px;overflow:hidden;width:15px;max-width:15px;color:gainsboro;">x</span>';}else{t+='<span style="padding:0 4px;float:left;height:15px;overflow:hidden;width:15px;max-width:15px;"></span>'}}
result=$('<li></li>').data('ui-autocomplete-item',item).append('<a class="mcacAnchor">'+t+'<div style="clear: both;"></div></a>').appendTo(ul);$("#del"+item.UID).click(function(e){e.stopPropagation();Application.Confirm("Are you sure you wish to delete this record?<br/><br/>"+item.RID,function(r){if(r)
Application.RunNext(function(){BEGINTRANSACTION(function(){GET(item.RID,function(rec){if(rec.Count>0)
DELETE(rec,function(){COMMITTRANSACTION();});});});});});}).mouseover(function(){$(this).css("color","red")}).mouseout(function(){$(this).css("color","gainsboro")});return result;}});

(function($){$.extend($.ui,{multiDatesPicker:{version:"1.6.4"}});$.fn.multiDatesPicker=function(method){var mdp_arguments=arguments;var ret=this;var today_date=new Date();var day_zero=new Date(0);var mdp_events={};function removeDate(date,type){if(!type)type='picked';date=dateConvert.call(this,date);for(var i=0;i<this.multiDatesPicker.dates[type].length;i++)
if(!methods.compareDates(this.multiDatesPicker.dates[type][i],date))
return this.multiDatesPicker.dates[type].splice(i,1).pop();}
function removeIndex(index,type){if(!type)type='picked';return this.multiDatesPicker.dates[type].splice(index,1).pop();}
function addDate(date,type,no_sort){if(!type)type='picked';date=dateConvert.call(this,date);date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0);if(methods.gotDate.call(this,date,type)===false){this.multiDatesPicker.dates[type].push(date);if(!no_sort)this.multiDatesPicker.dates[type].sort(methods.compareDates);}}
function sortDates(type){if(!type)type='picked';this.multiDatesPicker.dates[type].sort(methods.compareDates);}
function dateConvert(date,desired_type,date_format){if(!desired_type)desired_type='object';return methods.dateConvert.call(this,date,desired_type,date_format);}
var methods={init:function(options){var $this=$(this);this.multiDatesPicker.changed=false;var mdp_events={beforeShow:function(input,inst){this.multiDatesPicker.changed=false;if(this.multiDatesPicker.originalBeforeShow)
this.multiDatesPicker.originalBeforeShow.call(this,input,inst);},onSelect:function(dateText,inst){var $this=$(this);this.multiDatesPicker.changed=true;if(dateText){$this.multiDatesPicker('toggleDate',dateText);this.multiDatesPicker.changed=true;}
if(this.multiDatesPicker.mode=='normal'&&this.multiDatesPicker.pickableRange){if(this.multiDatesPicker.dates.picked.length>0){var min_date=this.multiDatesPicker.dates.picked[0],max_date=new Date(min_date.getTime());methods.sumDays(max_date,this.multiDatesPicker.pickableRange-1);if(this.multiDatesPicker.adjustRangeToDisabled){var c_disabled,disabled=this.multiDatesPicker.dates.disabled.slice(0);do{c_disabled=0;for(var i=0;i<disabled.length;i++){if(disabled[i].getTime()<=max_date.getTime()){if((min_date.getTime()<=disabled[i].getTime())&&(disabled[i].getTime()<=max_date.getTime())){c_disabled++;}
disabled.splice(i,1);i--;}}
max_date.setDate(max_date.getDate()+c_disabled);}while(c_disabled!=0);}
if(this.multiDatesPicker.maxDate&&(max_date>this.multiDatesPicker.maxDate))
max_date=this.multiDatesPicker.maxDate;$this.datepicker("option","minDate",min_date).datepicker("option","maxDate",max_date);}else{$this.datepicker("option","minDate",this.multiDatesPicker.minDate).datepicker("option","maxDate",this.multiDatesPicker.maxDate);}}
if(this.multiDatesPicker.originalOnSelect&&dateText)
this.multiDatesPicker.originalOnSelect.call(this,dateText,inst);},beforeShowDay:function(date){var $this=$(this),gotThisDate=$this.multiDatesPicker('gotDate',date)!==false,isDisabledCalendar=$this.datepicker('option','disabled'),isDisabledDate=$this.multiDatesPicker('gotDate',date,'disabled')!==false,areAllSelected=this.multiDatesPicker.maxPicks<=this.multiDatesPicker.dates.picked.length;var bsdReturn=[true,'',null];if(this.multiDatesPicker.originalBeforeShowDay)
bsdReturn=this.multiDatesPicker.originalBeforeShowDay.call(this,date);bsdReturn[1]=gotThisDate?'ui-state-highlight '+bsdReturn[1]:bsdReturn[1];bsdReturn[0]=bsdReturn[0]&&!(isDisabledCalendar||isDisabledDate||(areAllSelected&&!bsdReturn[1]));return bsdReturn;}};if($this.val())var inputDates=$this.val()
if(options){if(options.separator)this.multiDatesPicker.separator=options.separator;if(!this.multiDatesPicker.separator)this.multiDatesPicker.separator=', ';this.multiDatesPicker.originalBeforeShow=options.beforeShow;this.multiDatesPicker.originalOnSelect=options.onSelect;this.multiDatesPicker.originalBeforeShowDay=options.beforeShowDay;this.multiDatesPicker.originalOnClose=options.onClose;$this.datepicker(options);this.multiDatesPicker.minDate=$.datepicker._determineDate(this,options.minDate,null);this.multiDatesPicker.maxDate=$.datepicker._determineDate(this,options.maxDate,null);if(options.addDates)methods.addDates.call(this,options.addDates);if(options.addDisabledDates)
methods.addDates.call(this,options.addDisabledDates,'disabled');methods.setMode.call(this,options);}else{$this.datepicker();}
$this.datepicker('option',mdp_events);$this.datepicker('option','dateFormat',options.dateFormat);if(inputDates)$this.multiDatesPicker('value',inputDates);var inputs_values=$this.multiDatesPicker('value');$this.val(inputs_values);var altFieldOption=$this.datepicker('option','altField');if(altFieldOption)$(altFieldOption).val(inputs_values);$this.datepicker('refresh');},compareDates:function(date1,date2){date1=dateConvert.call(this,date1);date2=dateConvert.call(this,date2);var diff=date1.getFullYear()-date2.getFullYear();if(!diff){diff=date1.getMonth()-date2.getMonth();if(!diff)
diff=date1.getDate()-date2.getDate();}
return diff;},sumDays:function(date,n_days){var origDateType=typeof date;obj_date=dateConvert.call(this,date);obj_date.setDate(obj_date.getDate()+n_days);return dateConvert.call(this,obj_date,origDateType);},dateConvert:function(date,desired_format,dateFormat){var from_format=typeof date;var $this=$(this);if(from_format==desired_format){if(from_format=='object'){try{date.getTime();}catch(e){$.error('Received date is in a non supported format!');return false;}}
return date;}
if(typeof date=='undefined')date=new Date(0);if(desired_format!='string'&&desired_format!='object'&&desired_format!='number')
$.error('Date format "'+desired_format+'" not supported!');if(!dateFormat){var dp_dateFormat=$this.datepicker('option','dateFormat');if(dp_dateFormat){dateFormat=dp_dateFormat;}else{dateFormat=$.datepicker._defaults.dateFormat;}}
switch(from_format){case'object':break;case'string':date=$.datepicker.parseDate(dateFormat,date);break;case'number':date=new Date(date);break;default:$.error('Conversion from "'+desired_format+'" format not allowed on jQuery.multiDatesPicker');}
switch(desired_format){case'object':return date;case'string':return $.datepicker.formatDate(dateFormat,date);case'number':return date.getTime();default:$.error('Conversion to "'+desired_format+'" format not allowed on jQuery.multiDatesPicker');}
return false;},gotDate:function(date,type){if(!type)type='picked';for(var i=0;i<this.multiDatesPicker.dates[type].length;i++){if(methods.compareDates.call(this,this.multiDatesPicker.dates[type][i],date)===0){return i;}}
return false;},value:function(value){if(value&&typeof value=='string'){methods.addDates.call(this,value.split(this.multiDatesPicker.separator));}else{var dates=methods.getDates.call(this,'string');return dates.length?dates.join(this.multiDatesPicker.separator):"";}},getDates:function(format,type){if(!format)format='string';if(!type)type='picked';switch(format){case'object':return this.multiDatesPicker.dates[type];case'string':case'number':var o_dates=new Array();for(var i=0;i<this.multiDatesPicker.dates[type].length;i++)
o_dates.push(dateConvert.call(this,this.multiDatesPicker.dates[type][i],format));return o_dates;default:$.error('Format "'+format+'" not supported!');}},addDates:function(dates,type){if(dates.length>0){if(!type)type='picked';switch(typeof dates){case'object':case'array':if(dates.length){for(var i=0;i<dates.length;i++)
addDate.call(this,dates[i],type,true);sortDates.call(this,type);break;}
case'string':case'number':addDate.call(this,dates,type);break;default:$.error('Date format "'+typeof dates+'" not allowed on jQuery.multiDatesPicker');}}else{$.error('Empty array of dates received.');}},removeDates:function(dates,type){if(!type)type='picked';var removed=[];if(Object.prototype.toString.call(dates)==='[object Array]'){for(var i in dates.sort(function(a,b){return b-a})){removed.push(removeDate.call(this,dates[i],type));}}else{removed.push(removeDate.call(this,dates,type));}
return removed;},removeIndexes:function(indexes,type){if(!type)type='picked';var removed=[];if(Object.prototype.toString.call(indexes)==='[object Array]'){for(var i in indexes.sort(function(a,b){return b-a})){removed.push(removeIndex.call(this,indexes[i],type));}}else{removed.push(removeIndex.call(this,indexes,type));}
return removed;},resetDates:function(type){if(!type)type='picked';this.multiDatesPicker.dates[type]=[];},toggleDate:function(date,type){if(!type)type='picked';switch(this.multiDatesPicker.mode){case'daysRange':this.multiDatesPicker.dates[type]=[];var end=this.multiDatesPicker.autoselectRange[1];var begin=this.multiDatesPicker.autoselectRange[0];if(end<begin){end=this.multiDatesPicker.autoselectRange[0];begin=this.multiDatesPicker.autoselectRange[1];}
for(var i=begin;i<end;i++)
methods.addDates.call(this,methods.sumDays.call(this,date,i),type);break;default:if(methods.gotDate.call(this,date)===false)
methods.addDates.call(this,date,type);else
methods.removeDates.call(this,date,type);break;}},setMode:function(options){var $this=$(this);if(options.mode)this.multiDatesPicker.mode=options.mode;switch(this.multiDatesPicker.mode){case'normal':for(option in options)
switch(option){case'maxPicks':case'minPicks':case'pickableRange':case'adjustRangeToDisabled':this.multiDatesPicker[option]=options[option];break;}
break;case'daysRange':case'weeksRange':var mandatory=1;for(option in options)
switch(option){case'autoselectRange':mandatory--;case'pickableRange':case'adjustRangeToDisabled':this.multiDatesPicker[option]=options[option];break;}
if(mandatory>0)$.error('Some mandatory options not specified!');break;}
if(mdp_events.onSelect)
mdp_events.onSelect();},destroy:function(){this.multiDatesPicker=null;$(this).datepicker('destroy');},show:function(){$(this).datepicker('show');}};this.each(function(){var $this=$(this);if(!this.multiDatesPicker){this.multiDatesPicker={dates:{picked:[],disabled:[]},mode:'normal',adjustRangeToDisabled:true};}
if(methods[method]){var exec_result=methods[method].apply(this,Array.prototype.slice.call(mdp_arguments,1));switch(method){case'removeDates':case'removeIndexes':case'resetDates':case'toggleDate':case'addDates':var altField=$this.datepicker('option','altField');var dates_string=methods.value.call(this);if(altField!==undefined&&altField!=""){$(altField).val(dates_string);}
$this.val(dates_string);$.datepicker._refreshDatepicker(this);}
switch(method){case'removeDates':case'getDates':case'gotDate':case'sumDays':case'compareDates':case'dateConvert':case'value':ret=exec_result;}
return exec_result;}else if(typeof method==='object'||!method){return methods.init.apply(this,mdp_arguments);}else{$.error('Method '+method+' does not exist on jQuery.multiDatesPicker');}
return false;});return ret;};var PROP_NAME='multiDatesPicker';var dpuuid=new Date().getTime();var instActive;$.multiDatesPicker={version:false};$.multiDatesPicker.initialized=false;$.multiDatesPicker.uuid=new Date().getTime();$.multiDatesPicker.version=$.ui.multiDatesPicker.version;$.multiDatesPicker._hideDatepicker=$.datepicker._hideDatepicker;$.datepicker._hideDatepicker=function(){var target=this._curInst.input[0];var mdp=target.multiDatesPicker;if(!mdp||(this._curInst.inline===false&&!mdp.changed)){return $.multiDatesPicker._hideDatepicker.apply(this,arguments);}else{mdp.changed=false;$.datepicker._refreshDatepicker(target);return;}};window['DP_jQuery_'+dpuuid]=$;})(jQuery);

(function($,undefined){var multiselectID=0;var $doc=$(document);$.widget("ech.multiselectcombo",{options:{header:true,height:175,minWidth:225,classes:'',checkAllText:'Check all',uncheckAllText:'Uncheck all',noneSelectedText:'Select options',selectedText:'# selected',selectedList:0,show:null,hide:null,autoOpen:false,multiple:true,position:{},appendTo:"body"},_create:function(){var el=this.element.hide();var o=this.options;this.speed=$.fx.speeds._default;this._isOpen=false;this._namespaceID=this.eventNamespace||('multiselectcombo'+multiselectID);var button=(this.button=$('<button type="button"><span class="ui-icon ui-icon-triangle-1-s"></span></button>')).addClass('ui-multiselect ui-widget ui-state-default ui-corner-all').addClass(o.classes).attr({'title':el.attr('title'),'aria-haspopup':true,'tabIndex':el.attr('tabIndex')}).insertAfter(el),buttonlabel=(this.buttonlabel=$('<span />')).html(o.noneSelectedText).appendTo(button),menu=(this.menu=$('<div />')).addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all').addClass(o.classes).appendTo($(o.appendTo)),header=(this.header=$('<div />')).addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix').appendTo(menu),headerLinkContainer=(this.headerLinkContainer=$('<ul />')).addClass('ui-helper-reset').html(function(){if(o.header===true){var drilldown="";o.drilldown=Default(o.drilldown,"");if(o.drilldown!=""){drilldown='<li><a class="ui-multiselect-edit" href="#"><span class="ui-icon ui-icon-pencil"></span><span>Edit</span></a></li>';}
return'<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>'+o.checkAllText+'</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>'+o.uncheckAllText+'</span></a></li>'+drilldown;}else if(typeof o.header==="string"){return'<li>'+o.header+'</li>';}else{return'';}}).append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>').appendTo(header),checkboxContainer=(this.checkboxContainer=$('<ul />')).addClass('ui-multiselect-checkboxes ui-helper-reset').appendTo(menu);this._bindEvents();this.refresh(true);if(!o.multiple){menu.addClass('ui-multiselect-single');}
multiselectID++;},_init:function(){if(this.options.header===false){this.header.hide();}
if(!this.options.multiple){this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide();}
if(this.options.autoOpen){this.open();}
if(this.element.is(':disabled')){this.disable();}},refresh:function(init){var el=this.element;var o=this.options;var menu=this.menu;var checkboxContainer=this.checkboxContainer;var optgroups=[];var html="";var id=el.attr('id')||multiselectID++;el.find('option').each(function(i){var $this=$(this);var parent=this.parentNode;var description=this.innerHTML;var title=this.title;var value=this.value;var inputID='ui-multiselect-'+(this.id||id+'-option-'+i);var isDisabled=this.disabled;var isSelected=this.selected;var labelClasses=['ui-corner-all'];var liClasses=(isDisabled?'ui-multiselect-disabled ':' ')+this.className;var optLabel;if(parent.tagName==='OPTGROUP'){optLabel=parent.getAttribute('label');if($.inArray(optLabel,optgroups)===-1){html+='<li class="ui-multiselect-optgroup-label '+parent.className+'"><a href="#">'+optLabel+'</a></li>';optgroups.push(optLabel);}}
if(isDisabled){labelClasses.push('ui-state-disabled');}
if(isSelected&&!o.multiple){labelClasses.push('ui-state-active');}
html+='<li class="'+liClasses+'">';html+='<label for="'+inputID+'" title="'+title+'" class="'+labelClasses.join(' ')+'">';html+='<input id="'+inputID+'" name="multiselect_'+id+'" type="'+(o.multiple?"checkbox":"radio")+'" value="'+value+'" title="'+title+'"';if(isSelected){html+=' checked="checked"';html+=' aria-selected="true"';}
if(isDisabled){html+=' disabled="disabled"';html+=' aria-disabled="true"';}
html+=' /><span>'+description+'</span></label></li>';});checkboxContainer.html(html);this.labels=menu.find('label');this.inputs=this.labels.children('input');this._setButtonWidth();this._setMenuWidth();this.button[0].defaultValue=this.update();if(!init){this._trigger('refresh');}},update:function(){var o=this.options;var $inputs=this.inputs;var $checked=$inputs.filter(':checked');var numChecked=$checked.length;var value;if(numChecked===0){value=o.noneSelectedText;}else{if($.isFunction(o.selectedText)){value=o.selectedText.call(this,numChecked,$inputs.length,$checked.get());}else if(/\d/.test(o.selectedList)&&o.selectedList>0&&numChecked<=o.selectedList){value=$checked.map(function(){return $(this).next().html();}).get().join(', ');}else{value=o.selectedText.replace('#',numChecked).replace('#',$inputs.length);}}
this._setButtonValue(value);return value;},_setButtonValue:function(value){this.buttonlabel.text(value);},_bindEvents:function(){var self=this;var button=this.button;function clickHandler(){self[self._isOpen?'close':'open']();return false;}
button.find('span').bind('click.multiselectcombo',clickHandler);button.bind({click:clickHandler,keypress:function(e){switch(e.which){case 27:case 38:case 37:self.close();break;case 39:case 40:self.open();break;}},mouseenter:function(){if(!button.hasClass('ui-state-disabled')){$(this).addClass('ui-state-hover');}},mouseleave:function(){$(this).removeClass('ui-state-hover');},focus:function(){if(!button.hasClass('ui-state-disabled')){$(this).addClass('ui-state-focus');}},blur:function(){$(this).removeClass('ui-state-focus');}});this.header.delegate('a','click.multiselectcombo',function(e){if($(this).hasClass('ui-multiselect-edit')){self.close();Application.App.LoadPage(self.options.drilldown,self.options.drilldownview);}else if($(this).hasClass('ui-multiselect-close')){self.close();}else{self[$(this).hasClass('ui-multiselect-all')?'checkAll':'uncheckAll']();}
e.preventDefault();});this.menu.delegate('li.ui-multiselect-optgroup-label a','click.multiselectcombo',function(e){e.preventDefault();var $this=$(this);var $inputs=$this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)');var nodes=$inputs.get();var label=$this.parent().text();if(self._trigger('beforeoptgrouptoggle',e,{inputs:nodes,label:label})===false){return;}
self._toggleChecked($inputs.filter(':checked').length!==$inputs.length,$inputs);self._trigger('optgrouptoggle',e,{inputs:nodes,label:label,checked:nodes[0].checked});}).delegate('label','mouseenter.multiselectcombo',function(){if(!$(this).hasClass('ui-state-disabled')){self.labels.removeClass('ui-state-hover');$(this).addClass('ui-state-hover').find('input').focus();}}).delegate('label','keydown.multiselectcombo',function(e){e.preventDefault();switch(e.which){case 9:case 27:self.close();break;case 38:case 40:case 37:case 39:self._traverse(e.which,this);break;case 13:$(this).find('input')[0].click();break;}}).delegate('input[type="checkbox"], input[type="radio"]','click.multiselectcombo',function(e){var $this=$(this);var val=this.value;var checked=this.checked;var tags=self.element.find('option');if(this.disabled||self._trigger('click',e,{value:val,text:this.title,checked:checked})===false){e.preventDefault();return;}
$this.focus();$this.attr('aria-selected',checked);tags.each(function(){if(this.value===val){this.selected=checked;}else if(!self.options.multiple){this.selected=false;}});if(!self.options.multiple){self.labels.removeClass('ui-state-active');$this.closest('label').toggleClass('ui-state-active',checked);self.close();}
self.element.trigger("change");setTimeout($.proxy(self.refresh,self),10);});$doc.bind('mousedown.'+this._namespaceID,function(event){var target=event.target;if(self._isOpen&&target!==self.button[0]&&target!==self.menu[0]&&!$.contains(self.menu[0],target)&&!$.contains(self.button[0],target)){self.close();}});$(this.element[0].form).bind('reset.multiselectcombo',function(){setTimeout($.proxy(self.refresh,self),10);});},_setButtonWidth:function(){var width=this.element.outerWidth();var o=this.options;if(/\d/.test(o.minWidth)&&width<o.minWidth){width=o.minWidth;}
this.button.outerWidth(width);},_setMenuWidth:function(){var m=this.menu;m.outerWidth(this.button.outerWidth());},_traverse:function(which,start){var $start=$(start);var moveToLast=which===38||which===37;var $next=$start.parent()[moveToLast?'prevAll':'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)').first();if(!$next.length){var $container=this.menu.find('ul').last();this.menu.find('label')[moveToLast?'last':'first']().trigger('mouseover');$container.scrollTop(moveToLast?$container.height():0);}else{$next.find('label').trigger('mouseover');}},_toggleState:function(prop,flag){return function(){if(!this.disabled){this[prop]=flag;}
if(flag){this.setAttribute('aria-selected',true);}else{this.removeAttribute('aria-selected');}};},_toggleChecked:function(flag,group){var $inputs=(group&&group.length)?group:this.inputs;var self=this;$inputs.each(this._toggleState('checked',flag));$inputs.eq(0).focus();this.refresh();var values=$inputs.map(function(){return this.value;}).get();this.element.find('option').each(function(){if(!this.disabled&&$.inArray(this.value,values)>-1){self._toggleState('selected',flag).call(this);}});if($inputs.length){this.element.trigger("change");}},_toggleDisabled:function(flag){this.button.attr({'disabled':flag,'aria-disabled':flag})[flag?'addClass':'removeClass']('ui-state-disabled');var inputs=this.menu.find('input');var key="ech-multiselect-disabled";if(flag){inputs=inputs.filter(':enabled').data(key,true)}else{inputs=inputs.filter(function(){return $.data(this,key)===true;}).removeData(key);}
inputs.attr({'disabled':flag,'arial-disabled':flag}).parent()[flag?'addClass':'removeClass']('ui-state-disabled');this.element.attr({'disabled':flag,'aria-disabled':flag});},open:function(e){var self=this;var button=this.button;var menu=this.menu;var speed=this.speed;var o=this.options;var args=[];if(this._trigger('beforeopen')===false||button.hasClass('ui-state-disabled')||this._isOpen){return;}
var $container=menu.find('ul').last();var effect=o.show;if($.isArray(o.show)){effect=o.show[0];speed=o.show[1]||self.speed;}
if(effect){args=[effect,speed];}
$container.scrollTop(0).height(o.height);this.position();$.fn.show.apply(menu,args);this.labels.filter(':not(.ui-state-disabled)').eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus');button.addClass('ui-state-active');this._isOpen=true;this._trigger('open');},close:function(){if(this._trigger('beforeclose')===false){return;}
var o=this.options;var effect=o.hide;var speed=this.speed;var args=[];if($.isArray(o.hide)){effect=o.hide[0];speed=o.hide[1]||this.speed;}
if(effect){args=[effect,speed];}
$.fn.hide.apply(this.menu,args);this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave');this._isOpen=false;this._trigger('close');},enable:function(){this._toggleDisabled(false);},disable:function(){this._toggleDisabled(true);},checkAll:function(e){this._toggleChecked(true);this._trigger('checkAll');},uncheckAll:function(){this._toggleChecked(false);this._trigger('uncheckAll');},getChecked:function(){return this.menu.find('input').filter(':checked');},destroy:function(){$.Widget.prototype.destroy.call(this);$doc.unbind(this._namespaceID);this.button.remove();this.menu.remove();this.element.show();return this;},isOpen:function(){return this._isOpen;},widget:function(){return this.menu;},getButton:function(){return this.button;},position:function(){var o=this.options;if($.ui.position&&!$.isEmptyObject(o.position)){o.position.of=o.position.of||this.button;this.menu.show().position(o.position).hide();}else{var pos=this.button.offset();this.menu.css({top:pos.top+this.button.outerHeight(),left:pos.left});}},_setOption:function(key,value){var menu=this.menu;switch(key){case'header':menu.find('div.ui-multiselect-header')[value?'show':'hide']();break;case'checkAllText':menu.find('a.ui-multiselect-all span').eq(-1).text(value);break;case'uncheckAllText':menu.find('a.ui-multiselect-none span').eq(-1).text(value);break;case'height':menu.find('ul').last().height(parseInt(value,10));break;case'minWidth':this.options[key]=parseInt(value,10);this._setButtonWidth();this._setMenuWidth();break;case'selectedText':case'selectedList':case'noneSelectedText':this.options[key]=value;this.refresh();break;case'classes':menu.add(this.button).removeClass(this.options.classes).addClass(value);break;case'multiple':menu.toggleClass('ui-multiselect-single',!value);this.options.multiple=value;this.element[0].multiple=value;this.refresh();break;case'position':this.position();}
$.Widget.prototype._setOption.apply(this,arguments);}});})(jQuery);

(function(window,document,$,undefined){'use strict';var Notification,addStyle,blankFieldName,coreStyle,createElem,defaults,encode,find,findFields,getAnchorElement,getStyle,globalAnchors,hAligns,incr,inherit,insertCSS,mainPositions,opposites,parsePosition,pluginClassName,pluginName,pluginOptions,positions,realign,stylePrefixes,styles,vAligns,__indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i;}return-1;};pluginName='notify';pluginClassName=pluginName+'js';blankFieldName=pluginName+"!blank";positions={t:'top',m:'middle',b:'bottom',l:'left',c:'center',r:'right'};hAligns=['l','c','r'];vAligns=['t','m','b'];mainPositions=['t','b','l','r'];opposites={t:'b',m:null,b:'t',l:'r',c:null,r:'l'};parsePosition=function(str){var pos;pos=[];$.each(str.split(/\W+/),function(i,word){var w;w=word.toLowerCase().charAt(0);if(positions[w]){return pos.push(w);}});return pos;};styles={};coreStyle={name:'core',html:"<div class=\""+pluginClassName+"-wrapper\">\n  <div class=\""+pluginClassName+"-arrow\"></div>\n  <div class=\""+pluginClassName+"-container\"></div>\n</div>",css:"."+pluginClassName+"-corner {\n  position: fixed;\n  margin: 5px;\n  z-index: 30050;\n}\n\n."+pluginClassName+"-corner ."+pluginClassName+"-wrapper,\n."+pluginClassName+"-corner ."+pluginClassName+"-container {\n  position: relative;\n  display: block;\n  height: inherit;\n  width: inherit;\n  margin: 3px;\n}\n\n."+pluginClassName+"-wrapper {\n  z-index: 30050;\n  position: absolute;\n  display: inline-block;\n  height: 0;\n  width: 0;\n}\n\n."+pluginClassName+"-container {\n  display: none;\n  z-index: 30050;\n  position: absolute;\n  cursor: pointer;\n}\n\n[data-notify-text],[data-notify-html] {\n  position: relative;\n}\n\n."+pluginClassName+"-arrow {\n  position: absolute;\n  z-index: 30051;\n  width: 0;\n  height: 0;\n}"};stylePrefixes={"border-radius":["-webkit-","-moz-"]};getStyle=function(name){return styles[name];};addStyle=function(name,def){var cssText,elem,fields,_ref;if(!name){throw"Missing Style name";}
if(!def){throw"Missing Style definition";}
if(!def.html){throw"Missing Style HTML";}
if((_ref=styles[name])!=null?_ref.cssElem:void 0){if(window.console){console.warn(""+pluginName+": overwriting style '"+name+"'");}
styles[name].cssElem.remove();}
def.name=name;styles[name]=def;cssText="";if(def.classes){$.each(def.classes,function(className,props){cssText+="."+pluginClassName+"-"+def.name+"-"+className+" {\n";$.each(props,function(name,val){if(stylePrefixes[name]){$.each(stylePrefixes[name],function(i,prefix){return cssText+="  "+prefix+name+": "+val+";\n";});}
return cssText+="  "+name+": "+val+";\n";});return cssText+="}\n";});}
if(def.css){cssText+="/* styles for "+def.name+" */\n"+def.css;}
if(cssText){def.cssElem=insertCSS(cssText);def.cssElem.attr('id',"notify-"+def.name);}
fields={};elem=$(def.html);findFields('html',elem,fields);findFields('text',elem,fields);return def.fields=fields;};insertCSS=function(cssText){var elem;elem=createElem("style");elem.attr('type','text/css');$("head").append(elem);try{elem.html(cssText);}catch(e){elem[0].styleSheet.cssText=cssText;}
return elem;};findFields=function(type,elem,fields){var attr;if(type!=='html'){type='text';}
attr="data-notify-"+type;return find(elem,"["+attr+"]").each(function(){var name;name=$(this).attr(attr);if(!name){name=blankFieldName;}
return fields[name]=type;});};find=function(elem,selector){if(elem.is(selector)){return elem;}else{return elem.find(selector);}};pluginOptions={clickToHide:true,autoHide:true,autoHideDelay:5000,arrowShow:true,arrowSize:5,breakNewLines:true,elementPosition:'bottom',globalPosition:'top right',style:'bootstrap',className:'error',showAnimation:'slideDown',showDuration:400,hideAnimation:'slideUp',hideDuration:200,gap:5};inherit=function(a,b){var F;F=function(){};F.prototype=a;return $.extend(true,new F(),b);};defaults=function(opts){return $.extend(pluginOptions,opts);};createElem=function(tag){return $("<"+tag+"></"+tag+">");};globalAnchors={};getAnchorElement=function(element){var radios;if(element.is('[type=radio]')){radios=element.parents('form:first').find('[type=radio]').filter(function(i,e){return $(e).attr('name')===element.attr('name');});element=radios.first();}
return element;};incr=function(obj,pos,val){var opp,temp;if(typeof val==='string'){val=parseInt(val,10);}else if(typeof val!=='number'){return;}
if(isNaN(val)){return;}
opp=positions[opposites[pos.charAt(0)]];temp=pos;if(obj[opp]!==undefined){pos=positions[opp.charAt(0)];val=-val;}
if(obj[pos]===undefined){obj[pos]=val;}else{obj[pos]+=val;}
return null;};realign=function(alignment,inner,outer){if(alignment==='l'||alignment==='t'){return 0;}else if(alignment==='c'||alignment==='m'){return outer/2-inner/2;}else if(alignment==='r'||alignment==='b'){return outer-inner;}
throw"Invalid alignment";};encode=function(text){encode.e=encode.e||createElem("div");return encode.e.text(text).html();};Notification=(function(){function Notification(elem,data,options){if(typeof options==='string'){options={className:options};}
this.options=inherit(pluginOptions,$.isPlainObject(options)?options:{});this.loadHTML();this.wrapper=$(coreStyle.html);this.wrapper.data(pluginClassName,this);this.arrow=this.wrapper.find("."+pluginClassName+"-arrow");this.container=this.wrapper.find("."+pluginClassName+"-container");this.container.append(this.userContainer);if(elem&&elem.length){this.elementType=elem.attr('type');this.originalElement=elem;this.elem=getAnchorElement(elem);this.elem.data(pluginClassName,this);this.elem.before(this.wrapper);}
this.container.hide();this.run(data);}
Notification.prototype.loadHTML=function(){var style;style=this.getStyle();this.userContainer=$(style.html);return this.userFields=style.fields;};Notification.prototype.show=function(show,userCallback){var args,callback,elems,fn,hidden,_this=this;callback=function(){if(!show&&!_this.elem){_this.destroy();}
if(userCallback){return userCallback();}};hidden=this.container.parent().parents(':hidden').length>0;elems=this.container.add(this.arrow);args=[];if(hidden&&show){fn='show';}else if(hidden&&!show){fn='hide';}else if(!hidden&&show){fn=this.options.showAnimation;args.push(this.options.showDuration);}else if(!hidden&&!show){fn=this.options.hideAnimation;args.push(this.options.hideDuration);}else{return callback();}
args.push(callback);return elems[fn].apply(elems,args);};Notification.prototype.setGlobalPosition=function(){var align,anchor,css,key,main,pAlign,pMain,_ref;_ref=this.getPosition(),pMain=_ref[0],pAlign=_ref[1];main=positions[pMain];align=positions[pAlign];key=pMain+"|"+pAlign;anchor=globalAnchors[key];if(!anchor){anchor=globalAnchors[key]=createElem("div");css={};css[main]=0;if(align==='middle'){css.top='45%';}else if(align==='center'){css.left='45%';}else{css[align]=0;}
anchor.css(css).addClass(""+pluginClassName+"-corner");$("body").append(anchor);}
return anchor.prepend(this.wrapper);};Notification.prototype.setElementPosition=function(){var arrowColor,arrowCss,arrowSize,color,contH,contW,css,elemH,elemIH,elemIW,elemPos,elemW,gap,mainFull,margin,opp,oppFull,pAlign,pArrow,pMain,pos,posFull,position,wrapPos,_i,_j,_len,_len1,_ref;position=this.getPosition();pMain=position[0],pAlign=position[1],pArrow=position[2];elemPos=this.elem.position();elemH=this.elem.outerHeight();elemW=this.elem.outerWidth();elemIH=this.elem.innerHeight();elemIW=this.elem.innerWidth();wrapPos=this.wrapper.position();contH=this.container.height();contW=this.container.width();mainFull=positions[pMain];opp=opposites[pMain];oppFull=positions[opp];css={};css[oppFull]=pMain==='b'?elemH:pMain==='r'?elemW:0;incr(css,'top',elemPos.top-wrapPos.top);incr(css,'left',elemPos.left-wrapPos.left);_ref=['top','left'];for(_i=0,_len=_ref.length;_i<_len;_i++){pos=_ref[_i];margin=parseInt(this.elem.css("margin-"+pos),10);if(margin){incr(css,pos,margin);}}
gap=Math.max(0,this.options.gap-(this.options.arrowShow?arrowSize:0));incr(css,oppFull,gap);if(!this.options.arrowShow){this.arrow.hide();}else{arrowSize=this.options.arrowSize;arrowCss=$.extend({},css);arrowColor=this.userContainer.css("border-color")||this.userContainer.css("background-color")||'white';for(_j=0,_len1=mainPositions.length;_j<_len1;_j++){pos=mainPositions[_j];posFull=positions[pos];if(pos===opp){continue;}
color=posFull===mainFull?arrowColor:'transparent';arrowCss["border-"+posFull]=""+arrowSize+"px solid "+color;}
incr(css,positions[opp],arrowSize);if(__indexOf.call(mainPositions,pAlign)>=0){incr(arrowCss,positions[pAlign],arrowSize*2);}}
if(__indexOf.call(vAligns,pMain)>=0){incr(css,'left',realign(pAlign,contW,elemW));if(arrowCss){incr(arrowCss,'left',realign(pAlign,arrowSize,elemIW));}}else if(__indexOf.call(hAligns,pMain)>=0){incr(css,'top',realign(pAlign,contH,elemH));if(arrowCss){incr(arrowCss,'top',realign(pAlign,arrowSize,elemIH));}}
if(this.container.is(":visible")){css.display='block';}
this.container.removeAttr('style').css(css);if(arrowCss){return this.arrow.removeAttr('style').css(arrowCss);}};Notification.prototype.getPosition=function(){var pos,text,_ref,_ref1,_ref2,_ref3,_ref4,_ref5;text=this.options.position||(this.elem?this.options.elementPosition:this.options.globalPosition);pos=parsePosition(text);if(pos.length===0){pos[0]='b';}
if(_ref=pos[0],__indexOf.call(mainPositions,_ref)<0){throw"Must be one of ["+mainPositions+"]";}
if(pos.length===1||((_ref1=pos[0],__indexOf.call(vAligns,_ref1)>=0)&&(_ref2=pos[1],__indexOf.call(hAligns,_ref2)<0))||((_ref3=pos[0],__indexOf.call(hAligns,_ref3)>=0)&&(_ref4=pos[1],__indexOf.call(vAligns,_ref4)<0))){pos[1]=(_ref5=pos[0],__indexOf.call(hAligns,_ref5)>=0)?'m':'l';}
if(pos.length===2){pos[2]=pos[1];}
return pos;};Notification.prototype.getStyle=function(name){var style;if(!name){name=this.options.style;}
if(!name){name='default';}
style=styles[name];if(!style){throw"Missing style: "+name;}
return style;};Notification.prototype.updateClasses=function(){var classes,style;classes=['base'];if($.isArray(this.options.className)){classes=classes.concat(this.options.className);}else if(this.options.className){classes.push(this.options.className);}
style=this.getStyle();classes=$.map(classes,function(n){return""+pluginClassName+"-"+style.name+"-"+n;}).join(' ');return this.userContainer.attr('class',classes);};Notification.prototype.run=function(data,options){var d,datas,name,type,value,_this=this;if($.isPlainObject(options)){$.extend(this.options,options);}else if($.type(options)==='string'){this.options.className=options;}
if(this.container&&!data){this.show(false);return;}else if(!this.container&&!data){return;}
datas={};if($.isPlainObject(data)){datas=data;}else{datas[blankFieldName]=data;}
for(name in datas){d=datas[name];type=this.userFields[name];if(!type){continue;}
if(type==='text'){if(this.options.breakNewLines){d=d.replace(/\n/g,'<br/>');}}
value=name===blankFieldName?'':'='+name;find(this.userContainer,"[data-notify-"+type+value+"]").html(d);}
this.updateClasses();if(this.elem){this.setElementPosition();}else{this.setGlobalPosition();}
this.show(true);if(this.options.autoHide){clearTimeout(this.autohideTimer);return this.autohideTimer=setTimeout(function(){return _this.show(false);},this.options.autoHideDelay);}};Notification.prototype.destroy=function(){return this.wrapper.remove();};return Notification;})();$[pluginName]=function(elem,data,options){if((elem&&elem.nodeName)||elem.jquery){$(elem)[pluginName](data,options);}else{options=data;data=elem;new Notification(null,data,options);}
return elem;};$.fn[pluginName]=function(data,options){$(this).each(function(){var inst;inst=getAnchorElement($(this)).data(pluginClassName);if(inst){return inst.run(data,options);}else{return new Notification($(this),data,options);}});return this;};$.extend($[pluginName],{defaults:defaults,addStyle:addStyle,pluginOptions:pluginOptions,getStyle:getStyle,insertCSS:insertCSS});$(function(){insertCSS(coreStyle.css).attr('id','core-notify');return $(document).on('click notify-hide',"."+pluginClassName+"-wrapper",function(e){var inst;inst=$(this).data(pluginClassName);if(inst&&(inst.options.clickToHide||e.type==='notify-hide')){return inst.show(false);}});});}(window,document,jQuery));$.notify.addStyle("bootstrap",{html:"<div>\n<span data-notify-text></span>\n</div>",classes:{base:{"padding":"2px 2px 2px 2px","background-color":"#fcf8e3","border":"1px solid #fbeed5","border-radius":"4px","white-space":"nowrap","background-repeat":"no-repeat","background-position":"3px 7px","font-size":"15px","z-index":30050},error:{"color":"#B94A48","background-color":"#F2DEDE","border-color":"#EED3D7"},success:{"color":"#468847","background-color":"#DFF0D8","border-color":"#D6E9C6"},info:{"color":"#3A87AD","background-color":"#D9EDF7","border-color":"#BCE8F1"},warn:{"color":"#C09853","background-color":"#FCF8E3","border-color":"#FBEED5"}}});



(function($){$.extend($.ui,{timepicker:{version:"0.3.3"}});var PROP_NAME='timepicker',tpuuid=new Date().getTime();function Timepicker(){this.debug=true;this._curInst=null;this._disabledInputs=[];this._timepickerShowing=false;this._inDialog=false;this._dialogClass='ui-timepicker-dialog';this._mainDivId='ui-timepicker-div';this._inlineClass='ui-timepicker-inline';this._currentClass='ui-timepicker-current';this._dayOverClass='ui-timepicker-days-cell-over';this.regional=[];this.regional['']={hourText:'Hour',minuteText:'Minute',amPmText:['AM','PM'],closeButtonText:'Done',nowButtonText:'Now',deselectButtonText:'Deselect'};this._defaults={showOn:'focus',button:null,showAnim:'fadeIn',showOptions:{},appendText:'',beforeShow:null,onSelect:null,onClose:null,timeSeparator:':',periodSeparator:' ',showPeriod:false,showPeriodLabels:true,showLeadingZero:true,showMinutesLeadingZero:true,altField:'',defaultTime:'now',myPosition:'left top',atPosition:'left bottom',onHourShow:null,onMinuteShow:null,hours:{starts:0,ends:23},minutes:{starts:0,ends:55,interval:5,manual:[]},rows:4,showHours:true,showMinutes:true,optionalMinutes:false,showCloseButton:false,showNowButton:false,showDeselectButton:false,maxTime:{hour:null,minute:null},minTime:{hour:null,minute:null}};$.extend(this._defaults,this.regional['']);this.tpDiv=$('<div id="'+this._mainDivId+'" class="ui-timepicker ui-widget ui-helper-clearfix ui-corner-all " style="display: none"></div>');}
$.extend(Timepicker.prototype,{markerClassName:'hasTimepicker',log:function(){if(this.debug)
console.log.apply('',arguments);},_widgetTimepicker:function(){return this.tpDiv;},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this;},_attachTimepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute('time:'+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue);}catch(err){inlineSettings[attrName]=attrValue;}}}
var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=='div'||nodeName=='span');if(!target.id){this.uuid+=1;target.id='tp'+this.uuid;}
var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=='input'){this._connectTimepicker(target,inst);this._setTimeFromField(inst);}else if(inline){this._inlineTimepicker(target,inst);}},_newInst:function(target,inline){var id=target[0].id.replace(/([^A-Za-z0-9_-])/g,'\\\\$1');return{id:id,input:target,inline:inline,tpDiv:(!inline?this.tpDiv:$('<div class="'+this._inlineClass+' ui-timepicker ui-widget  ui-helper-clearfix"></div>'))};},_connectTimepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return;}
this._attachments(input,inst);input.addClass(this.markerClassName).keydown(this._doKeyDown).keyup(this._doKeyUp).bind("setData.timepicker",function(event,key,value){inst.settings[key]=value;}).bind("getData.timepicker",function(event,key){return this._get(inst,key);});$.data(target,PROP_NAME,inst);},_doKeyDown:function(event){var inst=$.timepicker._getInst(event.target);var handled=true;inst._keyEvent=true;if($.timepicker._timepickerShowing){switch(event.keyCode){case 9:$.timepicker._hideTimepicker();handled=false;break;case 13:$.timepicker._updateSelectedValue(inst);$.timepicker._hideTimepicker();return false;break;case 27:$.timepicker._hideTimepicker();break;default:handled=false;}}
else if(event.keyCode==36&&event.ctrlKey){$.timepicker._showTimepicker(this);}
else{handled=false;}
if(handled){event.preventDefault();event.stopPropagation();}},_doKeyUp:function(event){var inst=$.timepicker._getInst(event.target);$.timepicker._setTimeFromField(inst);$.timepicker._updateTimepicker(inst);},_attachments:function(input,inst){var appendText=this._get(inst,'appendText');var isRTL=this._get(inst,'isRTL');if(inst.append){inst.append.remove();}
if(appendText){inst.append=$('<span class="'+this._appendClass+'">'+appendText+'</span>');input[isRTL?'before':'after'](inst.append);}
input.unbind('focus.timepicker',this._showTimepicker);input.unbind('click.timepicker',this._adjustZIndex);if(inst.trigger){inst.trigger.remove();}
var showOn=this._get(inst,'showOn');if(showOn=='focus'||showOn=='both'){input.bind("click.timepicker",this._showTimepicker);}
if(showOn=='button'||showOn=='both'){var button=this._get(inst,'button');if(button==null){button=$('<button class="ui-timepicker-trigger" type="button">...</button>');input.after(button);}
$(button).bind("click.timepicker",function(){if($.timepicker._timepickerShowing&&$.timepicker._lastInput==input[0]){$.timepicker._hideTimepicker();}else if(!inst.input.is(':disabled')){$.timepicker._showTimepicker(input[0]);}
return false;});}},_inlineTimepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName))
return;divSpan.addClass(this.markerClassName).append(inst.tpDiv).bind("setData.timepicker",function(event,key,value){inst.settings[key]=value;}).bind("getData.timepicker",function(event,key){return this._get(inst,key);});$.data(target,PROP_NAME,inst);this._setTimeFromField(inst);this._updateTimepicker(inst);inst.tpDiv.show();},_adjustZIndex:function(input){input=input.target||input;var inst=$.timepicker._getInst(input);inst.tpDiv.css('zIndex',$.timepicker._getZIndex(input)+1);},_showTimepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!='input'){input=$('input',input.parentNode)[0];}
if($.timepicker._isDisabledTimepicker(input)||$.timepicker._lastInput==input){return;}
$.timepicker._hideTimepicker();var inst=$.timepicker._getInst(input);if($.timepicker._curInst&&$.timepicker._curInst!=inst){$.timepicker._curInst.tpDiv.stop(true,true);}
var beforeShow=$.timepicker._get(inst,'beforeShow');extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));inst.lastVal=null;$.timepicker._lastInput=input;$.timepicker._setTimeFromField(inst);if($.timepicker._inDialog){input.value='';}
if(!$.timepicker._pos){$.timepicker._pos=$.timepicker._findPos(input);$.timepicker._pos[1]+=input.offsetHeight;}
var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css('position')=='fixed';return!isFixed;});var offset={left:$.timepicker._pos[0],top:$.timepicker._pos[1]};$.timepicker._pos=null;inst.tpDiv.css({position:'absolute',display:'block',top:'-1000px'});$.timepicker._updateTimepicker(inst);if((!inst.inline)&&(typeof $.ui.position=='object')){inst.tpDiv.position({of:inst.input,my:$.timepicker._get(inst,'myPosition'),at:$.timepicker._get(inst,'atPosition'),collision:'flip'});var offset=inst.tpDiv.offset();$.timepicker._pos=[offset.top,offset.left];}
inst._hoursClicked=false;inst._minutesClicked=false;offset=$.timepicker._checkOffset(inst,offset,isFixed);inst.tpDiv.css({position:($.timepicker._inDialog&&$.blockUI?'static':(isFixed?'fixed':'absolute')),display:'none',left:offset.left+'px',top:offset.top+'px'});if(!inst.inline){var showAnim=$.timepicker._get(inst,'showAnim');var duration=$.timepicker._get(inst,'duration');var postProcess=function(){$.timepicker._timepickerShowing=true;var borders=$.timepicker._getBorders(inst.tpDiv);inst.tpDiv.find('iframe.ui-timepicker-cover').css({left:-borders[0],top:-borders[1],width:inst.tpDiv.outerWidth(),height:inst.tpDiv.outerHeight()});};$.timepicker._adjustZIndex(input);if($.effects&&$.effects[showAnim]){inst.tpDiv.show(showAnim,$.timepicker._get(inst,'showOptions'),duration,postProcess);}
else{inst.tpDiv.show((showAnim?duration:null),postProcess);}
if(!showAnim||!duration){postProcess();}
if(inst.input.is(':visible')&&!inst.input.is(':disabled')){inst.input.focus();}
$.timepicker._curInst=inst;}},_getZIndex:function(target){var elem=$(target);var maxValue=0;var position,value;while(elem.length&&elem[0]!==document){position=elem.css("position");if(position==="absolute"||position==="relative"||position==="fixed"){value=parseInt(elem.css("zIndex"),10);if(!isNaN(value)&&value!==0){if(value>maxValue){maxValue=value;}}}
elem=elem.parent();}
return maxValue;},_refreshTimepicker:function(target){var inst=this._getInst(target);if(inst){this._updateTimepicker(inst);}},_updateTimepicker:function(inst){inst.tpDiv.empty().append(this._generateHTML(inst));this._rebindDialogEvents(inst);},_rebindDialogEvents:function(inst){var borders=$.timepicker._getBorders(inst.tpDiv),self=this;inst.tpDiv.find('iframe.ui-timepicker-cover').css({left:-borders[0],top:-borders[1],width:inst.tpDiv.outerWidth(),height:inst.tpDiv.outerHeight()}).end().find('.ui-timepicker-minute-cell').unbind().bind("click",{fromDoubleClick:false},$.proxy($.timepicker.selectMinutes,this)).bind("dblclick",{fromDoubleClick:true},$.proxy($.timepicker.selectMinutes,this)).end().find('.ui-timepicker-hour-cell').unbind().bind("click",{fromDoubleClick:false},$.proxy($.timepicker.selectHours,this)).bind("dblclick",{fromDoubleClick:true},$.proxy($.timepicker.selectHours,this)).end().find('.ui-timepicker td a').unbind().bind('mouseout',function(){$(this).removeClass('ui-state-hover');if(this.className.indexOf('ui-timepicker-prev')!=-1)$(this).removeClass('ui-timepicker-prev-hover');if(this.className.indexOf('ui-timepicker-next')!=-1)$(this).removeClass('ui-timepicker-next-hover');}).bind('mouseover',function(){if(!self._isDisabledTimepicker(inst.inline?inst.tpDiv.parent()[0]:inst.input[0])){$(this).parents('.ui-timepicker-calendar').find('a').removeClass('ui-state-hover');$(this).addClass('ui-state-hover');if(this.className.indexOf('ui-timepicker-prev')!=-1)$(this).addClass('ui-timepicker-prev-hover');if(this.className.indexOf('ui-timepicker-next')!=-1)$(this).addClass('ui-timepicker-next-hover');}}).end().find('.'+this._dayOverClass+' a').trigger('mouseover').end().find('.ui-timepicker-now').bind("click",function(e){$.timepicker.selectNow(e);}).end().find('.ui-timepicker-deselect').bind("click",function(e){$.timepicker.deselectTime(e);}).end().find('.ui-timepicker-close').bind("click",function(e){$.timepicker._hideTimepicker();}).end();},_generateHTML:function(inst){var h,m,row,col,html,hoursHtml,minutesHtml='',showPeriod=(this._get(inst,'showPeriod')==true),showPeriodLabels=(this._get(inst,'showPeriodLabels')==true),showLeadingZero=(this._get(inst,'showLeadingZero')==true),showHours=(this._get(inst,'showHours')==true),showMinutes=(this._get(inst,'showMinutes')==true),amPmText=this._get(inst,'amPmText'),rows=this._get(inst,'rows'),amRows=0,pmRows=0,amItems=0,pmItems=0,amFirstRow=0,pmFirstRow=0,hours=Array(),hours_options=this._get(inst,'hours'),hoursPerRow=null,hourCounter=0,hourLabel=this._get(inst,'hourText'),showCloseButton=this._get(inst,'showCloseButton'),closeButtonText=this._get(inst,'closeButtonText'),showNowButton=this._get(inst,'showNowButton'),nowButtonText=this._get(inst,'nowButtonText'),showDeselectButton=this._get(inst,'showDeselectButton'),deselectButtonText=this._get(inst,'deselectButtonText'),showButtonPanel=showCloseButton||showNowButton||showDeselectButton;for(h=hours_options.starts;h<=hours_options.ends;h++){hours.push(h);}
hoursPerRow=Math.ceil(hours.length/rows);if(showPeriodLabels){for(hourCounter=0;hourCounter<hours.length;hourCounter++){if(hours[hourCounter]<12){amItems++;}
else{pmItems++;}}
hourCounter=0;amRows=Math.floor(amItems/hours.length*rows);pmRows=Math.floor(pmItems/hours.length*rows);if(rows!=amRows+pmRows){if(amItems&&(!pmItems||!amRows||(pmRows&&amItems/amRows>=pmItems/pmRows))){amRows++;}else{pmRows++;}}
amFirstRow=Math.min(amRows,1);pmFirstRow=amRows+1;if(amRows==0){hoursPerRow=Math.ceil(pmItems/pmRows);}else if(pmRows==0){hoursPerRow=Math.ceil(amItems/amRows);}else{hoursPerRow=Math.ceil(Math.max(amItems/amRows,pmItems/pmRows));}}
html='<table class="ui-timepicker-table ui-widget-content ui-corner-all"><tr>';if(showHours){html+='<td class="ui-timepicker-hours">'+'<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">'+
hourLabel+'</div>'+'<table class="ui-timepicker">';for(row=1;row<=rows;row++){html+='<tr>';if(row==amFirstRow&&showPeriodLabels){html+='<th rowspan="'+amRows.toString()+'" class="periods" scope="row">'+amPmText[0]+'</th>';}
if(row==pmFirstRow&&showPeriodLabels){html+='<th rowspan="'+pmRows.toString()+'" class="periods" scope="row">'+amPmText[1]+'</th>';}
for(col=1;col<=hoursPerRow;col++){if(showPeriodLabels&&row<pmFirstRow&&hours[hourCounter]>=12){html+=this._generateHTMLHourCell(inst,undefined,showPeriod,showLeadingZero);}else{html+=this._generateHTMLHourCell(inst,hours[hourCounter],showPeriod,showLeadingZero);hourCounter++;}}
html+='</tr>';}
html+='</table>'+'</td>';}
if(showMinutes){html+='<td class="ui-timepicker-minutes">';html+=this._generateHTMLMinutes(inst);html+='</td>';}
html+='</tr>';if(showButtonPanel){var buttonPanel='<tr><td colspan="3"><div class="ui-timepicker-buttonpane ui-widget-content">';if(showNowButton){buttonPanel+='<button type="button" class="ui-timepicker-now ui-state-default ui-corner-all" '
+' data-timepicker-instance-id="#'+inst.id.replace(/\\\\/g,"\\")+'" >'
+nowButtonText+'</button>';}
if(showDeselectButton){buttonPanel+='<button type="button" class="ui-timepicker-deselect ui-state-default ui-corner-all" '
+' data-timepicker-instance-id="#'+inst.id.replace(/\\\\/g,"\\")+'" >'
+deselectButtonText+'</button>';}
if(showCloseButton){buttonPanel+='<button type="button" class="ui-timepicker-close ui-state-default ui-corner-all" '
+' data-timepicker-instance-id="#'+inst.id.replace(/\\\\/g,"\\")+'" >'
+closeButtonText+'</button>';}
html+=buttonPanel+'</div></td></tr>';}
html+='</table>';return html;},_updateMinuteDisplay:function(inst){var newHtml=this._generateHTMLMinutes(inst);inst.tpDiv.find('td.ui-timepicker-minutes').html(newHtml);this._rebindDialogEvents(inst);},_generateHTMLMinutes:function(inst){var m,row,html='',rows=this._get(inst,'rows'),minutes=Array(),minutes_options=this._get(inst,'minutes'),minutesPerRow=null,minuteCounter=0,showMinutesLeadingZero=(this._get(inst,'showMinutesLeadingZero')==true),onMinuteShow=this._get(inst,'onMinuteShow'),minuteLabel=this._get(inst,'minuteText');if(!minutes_options.starts){minutes_options.starts=0;}
if(!minutes_options.ends){minutes_options.ends=59;}
if(!minutes_options.manual){minutes_options.manual=[];}
for(m=minutes_options.starts;m<=minutes_options.ends;m+=minutes_options.interval){minutes.push(m);}
for(var i=0;i<minutes_options.manual.length;i++){var currMin=minutes_options.manual[i];if(typeof currMin!='number'||currMin<0||currMin>59||$.inArray(currMin,minutes)>=0){continue;}
minutes.push(currMin);}
minutes.sort(function(a,b){return a-b;});minutesPerRow=Math.round(minutes.length/rows+0.49);if(onMinuteShow&&(onMinuteShow.apply((inst.input?inst.input[0]:null),[inst.hours,inst.minutes])==false)){for(minuteCounter=0;minuteCounter<minutes.length;minuteCounter+=1){m=minutes[minuteCounter];if(onMinuteShow.apply((inst.input?inst.input[0]:null),[inst.hours,m])){inst.minutes=m;break;}}}
html+='<div class="ui-timepicker-title ui-widget-header ui-helper-clearfix ui-corner-all">'+
minuteLabel+'</div>'+'<table class="ui-timepicker">';minuteCounter=0;for(row=1;row<=rows;row++){html+='<tr>';while(minuteCounter<row*minutesPerRow){var m=minutes[minuteCounter];var displayText='';if(m!==undefined){displayText=(m<10)&&showMinutesLeadingZero?"0"+m.toString():m.toString();}
html+=this._generateHTMLMinuteCell(inst,m,displayText);minuteCounter++;}
html+='</tr>';}
html+='</table>';return html;},_generateHTMLHourCell:function(inst,hour,showPeriod,showLeadingZero){var displayHour=hour;if((hour>12)&&showPeriod){displayHour=hour-12;}
if((displayHour==0)&&showPeriod){displayHour=12;}
if((displayHour<10)&&showLeadingZero){displayHour='0'+displayHour;}
var html="";var enabled=true;var onHourShow=this._get(inst,'onHourShow');var maxTime=this._get(inst,'maxTime');var minTime=this._get(inst,'minTime');if(hour==undefined){html='<td><span class="ui-state-default ui-state-disabled">&nbsp;</span></td>';return html;}
if(onHourShow){enabled=onHourShow.apply((inst.input?inst.input[0]:null),[hour]);}
if(enabled){if(!isNaN(parseInt(maxTime.hour))&&hour>maxTime.hour)enabled=false;if(!isNaN(parseInt(minTime.hour))&&hour<minTime.hour)enabled=false;}
if(enabled){html='<td class="ui-timepicker-hour-cell" data-timepicker-instance-id="#'+inst.id.replace(/\\\\/g,"\\")+'" data-hour="'+hour.toString()+'">'+'<a class="ui-state-default '+
(hour==inst.hours?'ui-state-active':'')+'">'+
displayHour.toString()+'</a></td>';}
else{html='<td>'+'<span class="ui-state-default ui-state-disabled '+
(hour==inst.hours?' ui-state-active ':' ')+'">'+
displayHour.toString()+'</span>'+'</td>';}
return html;},_generateHTMLMinuteCell:function(inst,minute,displayText){var html="";var enabled=true;var hour=inst.hours;var onMinuteShow=this._get(inst,'onMinuteShow');var maxTime=this._get(inst,'maxTime');var minTime=this._get(inst,'minTime');if(onMinuteShow){enabled=onMinuteShow.apply((inst.input?inst.input[0]:null),[inst.hours,minute]);}
if(minute==undefined){html='<td><span class="ui-state-default ui-state-disabled">&nbsp;</span></td>';return html;}
if(enabled&&hour!==null){if(!isNaN(parseInt(maxTime.hour))&&!isNaN(parseInt(maxTime.minute))&&hour>=maxTime.hour&&minute>maxTime.minute)enabled=false;if(!isNaN(parseInt(minTime.hour))&&!isNaN(parseInt(minTime.minute))&&hour<=minTime.hour&&minute<minTime.minute)enabled=false;}
if(enabled){html='<td class="ui-timepicker-minute-cell" data-timepicker-instance-id="#'+inst.id.replace(/\\\\/g,"\\")+'" data-minute="'+minute.toString()+'" >'+'<a class="ui-state-default '+
(minute==inst.minutes?'ui-state-active':'')+'" >'+
displayText+'</a></td>';}
else{html='<td>'+'<span class="ui-state-default ui-state-disabled" >'+
displayText+'</span>'+'</td>';}
return html;},_destroyTimepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=='input'){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind('focus.timepicker',this._showTimepicker).unbind('click.timepicker',this._adjustZIndex);}else if(nodeName=='div'||nodeName=='span')
$target.removeClass(this.markerClassName).empty();},_enableTimepicker:function(target){var $target=$(target),target_id=$target.attr('id'),inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
var nodeName=target.nodeName.toLowerCase();if(nodeName=='input'){target.disabled=false;var button=this._get(inst,'button');$(button).removeClass('ui-state-disabled').disabled=false;inst.trigger.filter('button').each(function(){this.disabled=false;}).end();}
else if(nodeName=='div'||nodeName=='span'){var inline=$target.children('.'+this._inlineClass);inline.children().removeClass('ui-state-disabled');inline.find('button').each(function(){this.disabled=false})}
this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target_id?null:value);});},_disableTimepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return;}
var nodeName=target.nodeName.toLowerCase();if(nodeName=='input'){var button=this._get(inst,'button');$(button).addClass('ui-state-disabled').disabled=true;target.disabled=true;inst.trigger.filter('button').each(function(){this.disabled=true;}).end();}
else if(nodeName=='div'||nodeName=='span'){var inline=$target.children('.'+this._inlineClass);inline.children().addClass('ui-state-disabled');inline.find('button').each(function(){this.disabled=true})}
this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value);});this._disabledInputs[this._disabledInputs.length]=$target.attr('id');},_isDisabledTimepicker:function(target_id){if(!target_id){return false;}
for(var i=0;i<this._disabledInputs.length;i++){if(this._disabledInputs[i]==target_id){return true;}}
return false;},_checkOffset:function(inst,offset,isFixed){var tpWidth=inst.tpDiv.outerWidth();var tpHeight=inst.tpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=document.documentElement.clientWidth+$(document).scrollLeft();var viewHeight=document.documentElement.clientHeight+$(document).scrollTop();offset.left-=(this._get(inst,'isRTL')?(tpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=Math.min(offset.left,(offset.left+tpWidth>viewWidth&&viewWidth>tpWidth)?Math.abs(offset.left+tpWidth-viewWidth):0);offset.top-=Math.min(offset.top,(offset.top+tpHeight>viewHeight&&viewHeight>tpHeight)?Math.abs(tpHeight+inputHeight):0);return offset;},_findPos:function(obj){var inst=this._getInst(obj);var isRTL=this._get(inst,'isRTL');while(obj&&(obj.type=='hidden'||obj.nodeType!=1)){obj=obj[isRTL?'previousSibling':'nextSibling'];}
var position=$(obj).offset();return[position.left,position.top];},_getBorders:function(elem){var convert=function(value){return{thin:1,medium:2,thick:3}[value]||value;};return[parseFloat(convert(elem.css('border-left-width'))),parseFloat(convert(elem.css('border-top-width')))];},_checkExternalClick:function(event){if(!$.timepicker._curInst){return;}
var $target=$(event.target);if($target[0].id!=$.timepicker._mainDivId&&$target.parents('#'+$.timepicker._mainDivId).length==0&&!$target.hasClass($.timepicker.markerClassName)&&!$target.hasClass($.timepicker._triggerClass)&&$.timepicker._timepickerShowing&&!($.timepicker._inDialog&&$.blockUI))
$.timepicker._hideTimepicker();},_hideTimepicker:function(input){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return;}
if(this._timepickerShowing){var showAnim=this._get(inst,'showAnim');var duration=this._get(inst,'duration');var postProcess=function(){$.timepicker._tidyDialog(inst);this._curInst=null;};if($.effects&&$.effects[showAnim]){inst.tpDiv.hide(showAnim,$.timepicker._get(inst,'showOptions'),duration,postProcess);}
else{inst.tpDiv[(showAnim=='slideDown'?'slideUp':(showAnim=='fadeIn'?'fadeOut':'hide'))]((showAnim?duration:null),postProcess);}
if(!showAnim){postProcess();}
this._timepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:'absolute',left:'0',top:'-100px'});if($.blockUI){$.unblockUI();$('body').append(this.tpDiv);}}
this._inDialog=false;var onClose=this._get(inst,'onClose');if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():''),inst]);}}},_tidyDialog:function(inst){inst.tpDiv.removeClass(this._dialogClass).unbind('.ui-timepicker');},_getInst:function(target){try{return $.data(target,PROP_NAME);}
catch(err){throw'Missing instance data for this timepicker';}},_get:function(inst,name){return inst.settings[name]!==undefined?inst.settings[name]:this._defaults[name];},_setTimeFromField:function(inst){if(inst.input.val()==inst.lastVal){return;}
var defaultTime=this._get(inst,'defaultTime');var timeToParse=defaultTime=='now'?this._getCurrentTimeRounded(inst):defaultTime;if((inst.inline==false)&&(inst.input.val()!='')){timeToParse=inst.input.val()}
if(timeToParse instanceof Date){inst.hours=timeToParse.getHours();inst.minutes=timeToParse.getMinutes();}else{var timeVal=inst.lastVal=timeToParse;if(timeToParse==''){inst.hours=-1;inst.minutes=-1;}else{var time=this.parseTime(inst,timeVal);inst.hours=time.hours;inst.minutes=time.minutes;}}
$.timepicker._updateTimepicker(inst);},_optionTimepicker:function(target,name,value){var inst=this._getInst(target);if(arguments.length==2&&typeof name=='string'){return(name=='defaults'?$.extend({},$.timepicker._defaults):(inst?(name=='all'?$.extend({},inst.settings):this._get(inst,name)):null));}
var settings=name||{};if(typeof name=='string'){settings={};settings[name]=value;}
if(inst){extendRemove(inst.settings,settings);if(this._curInst==inst){this._hideTimepicker();this._updateTimepicker(inst);}
if(inst.inline){this._updateTimepicker(inst);}}},_setTimeTimepicker:function(target,time,noChange){var inst=this._getInst(target);if(inst){this._setTime(inst,time,noChange);this._updateTimepicker(inst);this._updateAlternate(inst,time);}},_setTime:function(inst,time,noChange){var origHours=inst.hours;var origMinutes=inst.minutes;if(time instanceof Date){inst.hours=time.getHours();inst.minutes=time.getMinutes();}else{var time=this.parseTime(inst,time);inst.hours=time.hours;inst.minutes=time.minutes;}
if((origHours!=inst.hours||origMinutes!=inst.minutes)&&!noChange){inst.input.trigger('change');}
this._updateTimepicker(inst);this._updateSelectedValue(inst,noChange);},_getCurrentTimeRounded:function(inst){var currentTime=new Date(),currentMinutes=currentTime.getMinutes(),minutes_options=this._get(inst,'minutes'),adjustedMinutes=Math.round(currentMinutes/minutes_options.interval)*minutes_options.interval;currentTime.setMinutes(adjustedMinutes);return currentTime;},parseTime:function(inst,timeVal){var retVal=new Object();retVal.hours=-1;retVal.minutes=-1;if(!timeVal)
return retVal;var timeSeparator=this._get(inst,'timeSeparator'),amPmText=this._get(inst,'amPmText'),showHours=this._get(inst,'showHours'),showMinutes=this._get(inst,'showMinutes'),optionalMinutes=this._get(inst,'optionalMinutes'),showPeriod=(this._get(inst,'showPeriod')==true),p=timeVal.indexOf(timeSeparator);if(p!=-1){retVal.hours=parseInt(timeVal.substr(0,p),10);retVal.minutes=parseInt(timeVal.substr(p+1),10);}
else if((showHours)&&(!showMinutes||optionalMinutes)){retVal.hours=parseInt(timeVal,10);}
else if((!showHours)&&(showMinutes)){retVal.minutes=parseInt(timeVal,10);}
if(showHours){var timeValUpper=timeVal.toUpperCase();if((retVal.hours<12)&&(showPeriod)&&(timeValUpper.indexOf(amPmText[1].toUpperCase())!=-1)){retVal.hours+=12;}
if((retVal.hours==12)&&(showPeriod)&&(timeValUpper.indexOf(amPmText[0].toUpperCase())!=-1)){retVal.hours=0;}}
return retVal;},selectNow:function(event){var id=$(event.target).attr("data-timepicker-instance-id"),$target=$(id),inst=this._getInst($target[0]);var currentTime=new Date();inst.hours=currentTime.getHours();inst.minutes=currentTime.getMinutes();this._updateSelectedValue(inst);this._updateTimepicker(inst);this._hideTimepicker();},deselectTime:function(event){var id=$(event.target).attr("data-timepicker-instance-id"),$target=$(id),inst=this._getInst($target[0]);inst.hours=-1;inst.minutes=-1;this._updateSelectedValue(inst);this._hideTimepicker();},selectHours:function(event){var $td=$(event.currentTarget),id=$td.attr("data-timepicker-instance-id"),newHours=parseInt($td.attr("data-hour")),fromDoubleClick=event.data.fromDoubleClick,$target=$(id),inst=this._getInst($target[0]),showMinutes=(this._get(inst,'showMinutes')==true);if($.timepicker._isDisabledTimepicker($target.attr('id'))){return false}
$td.parents('.ui-timepicker-hours:first').find('a').removeClass('ui-state-active');$td.children('a').addClass('ui-state-active');inst.hours=newHours;var onMinuteShow=this._get(inst,'onMinuteShow'),maxTime=this._get(inst,'maxTime'),minTime=this._get(inst,'minTime');if(onMinuteShow||maxTime.minute||minTime.minute){this._updateMinuteDisplay(inst);}
this._updateSelectedValue(inst);inst._hoursClicked=true;if((inst._minutesClicked)||(fromDoubleClick)||(showMinutes==false)){$.timepicker._hideTimepicker();}
return false;},selectMinutes:function(event){var $td=$(event.currentTarget),id=$td.attr("data-timepicker-instance-id"),newMinutes=parseInt($td.attr("data-minute")),fromDoubleClick=event.data.fromDoubleClick,$target=$(id),inst=this._getInst($target[0]),showHours=(this._get(inst,'showHours')==true);if($.timepicker._isDisabledTimepicker($target.attr('id'))){return false}
$td.parents('.ui-timepicker-minutes:first').find('a').removeClass('ui-state-active');$td.children('a').addClass('ui-state-active');inst.minutes=newMinutes;this._updateSelectedValue(inst);inst._minutesClicked=true;$.timepicker._hideTimepicker();return false;},_updateSelectedValue:function(inst,noChange){var newTime=this._getParsedTime(inst);if(inst.input){inst.input.val(newTime);if(!noChange)
inst.input.trigger('change');}
var onSelect=this._get(inst,'onSelect');if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[newTime,inst]);}
this._updateAlternate(inst,newTime);return newTime;},_getParsedTime:function(inst){if(inst.hours==-1&&inst.minutes==-1){return'';}
if((inst.hours<inst.hours.starts)||(inst.hours>inst.hours.ends)){inst.hours=0;}
if((inst.minutes<inst.minutes.starts)||(inst.minutes>inst.minutes.ends)){inst.minutes=0;}
var period="",showPeriod=(this._get(inst,'showPeriod')==true),showLeadingZero=(this._get(inst,'showLeadingZero')==true),showHours=(this._get(inst,'showHours')==true),showMinutes=(this._get(inst,'showMinutes')==true),optionalMinutes=(this._get(inst,'optionalMinutes')==true),amPmText=this._get(inst,'amPmText'),selectedHours=inst.hours?inst.hours:0,selectedMinutes=inst.minutes?inst.minutes:0,displayHours=selectedHours?selectedHours:0,parsedTime='';if(displayHours==-1){displayHours=0}
if(selectedMinutes==-1){selectedMinutes=0}
if(showPeriod){if(inst.hours==0){displayHours=12;}
if(inst.hours<12){period=amPmText[0];}
else{period=amPmText[1];if(displayHours>12){displayHours-=12;}}}
var h=displayHours.toString();if(showLeadingZero&&(displayHours<10)){h='0'+h;}
var m=selectedMinutes.toString();if(selectedMinutes<10){m='0'+m;}
if(showHours){parsedTime+=h;}
if(showHours&&showMinutes&&(!optionalMinutes||m!=0)){parsedTime+=this._get(inst,'timeSeparator');}
if(showMinutes&&(!optionalMinutes||m!=0)){parsedTime+=m;}
if(showHours){if(period.length>0){parsedTime+=this._get(inst,'periodSeparator')+period;}}
return parsedTime;},_updateAlternate:function(inst,newTime){var altField=this._get(inst,'altField');if(altField){$(altField).each(function(i,e){$(e).val(newTime);});}},_getTimeAsDateTimepicker:function(input){var inst=this._getInst(input);if(inst.hours==-1&&inst.minutes==-1){return'';}
if((inst.hours<inst.hours.starts)||(inst.hours>inst.hours.ends)){inst.hours=0;}
if((inst.minutes<inst.minutes.starts)||(inst.minutes>inst.minutes.ends)){inst.minutes=0;}
return new Date(0,0,0,inst.hours,inst.minutes,0);},_getTimeTimepicker:function(input){var inst=this._getInst(input);return this._getParsedTime(inst);},_getHourTimepicker:function(input){var inst=this._getInst(input);if(inst==undefined){return-1;}
return inst.hours;},_getMinuteTimepicker:function(input){var inst=this._getInst(input);if(inst==undefined){return-1;}
return inst.minutes;}});$.fn.timepicker=function(options){if(!$.timepicker.initialized){$(document).mousedown($.timepicker._checkExternalClick);$.timepicker.initialized=true;}
if($("#"+$.timepicker._mainDivId).length===0){$('body').append($.timepicker.tpDiv);}
var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=='string'&&(options=='getTime'||options=='getTimeAsDate'||options=='getHour'||options=='getMinute'))
return $.timepicker['_'+options+'Timepicker'].apply($.timepicker,[this[0]].concat(otherArgs));if(options=='option'&&arguments.length==2&&typeof arguments[1]=='string')
return $.timepicker['_'+options+'Timepicker'].apply($.timepicker,[this[0]].concat(otherArgs));return this.each(function(){typeof options=='string'?$.timepicker['_'+options+'Timepicker'].apply($.timepicker,[this].concat(otherArgs)):$.timepicker._attachTimepicker(this,options);});};function extendRemove(target,props){$.extend(target,props);for(var name in props)
if(props[name]==null||props[name]==undefined)
target[name]=props[name];return target;};$.timepicker=new Timepicker();$.timepicker.initialized=false;$.timepicker.uuid=new Date().getTime();$.timepicker.version="0.3.3";window['TP_jQuery_'+tpuuid]=$;})(jQuery);
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS = CryptoJS || function (u, p) {
    var d = {}, l = d.lib = {}, s = function () { }, t = l.Base = { extend: function (a) { s.prototype = this; var c = new s; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () { c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } },
r = l.WordArray = t.extend({ init: function (a, c) { a = this.words = a || []; this.sigBytes = c != p ? c : 4 * a.length }, toString: function (a) { return (a || v).stringify(this) }, concat: function (a) { var c = this.words, e = a.words, j = this.sigBytes; a = a.sigBytes; this.clamp(); if (j % 4) for (var k = 0; k < a; k++) c[j + k >>> 2] |= (e[k >>> 2] >>> 24 - 8 * (k % 4) & 255) << 24 - 8 * ((j + k) % 4); else if (65535 < e.length) for (k = 0; k < a; k += 4) c[j + k >>> 2] = e[k >>> 2]; else c.push.apply(c, e); this.sigBytes += a; return this }, clamp: function () {
    var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 <<
32 - 8 * (c % 4); a.length = u.ceil(c / 4)
}, clone: function () { var a = t.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], e = 0; e < a; e += 4) c.push(4294967296 * u.random() | 0); return new r.init(c, a) } 
}), w = d.enc = {}, v = w.Hex = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++) { var k = c[j >>> 2] >>> 24 - 8 * (j % 4) & 255; e.push((k >>> 4).toString(16)); e.push((k & 15).toString(16)) } return e.join("") }, parse: function (a) {
    for (var c = a.length, e = [], j = 0; j < c; j += 2) e[j >>> 3] |= parseInt(a.substr(j,
2), 16) << 24 - 4 * (j % 8); return new r.init(e, c / 2)
} 
}, b = w.Latin1 = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var e = [], j = 0; j < a; j++) e.push(String.fromCharCode(c[j >>> 2] >>> 24 - 8 * (j % 4) & 255)); return e.join("") }, parse: function (a) { for (var c = a.length, e = [], j = 0; j < c; j++) e[j >>> 2] |= (a.charCodeAt(j) & 255) << 24 - 8 * (j % 4); return new r.init(e, c) } }, x = w.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(b.stringify(a))) } catch (c) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return b.parse(unescape(encodeURIComponent(a))) } },
q = l.BufferedBlockAlgorithm = t.extend({ reset: function () { this._data = new r.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = x.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var c = this._data, e = c.words, j = c.sigBytes, k = this.blockSize, b = j / (4 * k), b = a ? u.ceil(b) : u.max((b | 0) - this._minBufferSize, 0); a = b * k; j = u.min(4 * a, j); if (a) { for (var q = 0; q < a; q += k) this._doProcessBlock(e, q); q = e.splice(0, a); c.sigBytes -= j } return new r.init(q, j) }, clone: function () {
    var a = t.clone.call(this);
    a._data = this._data.clone(); return a
}, _minBufferSize: 0
}); l.Hasher = q.extend({ cfg: t.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { q.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (b, e) { return (new a.init(e)).finalize(b) } }, _createHmacHelper: function (a) {
    return function (b, e) {
        return (new n.HMAC.init(a,
e)).finalize(b)
    } 
} 
}); var n = d.algo = {}; return d
} (Math);
(function () {
    var u = CryptoJS, p = u.lib.WordArray; u.enc.Base64 = { stringify: function (d) { var l = d.words, p = d.sigBytes, t = this._map; d.clamp(); d = []; for (var r = 0; r < p; r += 3) for (var w = (l[r >>> 2] >>> 24 - 8 * (r % 4) & 255) << 16 | (l[r + 1 >>> 2] >>> 24 - 8 * ((r + 1) % 4) & 255) << 8 | l[r + 2 >>> 2] >>> 24 - 8 * ((r + 2) % 4) & 255, v = 0; 4 > v && r + 0.75 * v < p; v++) d.push(t.charAt(w >>> 6 * (3 - v) & 63)); if (l = t.charAt(64)) for (; d.length % 4; ) d.push(l); return d.join("") }, parse: function (d) {
        var l = d.length, s = this._map, t = s.charAt(64); t && (t = d.indexOf(t), -1 != t && (l = t)); for (var t = [], r = 0, w = 0; w <
l; w++) if (w % 4) { var v = s.indexOf(d.charAt(w - 1)) << 2 * (w % 4), b = s.indexOf(d.charAt(w)) >>> 6 - 2 * (w % 4); t[r >>> 2] |= (v | b) << 24 - 8 * (r % 4); r++ } return p.create(t, r)
    }, _map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
    }
})();
(function (u) {
    function p(b, n, a, c, e, j, k) { b = b + (n & a | ~n & c) + e + k; return (b << j | b >>> 32 - j) + n } function d(b, n, a, c, e, j, k) { b = b + (n & c | a & ~c) + e + k; return (b << j | b >>> 32 - j) + n } function l(b, n, a, c, e, j, k) { b = b + (n ^ a ^ c) + e + k; return (b << j | b >>> 32 - j) + n } function s(b, n, a, c, e, j, k) { b = b + (a ^ (n | ~c)) + e + k; return (b << j | b >>> 32 - j) + n } for (var t = CryptoJS, r = t.lib, w = r.WordArray, v = r.Hasher, r = t.algo, b = [], x = 0; 64 > x; x++) b[x] = 4294967296 * u.abs(u.sin(x + 1)) | 0; r = r.MD5 = v.extend({ _doReset: function () { this._hash = new w.init([1732584193, 4023233417, 2562383102, 271733878]) },
        _doProcessBlock: function (q, n) {
            for (var a = 0; 16 > a; a++) { var c = n + a, e = q[c]; q[c] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360 } var a = this._hash.words, c = q[n + 0], e = q[n + 1], j = q[n + 2], k = q[n + 3], z = q[n + 4], r = q[n + 5], t = q[n + 6], w = q[n + 7], v = q[n + 8], A = q[n + 9], B = q[n + 10], C = q[n + 11], u = q[n + 12], D = q[n + 13], E = q[n + 14], x = q[n + 15], f = a[0], m = a[1], g = a[2], h = a[3], f = p(f, m, g, h, c, 7, b[0]), h = p(h, f, m, g, e, 12, b[1]), g = p(g, h, f, m, j, 17, b[2]), m = p(m, g, h, f, k, 22, b[3]), f = p(f, m, g, h, z, 7, b[4]), h = p(h, f, m, g, r, 12, b[5]), g = p(g, h, f, m, t, 17, b[6]), m = p(m, g, h, f, w, 22, b[7]),
f = p(f, m, g, h, v, 7, b[8]), h = p(h, f, m, g, A, 12, b[9]), g = p(g, h, f, m, B, 17, b[10]), m = p(m, g, h, f, C, 22, b[11]), f = p(f, m, g, h, u, 7, b[12]), h = p(h, f, m, g, D, 12, b[13]), g = p(g, h, f, m, E, 17, b[14]), m = p(m, g, h, f, x, 22, b[15]), f = d(f, m, g, h, e, 5, b[16]), h = d(h, f, m, g, t, 9, b[17]), g = d(g, h, f, m, C, 14, b[18]), m = d(m, g, h, f, c, 20, b[19]), f = d(f, m, g, h, r, 5, b[20]), h = d(h, f, m, g, B, 9, b[21]), g = d(g, h, f, m, x, 14, b[22]), m = d(m, g, h, f, z, 20, b[23]), f = d(f, m, g, h, A, 5, b[24]), h = d(h, f, m, g, E, 9, b[25]), g = d(g, h, f, m, k, 14, b[26]), m = d(m, g, h, f, v, 20, b[27]), f = d(f, m, g, h, D, 5, b[28]), h = d(h, f,
m, g, j, 9, b[29]), g = d(g, h, f, m, w, 14, b[30]), m = d(m, g, h, f, u, 20, b[31]), f = l(f, m, g, h, r, 4, b[32]), h = l(h, f, m, g, v, 11, b[33]), g = l(g, h, f, m, C, 16, b[34]), m = l(m, g, h, f, E, 23, b[35]), f = l(f, m, g, h, e, 4, b[36]), h = l(h, f, m, g, z, 11, b[37]), g = l(g, h, f, m, w, 16, b[38]), m = l(m, g, h, f, B, 23, b[39]), f = l(f, m, g, h, D, 4, b[40]), h = l(h, f, m, g, c, 11, b[41]), g = l(g, h, f, m, k, 16, b[42]), m = l(m, g, h, f, t, 23, b[43]), f = l(f, m, g, h, A, 4, b[44]), h = l(h, f, m, g, u, 11, b[45]), g = l(g, h, f, m, x, 16, b[46]), m = l(m, g, h, f, j, 23, b[47]), f = s(f, m, g, h, c, 6, b[48]), h = s(h, f, m, g, w, 10, b[49]), g = s(g, h, f, m,
E, 15, b[50]), m = s(m, g, h, f, r, 21, b[51]), f = s(f, m, g, h, u, 6, b[52]), h = s(h, f, m, g, k, 10, b[53]), g = s(g, h, f, m, B, 15, b[54]), m = s(m, g, h, f, e, 21, b[55]), f = s(f, m, g, h, v, 6, b[56]), h = s(h, f, m, g, x, 10, b[57]), g = s(g, h, f, m, t, 15, b[58]), m = s(m, g, h, f, D, 21, b[59]), f = s(f, m, g, h, z, 6, b[60]), h = s(h, f, m, g, C, 10, b[61]), g = s(g, h, f, m, j, 15, b[62]), m = s(m, g, h, f, A, 21, b[63]); a[0] = a[0] + f | 0; a[1] = a[1] + m | 0; a[2] = a[2] + g | 0; a[3] = a[3] + h | 0
        }, _doFinalize: function () {
            var b = this._data, n = b.words, a = 8 * this._nDataBytes, c = 8 * b.sigBytes; n[c >>> 5] |= 128 << 24 - c % 32; var e = u.floor(a /
4294967296); n[(c + 64 >>> 9 << 4) + 15] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360; n[(c + 64 >>> 9 << 4) + 14] = (a << 8 | a >>> 24) & 16711935 | (a << 24 | a >>> 8) & 4278255360; b.sigBytes = 4 * (n.length + 1); this._process(); b = this._hash; n = b.words; for (a = 0; 4 > a; a++) c = n[a], n[a] = (c << 8 | c >>> 24) & 16711935 | (c << 24 | c >>> 8) & 4278255360; return b
        }, clone: function () { var b = v.clone.call(this); b._hash = this._hash.clone(); return b } 
    }); t.MD5 = v._createHelper(r); t.HmacMD5 = v._createHmacHelper(r)
})(Math);
(function () {
    var u = CryptoJS, p = u.lib, d = p.Base, l = p.WordArray, p = u.algo, s = p.EvpKDF = d.extend({ cfg: d.extend({ keySize: 4, hasher: p.MD5, iterations: 1 }), init: function (d) { this.cfg = this.cfg.extend(d) }, compute: function (d, r) { for (var p = this.cfg, s = p.hasher.create(), b = l.create(), u = b.words, q = p.keySize, p = p.iterations; u.length < q; ) { n && s.update(n); var n = s.update(d).finalize(r); s.reset(); for (var a = 1; a < p; a++) n = s.finalize(n), s.reset(); b.concat(n) } b.sigBytes = 4 * q; return b } }); u.EvpKDF = function (d, l, p) {
        return s.create(p).compute(d,
l)
    } 
})();
CryptoJS.lib.Cipher || function (u) {
    var p = CryptoJS, d = p.lib, l = d.Base, s = d.WordArray, t = d.BufferedBlockAlgorithm, r = p.enc.Base64, w = p.algo.EvpKDF, v = d.Cipher = t.extend({ cfg: l.extend(), createEncryptor: function (e, a) { return this.create(this._ENC_XFORM_MODE, e, a) }, createDecryptor: function (e, a) { return this.create(this._DEC_XFORM_MODE, e, a) }, init: function (e, a, b) { this.cfg = this.cfg.extend(b); this._xformMode = e; this._key = a; this.reset() }, reset: function () { t.reset.call(this); this._doReset() }, process: function (e) { this._append(e); return this._process() },
        finalize: function (e) { e && this._append(e); return this._doFinalize() }, keySize: 4, ivSize: 4, _ENC_XFORM_MODE: 1, _DEC_XFORM_MODE: 2, _createHelper: function (e) { return { encrypt: function (b, k, d) { return ("string" == typeof k ? c : a).encrypt(e, b, k, d) }, decrypt: function (b, k, d) { return ("string" == typeof k ? c : a).decrypt(e, b, k, d) } } } 
    }); d.StreamCipher = v.extend({ _doFinalize: function () { return this._process(!0) }, blockSize: 1 }); var b = p.mode = {}, x = function (e, a, b) {
        var c = this._iv; c ? this._iv = u : c = this._prevBlock; for (var d = 0; d < b; d++) e[a + d] ^=
c[d]
    }, q = (d.BlockCipherMode = l.extend({ createEncryptor: function (e, a) { return this.Encryptor.create(e, a) }, createDecryptor: function (e, a) { return this.Decryptor.create(e, a) }, init: function (e, a) { this._cipher = e; this._iv = a } })).extend(); q.Encryptor = q.extend({ processBlock: function (e, a) { var b = this._cipher, c = b.blockSize; x.call(this, e, a, c); b.encryptBlock(e, a); this._prevBlock = e.slice(a, a + c) } }); q.Decryptor = q.extend({ processBlock: function (e, a) {
        var b = this._cipher, c = b.blockSize, d = e.slice(a, a + c); b.decryptBlock(e, a); x.call(this,
e, a, c); this._prevBlock = d
    } 
    }); b = b.CBC = q; q = (p.pad = {}).Pkcs7 = { pad: function (a, b) { for (var c = 4 * b, c = c - a.sigBytes % c, d = c << 24 | c << 16 | c << 8 | c, l = [], n = 0; n < c; n += 4) l.push(d); c = s.create(l, c); a.concat(c) }, unpad: function (a) { a.sigBytes -= a.words[a.sigBytes - 1 >>> 2] & 255 } }; d.BlockCipher = v.extend({ cfg: v.cfg.extend({ mode: b, padding: q }), reset: function () {
        v.reset.call(this); var a = this.cfg, b = a.iv, a = a.mode; if (this._xformMode == this._ENC_XFORM_MODE) var c = a.createEncryptor; else c = a.createDecryptor, this._minBufferSize = 1; this._mode = c.call(a,
this, b && b.words)
    }, _doProcessBlock: function (a, b) { this._mode.processBlock(a, b) }, _doFinalize: function () { var a = this.cfg.padding; if (this._xformMode == this._ENC_XFORM_MODE) { a.pad(this._data, this.blockSize); var b = this._process(!0) } else b = this._process(!0), a.unpad(b); return b }, blockSize: 4
    }); var n = d.CipherParams = l.extend({ init: function (a) { this.mixIn(a) }, toString: function (a) { return (a || this.formatter).stringify(this) } }), b = (p.format = {}).OpenSSL = { stringify: function (a) {
        var b = a.ciphertext; a = a.salt; return (a ? s.create([1398893684,
1701076831]).concat(a).concat(b) : b).toString(r)
    }, parse: function (a) { a = r.parse(a); var b = a.words; if (1398893684 == b[0] && 1701076831 == b[1]) { var c = s.create(b.slice(2, 4)); b.splice(0, 4); a.sigBytes -= 16 } return n.create({ ciphertext: a, salt: c }) } 
    }, a = d.SerializableCipher = l.extend({ cfg: l.extend({ format: b }), encrypt: function (a, b, c, d) { d = this.cfg.extend(d); var l = a.createEncryptor(c, d); b = l.finalize(b); l = l.cfg; return n.create({ ciphertext: b, key: c, iv: l.iv, algorithm: a, mode: l.mode, padding: l.padding, blockSize: a.blockSize, formatter: d.format }) },
        decrypt: function (a, b, c, d) { d = this.cfg.extend(d); b = this._parse(b, d.format); return a.createDecryptor(c, d).finalize(b.ciphertext) }, _parse: function (a, b) { return "string" == typeof a ? b.parse(a, this) : a } 
    }), p = (p.kdf = {}).OpenSSL = { execute: function (a, b, c, d) { d || (d = s.random(8)); a = w.create({ keySize: b + c }).compute(a, d); c = s.create(a.words.slice(b), 4 * c); a.sigBytes = 4 * b; return n.create({ key: a, iv: c, salt: d }) } }, c = d.PasswordBasedCipher = a.extend({ cfg: a.cfg.extend({ kdf: p }), encrypt: function (b, c, d, l) {
        l = this.cfg.extend(l); d = l.kdf.execute(d,
b.keySize, b.ivSize); l.iv = d.iv; b = a.encrypt.call(this, b, c, d.key, l); b.mixIn(d); return b
    }, decrypt: function (b, c, d, l) { l = this.cfg.extend(l); c = this._parse(c, l.format); d = l.kdf.execute(d, b.keySize, b.ivSize, c.salt); l.iv = d.iv; return a.decrypt.call(this, b, c, d.key, l) } 
    })
} ();
(function () {
    for (var u = CryptoJS, p = u.lib.BlockCipher, d = u.algo, l = [], s = [], t = [], r = [], w = [], v = [], b = [], x = [], q = [], n = [], a = [], c = 0; 256 > c; c++) a[c] = 128 > c ? c << 1 : c << 1 ^ 283; for (var e = 0, j = 0, c = 0; 256 > c; c++) { var k = j ^ j << 1 ^ j << 2 ^ j << 3 ^ j << 4, k = k >>> 8 ^ k & 255 ^ 99; l[e] = k; s[k] = e; var z = a[e], F = a[z], G = a[F], y = 257 * a[k] ^ 16843008 * k; t[e] = y << 24 | y >>> 8; r[e] = y << 16 | y >>> 16; w[e] = y << 8 | y >>> 24; v[e] = y; y = 16843009 * G ^ 65537 * F ^ 257 * z ^ 16843008 * e; b[k] = y << 24 | y >>> 8; x[k] = y << 16 | y >>> 16; q[k] = y << 8 | y >>> 24; n[k] = y; e ? (e = z ^ a[a[a[G ^ z]]], j ^= a[a[j]]) : e = j = 1 } var H = [0, 1, 2, 4, 8,
16, 32, 64, 128, 27, 54], d = d.AES = p.extend({ _doReset: function () {
    for (var a = this._key, c = a.words, d = a.sigBytes / 4, a = 4 * ((this._nRounds = d + 6) + 1), e = this._keySchedule = [], j = 0; j < a; j++) if (j < d) e[j] = c[j]; else { var k = e[j - 1]; j % d ? 6 < d && 4 == j % d && (k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255]) : (k = k << 8 | k >>> 24, k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255], k ^= H[j / d | 0] << 24); e[j] = e[j - d] ^ k } c = this._invKeySchedule = []; for (d = 0; d < a; d++) j = a - d, k = d % 4 ? e[j] : e[j - 4], c[d] = 4 > d || 4 >= j ? k : b[l[k >>> 24]] ^ x[l[k >>> 16 & 255]] ^ q[l[k >>>
8 & 255]] ^ n[l[k & 255]]
}, encryptBlock: function (a, b) { this._doCryptBlock(a, b, this._keySchedule, t, r, w, v, l) }, decryptBlock: function (a, c) { var d = a[c + 1]; a[c + 1] = a[c + 3]; a[c + 3] = d; this._doCryptBlock(a, c, this._invKeySchedule, b, x, q, n, s); d = a[c + 1]; a[c + 1] = a[c + 3]; a[c + 3] = d }, _doCryptBlock: function (a, b, c, d, e, j, l, f) {
    for (var m = this._nRounds, g = a[b] ^ c[0], h = a[b + 1] ^ c[1], k = a[b + 2] ^ c[2], n = a[b + 3] ^ c[3], p = 4, r = 1; r < m; r++) var q = d[g >>> 24] ^ e[h >>> 16 & 255] ^ j[k >>> 8 & 255] ^ l[n & 255] ^ c[p++], s = d[h >>> 24] ^ e[k >>> 16 & 255] ^ j[n >>> 8 & 255] ^ l[g & 255] ^ c[p++], t =
d[k >>> 24] ^ e[n >>> 16 & 255] ^ j[g >>> 8 & 255] ^ l[h & 255] ^ c[p++], n = d[n >>> 24] ^ e[g >>> 16 & 255] ^ j[h >>> 8 & 255] ^ l[k & 255] ^ c[p++], g = q, h = s, k = t; q = (f[g >>> 24] << 24 | f[h >>> 16 & 255] << 16 | f[k >>> 8 & 255] << 8 | f[n & 255]) ^ c[p++]; s = (f[h >>> 24] << 24 | f[k >>> 16 & 255] << 16 | f[n >>> 8 & 255] << 8 | f[g & 255]) ^ c[p++]; t = (f[k >>> 24] << 24 | f[n >>> 16 & 255] << 16 | f[g >>> 8 & 255] << 8 | f[h & 255]) ^ c[p++]; n = (f[n >>> 24] << 24 | f[g >>> 16 & 255] << 16 | f[h >>> 8 & 255] << 8 | f[k & 255]) ^ c[p++]; a[b] = q; a[b + 1] = s; a[b + 2] = t; a[b + 3] = n
}, keySize: 8
}); u.AES = p._createHelper(d)
})();

/*!
 *  BarCode Coder Library (BCC Library)
 *  BCCL Version 2.0
 *    
 *  Porting : jQuery barcode plugin 
 *  Version : 2.0.3
 *   
 *  Date    : 2013-01-06
 *  Author  : DEMONTE Jean-Baptiste <jbdemonte@gmail.com>
 *            HOUREZ Jonathan
 *             
 *  Web site: http://barcode-coder.com/
 *  dual licence :  http://www.cecill.info/licences/Licence_CeCILL_V2-fr.html
 *                  http://www.gnu.org/licenses/gpl.html
 */

(function ($) {
  
  var barcode = {
    settings:{
      barWidth: 1,
      barHeight: 50,
      moduleSize: 5,
      showHRI: true,
      addQuietZone: true,
      marginHRI: 5,
      bgColor: "#FFFFFF",
      color: "#000000",
      fontSize: 10,
      output: "css",
      posX: 0,
      posY: 0
    },
    intval: function(val){
      var type = typeof( val );
      if (type == 'string'){
        val = val.replace(/[^0-9-.]/g, "");
        val = parseInt(val * 1, 10);
        return isNaN(val) || !isFinite(val) ? 0 : val;
      }
      return type == 'number' && isFinite(val) ? Math.floor(val) : 0;
    },
    i25: { // std25 int25
      encoding: ["NNWWN", "WNNNW", "NWNNW", "WWNNN", "NNWNW", "WNWNN", "NWWNN", "NNNWW", "WNNWN","NWNWN"],
      compute: function(code, crc, type){
        if (! crc) {
          if (code.length % 2 != 0) code = '0' + code;
        } else {
          if ( (type == "int25") && (code.length % 2 == 0) ) code = '0' + code;
          var odd = true, v, sum = 0;
          for(var i=code.length-1; i>-1; i--){
            v = barcode.intval(code.charAt(i));
            if (isNaN(v)) return("");
            sum += odd ? 3 * v : v;
            odd = ! odd;
          }
          code += ((10 - sum % 10) % 10).toString();
        }
        return(code);
      },
      getDigit: function(code, crc, type){
        code = this.compute(code, crc, type);
        if (code == "") return("");
        result = "";
        
        var i, j;
        if (type == "int25") {
          // Interleaved 2 of 5
          
          // start
          result += "1010";
          
          // digits + CRC
          var c1, c2;
          for(i=0; i<code.length / 2; i++){
            c1 = code.charAt(2*i);
            c2 = code.charAt(2*i+1);
            for(j=0; j<5; j++){
              result += '1';
              if (this.encoding[c1].charAt(j) == 'W') result += '1';
              result += '0';
              if (this.encoding[c2].charAt(j) == 'W') result += '0';
            }
          }
          // stop
          result += "1101";
        } else if (type == "std25") {
          // Standard 2 of 5 is a numeric-only barcode that has been in use a long time. 
          // Unlike Interleaved 2 of 5, all of the information is encoded in the bars; the spaces are fixed width and are used only to separate the bars.
          // The code is self-checking and does not include a checksum.
          
          // start
          result += "11011010";
          
          // digits + CRC
          var c;
          for(i=0; i<code.length; i++){
            c = code.charAt(i);
            for(j=0; j<5; j++){
              result += '1';
              if (this.encoding[c].charAt(j) == 'W') result += "11";
              result += '0';
            }
          }
          // stop
          result += "11010110";
        }
        return(result);
      }
    },
    ean: {
      encoding: [ ["0001101", "0100111", "1110010"],
                  ["0011001", "0110011", "1100110"], 
                  ["0010011", "0011011", "1101100"],
                  ["0111101", "0100001", "1000010"], 
                  ["0100011", "0011101", "1011100"], 
                  ["0110001", "0111001", "1001110"],
                  ["0101111", "0000101", "1010000"],
                  ["0111011", "0010001", "1000100"],
                  ["0110111", "0001001", "1001000"],
                  ["0001011", "0010111", "1110100"] ],
      first:  ["000000","001011","001101","001110","010011","011001","011100","010101","010110","011010"],
      getDigit: function(code, type){
        // Check len (12 for ean13, 7 for ean8)
        var len = type == "ean8" ? 7 : 12;
        code = code.substring(0, len);
        if (code.length != len) return("");
        // Check each digit is numeric
        var c;
        for(var i=0; i<code.length; i++){
          c = code.charAt(i);
          if ( (c < '0') || (c > '9') ) return("");
        }
        // get checksum
        code = this.compute(code, type);
        
        // process analyse
        var result = "101"; // start
        
        if (type == "ean8"){
  
          // process left part
          for(var i=0; i<4; i++){
            result += this.encoding[barcode.intval(code.charAt(i))][0];
          }
              
          // center guard bars
          result += "01010";
              
          // process right part
          for(var i=4; i<8; i++){
            result += this.encoding[barcode.intval(code.charAt(i))][2];
          }
              
        } else { // ean13
          // extract first digit and get sequence
          var seq = this.first[ barcode.intval(code.charAt(0)) ];
          
          // process left part
          for(var i=1; i<7; i++){
            result += this.encoding[barcode.intval(code.charAt(i))][ barcode.intval(seq.charAt(i-1)) ];
          }
          
          // center guard bars
          result += "01010";
              
          // process right part
          for(var i=7; i<13; i++){
            result += this.encoding[barcode.intval(code.charAt(i))][ 2 ];
          }
        } // ean13
        
        result += "101"; // stop
        return(result);
      },
      compute: function (code, type){
        var len = type == "ean13" ? 12 : 7;
        code = code.substring(0, len);
        var sum = 0, odd = true;
        for(i=code.length-1; i>-1; i--){
          sum += (odd ? 3 : 1) * barcode.intval(code.charAt(i));
          odd = ! odd;
        }
        return(code + ((10 - sum % 10) % 10).toString());
      }
    },
    upc: {
      getDigit: function(code){
        if (code.length < 12) {
          code = '0' + code;
        }
        return barcode.ean.getDigit(code, 'ean13');
      },
      compute: function (code){
        if (code.length < 12) {
          code = '0' + code;
        }
        return barcode.ean.compute(code, 'ean13').substr(1);
      }
    },
    msi: {
      encoding:["100100100100", "100100100110", "100100110100", "100100110110",
                "100110100100", "100110100110", "100110110100", "100110110110",
                "110100100100", "110100100110"],
      compute: function(code, crc){
        if (typeof(crc) == "object"){
          if (crc.crc1 == "mod10"){
            code = this.computeMod10(code);
          } else if (crc.crc1 == "mod11"){
            code = this.computeMod11(code);
          }
          if (crc.crc2 == "mod10"){
            code = this.computeMod10(code);
          } else if (crc.crc2 == "mod11"){
            code = this.computeMod11(code);
          }
        } else if (typeof(crc) == "boolean"){
          if (crc) code = this.computeMod10(code);
        }
        return(code);
      },
      computeMod10:function(code){
        var i, 
        toPart1 = code.length % 2;
        var n1 = 0, sum = 0;
        for(i=0; i<code.length; i++){
          if (toPart1) {
            n1 = 10 * n1 + barcode.intval(code.charAt(i));
          } else {
            sum += barcode.intval(code.charAt(i));
          }
          toPart1 = ! toPart1;
        }
        var s1 = (2 * n1).toString();
        for(i=0; i<s1.length; i++){
          sum += barcode.intval(s1.charAt(i));
        }
        return(code + ((10 - sum % 10) % 10).toString());
      },
      computeMod11:function(code){
        var sum = 0, weight = 2;
        for(var i=code.length-1; i>=0; i--){
          sum += weight * barcode.intval(code.charAt(i));
          weight = weight == 7 ? 2 : weight + 1;
        }
        return(code + ((11 - sum % 11) % 11).toString());
      },
      getDigit: function(code, crc){
        var table = "0123456789";
        var index = 0;
        var result = "";
        
        code = this.compute(code, false);
        
        // start
        result = "110";
        
        // digits
        for(i=0; i<code.length; i++){
          index = table.indexOf( code.charAt(i) );
          if (index < 0) return("");
          result += this.encoding[ index ];
        }
        
        // stop
        result += "1001";
        
        return(result);
      }
    },
    code11: {
      encoding:[  "101011", "1101011", "1001011", "1100101",
                  "1011011", "1101101", "1001101", "1010011",
                  "1101001", "110101", "101101"],
      getDigit: function(code){
        var table = "0123456789-";
        var i, index, result = "", intercharacter = '0'
        
        // start
        result = "1011001" + intercharacter;
        
        // digits
        for(i=0; i<code.length; i++){
          index = table.indexOf( code.charAt(i) );
          if (index < 0) return("");
          result += this.encoding[ index ] + intercharacter;
        }
        
        // checksum
        var weightC    = 0,
        weightSumC = 0,
        weightK    = 1, // start at 1 because the right-most character is "C" checksum
        weightSumK   = 0;
        for(i=code.length-1; i>=0; i--){
          weightC = weightC == 10 ? 1 : weightC + 1;
          weightK = weightK == 10 ? 1 : weightK + 1;
          
          index = table.indexOf( code.charAt(i) );
          
          weightSumC += weightC * index;
          weightSumK += weightK * index;
        }
        
        var c = weightSumC % 11;
        weightSumK += c;
        var k = weightSumK % 11;
        
        result += this.encoding[c] + intercharacter;
        
        if (code.length >= 10){
          result += this.encoding[k] + intercharacter;
        }
        
        // stop
        result  += "1011001";
        
        return(result);
      }   
    },
    code39: {
      encoding:["101001101101", "110100101011", "101100101011", "110110010101",
                "101001101011", "110100110101", "101100110101", "101001011011",
                "110100101101", "101100101101", "110101001011", "101101001011",
                "110110100101", "101011001011", "110101100101", "101101100101",
                "101010011011", "110101001101", "101101001101", "101011001101",
                "110101010011", "101101010011", "110110101001", "101011010011",
                "110101101001", "101101101001", "101010110011", "110101011001",
                "101101011001", "101011011001", "110010101011", "100110101011",
                "110011010101", "100101101011", "110010110101", "100110110101",
                "100101011011", "110010101101", "100110101101", "100100100101",
                "100100101001", "100101001001", "101001001001", "100101101101"],
      getDigit: function(code){
        var table = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%*";
        var i, index, result="", intercharacter='0';
        
        if (code.indexOf('*') >= 0) return("");
        
        // Add Start and Stop charactere : *
        code = ("*" + code + "*").toUpperCase();
        
        for(i=0; i<code.length; i++){
          index = table.indexOf( code.charAt(i) );
          if (index < 0) return("");
          if (i > 0) result += intercharacter;
          result += this.encoding[ index ];
        }
        return(result);
      }
    },
    code93:{
      encoding:["100010100", "101001000", "101000100", "101000010",
                "100101000", "100100100", "100100010", "101010000",
                "100010010", "100001010", "110101000", "110100100",
                "110100010", "110010100", "110010010", "110001010",
                "101101000", "101100100", "101100010", "100110100",
                "100011010", "101011000", "101001100", "101000110",
                "100101100", "100010110", "110110100", "110110010",
                "110101100", "110100110", "110010110", "110011010",
                "101101100", "101100110", "100110110", "100111010",
                "100101110", "111010100", "111010010", "111001010",
                "101101110", "101110110", "110101110", "100100110",
                "111011010", "111010110", "100110010", "101011110"],
      getDigit: function(code, crc){
        var table = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%____*", // _ => ($), (%), (/) et (+)
        c, result = "";
        
        if (code.indexOf('*') >= 0) return("");
        
        code = code.toUpperCase();
        
        // start :  *
        result  += this.encoding[47];
        
        // digits
        for(i=0; i<code.length; i++){
          c = code.charAt(i);
          index = table.indexOf( c );
          if ( (c == '_') || (index < 0) ) return("");
          result += this.encoding[ index ];
        }
        
        // checksum
        if (crc){
          var weightC    = 0,
          weightSumC = 0,
          weightK    = 1, // start at 1 because the right-most character is "C" checksum
          weightSumK   = 0;
          for(i=code.length-1; i>=0; i--){
            weightC = weightC == 20 ? 1 : weightC + 1;
            weightK = weightK == 15 ? 1 : weightK + 1;
            
            index = table.indexOf( code.charAt(i) );
            
            weightSumC += weightC * index;
            weightSumK += weightK * index;
          }
          
          var c = weightSumC % 47;
          weightSumK += c;
          var k = weightSumK % 47;
          
          result += this.encoding[c];
          result += this.encoding[k];
        }
        
        // stop : *
        result  += this.encoding[47];
        
        // Terminaison bar
        result  += '1';
        return(result);
      }
    },
    code128: {
      encoding:["11011001100", "11001101100", "11001100110", "10010011000",
                "10010001100", "10001001100", "10011001000", "10011000100",
                "10001100100", "11001001000", "11001000100", "11000100100",
                "10110011100", "10011011100", "10011001110", "10111001100",
                "10011101100", "10011100110", "11001110010", "11001011100",
                "11001001110", "11011100100", "11001110100", "11101101110",
                "11101001100", "11100101100", "11100100110", "11101100100",
                "11100110100", "11100110010", "11011011000", "11011000110",
                "11000110110", "10100011000", "10001011000", "10001000110",
                "10110001000", "10001101000", "10001100010", "11010001000",
                "11000101000", "11000100010", "10110111000", "10110001110",
                "10001101110", "10111011000", "10111000110", "10001110110",
                "11101110110", "11010001110", "11000101110", "11011101000",
                "11011100010", "11011101110", "11101011000", "11101000110",
                "11100010110", "11101101000", "11101100010", "11100011010",
                "11101111010", "11001000010", "11110001010", "10100110000",
                "10100001100", "10010110000", "10010000110", "10000101100",
                "10000100110", "10110010000", "10110000100", "10011010000",
                "10011000010", "10000110100", "10000110010", "11000010010",
                "11001010000", "11110111010", "11000010100", "10001111010",
                "10100111100", "10010111100", "10010011110", "10111100100",
                "10011110100", "10011110010", "11110100100", "11110010100",
                "11110010010", "11011011110", "11011110110", "11110110110",
                "10101111000", "10100011110", "10001011110", "10111101000",
                "10111100010", "11110101000", "11110100010", "10111011110",
                "10111101110", "11101011110", "11110101110", "11010000100",
                "11010010000", "11010011100", "11000111010"],
      getDigit: function(code){
        var tableB = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
        var result = "";
        var sum = 0;
        var isum = 0;
        var i = 0;
        var j = 0;
        var value = 0;
        
        // check each characters
        for(i=0; i<code.length; i++){
          if (tableB.indexOf(code.charAt(i)) == -1) return("");
        }
        
        // check firsts characters : start with C table only if enought numeric
        var tableCActivated = code.length > 1;
        var c = '';
        for(i=0; i<3 && i<code.length; i++){
        c = code.charAt(i);
          tableCActivated &= c >= '0' && c <= '9';
        }
        
        sum = tableCActivated ? 105 : 104;
        
        // start : [105] : C table or [104] : B table 
        result = this.encoding[ sum ];
        
        i = 0;
        while( i < code.length ){
          if (! tableCActivated){
            j = 0;
            // check next character to activate C table if interresting
            while ( (i + j < code.length) && (code.charAt(i+j) >= '0') && (code.charAt(i+j) <= '9') ) j++;
            
            // 6 min everywhere or 4 mini at the end
            tableCActivated = (j > 5) || ((i + j - 1 == code.length) && (j > 3));
            
            if ( tableCActivated ){
            result += this.encoding[ 99 ]; // C table
            sum += ++isum * 99;
            }
            //         2 min for table C so need table B
          } else if ( (i == code.length) || (code.charAt(i) < '0') || (code.charAt(i) > '9') || (code.charAt(i+1) < '0') || (code.charAt(i+1) > '9') ) {
            tableCActivated = false;
            result += this.encoding[ 100 ]; // B table
            sum += ++isum * 100;
          }
          
          if ( tableCActivated ) {
            value = barcode.intval(code.charAt(i) + code.charAt(i+1)); // Add two characters (numeric)
            i += 2;
          } else {
            value = tableB.indexOf( code.charAt(i) ); // Add one character
            i += 1;
          }
          result  += this.encoding[ value ];
          sum += ++isum * value;
        }
        
        // Add CRC
        result  += this.encoding[ sum % 103 ];
        
        // Stop
        result += this.encoding[106];
        
        // Termination bar
        result += "11";
        
        return(result);
      }
    },
    codabar: {
      encoding:["101010011", "101011001", "101001011", "110010101",
                "101101001", "110101001", "100101011", "100101101",
                "100110101", "110100101", "101001101", "101100101",
                "1101011011", "1101101011", "1101101101", "1011011011",
                "1011001001", "1010010011", "1001001011", "1010011001"],
      getDigit: function(code){
        var table = "0123456789-$:/.+";
        var i, index, result="", intercharacter = '0';
        
        // add start : A->D : arbitrary choose A
        result += this.encoding[16] + intercharacter;
        
        for(i=0; i<code.length; i++){
          index = table.indexOf( code.charAt(i) );
          if (index < 0) return("");
          result += this.encoding[ index ] + intercharacter;
        }
        
        // add stop : A->D : arbitrary choose A
        result += this.encoding[16];
        return(result);
      }
    },
    datamatrix: {
      lengthRows:       [ 10, 12, 14, 16, 18, 20, 22, 24, 26,  // 24 squares et 6 rectangular
                          32, 36, 40, 44, 48, 52, 64, 72, 80,  88, 96, 104, 120, 132, 144,
                          8, 8, 12, 12, 16, 16],
      lengthCols:       [ 10, 12, 14, 16, 18, 20, 22, 24, 26,  // Number of columns for the entire datamatrix
                          32, 36, 40, 44, 48, 52, 64, 72, 80, 88, 96, 104, 120, 132, 144,
                          18, 32, 26, 36, 36, 48],
      dataCWCount:      [ 3, 5, 8, 12,  18,  22,  30,  36,  // Number of data codewords for the datamatrix
                          44, 62, 86, 114, 144, 174, 204, 280, 368, 456, 576, 696, 816, 1050, 
                          1304, 1558, 5, 10, 16, 22, 32, 49],
      solomonCWCount:   [ 5, 7, 10, 12, 14, 18, 20, 24, 28, // Number of Reed-Solomon codewords for the datamatrix
                          36, 42, 48, 56, 68, 84, 112, 144, 192, 224, 272, 336, 408, 496, 620,
                          7, 11, 14, 18, 24, 28],
      dataRegionRows:   [ 8, 10, 12, 14, 16, 18, 20, 22, // Number of rows per region
                          24, 14, 16, 18, 20, 22, 24, 14, 16, 18, 20, 22, 24, 18, 20, 22,
                          6,  6, 10, 10, 14, 14],
      dataRegionCols:   [ 8, 10, 12, 14, 16, 18, 20, 22, // Number of columns per region
                          24, 14, 16, 18, 20, 22, 24, 14, 16, 18, 20, 22, 24, 18, 20, 22,
                          16, 14, 24, 16, 16, 22],
      regionRows:       [ 1, 1, 1, 1, 1, 1, 1, 1, // Number of regions per row
                          1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6,
                          1, 1, 1, 1, 1, 1],
      regionCols:       [ 1, 1, 1, 1, 1, 1, 1, 1, // Number of regions per column
                          1, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 4, 6, 6, 6,
                          1, 2, 1, 2, 2, 2],
      interleavedBlocks:[ 1, 1, 1, 1, 1, 1, 1, 1, // Number of blocks
                          1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 4, 4, 6, 6, 8, 8,
                          1, 1, 1, 1, 1, 1],
      logTab:           [ -255, 255, 1, 240, 2, 225, 241, 53, 3,  // Table of log for the Galois field
                          38, 226, 133, 242, 43, 54, 210, 4, 195, 39, 114, 227, 106, 134, 28, 
                          243, 140, 44, 23, 55, 118, 211, 234, 5, 219, 196, 96, 40, 222, 115, 
                          103, 228, 78, 107, 125, 135, 8, 29, 162, 244, 186, 141, 180, 45, 99, 
                          24, 49, 56, 13, 119, 153, 212, 199, 235, 91, 6, 76, 220, 217, 197, 
                          11, 97, 184, 41, 36, 223, 253, 116, 138, 104, 193, 229, 86, 79, 171, 
                          108, 165, 126, 145, 136, 34, 9, 74, 30, 32, 163, 84, 245, 173, 187, 
                          204, 142, 81, 181, 190, 46, 88, 100, 159, 25, 231, 50, 207, 57, 147, 
                          14, 67, 120, 128, 154, 248, 213, 167, 200, 63, 236, 110, 92, 176, 7, 
                          161, 77, 124, 221, 102, 218, 95, 198, 90, 12, 152, 98, 48, 185, 179, 
                          42, 209, 37, 132, 224, 52, 254, 239, 117, 233, 139, 22, 105, 27, 194, 
                          113, 230, 206, 87, 158, 80, 189, 172, 203, 109, 175, 166, 62, 127, 
                          247, 146, 66, 137, 192, 35, 252, 10, 183, 75, 216, 31, 83, 33, 73, 
                          164, 144, 85, 170, 246, 65, 174, 61, 188, 202, 205, 157, 143, 169, 82, 
                          72, 182, 215, 191, 251, 47, 178, 89, 151, 101, 94, 160, 123, 26, 112, 
                          232, 21, 51, 238, 208, 131, 58, 69, 148, 18, 15, 16, 68, 17, 121, 149, 
                          129, 19, 155, 59, 249, 70, 214, 250, 168, 71, 201, 156, 64, 60, 237, 
                          130, 111, 20, 93, 122, 177, 150],
      aLogTab:          [ 1, 2, 4, 8, 16, 32, 64, 128, 45, 90, // Table of aLog for the Galois field
                          180, 69, 138, 57, 114, 228, 229, 231, 227, 235, 251, 219, 155, 27, 54, 
                          108, 216, 157, 23, 46, 92, 184, 93, 186, 89, 178, 73, 146, 9, 18, 36, 
                          72, 144, 13, 26, 52, 104, 208, 141, 55, 110, 220, 149, 7, 14, 28, 56, 
                          112, 224, 237, 247, 195, 171, 123, 246, 193, 175, 115, 230, 225, 239, 
                          243, 203, 187, 91, 182, 65, 130, 41, 82, 164, 101, 202, 185, 95, 190, 
                          81, 162, 105, 210, 137, 63, 126, 252, 213, 135, 35, 70, 140, 53, 106, 
                          212, 133, 39, 78, 156, 21, 42, 84, 168, 125, 250, 217, 159, 19, 38, 76, 
                          152, 29, 58, 116, 232, 253, 215, 131, 43, 86, 172, 117, 234, 249, 223, 
                          147, 11, 22, 44, 88, 176, 77, 154, 25, 50, 100, 200, 189, 87, 174, 113, 
                          226, 233, 255, 211, 139, 59, 118, 236, 245, 199, 163, 107, 214, 129, 
                          47, 94, 188, 85, 170, 121, 242, 201, 191, 83, 166, 97, 194, 169, 127, 
                          254, 209, 143, 51, 102, 204, 181, 71, 142, 49, 98, 196, 165, 103, 206, 
                          177, 79, 158, 17, 34, 68, 136, 61, 122, 244, 197, 167, 99, 198, 161, 
                          111, 222, 145, 15, 30, 60, 120, 240, 205, 183, 67, 134, 33, 66, 132, 
                          37, 74, 148, 5, 10, 20, 40, 80, 160, 109, 218, 153, 31, 62, 124, 248, 
                          221, 151, 3, 6, 12, 24, 48, 96, 192, 173, 119, 238, 241, 207, 179, 75, 
                          150, 1],
      champGaloisMult: function(a, b){  // MULTIPLICATION IN GALOIS FIELD GF(2^8)
        if(!a || !b) return 0;
        return this.aLogTab[(this.logTab[a] + this.logTab[b]) % 255];
      },
      champGaloisDoub: function(a, b){  // THE OPERATION a * 2^b IN GALOIS FIELD GF(2^8)
        if (!a) return 0;
        if (!b) return a;
        return this.aLogTab[(this.logTab[a] + b) % 255];
      },
      champGaloisSum: function(a, b){ // SUM IN GALOIS FIELD GF(2^8)
        return a ^ b;
      },
      selectIndex: function(dataCodeWordsCount, rectangular){ // CHOOSE THE GOOD INDEX FOR TABLES
        if ((dataCodeWordsCount<1 || dataCodeWordsCount>1558) && !rectangular) return -1;
        if ((dataCodeWordsCount<1 || dataCodeWordsCount>49) && rectangular)  return -1;
        
        var n = 0;
        if ( rectangular ) n = 24;
        
        while (this.dataCWCount[n] < dataCodeWordsCount) n++;
        return n;
      },
      encodeDataCodeWordsASCII: function(text) {
        var dataCodeWords = new Array();
        var n = 0, i, c;
        for (i=0; i<text.length; i++){
          c = text.charCodeAt(i);
          if (c > 127) {  
            dataCodeWords[n] = 235;
            c = c - 127;
            n++;
          } else if ((c>=48 && c<=57) && (i+1<text.length) && (text.charCodeAt(i+1)>=48 && text.charCodeAt(i+1)<=57)) {
            c = ((c - 48) * 10) + ((text.charCodeAt(i+1))-48);
            c += 130;
            i++;
          } else c++; 
          dataCodeWords[n] = c;
          n++;
        }
        return dataCodeWords;
      },
      addPadCW: function(tab, from, to){    
        if (from >= to) return ;
        tab[from] = 129;
        var r, i;
        for (i=from+1; i<to; i++){
          r = ((149 * (i+1)) % 253) + 1;
          tab[i] = (129 + r) % 254;
        }
      },
      calculSolFactorTable: function(solomonCWCount){ // CALCULATE THE REED SOLOMON FACTORS
        var g = new Array();
        var i, j;
        
        for (i=0; i<=solomonCWCount; i++) g[i] = 1;
        
        for(i = 1; i <= solomonCWCount; i++) {
          for(j = i - 1; j >= 0; j--) {
            g[j] = this.champGaloisDoub(g[j], i);  
            if(j > 0) g[j] = this.champGaloisSum(g[j], g[j-1]);
          }
        }
        return g;
      },
      addReedSolomonCW: function(nSolomonCW, coeffTab, nDataCW, dataTab, blocks){ // Add the Reed Solomon codewords
        var temp = 0;    
        var errorBlocks = nSolomonCW / blocks;
        var correctionCW = new Array();
        
        var i,j,k;
        for(k = 0; k < blocks; k++) {      
          for (i=0; i<errorBlocks; i++) correctionCW[i] = 0;
          
          for (i=k; i<nDataCW; i=i+blocks){    
            temp = this.champGaloisSum(dataTab[i], correctionCW[errorBlocks-1]);
            for (j=errorBlocks-1; j>=0; j--){     
              if ( !temp ) {
                correctionCW[j] = 0;
              } else { 
                correctionCW[j] = this.champGaloisMult(temp, coeffTab[j]);
              }
              if (j>0) correctionCW[j] = this.champGaloisSum(correctionCW[j-1], correctionCW[j]);
            }
          }
          // Renversement des blocs calcules
          j = nDataCW + k;
          for (i=errorBlocks-1; i>=0; i--){
            dataTab[j] = correctionCW[i];
            j=j+blocks;
          }
        }
        return dataTab;
      },
      getBits: function(entier){ // Transform integer to tab of bits
        var bits = new Array();
        for (var i=0; i<8; i++){
          bits[i] = entier & (128 >> i) ? 1 : 0;
        }
        return bits;
      },
      next: function(etape, totalRows, totalCols, codeWordsBits, datamatrix, assigned){ // Place codewords into the matrix
        var chr = 0; // Place of the 8st bit from the first character to [4][0]
        var row = 4;
        var col = 0;
        
        do {
          // Check for a special case of corner
          if((row == totalRows) && (col == 0)){
            this.patternShapeSpecial1(datamatrix, assigned, codeWordsBits[chr], totalRows, totalCols);  
            chr++;
          } else if((etape<3) && (row == totalRows-2) && (col == 0) && (totalCols%4 != 0)){
            this.patternShapeSpecial2(datamatrix, assigned, codeWordsBits[chr], totalRows, totalCols);
            chr++;
          } else if((row == totalRows-2) && (col == 0) && (totalCols%8 == 4)){
            this.patternShapeSpecial3(datamatrix, assigned, codeWordsBits[chr], totalRows, totalCols);
            chr++;
          }
          else if((row == totalRows+4) && (col == 2) && (totalCols%8 == 0)){
            this.patternShapeSpecial4(datamatrix, assigned, codeWordsBits[chr], totalRows, totalCols);
            chr++;
          }
          
          // Go up and right in the datamatrix
          do {
            if((row < totalRows) && (col >= 0) && (assigned[row][col]!=1)) {
              this.patternShapeStandard(datamatrix, assigned, codeWordsBits[chr], row, col, totalRows, totalCols);
              chr++;
            }
            row -= 2;
            col += 2;      
          } while ((row >= 0) && (col < totalCols));
          row += 1;
          col += 3;
          
          // Go down and left in the datamatrix
          do {
            if((row >= 0) && (col < totalCols) && (assigned[row][col]!=1)){
              this.patternShapeStandard(datamatrix, assigned, codeWordsBits[chr], row, col, totalRows, totalCols);
              chr++;
            }
            row += 2;
            col -= 2;
          } while ((row < totalRows) && (col >=0));
          row += 3;
          col += 1;
        } while ((row < totalRows) || (col < totalCols));
      },
      patternShapeStandard: function(datamatrix, assigned, bits, row, col, totalRows, totalCols){ // Place bits in the matrix (standard or special case)
        this.placeBitInDatamatrix(datamatrix, assigned, bits[0], row-2, col-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[1], row-2, col-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[2], row-1, col-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[3], row-1, col-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[4], row-1, col, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[5], row, col-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[6], row, col-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[7], row,  col, totalRows, totalCols);
      },  
      patternShapeSpecial1: function(datamatrix, assigned, bits, totalRows, totalCols ){
        this.placeBitInDatamatrix(datamatrix, assigned, bits[0], totalRows-1,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[1], totalRows-1,  1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[2], totalRows-1,  2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[3], 0, totalCols-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[4], 0, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[5], 1, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[6], 2, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[7], 3, totalCols-1, totalRows, totalCols);
      },
      patternShapeSpecial2: function(datamatrix, assigned, bits, totalRows, totalCols ){
        this.placeBitInDatamatrix(datamatrix, assigned, bits[0], totalRows-3,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[1], totalRows-2,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[2], totalRows-1,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[3], 0, totalCols-4, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[4], 0, totalCols-3, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[5], 0, totalCols-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[6], 0, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[7], 1, totalCols-1, totalRows, totalCols);
      },  
      patternShapeSpecial3: function(datamatrix, assigned, bits, totalRows, totalCols ){
        this.placeBitInDatamatrix(datamatrix, assigned, bits[0], totalRows-3,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[1], totalRows-2,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[2], totalRows-1,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[3], 0, totalCols-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[4], 0, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[5], 1, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[6], 2, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[7], 3, totalCols-1, totalRows, totalCols);
      },
      patternShapeSpecial4: function(datamatrix, assigned, bits, totalRows, totalCols ){
        this.placeBitInDatamatrix(datamatrix, assigned, bits[0], totalRows-1,  0, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[1], totalRows-1, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[2], 0, totalCols-3, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[3], 0, totalCols-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[4], 0, totalCols-1, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[5], 1, totalCols-3, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[6], 1, totalCols-2, totalRows, totalCols);
        this.placeBitInDatamatrix(datamatrix, assigned, bits[7], 1, totalCols-1, totalRows, totalCols);
      },
      placeBitInDatamatrix: function(datamatrix, assigned, bit, row, col, totalRows, totalCols){ // Put a bit into the matrix
        if (row < 0) {
          row += totalRows;
          col += 4 - ((totalRows+4)%8);
        }
        if (col < 0) {
          col += totalCols;
          row += 4 - ((totalCols+4)%8);
        }
        if (assigned[row][col] != 1) {
          datamatrix[row][col] = bit;
          assigned[row][col] = 1;
        }
      },
      addFinderPattern: function(datamatrix, rowsRegion, colsRegion, rowsRegionCW, colsRegionCW){ // Add the finder pattern
        var totalRowsCW = (rowsRegionCW+2) * rowsRegion;
        var totalColsCW = (colsRegionCW+2) * colsRegion;
        
        var datamatrixTemp = new Array();
        datamatrixTemp[0] = new Array();
        for (var j=0; j<totalColsCW+2; j++){
          datamatrixTemp[0][j] = 0;
        }
        for (var i=0; i<totalRowsCW; i++){
          datamatrixTemp[i+1] = new Array();
          datamatrixTemp[i+1][0] = 0;
          datamatrixTemp[i+1][totalColsCW+1] = 0;
          for (var j=0; j<totalColsCW; j++){
            if (i%(rowsRegionCW+2) == 0){
              if (j%2 == 0){
                datamatrixTemp[i+1][j+1] = 1;
              } else { 
                datamatrixTemp[i+1][j+1] = 0;
              }
            } else if (i%(rowsRegionCW+2) == rowsRegionCW+1){ 
              datamatrixTemp[i+1][j+1] = 1;
            } else if (j%(colsRegionCW+2) == colsRegionCW+1){
              if (i%2 == 0){
                datamatrixTemp[i+1][j+1] = 0;
              } else {
                datamatrixTemp[i+1][j+1] = 1;
              }
            } else if (j%(colsRegionCW+2) == 0){ 
              datamatrixTemp[i+1][j+1] = 1;
            } else{
              datamatrixTemp[i+1][j+1] = 0;
              datamatrixTemp[i+1][j+1] = datamatrix[i-1-(2*(parseInt(i/(rowsRegionCW+2))))][j-1-(2*(parseInt(j/(colsRegionCW+2))))];
            }
          }
        }
        datamatrixTemp[totalRowsCW+1] = new Array();
        for (var j=0; j<totalColsCW+2; j++){
          datamatrixTemp[totalRowsCW+1][j] = 0;
        }
        return datamatrixTemp;
      },
      getDigit: function(text, rectangular){
        var dataCodeWords = this.encodeDataCodeWordsASCII(text); // Code the text in the ASCII mode
        var dataCWCount = dataCodeWords.length;
        var index = this.selectIndex(dataCWCount, rectangular); // Select the index for the data tables
        var totalDataCWCount = this.dataCWCount[index]; // Number of data CW
        var solomonCWCount = this.solomonCWCount[index]; // Number of Reed Solomon CW 
        var totalCWCount = totalDataCWCount + solomonCWCount; // Number of CW      
        var rowsTotal = this.lengthRows[index]; // Size of symbol
        var colsTotal = this.lengthCols[index];
        var rowsRegion = this.regionRows[index]; // Number of region
        var colsRegion = this.regionCols[index];
        var rowsRegionCW = this.dataRegionRows[index];
        var colsRegionCW = this.dataRegionCols[index];
        var rowsLengthMatrice = rowsTotal-2*rowsRegion; // Size of matrice data
        var colsLengthMatrice = colsTotal-2*colsRegion;
        var blocks = this.interleavedBlocks[index];  // Number of Reed Solomon blocks
        var errorBlocks = (solomonCWCount / blocks);
        
        this.addPadCW(dataCodeWords, dataCWCount, totalDataCWCount); // Add codewords pads
        
        var g = this.calculSolFactorTable(errorBlocks); // Calculate correction coefficients
        
        this.addReedSolomonCW(solomonCWCount, g, totalDataCWCount, dataCodeWords, blocks); // Add Reed Solomon codewords
        
        var codeWordsBits = new Array(); // Calculte bits from codewords
        for (var i=0; i<totalCWCount; i++){
          codeWordsBits[i] = this.getBits(dataCodeWords[i]);
        }
        
        var datamatrix = new Array(); // Put data in the matrix
        var assigned = new Array();
        
        for (var i=0; i<colsLengthMatrice; i++){
          datamatrix[i] = new Array();
          assigned[i] = new Array();
        }
        
        // Add the bottom-right corner if needed
        if ( ((rowsLengthMatrice * colsLengthMatrice) % 8) == 4) {
          datamatrix[rowsLengthMatrice-2][colsLengthMatrice-2] = 1;
          datamatrix[rowsLengthMatrice-1][colsLengthMatrice-1] = 1;
          datamatrix[rowsLengthMatrice-1][colsLengthMatrice-2] = 0;
          datamatrix[rowsLengthMatrice-2][colsLengthMatrice-1] = 0;
          assigned[rowsLengthMatrice-2][colsLengthMatrice-2] = 1;
          assigned[rowsLengthMatrice-1][colsLengthMatrice-1] = 1;
          assigned[rowsLengthMatrice-1][colsLengthMatrice-2] = 1;
          assigned[rowsLengthMatrice-2][colsLengthMatrice-1] = 1;
        }
        
        // Put the codewords into the matrix
        this.next(0,rowsLengthMatrice,colsLengthMatrice, codeWordsBits, datamatrix, assigned);
        
        // Add the finder pattern
        datamatrix = this.addFinderPattern(datamatrix, rowsRegion, colsRegion, rowsRegionCW, colsRegionCW);
        
        return datamatrix;
      }
    },
    // little endian convertor
    lec:{
      // convert an int
      cInt: function(value, byteCount){
        var le = '';
        for(var i=0; i<byteCount; i++){
          le += String.fromCharCode(value & 0xFF);
          value = value >> 8;
        }
        return le;
      },
      // return a byte string from rgb values 
      cRgb: function(r,g,b){
        return String.fromCharCode(b) + String.fromCharCode(g) + String.fromCharCode(r);
      },
      // return a byte string from a hex string color
      cHexColor: function(hex){
        var v = parseInt('0x' + hex.substr(1));
        var b = v & 0xFF;
        v = v >> 8;
        var g = v & 0xFF;
        var r = v >> 8;
        return(this.cRgb(r,g,b));
      }
    },
    hexToRGB: function(hex){
      var v = parseInt('0x' + hex.substr(1));
      var b = v & 0xFF;
      v = v >> 8;
      var g = v & 0xFF;
      var r = v >> 8;
      return({r:r,g:g,b:b});
    },
    // test if a string is a hexa string color (like #FF0000)
    isHexColor: function (value){
      var r = new RegExp("#[0-91-F]", "gi");
      return  value.match(r);
    },
    // encode data in base64
    base64Encode: function(value) {
      var r = '', c1, c2, c3, b1, b2, b3, b4;
      var k = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
      var i = 0;
      while (i < value.length) {
        c1 = value.charCodeAt(i++);
        c2 = value.charCodeAt(i++);
        c3 = value.charCodeAt(i++);
        b1 = c1 >> 2;
        b2 = ((c1 & 3) << 4) | (c2 >> 4);
        b3 = ((c2 & 15) << 2) | (c3 >> 6);
        b4 = c3 & 63;
        if (isNaN(c2)) b3 = b4 = 64;
        else if (isNaN(c3)) b4 = 64;
        r += k.charAt(b1) + k.charAt(b2) + k.charAt(b3) + k.charAt(b4);
      }
      return r;
    },
    // convert a bit string to an array of array of bit char
    bitStringTo2DArray: function( digit ){
      var d = []; d[0] = [];
      for(var i=0; i<digit.length; i++) d[0][i] = digit.charAt(i);
      return(d);
    },
    // clear jQuery Target
    resize: function($container, w){
      $container
        .css("padding", "0px")
        .css("overflow", "auto")
        .css("width", w + "px")
        .html("");
        return $container;
    },
    // bmp barcode renderer
    digitToBmpRenderer: function($container, settings, digit, hri, mw, mh){
      var lines = digit.length;
      var columns = digit[0].length;
      var i = 0;
      var c0 = this.isHexColor(settings.bgColor) ? this.lec.cHexColor(settings.bgColor) : this.lec.cRgb(255,255,255);
      var c1 = this.isHexColor(settings.color) ? this.lec.cHexColor(settings.color) : this.lec.cRgb(0,0,0);
      var bar0 = '';
      var bar1 = '';
        
      // create one bar 0 and 1 of "mw" byte length 
      for(i=0; i<mw; i++){
        bar0 += c0;
        bar1 += c1;
      }
      var bars = '';
    
      var padding = (4 - ((mw * columns * 3) % 4)) % 4; // Padding for 4 byte alignment ("* 3" come from "3 byte to color R, G and B")
      var dataLen = (mw * columns + padding) * mh * lines;
    
      var pad = '';
      for(i=0; i<padding; i++) pad += '\0';
      
      // Bitmap header
      var bmp = 'BM' +                            // Magic Number
                this.lec.cInt(54 + dataLen, 4) +  // Size of Bitmap size (header size + data len)
                '\0\0\0\0' +                      // Unused
                this.lec.cInt(54, 4) +            // The offset where the bitmap data (pixels) can be found
                this.lec.cInt(40, 4) +            // The number of bytes in the header (from this point).
                this.lec.cInt(mw * columns, 4) +  // width
                this.lec.cInt(mh * lines, 4) +    // height
                this.lec.cInt(1, 2) +             // Number of color planes being used
                this.lec.cInt(24, 2) +            // The number of bits/pixel
                '\0\0\0\0' +                      // BI_RGB, No compression used
                this.lec.cInt(dataLen, 4) +       // The size of the raw BMP data (after this header)
                this.lec.cInt(2835, 4) +          // The horizontal resolution of the image (pixels/meter)
                this.lec.cInt(2835, 4) +          // The vertical resolution of the image (pixels/meter)
                this.lec.cInt(0, 4) +             // Number of colors in the palette
                this.lec.cInt(0, 4);              // Means all colors are important
      // Bitmap Data
      for(var y=lines-1; y>=0; y--){
        var line = '';
        for (var x=0; x<columns; x++){
          line += digit[y][x] == '0' ? bar0 : bar1;
        }
        line += pad;
        for(var k=0; k<mh; k++){
          bmp += line;
        }
      }
      // set bmp image to the container
      var object = document.createElement('object');
      object.setAttribute('type', 'image/bmp');
      object.setAttribute('data', 'data:image/bmp;base64,'+ this.base64Encode(bmp));
      this.resize($container, mw * columns + padding).append(object);
                      
    },
    // bmp 1D barcode renderer
    digitToBmp: function($container, settings, digit, hri){
      var w = barcode.intval(settings.barWidth);
      var h = barcode.intval(settings.barHeight);
      this.digitToBmpRenderer($container, settings, this.bitStringTo2DArray(digit), hri, w, h);
    },
    // bmp 2D barcode renderer
    digitToBmp2D: function($container, settings, digit, hri){
      var s = barcode.intval(settings.moduleSize);
      this.digitToBmpRenderer($container, settings, digit, hri, s, s);
    },
    // css barcode renderer
    digitToCssRenderer : function($container, settings, digit, hri, mw, mh){
      var lines = digit.length;
      var columns = digit[0].length;
      var content = "";
      var bar0 = "<div style=\"float: left; font-size: 0px; background-color: " + settings.bgColor + "; height: " + mh + "px; width: &Wpx\"></div>";    
      var bar1 = "<div style=\"float: left; font-size: 0px; width:0; border-left: &Wpx solid " + settings.color + "; height: " + mh + "px;\"></div>";
  
      var len, current;
      for(var y=0; y<lines; y++){
        len = 0;
        current = digit[y][0];
        for (var x=0; x<columns; x++){
          if ( current == digit[y][x] ) {
            len++;
          } else {
            content += (current == '0' ? bar0 : bar1).replace("&W", len * mw);
            current = digit[y][x];
            len=1;
          }
        }
        if (len > 0){
          content += (current == '0' ? bar0 : bar1).replace("&W", len * mw);
        }
      }  
      if (settings.showHRI){
        content += "<div style=\"clear:both; width: 100%; background-color: " + settings.bgColor + "; color: " + settings.color + "; text-align: center; font-size: " + settings.fontSize + "px; margin-top: " + settings.marginHRI + "px;\">"+hri+"</div>";
      }
      this.resize($container, mw * columns).html(content);
    },
    // css 1D barcode renderer  
    digitToCss: function($container, settings, digit, hri){
      var w = barcode.intval(settings.barWidth);
      var h = barcode.intval(settings.barHeight);
      this.digitToCssRenderer($container, settings, this.bitStringTo2DArray(digit), hri, w, h);
    },
    // css 2D barcode renderer
    digitToCss2D: function($container, settings, digit, hri){
      var s = barcode.intval(settings.moduleSize);
      this.digitToCssRenderer($container, settings, digit, hri, s, s);
    },
    // svg barcode renderer
    digitToSvgRenderer: function($container, settings, digit, hri, mw, mh){
      var lines = digit.length;
      var columns = digit[0].length;
      
      var width = mw * columns;
      var height = mh * lines;
      if (settings.showHRI){
        var fontSize = barcode.intval(settings.fontSize);
        height += barcode.intval(settings.marginHRI) + fontSize;
      }
      
      // svg header
      var svg = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="' + width + '" height="' + height + '">';
      
      // background
      svg += '<rect width="' +  width + '" height="' + height + '" x="0" y="0" fill="' + settings.bgColor + '" />';
      
      var bar1 = '<rect width="&W" height="' + mh + '" x="&X" y="&Y" fill="' + settings.color + '" />';
      
      var len, current;
      for(var y=0; y<lines; y++){
        len = 0;
        current = digit[y][0];
        for (var x=0; x<columns; x++){
          if ( current == digit[y][x] ) {
            len++;
          } else {
            if (current == '1') {
              svg += bar1.replace("&W", len * mw).replace("&X", (x - len) * mw).replace("&Y", y * mh);
            }
            current = digit[y][x];
            len=1;
          }
        }
        if ( (len > 0) && (current == '1') ){
          svg += bar1.replace("&W", len * mw).replace("&X", (columns - len) * mw).replace("&Y", y * mh);
        }
      }
      
      if (settings.showHRI){
        svg += '<g transform="translate(' + Math.floor(width/2) + ' 0)">';
        svg += '<text y="' + (height - Math.floor(fontSize/2)) + '" text-anchor="middle" style="font-family: Arial; font-size: ' + fontSize + 'px;" fill="' + settings.color + '">' + hri + '</text>';
        svg += '</g>';
      }
      // svg footer
      svg += '</svg>';
      
      // create a dom object, flush container and add object to the container
      var object = document.createElement('object');
      object.setAttribute('type', 'image/svg+xml');
      object.setAttribute('data', 'data:image/svg+xml,'+ svg);
      this.resize($container, width).append(object);
    },
    // svg 1D barcode renderer
    digitToSvg: function($container, settings, digit, hri){
      var w = barcode.intval(settings.barWidth);
      var h = barcode.intval(settings.barHeight);
      this.digitToSvgRenderer($container, settings, this.bitStringTo2DArray(digit), hri, w, h);
    },
    // svg 2D barcode renderer
    digitToSvg2D: function($container, settings, digit, hri){
      var s = barcode.intval(settings.moduleSize);
      this.digitToSvgRenderer($container, settings, digit, hri, s, s);
    },
    
    // canvas barcode renderer
    digitToCanvasRenderer : function($container, settings, digit, hri, xi, yi, mw, mh){
      var canvas = $container.get(0);
      if ( !canvas || !canvas.getContext ) return; // not compatible
      
      var lines = digit.length;
      var columns = digit[0].length;
      
      var ctx = canvas.getContext('2d');
      ctx.lineWidth = 1;
      ctx.lineCap = 'butt';
      ctx.fillStyle = settings.bgColor;
      ctx.fillRect (xi, yi, columns * mw, lines * mh);
      
      ctx.fillStyle = settings.color;
      
      for(var y=0; y<lines; y++){
        var len = 0;
        var current = digit[y][0];
        for(var x=0; x<columns; x++){
          if (current == digit[y][x]) {
            len++;
          } else {
            if (current == '1'){
              ctx.fillRect (xi + (x - len) * mw, yi + y * mh, mw * len, mh);
            }
            current = digit[y][x];
            len=1;
          }
        }
        if ( (len > 0) && (current == '1') ){
          ctx.fillRect (xi + (columns - len) * mw, yi + y * mh, mw * len, mh);
        }
      }
      if (settings.showHRI){
        var dim = ctx.measureText(hri);
        ctx.fillText(hri, xi + Math.floor((columns * mw - dim.width)/2), yi + lines * mh + settings.fontSize + settings.marginHRI);
      }
    },
    // canvas 1D barcode renderer
    digitToCanvas: function($container, settings, digit, hri){
      var w  = barcode.intval(settings.barWidth);
      var h = barcode.intval(settings.barHeight);
      var x = barcode.intval(settings.posX);
      var y = barcode.intval(settings.posY);
      this.digitToCanvasRenderer($container, settings, this.bitStringTo2DArray(digit), hri, x, y, w, h);
    },
    // canvas 2D barcode renderer
    digitToCanvas2D: function($container, settings, digit, hri){
      var s = barcode.intval(settings.moduleSize);
      var x = barcode.intval(settings.posX);
      var y = barcode.intval(settings.posY);
      this.digitToCanvasRenderer($container, settings, digit, hri, x, y, s, s);
    }
  };
  
  $.fn.extend({
    barcode: function(datas, type, settings) {
      var digit = "",
          hri   = "",
          code  = "",
          crc   = true,
          rect  = false,
          b2d   = false;
      
      if (typeof(datas) == "string"){
        code = datas;
      } else if (typeof(datas) == "object"){
        code = typeof(datas.code) == "string" ? datas.code : "";
        crc = typeof(datas.crc) != "undefined" ? datas.crc : true;
        rect = typeof(datas.rect) != "undefined" ? datas.rect : false;
      }
      if (code == "") return(false);
      
      if (typeof(settings) == "undefined") settings = [];
      for(var name in barcode.settings){
        if (settings[name] == undefined) settings[name] = barcode.settings[name];
      }
      
      switch(type){
        case "std25":
        case "int25":
          digit = barcode.i25.getDigit(code, crc, type);
          hri = barcode.i25.compute(code, crc, type);
        break;
        case "ean8":
        case "ean13":
          digit = barcode.ean.getDigit(code, type);
          hri = barcode.ean.compute(code, type);
        break;
        case "upc":
          digit = barcode.upc.getDigit(code);
          hri = barcode.upc.compute(code);
        break;
        case "code11":
          digit = barcode.code11.getDigit(code);
          hri = code;
        break;
        case "code39":
          digit = barcode.code39.getDigit(code);
          hri = code;
        break;
        case "code93":
          digit = barcode.code93.getDigit(code, crc);
          hri = code;
        break;
        case "code128":
          digit = barcode.code128.getDigit(code);
          hri = code;
        break;
        case "codabar":
          digit = barcode.codabar.getDigit(code);
          hri = code;
        break;
        case "msi":
          digit = barcode.msi.getDigit(code, crc);
          hri = barcode.msi.compute(code, crc);
        break;
        case "datamatrix":   
          digit = barcode.datamatrix.getDigit(code, rect);
          hri = code;
          b2d = true;
        break; 
      }
      if (digit.length == 0) return($(this));
      
      // Quiet Zone
      if ( !b2d && settings.addQuietZone) digit = "0000000000" + digit + "0000000000";
      
      var $this = $(this);
      var fname = 'digitTo' + settings.output.charAt(0).toUpperCase() + settings.output.substr(1) + (b2d ? '2D' : '');
      if (typeof(barcode[fname]) == 'function') {
        barcode[fname]($this, settings, digit, hri);
      }
      
      return($this);
    }
  });

}(jQuery));
/*!
* jquery.base64.js 0.1 - https://github.com/yckart/jquery.base64.js
* Makes Base64 en & -decoding simpler as it is.
*
* Based upon: https://gist.github.com/Yaffle/1284012
*
* Copyright (c) 2012 Yannick Albert (http://yckart.com)
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php).
* 2013/02/10
**/
; (function ($) {

    var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
        a256 = '',
        r64 = [256],
        r256 = [256],
        i = 0;

    var UTF8 = {

        /**
        * Encode multi-byte Unicode string into utf-8 multiple single-byte characters
        * (BMP / basic multilingual plane only)
        *
        * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
        *
        * @param {String} strUni Unicode string to be encoded as UTF-8
        * @returns {String} encoded string
        */
        encode: function (strUni) {
            // use regular expressions & String.replace callback function for better efficiency
            // than procedural approaches
            var strUtf = strUni.replace(/[\u0080-\u07ff]/g, // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
            function (c) {
                var cc = c.charCodeAt(0);
                return String.fromCharCode(0xc0 | cc >> 6, 0x80 | cc & 0x3f);
            })
            .replace(/[\u0800-\uffff]/g, // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
            function (c) {
                var cc = c.charCodeAt(0);
                return String.fromCharCode(0xe0 | cc >> 12, 0x80 | cc >> 6 & 0x3F, 0x80 | cc & 0x3f);
            });
            return strUtf;
        },

        /**
        * Decode utf-8 encoded string back into multi-byte Unicode characters
        *
        * @param {String} strUtf UTF-8 string to be decoded back to Unicode
        * @returns {String} decoded string
        */
        decode: function (strUtf) {
            // note: decode 3-byte chars first as decoded 2-byte strings could appear to be 3-byte char!
            var strUni = strUtf.replace(/[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g, // 3-byte chars
            function (c) { // (note parentheses for precence)
                var cc = ((c.charCodeAt(0) & 0x0f) << 12) | ((c.charCodeAt(1) & 0x3f) << 6) | (c.charCodeAt(2) & 0x3f);
                return String.fromCharCode(cc);
            })
            .replace(/[\u00c0-\u00df][\u0080-\u00bf]/g, // 2-byte chars
            function (c) { // (note parentheses for precence)
                var cc = (c.charCodeAt(0) & 0x1f) << 6 | c.charCodeAt(1) & 0x3f;
                return String.fromCharCode(cc);
            });
            return strUni;
        }
    };

    while (i < 256) {
        var c = String.fromCharCode(i);
        a256 += c;
        r256[i] = i;
        r64[i] = b64.indexOf(c);
        ++i;
    }

    function code(s, discard, alpha, beta, w1, w2) {
        s = String(s);
        var buffer = 0,
            i = 0,
            length = s.length,
            result = '',
            bitsInBuffer = 0;

        while (i < length) {
            var c = s.charCodeAt(i);
            c = c < 256 ? alpha[c] : -1;

            buffer = (buffer << w1) + c;
            bitsInBuffer += w1;

            while (bitsInBuffer >= w2) {
                bitsInBuffer -= w2;
                var tmp = buffer >> bitsInBuffer;
                result += beta.charAt(tmp);
                buffer ^= tmp << bitsInBuffer;
            }
            ++i;
        }
        if (!discard && bitsInBuffer > 0) result += beta.charAt(buffer << (w2 - bitsInBuffer));
        return result;
    }

    var Plugin = $.base64 = function (dir, input, encode) {
        return input ? Plugin[dir](input, encode) : dir ? null : this;
    };

    Plugin.btoa = Plugin.encode = function (plain, utf8encode) {
        plain = Plugin.raw === false || Plugin.utf8encode || utf8encode ? UTF8.encode(plain) : plain;
        plain = code(plain, false, r256, b64, 8, 6);
        return plain + '===='.slice((plain.length % 4) || 4);
    };

    Plugin.atob = Plugin.decode = function (coded, utf8decode) {
        coded = String(coded).split('=');
        var i = coded.length;
        do {
            --i;
            coded[i] = code(coded[i], true, r64, a256, 6, 8);
        } while (i > 0);
        coded = coded.join('');
        return Plugin.raw === false || Plugin.utf8decode || utf8decode ? UTF8.decode(coded) : coded;
    };
} (jQuery));
function isCanvasSupported(){
  var elem = document.createElement('canvas');
  return !!(elem.getContext && elem.getContext('2d'));
}

if (isCanvasSupported()) {

    /*
    * Javascript EXIF Reader - jQuery plugin 0.1.3
    * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/
    * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt]
    */

    /*
    * I added three functions for read EXIF from dataURL
    * - getImageDataFromDataURL
    * - getDataFromDataURL
    * - jQuery.fn.exifLoadFromDataURL
    * 
    * http://orientation.gokercebeci.com 
    * @gokercebeci
    */

    (function () {


        var BinaryFile = function (strData, iDataOffset, iDataLength) {
            var data = strData;
            var dataOffset = iDataOffset || 0;
            var dataLength = 0;

            this.getRawData = function () {
                return data;
            }

            if (typeof strData == "string") {
                dataLength = iDataLength || data.length;

                this.getByteAt = function (iOffset) {
                    return data.charCodeAt(iOffset + dataOffset) & 0xFF;
                }
            } else if (typeof strData == "unknown") {
                dataLength = iDataLength || IEBinary_getLength(data);

                this.getByteAt = function (iOffset) {
                    return IEBinary_getByteAt(data, iOffset + dataOffset);
                }
            }

            this.getLength = function () {
                return dataLength;
            }

            this.getSByteAt = function (iOffset) {
                var iByte = this.getByteAt(iOffset);
                if (iByte > 127)
                    return iByte - 256;
                else
                    return iByte;
            }

            this.getShortAt = function (iOffset, bBigEndian) {
                var iShort = bBigEndian ?
                    (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1)
                    : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset)
                if (iShort < 0)
                    iShort += 65536;
                return iShort;
            }
            this.getSShortAt = function (iOffset, bBigEndian) {
                var iUShort = this.getShortAt(iOffset, bBigEndian);
                if (iUShort > 32767)
                    return iUShort - 65536;
                else
                    return iUShort;
            }
            this.getLongAt = function (iOffset, bBigEndian) {
                var iByte1 = this.getByteAt(iOffset),
                    iByte2 = this.getByteAt(iOffset + 1),
                    iByte3 = this.getByteAt(iOffset + 2),
                    iByte4 = this.getByteAt(iOffset + 3);

                var iLong = bBigEndian ?
                    (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4
                    : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1;
                if (iLong < 0)
                    iLong += 4294967296;
                return iLong;
            }
            this.getSLongAt = function (iOffset, bBigEndian) {
                var iULong = this.getLongAt(iOffset, bBigEndian);
                if (iULong > 2147483647)
                    return iULong - 4294967296;
                else
                    return iULong;
            }
            this.getStringAt = function (iOffset, iLength) {
                var aStr = [];
                for (var i = iOffset, j = 0; i < iOffset + iLength; i++, j++) {
                    aStr[j] = String.fromCharCode(this.getByteAt(i));
                }
                return aStr.join("");
            }

            this.getCharAt = function (iOffset) {
                return String.fromCharCode(this.getByteAt(iOffset));
            }
            this.toBase64 = function () {
                return window.btoa(data);
            }
            this.fromBase64 = function (strBase64) {
                data = window.atob(strBase64);
            }
        }


        var BinaryAjax = (function () {

            function createRequest() {
                var oHTTP = null;
                if (window.XMLHttpRequest) {
                    oHTTP = new XMLHttpRequest();
                } else if (window.ActiveXObject) {
                    oHTTP = new ActiveXObject("Microsoft.XMLHTTP");
                }
                return oHTTP;
            }

            function getHead(strURL, fncCallback, fncError) {
                var oHTTP = createRequest();
                if (oHTTP) {
                    if (fncCallback) {
                        if (typeof (oHTTP.onload) != "undefined") {
                            oHTTP.onload = function () {
                                if (oHTTP.status == "200") {
                                    fncCallback(this);
                                } else {
                                    if (fncError)
                                        fncError();
                                }
                                oHTTP = null;
                            };
                        } else {
                            oHTTP.onreadystatechange = function () {
                                if (oHTTP.readyState == 4) {
                                    if (oHTTP.status == "200") {
                                        fncCallback(this);
                                    } else {
                                        if (fncError)
                                            fncError();
                                    }
                                    oHTTP = null;
                                }
                            };
                        }
                    }
                    oHTTP.open("HEAD", strURL, true);
                    oHTTP.send(null);
                } else {
                    if (fncError)
                        fncError();
                }
            }

            function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) {
                var oHTTP = createRequest();
                if (oHTTP) {

                    var iDataOffset = 0;
                    if (aRange && !bAcceptRanges) {
                        iDataOffset = aRange[0];
                    }
                    var iDataLen = 0;
                    if (aRange) {
                        iDataLen = aRange[1] - aRange[0] + 1;
                    }

                    if (fncCallback) {
                        if (typeof (oHTTP.onload) != "undefined") {
                            oHTTP.onload = function () {

                                if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
                                    this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen);
                                    this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
                                    fncCallback(this);
                                } else {
                                    if (fncError)
                                        fncError();
                                }
                                oHTTP = null;
                            };
                        } else {
                            oHTTP.onreadystatechange = function () {
                                if (oHTTP.readyState == 4) {
                                    if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") {
                                        this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen);
                                        this.fileSize = iFileSize || this.getResponseHeader("Content-Length");
                                        fncCallback(this);
                                    } else {
                                        if (fncError)
                                            fncError();
                                    }
                                    oHTTP = null;
                                }
                            };
                        }
                    }
                    oHTTP.open("GET", strURL, true);

                    if (oHTTP.overrideMimeType)
                        oHTTP.overrideMimeType('text/plain; charset=x-user-defined');

                    if (aRange && bAcceptRanges) {
                        oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]);
                    }

                    oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT");

                    oHTTP.send(null);
                } else {
                    if (fncError)
                        fncError();
                }
            }

            return function (strURL, fncCallback, fncError, aRange) {

                if (aRange) {
                    getHead(
                        strURL,
                        function (oHTTP) {
                            var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"), 10);
                            var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges");

                            var iStart, iEnd;
                            iStart = aRange[0];
                            if (aRange[0] < 0)
                                iStart += iLength;
                            iEnd = iStart + aRange[1] - 1;

                            sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength);
                        }
                );

                } else {
                    sendRequest(strURL, fncCallback, fncError);
                }
            }

        } ());


        // document.write(
            // "<script type='text/vbscript'>\r\n"
            // + "Function IEBinary_getByteAt(strBinary, iOffset)\r\n"
            // + "	IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n"
            // + "End Function\r\n"
            // + "Function IEBinary_getLength(strBinary)\r\n"
            // + "	IEBinary_getLength = LenB(strBinary)\r\n"
            // + "End Function\r\n"
            // + "</script>\r\n"
            // );


        var EXIF = {};

        (function () {

            var bDebug = false;

            EXIF.Tags = {

                // version tags
                0x9000: "ExifVersion", // EXIF version
                0xA000: "FlashpixVersion", // Flashpix format version

                // colorspace tags
                0xA001: "ColorSpace", // Color space information tag

                // image configuration
                0xA002: "PixelXDimension", // Valid width of meaningful image
                0xA003: "PixelYDimension", // Valid height of meaningful image
                0x9101: "ComponentsConfiguration", // Information about channels
                0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel

                // user information
                0x927C: "MakerNote", // Any desired information written by the manufacturer
                0x9286: "UserComment", // Comments by user

                // related file
                0xA004: "RelatedSoundFile", // Name of related sound file

                // date and time
                0x9003: "DateTimeOriginal", // Date and time when the original image was generated
                0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally
                0x9290: "SubsecTime", // Fractions of seconds for DateTime
                0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal
                0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized

                // picture-taking conditions
                0x829A: "ExposureTime", // Exposure time (in seconds)
                0x829D: "FNumber", // F number
                0x8822: "ExposureProgram", // Exposure program
                0x8824: "SpectralSensitivity", // Spectral sensitivity
                0x8827: "ISOSpeedRatings", // ISO speed rating
                0x8828: "OECF", // Optoelectric conversion factor
                0x9201: "ShutterSpeedValue", // Shutter speed
                0x9202: "ApertureValue", // Lens aperture
                0x9203: "BrightnessValue", // Value of brightness
                0x9204: "ExposureBias", // Exposure bias
                0x9205: "MaxApertureValue", // Smallest F number of lens
                0x9206: "SubjectDistance", // Distance to subject in meters
                0x9207: "MeteringMode", // Metering mode
                0x9208: "LightSource", // Kind of light source
                0x9209: "Flash", // Flash status
                0x9214: "SubjectArea", // Location and area of main subject
                0x920A: "FocalLength", // Focal length of the lens in mm
                0xA20B: "FlashEnergy", // Strobe energy in BCPS
                0xA20C: "SpatialFrequencyResponse", // 
                0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
                0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
                0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
                0xA214: "SubjectLocation", // Location of subject in image
                0xA215: "ExposureIndex", // Exposure index selected on camera
                0xA217: "SensingMethod", // Image sensor type
                0xA300: "FileSource", // Image source (3 == DSC)
                0xA301: "SceneType", // Scene type (1 == directly photographed)
                0xA302: "CFAPattern", // Color filter array geometric pattern
                0xA401: "CustomRendered", // Special processing
                0xA402: "ExposureMode", // Exposure mode
                0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual
                0xA404: "DigitalZoomRation", // Digital zoom ratio
                0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm)
                0xA406: "SceneCaptureType", // Type of scene
                0xA407: "GainControl", // Degree of overall image gain adjustment
                0xA408: "Contrast", // Direction of contrast processing applied by camera
                0xA409: "Saturation", // Direction of saturation processing applied by camera
                0xA40A: "Sharpness", // Direction of sharpness processing applied by camera
                0xA40B: "DeviceSettingDescription", // 
                0xA40C: "SubjectDistanceRange", // Distance to subject

                // other tags
                0xA005: "InteroperabilityIFDPointer",
                0xA420: "ImageUniqueID"		// Identifier assigned uniquely to each image
            };

            EXIF.TiffTags = {
                0x0100: "ImageWidth",
                0x0101: "ImageHeight",
                0x8769: "ExifIFDPointer",
                0x8825: "GPSInfoIFDPointer",
                0xA005: "InteroperabilityIFDPointer",
                0x0102: "BitsPerSample",
                0x0103: "Compression",
                0x0106: "PhotometricInterpretation",
                0x0112: "Orientation",
                0x0115: "SamplesPerPixel",
                0x011C: "PlanarConfiguration",
                0x0212: "YCbCrSubSampling",
                0x0213: "YCbCrPositioning",
                0x011A: "XResolution",
                0x011B: "YResolution",
                0x0128: "ResolutionUnit",
                0x0111: "StripOffsets",
                0x0116: "RowsPerStrip",
                0x0117: "StripByteCounts",
                0x0201: "JPEGInterchangeFormat",
                0x0202: "JPEGInterchangeFormatLength",
                0x012D: "TransferFunction",
                0x013E: "WhitePoint",
                0x013F: "PrimaryChromaticities",
                0x0211: "YCbCrCoefficients",
                0x0214: "ReferenceBlackWhite",
                0x0132: "DateTime",
                0x010E: "ImageDescription",
                0x010F: "Make",
                0x0110: "Model",
                0x0131: "Software",
                0x013B: "Artist",
                0x8298: "Copyright"
            }

            EXIF.GPSTags = {
                0x0000: "GPSVersionID",
                0x0001: "GPSLatitudeRef",
                0x0002: "GPSLatitude",
                0x0003: "GPSLongitudeRef",
                0x0004: "GPSLongitude",
                0x0005: "GPSAltitudeRef",
                0x0006: "GPSAltitude",
                0x0007: "GPSTimeStamp",
                0x0008: "GPSSatellites",
                0x0009: "GPSStatus",
                0x000A: "GPSMeasureMode",
                0x000B: "GPSDOP",
                0x000C: "GPSSpeedRef",
                0x000D: "GPSSpeed",
                0x000E: "GPSTrackRef",
                0x000F: "GPSTrack",
                0x0010: "GPSImgDirectionRef",
                0x0011: "GPSImgDirection",
                0x0012: "GPSMapDatum",
                0x0013: "GPSDestLatitudeRef",
                0x0014: "GPSDestLatitude",
                0x0015: "GPSDestLongitudeRef",
                0x0016: "GPSDestLongitude",
                0x0017: "GPSDestBearingRef",
                0x0018: "GPSDestBearing",
                0x0019: "GPSDestDistanceRef",
                0x001A: "GPSDestDistance",
                0x001B: "GPSProcessingMethod",
                0x001C: "GPSAreaInformation",
                0x001D: "GPSDateStamp",
                0x001E: "GPSDifferential"
            }

            EXIF.StringValues = {
                ExposureProgram: {
                    0: "Not defined",
                    1: "Manual",
                    2: "Normal program",
                    3: "Aperture priority",
                    4: "Shutter priority",
                    5: "Creative program",
                    6: "Action program",
                    7: "Portrait mode",
                    8: "Landscape mode"
                },
                MeteringMode: {
                    0: "Unknown",
                    1: "Average",
                    2: "CenterWeightedAverage",
                    3: "Spot",
                    4: "MultiSpot",
                    5: "Pattern",
                    6: "Partial",
                    255: "Other"
                },
                LightSource: {
                    0: "Unknown",
                    1: "Daylight",
                    2: "Fluorescent",
                    3: "Tungsten (incandescent light)",
                    4: "Flash",
                    9: "Fine weather",
                    10: "Cloudy weather",
                    11: "Shade",
                    12: "Daylight fluorescent (D 5700 - 7100K)",
                    13: "Day white fluorescent (N 4600 - 5400K)",
                    14: "Cool white fluorescent (W 3900 - 4500K)",
                    15: "White fluorescent (WW 3200 - 3700K)",
                    17: "Standard light A",
                    18: "Standard light B",
                    19: "Standard light C",
                    20: "D55",
                    21: "D65",
                    22: "D75",
                    23: "D50",
                    24: "ISO studio tungsten",
                    255: "Other"
                },
                Flash: {
                    0x0000: "Flash did not fire",
                    0x0001: "Flash fired",
                    0x0005: "Strobe return light not detected",
                    0x0007: "Strobe return light detected",
                    0x0009: "Flash fired, compulsory flash mode",
                    0x000D: "Flash fired, compulsory flash mode, return light not detected",
                    0x000F: "Flash fired, compulsory flash mode, return light detected",
                    0x0010: "Flash did not fire, compulsory flash mode",
                    0x0018: "Flash did not fire, auto mode",
                    0x0019: "Flash fired, auto mode",
                    0x001D: "Flash fired, auto mode, return light not detected",
                    0x001F: "Flash fired, auto mode, return light detected",
                    0x0020: "No flash function",
                    0x0041: "Flash fired, red-eye reduction mode",
                    0x0045: "Flash fired, red-eye reduction mode, return light not detected",
                    0x0047: "Flash fired, red-eye reduction mode, return light detected",
                    0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode",
                    0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
                    0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
                    0x0059: "Flash fired, auto mode, red-eye reduction mode",
                    0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode",
                    0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode"
                },
                SensingMethod: {
                    1: "Not defined",
                    2: "One-chip color area sensor",
                    3: "Two-chip color area sensor",
                    4: "Three-chip color area sensor",
                    5: "Color sequential area sensor",
                    7: "Trilinear sensor",
                    8: "Color sequential linear sensor"
                },
                SceneCaptureType: {
                    0: "Standard",
                    1: "Landscape",
                    2: "Portrait",
                    3: "Night scene"
                },
                SceneType: {
                    1: "Directly photographed"
                },
                CustomRendered: {
                    0: "Normal process",
                    1: "Custom process"
                },
                WhiteBalance: {
                    0: "Auto white balance",
                    1: "Manual white balance"
                },
                GainControl: {
                    0: "None",
                    1: "Low gain up",
                    2: "High gain up",
                    3: "Low gain down",
                    4: "High gain down"
                },
                Contrast: {
                    0: "Normal",
                    1: "Soft",
                    2: "Hard"
                },
                Saturation: {
                    0: "Normal",
                    1: "Low saturation",
                    2: "High saturation"
                },
                Sharpness: {
                    0: "Normal",
                    1: "Soft",
                    2: "Hard"
                },
                SubjectDistanceRange: {
                    0: "Unknown",
                    1: "Macro",
                    2: "Close view",
                    3: "Distant view"
                },
                FileSource: {
                    3: "DSC"
                },
                Components: {
                    0: "",
                    1: "Y",
                    2: "Cb",
                    3: "Cr",
                    4: "R",
                    5: "G",
                    6: "B"
                }
            }

            function addEvent(oElement, strEvent, fncHandler) {
                if (oElement.addEventListener) {
                    oElement.addEventListener(strEvent, fncHandler, false);
                } else if (oElement.attachEvent) {
                    oElement.attachEvent("on" + strEvent, fncHandler);
                }
            }


            function imageHasData(oImg) {
                return !!(oImg.exifdata);
            }

            function getImageData(oImg, fncCallback) {
                BinaryAjax(
                    oImg.src,
                    function (oHTTP) {
                        console.log('BINARY', oHTTP.binaryResponse);
                        var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse);
                        oImg.exifdata = oEXIF || {};
                        if (fncCallback)
                            fncCallback();
                    }
            )
            }

            function getImageDataFromDataURL(oImg, fncCallback) {
                var byteString = atob(oImg.src.split(',')[1]);
                var f = new BinaryFile(byteString, 0, byteString.length)
                var oEXIF = findEXIFinJPEG(f);
                oImg.exifdata = oEXIF || {};
                if (fncCallback)
                    fncCallback();
            }

            function findEXIFinJPEG(oFile) {
                var aMarkers = [];

                if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) {
                    return false; // not a valid jpeg
                }

                var iOffset = 2;
                var iLength = oFile.getLength();
                while (iOffset < iLength) {
                    if (oFile.getByteAt(iOffset) != 0xFF) {
                        if (bDebug)
                            console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset));
                        return false; // not a valid marker, something is wrong
                    }

                    var iMarker = oFile.getByteAt(iOffset + 1);

                    // we could implement handling for other markers here, 
                    // but we're only looking for 0xFFE1 for EXIF data

                    if (iMarker == 22400) {
                        if (bDebug)
                            console.log("Found 0xFFE1 marker");
                        return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);
                        iOffset += 2 + oFile.getShortAt(iOffset + 2, true);

                    } else if (iMarker == 225) {
                        // 0xE1 = Application-specific 1 (for EXIF)
                        if (bDebug)
                            console.log("Found 0xFFE1 marker");
                        return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2);

                    } else {
                        iOffset += 2 + oFile.getShortAt(iOffset + 2, true);
                    }

                }

            }


            function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd) {
                var iEntries = oFile.getShortAt(iDirStart, bBigEnd);
                var oTags = {};
                for (var i = 0; i < iEntries; i++) {
                    var iEntryOffset = iDirStart + i * 12 + 2;
                    var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)];
                    if (!strTag && bDebug)
                        console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd));
                    oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd);
                }
                return oTags;
            }


            function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd) {
                var iType = oFile.getShortAt(iEntryOffset + 2, bBigEnd);
                var iNumValues = oFile.getLongAt(iEntryOffset + 4, bBigEnd);
                var iValueOffset = oFile.getLongAt(iEntryOffset + 8, bBigEnd) + iTIFFStart;

                switch (iType) {
                    case 1: // byte, 8-bit unsigned int
                    case 7: // undefined, 8-bit byte, value depending on field
                        if (iNumValues == 1) {
                            return oFile.getByteAt(iEntryOffset + 8, bBigEnd);
                        } else {
                            var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getByteAt(iValOffset + n);
                            }
                            return aVals;
                        }
                        break;

                    case 2: // ascii, 8-bit byte
                        var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8);
                        return oFile.getStringAt(iStringOffset, iNumValues - 1);
                        break;

                    case 3: // short, 16 bit int
                        if (iNumValues == 1) {
                            return oFile.getShortAt(iEntryOffset + 8, bBigEnd);
                        } else {
                            var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8);
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getShortAt(iValOffset + 2 * n, bBigEnd);
                            }
                            return aVals;
                        }
                        break;

                    case 4: // long, 32 bit int
                        if (iNumValues == 1) {
                            return oFile.getLongAt(iEntryOffset + 8, bBigEnd);
                        } else {
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getLongAt(iValueOffset + 4 * n, bBigEnd);
                            }
                            return aVals;
                        }
                        break;
                    case 5: // rational = two long values, first is numerator, second is denominator
                        if (iNumValues == 1) {
                            return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset + 4, bBigEnd);
                        } else {
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
                            }
                            return aVals;
                        }
                        break;
                    case 9: // slong, 32 bit signed int
                        if (iNumValues == 1) {
                            return oFile.getSLongAt(iEntryOffset + 8, bBigEnd);
                        } else {
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getSLongAt(iValueOffset + 4 * n, bBigEnd);
                            }
                            return aVals;
                        }
                        break;
                    case 10: // signed rational, two slongs, first is numerator, second is denominator
                        if (iNumValues == 1) {
                            return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset + 4, bBigEnd);
                        } else {
                            var aVals = [];
                            for (var n = 0; n < iNumValues; n++) {
                                aVals[n] = oFile.getSLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getSLongAt(iValueOffset + 4 + 8 * n, bBigEnd);
                            }
                            return aVals;
                        }
                        break;
                }
            }


            function readEXIFData(oFile, iStart, iLength) {
                if (oFile.getStringAt(iStart, 4) != "Exif") {
                    if (bDebug)
                        console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4));
                    return false;
                }

                var bBigEnd;

                var iTIFFOffset = iStart + 6;

                // test for TIFF validity and endianness
                if (oFile.getShortAt(iTIFFOffset) == 0x4949) {
                    bBigEnd = false;
                } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) {
                    bBigEnd = true;
                } else {
                    if (bDebug)
                        console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
                    return false;
                }

                if (oFile.getShortAt(iTIFFOffset + 2, bBigEnd) != 0x002A) {
                    if (bDebug)
                        console.log("Not valid TIFF data! (no 0x002A)");
                    return false;
                }

                if (oFile.getLongAt(iTIFFOffset + 4, bBigEnd) != 0x00000008) {
                    if (bDebug)
                        console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset + 4, bBigEnd));
                    return false;
                }

                var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset + 8, EXIF.TiffTags, bBigEnd);

                if (oTags.ExifIFDPointer) {
                    var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd);
                    for (var strTag in oEXIFTags) {
                        switch (strTag) {
                            case "LightSource":
                            case "Flash":
                            case "MeteringMode":
                            case "ExposureProgram":
                            case "SensingMethod":
                            case "SceneCaptureType":
                            case "SceneType":
                            case "CustomRendered":
                            case "WhiteBalance":
                            case "GainControl":
                            case "Contrast":
                            case "Saturation":
                            case "Sharpness":
                            case "SubjectDistanceRange":
                            case "FileSource":
                                oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]];
                                break;

                            case "ExifVersion":
                            case "FlashpixVersion":
                                oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]);
                                break;

                            case "ComponentsConfiguration":
                                oEXIFTags[strTag] =
                                    EXIF.StringValues.Components[oEXIFTags[strTag][0]]
                                    + EXIF.StringValues.Components[oEXIFTags[strTag][1]]
                                    + EXIF.StringValues.Components[oEXIFTags[strTag][2]]
                                    + EXIF.StringValues.Components[oEXIFTags[strTag][3]];
                                break;
                        }
                        oTags[strTag] = oEXIFTags[strTag];
                    }
                }

                if (oTags.GPSInfoIFDPointer) {
                    var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd);
                    for (var strTag in oGPSTags) {
                        switch (strTag) {
                            case "GPSVersionID":
                                oGPSTags[strTag] = oGPSTags[strTag][0]
                                    + "." + oGPSTags[strTag][1]
                                    + "." + oGPSTags[strTag][2]
                                    + "." + oGPSTags[strTag][3];
                                break;
                        }
                        oTags[strTag] = oGPSTags[strTag];
                    }
                }

                return oTags;
            }


            EXIF.getData = function (oImg, fncCallback) {
                if (!oImg.complete)
                    return false;
                if (!imageHasData(oImg)) {
                    getImageData(oImg, fncCallback);
                } else {
                    if (fncCallback)
                        fncCallback();
                }
                return true;
            }

            EXIF.getDataFromDataURL = function (oImg, fncCallback) {
                if (!oImg.complete)
                    return false;
                if (!imageHasData(oImg)) {
                    getImageDataFromDataURL(oImg, fncCallback);
                } else {
                    if (fncCallback)
                        fncCallback();
                }
                return true;
            }

            EXIF.getTag = function (oImg, strTag) {
                if (!imageHasData(oImg))
                    return;
                return oImg.exifdata[strTag];
            }

            EXIF.getAllTags = function (oImg) {
                if (!imageHasData(oImg))
                    return {};
                var oData = oImg.exifdata;
                var oAllTags = {};
                for (var a in oData) {
                    if (oData.hasOwnProperty(a)) {
                        oAllTags[a] = oData[a];
                    }
                }
                return oAllTags;
            }

            EXIF.pretty = function (oImg) {
                if (!imageHasData(oImg))
                    return "";
                var oData = oImg.exifdata;
                var strPretty = "";
                for (var a in oData) {
                    if (oData.hasOwnProperty(a)) {
                        if (typeof oData[a] == "object") {
                            strPretty += a + " : [" + oData[a].length + " values]\r\n";
                        } else {
                            strPretty += a + " : " + oData[a] + "\r\n";
                        }
                    }
                }
                return strPretty;
            }

            EXIF.readFromBinaryFile = function (oFile) {
                return findEXIFinJPEG(oFile);
            }

            function loadAllImages() {
                var aImages = document.getElementsByTagName("img");
                for (var i = 0; i < aImages.length; i++) {
                    if (aImages[i].getAttribute("exif") == "true") {
                        if (!aImages[i].complete) {
                            addEvent(aImages[i], "load",
                                function () {
                                    EXIF.getData(this);
                                }
                        );
                        } else {
                            EXIF.getData(aImages[i]);
                        }
                    }
                }
            }

            // automatically load exif data for all images with exif=true when doc is ready
            jQuery(document).ready(loadAllImages);

            // load data for images manually
            jQuery.fn.exifLoad = function (fncCallback) {
                return this.each(function () {
                    EXIF.getData(this, fncCallback)
                });
            }

            // load data for images manually
            jQuery.fn.exifLoadFromDataURL = function (fncCallback) {
                return this.each(function () {
                    EXIF.getDataFromDataURL(this, fncCallback)
                    return true;
                });
            }

            jQuery.fn.exif = function (strTag) {
                var aStrings = [];
                this.each(function () {
                    aStrings.push(EXIF.getTag(this, strTag));
                });
                return aStrings;
            }

            jQuery.fn.exifAll = function () {
                var aStrings = [];
                this.each(function () {
                    aStrings.push(EXIF.getAllTags(this));
                });
                return aStrings;
            }

            jQuery.fn.exifPretty = function () {
                var aStrings = [];
                this.each(function () {
                    aStrings.push(EXIF.pretty(this));
                });
                return aStrings;
            }


        })();


    })();

    /*
    * jQuery canvasResize plugin
    * 
    * Version: 1.2.0 
    * Date (d/m/y): 02/10/12
    * Update (d/m/y): 14/05/13
    * Original author: @gokercebeci 
    * Licensed under the MIT license
    * - This plugin working with jquery.exif.js 
    *   (It's under the MPL License http://www.nihilogic.dk/licenses/mpl-license.txt)
    * Demo: http://ios6-image-resize.gokercebeci.com/
    * 
    * - I fixed iOS6 Safari's image file rendering issue for large size image (over mega-pixel)
    *   using few functions from https://github.com/stomita/ios-imagefile-megapixel
    *   (detectSubsampling, )
    *   And fixed orientation issue by edited http://blog.nihilogic.dk/2008/05/jquery-exif-data-plugin.html
    *   Thanks, Shinichi Tomita and Jacob Seidelin
    */

    (function ($) {
        var pluginName = 'canvasResize',
            methods = {
                newsize: function (w, h, W, H, C) {
                    var c = C ? 'h' : '';
                    if ((W && w > W) || (H && h > H)) {
                        var r = w / h;
                        if ((r >= 1 || H === 0) && W && !C) {
                            w = W;
                            h = (W / r) >> 0;
                        } else if (C && r <= (W / H)) {
                            w = W;
                            h = (W / r) >> 0;
                            c = 'w';
                        } else {
                            w = (H * r) >> 0;
                            h = H;
                        }
                    }
                    return {
                        'width': w,
                        'height': h,
                        'cropped': c
                    };
                },
                dataURLtoBlob: function (data) {
                    var mimeString = data.split(',')[0].split(':')[1].split(';')[0];
                    var byteString = atob(data.split(',')[1]);
                    var ab = new ArrayBuffer(byteString.length);
                    var ia = new Uint8Array(ab);
                    for (var i = 0; i < byteString.length; i++) {
                        ia[i] = byteString.charCodeAt(i);
                    }
                    var bb = (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder);
                    if (bb) {
                        //    console.log('BlobBuilder');        
                        bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder)();
                        bb.append(ab);
                        return bb.getBlob(mimeString);
                    } else {
                        //    console.log('Blob');  
                        bb = new Blob([ab], {
                            'type': (mimeString)
                        });
                        return bb;
                    }
                },
                /**
                * Detect subsampling in loaded image.
                * In iOS, larger images than 2M pixels may be subsampled in rendering.
                */
                detectSubsampling: function (img) {
                    var iw = img.width, ih = img.height;
                    if (iw * ih > 1048576) { // subsampling may happen over megapixel image
                        var canvas = document.createElement('canvas');
                        canvas.width = canvas.height = 1;
                        var ctx = canvas.getContext('2d');
                        ctx.drawImage(img, -iw + 1, 0);
                        // subsampled image becomes half smaller in rendering size.
                        // check alpha channel value to confirm image is covering edge pixel or not.
                        // if alpha value is 0 image is not covering, hence subsampled.
                        return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
                    } else {
                        return false;
                    }
                },
                /**
                * Update the orientation according to the specified rotation angle
                */
                rotate: function (orientation, angle) {
                    var o = {
                        // nothing
                        1: { 90: 6, 180: 3, 270: 8 },
                        // horizontal flip
                        2: { 90: 7, 180: 4, 270: 5 },
                        // 180 rotate left
                        3: { 90: 8, 180: 1, 270: 6 },
                        // vertical flip
                        4: { 90: 5, 180: 2, 270: 7 },
                        // vertical flip + 90 rotate right
                        5: { 90: 2, 180: 7, 270: 4 },
                        // 90 rotate right
                        6: { 90: 3, 180: 8, 270: 1 },
                        // horizontal flip + 90 rotate right
                        7: { 90: 4, 180: 5, 270: 2 },
                        // 90 rotate left
                        8: { 90: 1, 180: 6, 270: 3 }
                    };
                    return o[orientation][angle] ? o[orientation][angle] : orientation;
                },
                /**
                * Transform canvas coordination according to specified frame size and orientation
                * Orientation value is from EXIF tag
                */
                transformCoordinate: function (canvas, width, height, orientation) {
                    //console.log(width, height);
                    switch (orientation) {
                        case 5:
                        case 6:
                        case 7:
                        case 8:
                            canvas.width = height;
                            canvas.height = width;
                            break;
                        default:
                            canvas.width = width;
                            canvas.height = height;
                    }
                    var ctx = canvas.getContext('2d');
                    switch (orientation) {
                        case 1:
                            // nothing
                            break;
                        case 2:
                            // horizontal flip
                            ctx.translate(width, 0);
                            ctx.scale(-1, 1);
                            break;
                        case 3:
                            // 180 rotate left
                            ctx.translate(width, height);
                            ctx.rotate(Math.PI);
                            break;
                        case 4:
                            // vertical flip
                            ctx.translate(0, height);
                            ctx.scale(1, -1);
                            break;
                        case 5:
                            // vertical flip + 90 rotate right
                            ctx.rotate(0.5 * Math.PI);
                            ctx.scale(1, -1);
                            break;
                        case 6:
                            // 90 rotate right
                            ctx.rotate(0.5 * Math.PI);
                            ctx.translate(0, -height);
                            break;
                        case 7:
                            // horizontal flip + 90 rotate right
                            ctx.rotate(0.5 * Math.PI);
                            ctx.translate(width, -height);
                            ctx.scale(-1, 1);
                            break;
                        case 8:
                            // 90 rotate left
                            ctx.rotate(-0.5 * Math.PI);
                            ctx.translate(-width, 0);
                            break;
                        default:
                            break;
                    }
                },
                /**
                * Detecting vertical squash in loaded image.
                * Fixes a bug which squash image vertically while drawing into canvas for some images.
                */
                detectVerticalSquash: function (img, iw, ih) {
                    var canvas = document.createElement('canvas');
                    canvas.width = 1;
                    canvas.height = ih;
                    var ctx = canvas.getContext('2d');
                    ctx.drawImage(img, 0, 0);
                    var data = ctx.getImageData(0, 0, 1, ih).data;
                    // search image edge pixel position in case it is squashed vertically.
                    var sy = 0;
                    var ey = ih;
                    var py = ih;
                    while (py > sy) {
                        var alpha = data[(py - 1) * 4 + 3];
                        if (alpha === 0) {
                            ey = py;
                        } else {
                            sy = py;
                        }
                        py = (ey + sy) >> 1;
                    }
                    var ratio = py / ih;
                    return ratio === 0 ? 1 : ratio;
                },
                callback: function (d) {
                    return d;
                }
            },
    defaults = {
        width: 300,
        height: 0,
        crop: false,
        quality: 80,
        'callback': methods.callback
    };
        function Plugin(file, options) {
            this.file = file;
            this.options = $.extend({}, defaults, options);
            this._defaults = defaults;
            this._name = pluginName;
            this.init();
        }
        Plugin.prototype = {
            init: function () {
                //this.options.init(this);
                var $this = this;
                var file = this.file;

                //var reader = new FileReader();
                //reader.onloadend = function(e) {
                var dataURL = file; //e.target.result;
                var img = new Image();
                img.onload = function (e) {
                    // Read Orientation Data in EXIF
                    $(img).exifLoadFromDataURL(function () {
                        var orientation = $(img).exif('Orientation')[0] || 1;
                        orientation = methods.rotate(orientation, $this.options.rotate);

                        // CW or CCW ? replace width and height
                        var size = (orientation >= 5 && orientation <= 8)
                                ? methods.newsize(img.height, img.width, $this.options.width, $this.options.height, $this.options.crop)
                                : methods.newsize(img.width, img.height, $this.options.width, $this.options.height, $this.options.crop);

                        var iw = img.width, ih = img.height;
                        var width = size.width, height = size.height;

                        //console.log(iw, ih, size.width, size.height, orientation);

                        var canvas = document.createElement("canvas");
                        var ctx = canvas.getContext("2d");
                        ctx.save();
                        methods.transformCoordinate(canvas, width, height, orientation);

                        // over image size
                        if (methods.detectSubsampling(img)) {
                            iw /= 2;
                            ih /= 2;
                        }
                        //var d = 1024; // size of tiling canvas
                        var d = 512; // size of tiling canvas
                        var tmpCanvas = document.createElement('canvas');
                        tmpCanvas.width = tmpCanvas.height = d;
                        var tmpCtx = tmpCanvas.getContext('2d');
                        var vertSquashRatio = methods.detectVerticalSquash(img, iw, ih);
                        var sy = 0;
                        while (sy < ih) {
                            var sh = sy + d > ih ? ih - sy : d;
                            var sx = 0;
                            while (sx < iw) {
                                var sw = sx + d > iw ? iw - sx : d;
                                tmpCtx.clearRect(0, 0, d, d);
                                tmpCtx.drawImage(img, -sx, -sy);
                                var dx = Math.floor(sx * width / iw);
                                var dw = Math.ceil(sw * width / iw);
                                var dy = Math.floor(sy * height / ih / vertSquashRatio);
                                var dh = Math.ceil(sh * height / ih / vertSquashRatio);
                                ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
                                sx += d;
                            }
                            sy += d;
                        }
                        ctx.restore();
                        tmpCanvas = tmpCtx = null;

                        // if cropped or rotated width and height data replacing issue 
                        var newcanvas = document.createElement('canvas');
                        newcanvas.width = size.cropped === 'h' ? height : width;
                        newcanvas.height = size.cropped === 'w' ? width : height;
                        var x = size.cropped === 'h' ? (height - width) * .5 : 0;
                        var y = size.cropped === 'w' ? (width - height) * .5 : 0;
                        newctx = newcanvas.getContext('2d');
                        newctx.drawImage(canvas, x, y, width, height);

                        if (file.type === "image/png") {
                            var data = newcanvas.toDataURL(file.type);
                        } else {
                            var data = newcanvas.toDataURL("image/jpeg", ($this.options.quality * .01));
                        }

                        // CALLBACK
                        $this.options.callback(data, width, height);

                    });
                };
                img.src = dataURL;
                // =====================================================
                //};
                //reader.readAsDataURL(file);

            }
        };
        $[pluginName] = function (file, options) {
            //if (typeof file === 'string')
            //    return methods[file](options);
            //else
            new Plugin(file, options);
        };

    })(jQuery);
}
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
module.exports = require('./lib/extend');


},{"./lib/extend":2}],2:[function(require,module,exports){
/*!
 * node.extend
 * Copyright 2011, John Resig
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * @fileoverview
 * Port of jQuery.extend that actually works on node.js
 */
var is = require('is');

function extend() {
  var target = arguments[0] || {};
  var i = 1;
  var length = arguments.length;
  var deep = false;
  var options, name, src, copy, copy_is_array, clone;

  // Handle a deep copy situation
  if (typeof target === 'boolean') {
    deep = target;
    target = arguments[1] || {};
    // skip the boolean and the target
    i = 2;
  }

  // Handle case when target is a string or something (possible in deep copy)
  if (typeof target !== 'object' && !is.fn(target)) {
    target = {};
  }

  for (; i < length; i++) {
    // Only deal with non-null/undefined values
    options = arguments[i]
    if (options != null) {
      if (typeof options === 'string') {
          options = options.split('');
      }
      // 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 && (is.hash(copy) || (copy_is_array = is.array(copy)))) {
          if (copy_is_array) {
            copy_is_array = false;
            clone = src && is.array(src) ? src : [];
          } else {
            clone = src && is.hash(src) ? src : {};
          }

          // Never move original objects, clone them
          target[name] = extend(deep, clone, copy);

        // Don't bring in undefined values
        } else if (typeof copy !== 'undefined') {
          target[name] = copy;
        }
      }
    }
  }

  // Return the modified object
  return target;
};

/**
 * @public
 */
extend.version = '1.1.3';

/**
 * Exports module.
 */
module.exports = extend;


},{"is":3}],3:[function(require,module,exports){

/**!
 * is
 * the definitive JavaScript type testing library
 *
 * @copyright 2013-2014 Enrico Marino / Jordan Harband
 * @license MIT
 */

var objProto = Object.prototype;
var owns = objProto.hasOwnProperty;
var toStr = objProto.toString;
var symbolValueOf;
if (typeof Symbol === 'function') {
  symbolValueOf = Symbol.prototype.valueOf;
}
var isActualNaN = function (value) {
  return value !== value;
};
var NON_HOST_TYPES = {
  boolean: 1,
  number: 1,
  string: 1,
  undefined: 1
};

var base64Regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/;
var hexRegex = /^[A-Fa-f0-9]+$/;

/**
 * Expose `is`
 */

var is = module.exports = {};

/**
 * Test general.
 */

/**
 * is.type
 * Test if `value` is a type of `type`.
 *
 * @param {Mixed} value value to test
 * @param {String} type type
 * @return {Boolean} true if `value` is a type of `type`, false otherwise
 * @api public
 */

is.a = is.type = function (value, type) {
  return typeof value === type;
};

/**
 * is.defined
 * Test if `value` is defined.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if 'value' is defined, false otherwise
 * @api public
 */

is.defined = function (value) {
  return typeof value !== 'undefined';
};

/**
 * is.empty
 * Test if `value` is empty.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is empty, false otherwise
 * @api public
 */

is.empty = function (value) {
  var type = toStr.call(value);
  var key;

  if ('[object Array]' === type || '[object Arguments]' === type || '[object String]' === type) {
    return value.length === 0;
  }

  if ('[object Object]' === type) {
    for (key in value) {
      if (owns.call(value, key)) { return false; }
    }
    return true;
  }

  return !value;
};

/**
 * is.equal
 * Test if `value` is equal to `other`.
 *
 * @param {Mixed} value value to test
 * @param {Mixed} other value to compare with
 * @return {Boolean} true if `value` is equal to `other`, false otherwise
 */

is.equal = function (value, other) {
  var strictlyEqual = value === other;
  if (strictlyEqual) {
    return true;
  }

  var type = toStr.call(value);
  var key;

  if (type !== toStr.call(other)) {
    return false;
  }

  if ('[object Object]' === type) {
    for (key in value) {
      if (!is.equal(value[key], other[key]) || !(key in other)) {
        return false;
      }
    }
    for (key in other) {
      if (!is.equal(value[key], other[key]) || !(key in value)) {
        return false;
      }
    }
    return true;
  }

  if ('[object Array]' === type) {
    key = value.length;
    if (key !== other.length) {
      return false;
    }
    while (--key) {
      if (!is.equal(value[key], other[key])) {
        return false;
      }
    }
    return true;
  }

  if ('[object Function]' === type) {
    return value.prototype === other.prototype;
  }

  if ('[object Date]' === type) {
    return value.getTime() === other.getTime();
  }

  return strictlyEqual;
};

/**
 * is.hosted
 * Test if `value` is hosted by `host`.
 *
 * @param {Mixed} value to test
 * @param {Mixed} host host to test with
 * @return {Boolean} true if `value` is hosted by `host`, false otherwise
 * @api public
 */

is.hosted = function (value, host) {
  var type = typeof host[value];
  return type === 'object' ? !!host[value] : !NON_HOST_TYPES[type];
};

/**
 * is.instance
 * Test if `value` is an instance of `constructor`.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an instance of `constructor`
 * @api public
 */

is.instance = is['instanceof'] = function (value, constructor) {
  return value instanceof constructor;
};

/**
 * is.nil / is.null
 * Test if `value` is null.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is null, false otherwise
 * @api public
 */

is.nil = is['null'] = function (value) {
  return value === null;
};

/**
 * is.undef / is.undefined
 * Test if `value` is undefined.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is undefined, false otherwise
 * @api public
 */

is.undef = is.undefined = function (value) {
  return typeof value === 'undefined';
};

/**
 * Test arguments.
 */

/**
 * is.args
 * Test if `value` is an arguments object.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an arguments object, false otherwise
 * @api public
 */

is.args = is.arguments = function (value) {
  var isStandardArguments = '[object Arguments]' === toStr.call(value);
  var isOldArguments = !is.array(value) && is.arraylike(value) && is.object(value) && is.fn(value.callee);
  return isStandardArguments || isOldArguments;
};

/**
 * Test array.
 */

/**
 * is.array
 * Test if 'value' is an array.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an array, false otherwise
 * @api public
 */

is.array = function (value) {
  return '[object Array]' === toStr.call(value);
};

/**
 * is.arguments.empty
 * Test if `value` is an empty arguments object.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an empty arguments object, false otherwise
 * @api public
 */
is.args.empty = function (value) {
  return is.args(value) && value.length === 0;
};

/**
 * is.array.empty
 * Test if `value` is an empty array.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an empty array, false otherwise
 * @api public
 */
is.array.empty = function (value) {
  return is.array(value) && value.length === 0;
};

/**
 * is.arraylike
 * Test if `value` is an arraylike object.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an arguments object, false otherwise
 * @api public
 */

is.arraylike = function (value) {
  return !!value && !is.boolean(value)
    && owns.call(value, 'length')
    && isFinite(value.length)
    && is.number(value.length)
    && value.length >= 0;
};

/**
 * Test boolean.
 */

/**
 * is.boolean
 * Test if `value` is a boolean.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a boolean, false otherwise
 * @api public
 */

is.boolean = function (value) {
  return '[object Boolean]' === toStr.call(value);
};

/**
 * is.false
 * Test if `value` is false.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is false, false otherwise
 * @api public
 */

is['false'] = function (value) {
  return is.boolean(value) && Boolean(Number(value)) === false;
};

/**
 * is.true
 * Test if `value` is true.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is true, false otherwise
 * @api public
 */

is['true'] = function (value) {
  return is.boolean(value) && Boolean(Number(value)) === true;
};

/**
 * Test date.
 */

/**
 * is.date
 * Test if `value` is a date.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a date, false otherwise
 * @api public
 */

is.date = function (value) {
  return '[object Date]' === toStr.call(value);
};

/**
 * Test element.
 */

/**
 * is.element
 * Test if `value` is an html element.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an HTML Element, false otherwise
 * @api public
 */

is.element = function (value) {
  return value !== undefined
    && typeof HTMLElement !== 'undefined'
    && value instanceof HTMLElement
    && value.nodeType === 1;
};

/**
 * Test error.
 */

/**
 * is.error
 * Test if `value` is an error object.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an error object, false otherwise
 * @api public
 */

is.error = function (value) {
  return '[object Error]' === toStr.call(value);
};

/**
 * Test function.
 */

/**
 * is.fn / is.function (deprecated)
 * Test if `value` is a function.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a function, false otherwise
 * @api public
 */

is.fn = is['function'] = function (value) {
  var isAlert = typeof window !== 'undefined' && value === window.alert;
  return isAlert || '[object Function]' === toStr.call(value);
};

/**
 * Test number.
 */

/**
 * is.number
 * Test if `value` is a number.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a number, false otherwise
 * @api public
 */

is.number = function (value) {
  return '[object Number]' === toStr.call(value);
};

/**
 * is.infinite
 * Test if `value` is positive or negative infinity.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is positive or negative Infinity, false otherwise
 * @api public
 */
is.infinite = function (value) {
  return value === Infinity || value === -Infinity;
};

/**
 * is.decimal
 * Test if `value` is a decimal number.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a decimal number, false otherwise
 * @api public
 */

is.decimal = function (value) {
  return is.number(value) && !isActualNaN(value) && !is.infinite(value) && value % 1 !== 0;
};

/**
 * is.divisibleBy
 * Test if `value` is divisible by `n`.
 *
 * @param {Number} value value to test
 * @param {Number} n dividend
 * @return {Boolean} true if `value` is divisible by `n`, false otherwise
 * @api public
 */

is.divisibleBy = function (value, n) {
  var isDividendInfinite = is.infinite(value);
  var isDivisorInfinite = is.infinite(n);
  var isNonZeroNumber = is.number(value) && !isActualNaN(value) && is.number(n) && !isActualNaN(n) && n !== 0;
  return isDividendInfinite || isDivisorInfinite || (isNonZeroNumber && value % n === 0);
};

/**
 * is.int
 * Test if `value` is an integer.
 *
 * @param value to test
 * @return {Boolean} true if `value` is an integer, false otherwise
 * @api public
 */

is.int = function (value) {
  return is.number(value) && !isActualNaN(value) && value % 1 === 0;
};

/**
 * is.maximum
 * Test if `value` is greater than 'others' values.
 *
 * @param {Number} value value to test
 * @param {Array} others values to compare with
 * @return {Boolean} true if `value` is greater than `others` values
 * @api public
 */

is.maximum = function (value, others) {
  if (isActualNaN(value)) {
    throw new TypeError('NaN is not a valid value');
  } else if (!is.arraylike(others)) {
    throw new TypeError('second argument must be array-like');
  }
  var len = others.length;

  while (--len >= 0) {
    if (value < others[len]) {
      return false;
    }
  }

  return true;
};

/**
 * is.minimum
 * Test if `value` is less than `others` values.
 *
 * @param {Number} value value to test
 * @param {Array} others values to compare with
 * @return {Boolean} true if `value` is less than `others` values
 * @api public
 */

is.minimum = function (value, others) {
  if (isActualNaN(value)) {
    throw new TypeError('NaN is not a valid value');
  } else if (!is.arraylike(others)) {
    throw new TypeError('second argument must be array-like');
  }
  var len = others.length;

  while (--len >= 0) {
    if (value > others[len]) {
      return false;
    }
  }

  return true;
};

/**
 * is.nan
 * Test if `value` is not a number.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is not a number, false otherwise
 * @api public
 */

is.nan = function (value) {
  return !is.number(value) || value !== value;
};

/**
 * is.even
 * Test if `value` is an even number.
 *
 * @param {Number} value value to test
 * @return {Boolean} true if `value` is an even number, false otherwise
 * @api public
 */

is.even = function (value) {
  return is.infinite(value) || (is.number(value) && value === value && value % 2 === 0);
};

/**
 * is.odd
 * Test if `value` is an odd number.
 *
 * @param {Number} value value to test
 * @return {Boolean} true if `value` is an odd number, false otherwise
 * @api public
 */

is.odd = function (value) {
  return is.infinite(value) || (is.number(value) && value === value && value % 2 !== 0);
};

/**
 * is.ge
 * Test if `value` is greater than or equal to `other`.
 *
 * @param {Number} value value to test
 * @param {Number} other value to compare with
 * @return {Boolean}
 * @api public
 */

is.ge = function (value, other) {
  if (isActualNaN(value) || isActualNaN(other)) {
    throw new TypeError('NaN is not a valid value');
  }
  return !is.infinite(value) && !is.infinite(other) && value >= other;
};

/**
 * is.gt
 * Test if `value` is greater than `other`.
 *
 * @param {Number} value value to test
 * @param {Number} other value to compare with
 * @return {Boolean}
 * @api public
 */

is.gt = function (value, other) {
  if (isActualNaN(value) || isActualNaN(other)) {
    throw new TypeError('NaN is not a valid value');
  }
  return !is.infinite(value) && !is.infinite(other) && value > other;
};

/**
 * is.le
 * Test if `value` is less than or equal to `other`.
 *
 * @param {Number} value value to test
 * @param {Number} other value to compare with
 * @return {Boolean} if 'value' is less than or equal to 'other'
 * @api public
 */

is.le = function (value, other) {
  if (isActualNaN(value) || isActualNaN(other)) {
    throw new TypeError('NaN is not a valid value');
  }
  return !is.infinite(value) && !is.infinite(other) && value <= other;
};

/**
 * is.lt
 * Test if `value` is less than `other`.
 *
 * @param {Number} value value to test
 * @param {Number} other value to compare with
 * @return {Boolean} if `value` is less than `other`
 * @api public
 */

is.lt = function (value, other) {
  if (isActualNaN(value) || isActualNaN(other)) {
    throw new TypeError('NaN is not a valid value');
  }
  return !is.infinite(value) && !is.infinite(other) && value < other;
};

/**
 * is.within
 * Test if `value` is within `start` and `finish`.
 *
 * @param {Number} value value to test
 * @param {Number} start lower bound
 * @param {Number} finish upper bound
 * @return {Boolean} true if 'value' is is within 'start' and 'finish'
 * @api public
 */
is.within = function (value, start, finish) {
  if (isActualNaN(value) || isActualNaN(start) || isActualNaN(finish)) {
    throw new TypeError('NaN is not a valid value');
  } else if (!is.number(value) || !is.number(start) || !is.number(finish)) {
    throw new TypeError('all arguments must be numbers');
  }
  var isAnyInfinite = is.infinite(value) || is.infinite(start) || is.infinite(finish);
  return isAnyInfinite || (value >= start && value <= finish);
};

/**
 * Test object.
 */

/**
 * is.object
 * Test if `value` is an object.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is an object, false otherwise
 * @api public
 */

is.object = function (value) {
  return '[object Object]' === toStr.call(value);
};

/**
 * is.hash
 * Test if `value` is a hash - a plain object literal.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a hash, false otherwise
 * @api public
 */

is.hash = function (value) {
  return is.object(value) && value.constructor === Object && !value.nodeType && !value.setInterval;
};

/**
 * Test regexp.
 */

/**
 * is.regexp
 * Test if `value` is a regular expression.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a regexp, false otherwise
 * @api public
 */

is.regexp = function (value) {
  return '[object RegExp]' === toStr.call(value);
};

/**
 * Test string.
 */

/**
 * is.string
 * Test if `value` is a string.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if 'value' is a string, false otherwise
 * @api public
 */

is.string = function (value) {
  return '[object String]' === toStr.call(value);
};

/**
 * Test base64 string.
 */

/**
 * is.base64
 * Test if `value` is a valid base64 encoded string.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if 'value' is a base64 encoded string, false otherwise
 * @api public
 */

is.base64 = function (value) {
  return is.string(value) && (!value.length || base64Regex.test(value));
};

/**
 * Test base64 string.
 */

/**
 * is.hex
 * Test if `value` is a valid hex encoded string.
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if 'value' is a hex encoded string, false otherwise
 * @api public
 */

is.hex = function (value) {
  return is.string(value) && (!value.length || hexRegex.test(value));
};

/**
 * is.symbol
 * Test if `value` is an ES6 Symbol
 *
 * @param {Mixed} value value to test
 * @return {Boolean} true if `value` is a Symbol, false otherise
 * @api public
 */

is.symbol = function (value) {
  return typeof Symbol === 'function' && toStr.call(value) === '[object Symbol]' && typeof symbolValueOf.call(value) === 'symbol';
};

},{}],4:[function(require,module,exports){
(function (global){
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),(f.qj||(f.qj={})).js=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
var QJ, rreturn, rtrim;

QJ = function(selector) {
  if (QJ.isDOMElement(selector)) {
    return selector;
  }
  return document.querySelectorAll(selector);
};

QJ.isDOMElement = function(el) {
  return el && (el.nodeName != null);
};

rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;

QJ.trim = function(text) {
  if (text === null) {
    return "";
  } else {
    return (text + "").replace(rtrim, "");
  }
};

rreturn = /\r/g;

QJ.val = function(el, val) {
  var ret;
  if (arguments.length > 1) {
    return el.value = val;
  } else {
    ret = el.value;
    if (typeof ret === "string") {
      return ret.replace(rreturn, "");
    } else {
      if (ret === null) {
        return "";
      } else {
        return ret;
      }
    }
  }
};

QJ.preventDefault = function(eventObject) {
  if (typeof eventObject.preventDefault === "function") {
    eventObject.preventDefault();
    return;
  }
  eventObject.returnValue = false;
  return false;
};

QJ.normalizeEvent = function(e) {
  var original;
  original = e;
  e = {
    which: original.which != null ? original.which : void 0,
    target: original.target || original.srcElement,
    preventDefault: function() {
      return QJ.preventDefault(original);
    },
    originalEvent: original,
    data: original.data || original.detail
  };
  if (e.which == null) {
    e.which = original.charCode != null ? original.charCode : original.keyCode;
  }
  return e;
};

QJ.on = function(element, eventName, callback) {
  var el, multEventName, originalCallback, _i, _j, _len, _len1, _ref;
  if (element.length) {
    for (_i = 0, _len = element.length; _i < _len; _i++) {
      el = element[_i];
      QJ.on(el, eventName, callback);
    }
    return;
  }
  if (eventName.match(" ")) {
    _ref = eventName.split(" ");
    for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
      multEventName = _ref[_j];
      QJ.on(element, multEventName, callback);
    }
    return;
  }
  originalCallback = callback;
  callback = function(e) {
    e = QJ.normalizeEvent(e);
    return originalCallback(e);
  };
  if (element.addEventListener) {
    return element.addEventListener(eventName, callback, false);
  }
  if (element.attachEvent) {
    eventName = "on" + eventName;
    return element.attachEvent(eventName, callback);
  }
  element['on' + eventName] = callback;
};

QJ.addClass = function(el, className) {
  var e;
  if (el.length) {
    return (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = el.length; _i < _len; _i++) {
        e = el[_i];
        _results.push(QJ.addClass(e, className));
      }
      return _results;
    })();
  }
  if (el.classList) {
    return el.classList.add(className);
  } else {
    return el.className += ' ' + className;
  }
};

QJ.hasClass = function(el, className) {
  var e, hasClass, _i, _len;
  if (el.length) {
    hasClass = true;
    for (_i = 0, _len = el.length; _i < _len; _i++) {
      e = el[_i];
      hasClass = hasClass && QJ.hasClass(e, className);
    }
    return hasClass;
  }
  if (el.classList) {
    return el.classList.contains(className);
  } else {
    return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
  }
};

QJ.removeClass = function(el, className) {
  var cls, e, _i, _len, _ref, _results;
  if (el.length) {
    return (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = el.length; _i < _len; _i++) {
        e = el[_i];
        _results.push(QJ.removeClass(e, className));
      }
      return _results;
    })();
  }
  if (el.classList) {
    _ref = className.split(' ');
    _results = [];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      cls = _ref[_i];
      _results.push(el.classList.remove(cls));
    }
    return _results;
  } else {
    return el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
  }
};

QJ.toggleClass = function(el, className, bool) {
  var e;
  if (el.length) {
    return (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = el.length; _i < _len; _i++) {
        e = el[_i];
        _results.push(QJ.toggleClass(e, className, bool));
      }
      return _results;
    })();
  }
  if (bool) {
    if (!QJ.hasClass(el, className)) {
      return QJ.addClass(el, className);
    }
  } else {
    return QJ.removeClass(el, className);
  }
};

QJ.append = function(el, toAppend) {
  var e;
  if (el.length) {
    return (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = el.length; _i < _len; _i++) {
        e = el[_i];
        _results.push(QJ.append(e, toAppend));
      }
      return _results;
    })();
  }
  return el.insertAdjacentHTML('beforeend', toAppend);
};

QJ.find = function(el, selector) {
  if (el instanceof NodeList || el instanceof Array) {
    el = el[0];
  }
  return el.querySelectorAll(selector);
};

QJ.trigger = function(el, name, data) {
  var e, ev;
  try {
    ev = new CustomEvent(name, {
      detail: data
    });
  } catch (_error) {
    e = _error;
    ev = document.createEvent('CustomEvent');
    if (ev.initCustomEvent) {
      ev.initCustomEvent(name, true, true, data);
    } else {
      ev.initEvent(name, true, true, data);
    }
  }
  return el.dispatchEvent(ev);
};

module.exports = QJ;


},{}]},{},[1])
(1)
});
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],5:[function(require,module,exports){
module.exports = require('cssify');
},{"cssify":6}],6:[function(require,module,exports){
module.exports = function (css, customDocument) {
  var doc = customDocument || document;
  if (doc.createStyleSheet) {
    var sheet = doc.createStyleSheet()
    sheet.cssText = css;
    return sheet.ownerNode;
  } else {
    var head = doc.getElementsByTagName('head')[0],
        style = doc.createElement('style');

    style.type = 'text/css';

    if (style.styleSheet) {
      style.styleSheet.cssText = css;
    } else {
      style.appendChild(doc.createTextNode(css));
    }

    head.appendChild(style);
    return style;
  }
};

module.exports.byUrl = function(url) {
  if (document.createStyleSheet) {
    return document.createStyleSheet(url).ownerNode;
  } else {
    var head = document.getElementsByTagName('head')[0],
        link = document.createElement('link');

    link.rel = 'stylesheet';
    link.href = url;

    head.appendChild(link);
    return link;
  }
};

},{}],7:[function(require,module,exports){
(function (global){
var Card, QJ, extend, payment;

require('../scss/card.scss');

QJ = require('qj');

payment = require('./payment/src/payment.coffee');

extend = require('node.extend');

Card = (function() {
  var bindVal;

  Card.prototype.cardTemplate = '' + '<div class="jp-card-container">' + '<div class="jp-card">' + '<div class="jp-card-front">' + '<div class="jp-card-logo jp-card-visa">visa</div>' + '<div class="jp-card-logo jp-card-mastercard">MasterCard</div>' + '<div class="jp-card-logo jp-card-maestro">Maestro</div>' + '<div class="jp-card-logo jp-card-amex"></div>' + '<div class="jp-card-logo jp-card-discover">discover</div>' + '<div class="jp-card-logo jp-card-dankort"><div class="dk"><div class="d"></div><div class="k"></div></div></div>' + '<div class="jp-card-lower">' + '<div class="jp-card-shiny"></div>' + '<div class="jp-card-cvc jp-card-display">{{cvc}}</div>' + '<div class="jp-card-number jp-card-display">{{number}}</div>' + '<div class="jp-card-name jp-card-display">{{name}}</div>' + '<div class="jp-card-expiry jp-card-display" data-before="{{monthYear}}" data-after="{{validDate}}">{{expiry}}</div>' + '</div>' + '</div>' + '<div class="jp-card-back">' + '<div class="jp-card-bar"></div>' + '<div class="jp-card-cvc jp-card-display">{{cvc}}</div>' + '<div class="jp-card-shiny"></div>' + '</div>' + '</div>' + '</div>';

  Card.prototype.template = function(tpl, data) {
    return tpl.replace(/\{\{(.*?)\}\}/g, function(match, key, str) {
      return data[key];
    });
  };

  Card.prototype.cardTypes = ['jp-card-amex', 'jp-card-dankort', 'jp-card-dinersclub', 'jp-card-discover', 'jp-card-jcb', 'jp-card-laser', 'jp-card-maestro', 'jp-card-mastercard', 'jp-card-unionpay', 'jp-card-visa', 'jp-card-visaelectron'];

  Card.prototype.defaults = {
    formatting: true,
    formSelectors: {
      numberInput: 'input[name="number"]',
      expiryInput: 'input[name="expiry"]',
      cvcInput: 'input[name="cvc"]',
      nameInput: 'input[name="name"]'
    },
    cardSelectors: {
      cardContainer: '.jp-card-container',
      card: '.jp-card',
      numberDisplay: '.jp-card-number',
      expiryDisplay: '.jp-card-expiry',
      cvcDisplay: '.jp-card-cvc',
      nameDisplay: '.jp-card-name'
    },
    messages: {
      validDate: 'valid\nthru',
      monthYear: 'month/year'
    },
    placeholders: {
      number: '&bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull; &bull;&bull;&bull;&bull;',
      cvc: '&bull;&bull;&bull;',
      expiry: '&bull;&bull;/&bull;&bull;',
      name: 'Full Name'
    },
    classes: {
      valid: 'jp-card-valid',
      invalid: 'jp-card-invalid'
    },
    debug: false
  };

  function Card(opts) {
    this.options = extend(true, this.defaults, opts);
    if (!this.options.form) {
      console.log("Please provide a form");
      return;
    }
    this.$el = QJ(this.options.form);
    if (!this.options.container) {
      console.log("Please provide a container");
      return;
    }
    this.$container = QJ(this.options.container);
    this.render();
    this.attachHandlers();
    this.handleInitialPlaceholders();
  }

  Card.prototype.render = function() {
    var $cardContainer, baseWidth, name, obj, selector, ua, _ref, _ref1;
    QJ.append(this.$container, this.template(this.cardTemplate, extend({}, this.options.messages, this.options.placeholders)));
    _ref = this.options.cardSelectors;
    for (name in _ref) {
      selector = _ref[name];
      this["$" + name] = QJ.find(this.$container, selector);
    }
    _ref1 = this.options.formSelectors;
    for (name in _ref1) {
      selector = _ref1[name];
      selector = this.options[name] ? this.options[name] : selector;
      obj = QJ.find(this.$el, selector);
      if (!obj.length && this.options.debug) {
        console.error("Card can't find a " + name + " in your form.");
      }
      this["$" + name] = obj;
    }
    if (this.options.formatting) {
      Payment.formatCardNumber(this.$numberInput);
      Payment.formatCardCVC(this.$cvcInput);
      if (this.$expiryInput.length === 1) {
        Payment.formatCardExpiry(this.$expiryInput);
      }
    }
    if (this.options.width) {
      $cardContainer = QJ(this.options.cardSelectors.cardContainer)[0];
      baseWidth = parseInt($cardContainer.clientWidth);
      $cardContainer.style.transform = "scale(" + (this.options.width / baseWidth) + ")";
    }
    if (typeof navigator !== "undefined" && navigator !== null ? navigator.userAgent : void 0) {
      ua = navigator.userAgent.toLowerCase();
      if (ua.indexOf('safari') !== -1 && ua.indexOf('chrome') === -1) {
        QJ.addClass(this.$card, 'jp-card-safari');
      }
    }
    if (/MSIE 10\./i.test(navigator.userAgent)) {
      QJ.addClass(this.$card, 'jp-card-ie-10');
    }
    if (/rv:11.0/i.test(navigator.userAgent)) {
      return QJ.addClass(this.$card, 'jp-card-ie-11');
    }
  };

  Card.prototype.attachHandlers = function() {
    var expiryFilters;
    bindVal(this.$numberInput, this.$numberDisplay, {
      fill: false,
      filters: this.validToggler('cardNumber')
    });
    QJ.on(this.$numberInput, 'payment.cardType', this.handle('setCardType'));
    expiryFilters = [
      function(val) {
        return val.replace(/(\s+)/g, '');
      }
    ];
    if (this.$expiryInput.length === 1) {
      expiryFilters.push(this.validToggler('cardExpiry'));
    }
    bindVal(this.$expiryInput, this.$expiryDisplay, {
      join: function(text) {
        if (text[0].length === 2 || text[1]) {
          return "/";
        } else {
          return "";
        }
      },
      filters: expiryFilters
    });
    bindVal(this.$cvcInput, this.$cvcDisplay, {
      filters: this.validToggler('cardCVC')
    });
    QJ.on(this.$cvcInput, 'focus', this.handle('flipCard'));
    QJ.on(this.$cvcInput, 'blur', this.handle('unflipCard'));
    return bindVal(this.$nameInput, this.$nameDisplay, {
      fill: false,
      filters: this.validToggler('cardHolderName'),
      join: ' '
    });
  };

  Card.prototype.handleInitialPlaceholders = function() {
    var el, name, selector, _ref, _results;
    _ref = this.options.formSelectors;
    _results = [];
    for (name in _ref) {
      selector = _ref[name];
      el = this["$" + name];
      if (QJ.val(el)) {
        QJ.trigger(el, 'paste');
        _results.push(setTimeout(function() {
          return QJ.trigger(el, 'keyup');
        }));
      } else {
        _results.push(void 0);
      }
    }
    return _results;
  };

  Card.prototype.handle = function(fn) {
    return (function(_this) {
      return function(e) {
        var args;
        args = Array.prototype.slice.call(arguments);
        args.unshift(e.target);
        return _this.handlers[fn].apply(_this, args);
      };
    })(this);
  };

  Card.prototype.validToggler = function(validatorName) {
    var isValid;
    if (validatorName === "cardExpiry") {
      isValid = function(val) {
        var objVal;
        objVal = Payment.fns.cardExpiryVal(val);
        return Payment.fns.validateCardExpiry(objVal.month, objVal.year);
      };
    } else if (validatorName === "cardCVC") {
      isValid = (function(_this) {
        return function(val) {
          return Payment.fns.validateCardCVC(val, _this.cardType);
        };
      })(this);
    } else if (validatorName === "cardNumber") {
      isValid = function(val) {
        return Payment.fns.validateCardNumber(val);
      };
    } else if (validatorName === "cardHolderName") {
      isValid = function(val) {
        return val !== "";
      };
    }
    return (function(_this) {
      return function(val, $in, $out) {
        var result;
        result = isValid(val);
        _this.toggleValidClass($in, result);
        _this.toggleValidClass($out, result);
        return val;
      };
    })(this);
  };

  Card.prototype.toggleValidClass = function(el, test) {
    QJ.toggleClass(el, this.options.classes.valid, test);
    return QJ.toggleClass(el, this.options.classes.invalid, !test);
  };

  Card.prototype.handlers = {
    setCardType: function($el, e) {
      var cardType;
      cardType = e.data;
      if (!QJ.hasClass(this.$card, cardType)) {
        QJ.removeClass(this.$card, 'jp-card-unknown');
        QJ.removeClass(this.$card, this.cardTypes.join(' '));
        QJ.addClass(this.$card, "jp-card-" + cardType);
        QJ.toggleClass(this.$card, 'jp-card-identified', cardType !== 'unknown');
        return this.cardType = cardType;
      }
    },
    flipCard: function() {
      return QJ.addClass(this.$card, 'jp-card-flipped');
    },
    unflipCard: function() {
      return QJ.removeClass(this.$card, 'jp-card-flipped');
    }
  };

  bindVal = function(el, out, opts) {
    var joiner, o, outDefaults;
    if (opts == null) {
      opts = {};
    }
    opts.fill = opts.fill || false;
    opts.filters = opts.filters || [];
    if (!(opts.filters instanceof Array)) {
      opts.filters = [opts.filters];
    }
    opts.join = opts.join || "";
    if (!(typeof opts.join === "function")) {
      joiner = opts.join;
      opts.join = function() {
        return joiner;
      };
    }
    outDefaults = (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = out.length; _i < _len; _i++) {
        o = out[_i];
        _results.push(o.textContent);
      }
      return _results;
    })();
    QJ.on(el, 'focus', function() {
      return QJ.addClass(out, 'jp-card-focused');
    });
    QJ.on(el, 'blur', function() {
      return QJ.removeClass(out, 'jp-card-focused');
    });
    QJ.on(el, 'keyup change paste', function(e) {
      var elem, filter, i, join, outEl, outVal, val, _i, _j, _len, _len1, _ref, _results;
      val = (function() {
        var _i, _len, _results;
        _results = [];
        for (_i = 0, _len = el.length; _i < _len; _i++) {
          elem = el[_i];
          _results.push(QJ.val(elem));
        }
        return _results;
      })();
      join = opts.join(val);
      val = val.join(join);
      if (val === join) {
        val = "";
      }
      _ref = opts.filters;
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        filter = _ref[_i];
        val = filter(val, el, out);
      }
      _results = [];
      for (i = _j = 0, _len1 = out.length; _j < _len1; i = ++_j) {
        outEl = out[i];
        if (opts.fill) {
          outVal = val + outDefaults[i].substring(val.length);
        } else {
          outVal = val || outDefaults[i];
        }
        _results.push(outEl.textContent = outVal);
      }
      return _results;
    });
    return el;
  };

  return Card;

})();

module.exports = Card;

global.Card = Card;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"../scss/card.scss":10,"./payment/src/payment.coffee":9,"node.extend":1,"qj":4}],8:[function(require,module,exports){
var $, Card,
  __slice = [].slice;

Card = require('./card');

$ = jQuery;

$.card = {};

$.card.fn = {};

$.fn.card = function(opts) {
  return $.card.fn.construct.apply(this, opts);
};

$.fn.extend({
  card: function() {
    var args, option;
    option = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    return this.each(function() {
      var $this, data;
      $this = $(this);
      data = $this.data('card');
      if (!data) {
        $.each(option, (function(_this) {
          return function(key, value) {
            if (value instanceof jQuery) {
              return option[key] = value[0];
            }
          };
        })(this));
        option['form'] = this;
        $this.data('card', (data = new Card(option)));
      }
      if (typeof option === 'string') {
        return data[option].apply(data, args);
      }
    });
  }
});

},{"./card":7}],9:[function(require,module,exports){
(function (global){
var Payment, QJ, cardFromNumber, cardFromType, cards, defaultFormat, formatBackCardNumber, formatBackExpiry, formatCardNumber, formatExpiry, formatForwardExpiry, formatForwardSlash, hasTextSelected, luhnCheck, reFormatCardNumber, restrictCVC, restrictCardNumber, restrictExpiry, restrictNumeric, setCardType,
  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

QJ = require('qj');

defaultFormat = /(\d{1,4})/g;

cards = [
  {
    type: 'amex',
    pattern: /^3[47]/,
    format: /(\d{1,4})(\d{1,6})?(\d{1,5})?/,
    length: [15],
    cvcLength: [4],
    luhn: true
  }, {
    type: 'dankort',
    pattern: /^5019/,
    format: defaultFormat,
    length: [16],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'dinersclub',
    pattern: /^(36|38|30[0-5])/,
    format: defaultFormat,
    length: [14],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'discover',
    pattern: /^(6011|65|64[4-9]|622)/,
    format: defaultFormat,
    length: [16],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'jcb',
    pattern: /^35/,
    format: defaultFormat,
    length: [16],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'laser',
    pattern: /^(6706|6771|6709)/,
    format: defaultFormat,
    length: [16, 17, 18, 19],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'maestro',
    pattern: /^(5018|5020|5038|6304|6703|6759|676[1-3])/,
    format: defaultFormat,
    length: [12, 13, 14, 15, 16, 17, 18, 19],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'mastercard',
    pattern: /^5[1-5]/,
    format: defaultFormat,
    length: [16],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'unionpay',
    pattern: /^62/,
    format: defaultFormat,
    length: [16, 17, 18, 19],
    cvcLength: [3],
    luhn: false
  }, {
    type: 'visaelectron',
    pattern: /^4(026|17500|405|508|844|91[37])/,
    format: defaultFormat,
    length: [16],
    cvcLength: [3],
    luhn: true
  }, {
    type: 'visa',
    pattern: /^4/,
    format: defaultFormat,
    length: [13, 14, 15, 16],
    cvcLength: [3],
    luhn: true
  }
];

cardFromNumber = function(num) {
  var card, _i, _len;
  num = (num + '').replace(/\D/g, '');
  for (_i = 0, _len = cards.length; _i < _len; _i++) {
    card = cards[_i];
    if (card.pattern.test(num)) {
      return card;
    }
  }
};

cardFromType = function(type) {
  var card, _i, _len;
  for (_i = 0, _len = cards.length; _i < _len; _i++) {
    card = cards[_i];
    if (card.type === type) {
      return card;
    }
  }
};

luhnCheck = function(num) {
  var digit, digits, odd, sum, _i, _len;
  odd = true;
  sum = 0;
  digits = (num + '').split('').reverse();
  for (_i = 0, _len = digits.length; _i < _len; _i++) {
    digit = digits[_i];
    digit = parseInt(digit, 10);
    if ((odd = !odd)) {
      digit *= 2;
    }
    if (digit > 9) {
      digit -= 9;
    }
    sum += digit;
  }
  return sum % 10 === 0;
};

hasTextSelected = function(target) {
  var _ref;
  if ((target.selectionStart != null) && target.selectionStart !== target.selectionEnd) {
    return true;
  }
  if ((typeof document !== "undefined" && document !== null ? (_ref = document.selection) != null ? _ref.createRange : void 0 : void 0) != null) {
    if (document.selection.createRange().text) {
      return true;
    }
  }
  return false;
};

reFormatCardNumber = function(e) {
  return setTimeout((function(_this) {
    return function() {
      var target, value;
      target = e.target;
      value = QJ.val(target);
      value = Payment.fns.formatCardNumber(value);
      return QJ.val(target, value);
    };
  })(this));
};

formatCardNumber = function(e) {
  var card, digit, length, re, target, upperLength, value;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  target = e.target;
  value = QJ.val(target);
  card = cardFromNumber(value + digit);
  length = (value.replace(/\D/g, '') + digit).length;
  upperLength = 16;
  if (card) {
    upperLength = card.length[card.length.length - 1];
  }
  if (length >= upperLength) {
    return;
  }
  if ((target.selectionStart != null) && target.selectionStart !== value.length) {
    return;
  }
  if (card && card.type === 'amex') {
    re = /^(\d{4}|\d{4}\s\d{6})$/;
  } else {
    re = /(?:^|\s)(\d{4})$/;
  }
  if (re.test(value)) {
    e.preventDefault();
    return QJ.val(target, value + ' ' + digit);
  } else if (re.test(value + digit)) {
    e.preventDefault();
    return QJ.val(target, value + digit + ' ');
  }
};

formatBackCardNumber = function(e) {
  var target, value;
  target = e.target;
  value = QJ.val(target);
  if (e.meta) {
    return;
  }
  if (e.which !== 8) {
    return;
  }
  if ((target.selectionStart != null) && target.selectionStart !== value.length) {
    return;
  }
  if (/\d\s$/.test(value)) {
    e.preventDefault();
    return QJ.val(target, value.replace(/\d\s$/, ''));
  } else if (/\s\d?$/.test(value)) {
    e.preventDefault();
    return QJ.val(target, value.replace(/\s\d?$/, ''));
  }
};

formatExpiry = function(e) {
  var digit, target, val;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  target = e.target;
  val = QJ.val(target) + digit;
  if (/^\d$/.test(val) && (val !== '0' && val !== '1')) {
    e.preventDefault();
    return QJ.val(target, "0" + val + " / ");
  } else if (/^\d\d$/.test(val)) {
    e.preventDefault();
    return QJ.val(target, "" + val + " / ");
  }
};

formatForwardExpiry = function(e) {
  var digit, target, val;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  target = e.target;
  val = QJ.val(target);
  if (/^\d\d$/.test(val)) {
    return QJ.val(target, "" + val + " / ");
  }
};

formatForwardSlash = function(e) {
  var slash, target, val;
  slash = String.fromCharCode(e.which);
  if (slash !== '/') {
    return;
  }
  target = e.target;
  val = QJ.val(target);
  if (/^\d$/.test(val) && val !== '0') {
    return QJ.val(target, "0" + val + " / ");
  }
};

formatBackExpiry = function(e) {
  var target, value;
  if (e.metaKey) {
    return;
  }
  target = e.target;
  value = QJ.val(target);
  if (e.which !== 8) {
    return;
  }
  if ((target.selectionStart != null) && target.selectionStart !== value.length) {
    return;
  }
  if (/\d(\s|\/)+$/.test(value)) {
    e.preventDefault();
    return QJ.val(target, value.replace(/\d(\s|\/)*$/, ''));
  } else if (/\s\/\s?\d?$/.test(value)) {
    e.preventDefault();
    return QJ.val(target, value.replace(/\s\/\s?\d?$/, ''));
  }
};

restrictNumeric = function(e) {
  var input;
  if (e.metaKey || e.ctrlKey) {
    return true;
  }
  if (e.which === 32) {
    return e.preventDefault();
  }
  if (e.which === 0) {
    return true;
  }
  if (e.which < 33) {
    return true;
  }
  input = String.fromCharCode(e.which);
  if (!/[\d\s]/.test(input)) {
    return e.preventDefault();
  }
};

restrictCardNumber = function(e) {
  var card, digit, target, value;
  target = e.target;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  if (hasTextSelected(target)) {
    return;
  }
  value = (QJ.val(target) + digit).replace(/\D/g, '');
  card = cardFromNumber(value);
  if (card) {
    if (!(value.length <= card.length[card.length.length - 1])) {
      return e.preventDefault();
    }
  } else {
    if (!(value.length <= 16)) {
      return e.preventDefault();
    }
  }
};

restrictExpiry = function(e) {
  var digit, target, value;
  target = e.target;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  if (hasTextSelected(target)) {
    return;
  }
  value = QJ.val(target) + digit;
  value = value.replace(/\D/g, '');
  if (value.length > 6) {
    return e.preventDefault();
  }
};

restrictCVC = function(e) {
  var digit, target, val;
  target = e.target;
  digit = String.fromCharCode(e.which);
  if (!/^\d+$/.test(digit)) {
    return;
  }
  val = QJ.val(target) + digit;
  if (!(val.length <= 4)) {
    return e.preventDefault();
  }
};

setCardType = function(e) {
  var allTypes, card, cardType, target, val;
  target = e.target;
  val = QJ.val(target);
  cardType = Payment.fns.cardType(val) || 'unknown';
  if (!QJ.hasClass(target, cardType)) {
    allTypes = (function() {
      var _i, _len, _results;
      _results = [];
      for (_i = 0, _len = cards.length; _i < _len; _i++) {
        card = cards[_i];
        _results.push(card.type);
      }
      return _results;
    })();
    QJ.removeClass(target, 'unknown');
    QJ.removeClass(target, allTypes.join(' '));
    QJ.addClass(target, cardType);
    QJ.toggleClass(target, 'identified', cardType !== 'unknown');
    return QJ.trigger(target, 'payment.cardType', cardType);
  }
};

Payment = (function() {
  function Payment() {}

  Payment.fns = {
    cardExpiryVal: function(value) {
      var month, prefix, year, _ref;
      value = value.replace(/\s/g, '');
      _ref = value.split('/', 2), month = _ref[0], year = _ref[1];
      if ((year != null ? year.length : void 0) === 2 && /^\d+$/.test(year)) {
        prefix = (new Date).getFullYear();
        prefix = prefix.toString().slice(0, 2);
        year = prefix + year;
      }
      month = parseInt(month, 10);
      year = parseInt(year, 10);
      return {
        month: month,
        year: year
      };
    },
    validateCardNumber: function(num) {
      var card, _ref;
      num = (num + '').replace(/\s+|-/g, '');
      if (!/^\d+$/.test(num)) {
        return false;
      }
      card = cardFromNumber(num);
      if (!card) {
        return false;
      }
      return (_ref = num.length, __indexOf.call(card.length, _ref) >= 0) && (card.luhn === false || luhnCheck(num));
    },
    validateCardExpiry: function(month, year) {
      var currentTime, expiry, prefix, _ref;
      if (typeof month === 'object' && 'month' in month) {
        _ref = month, month = _ref.month, year = _ref.year;
      }
      if (!(month && year)) {
        return false;
      }
      month = QJ.trim(month);
      year = QJ.trim(year);
      if (!/^\d+$/.test(month)) {
        return false;
      }
      if (!/^\d+$/.test(year)) {
        return false;
      }
      if (!(parseInt(month, 10) <= 12)) {
        return false;
      }
      if (year.length === 2) {
        prefix = (new Date).getFullYear();
        prefix = prefix.toString().slice(0, 2);
        year = prefix + year;
      }
      expiry = new Date(year, month);
      currentTime = new Date;
      expiry.setMonth(expiry.getMonth() - 1);
      expiry.setMonth(expiry.getMonth() + 1, 1);
      return expiry > currentTime;
    },
    validateCardCVC: function(cvc, type) {
      var _ref, _ref1;
      cvc = QJ.trim(cvc);
      if (!/^\d+$/.test(cvc)) {
        return false;
      }
      if (type && cardFromType(type)) {
        return _ref = cvc.length, __indexOf.call((_ref1 = cardFromType(type)) != null ? _ref1.cvcLength : void 0, _ref) >= 0;
      } else {
        return cvc.length >= 3 && cvc.length <= 4;
      }
    },
    cardType: function(num) {
      var _ref;
      if (!num) {
        return null;
      }
      return ((_ref = cardFromNumber(num)) != null ? _ref.type : void 0) || null;
    },
    formatCardNumber: function(num) {
      var card, groups, upperLength, _ref;
      card = cardFromNumber(num);
      if (!card) {
        return num;
      }
      upperLength = card.length[card.length.length - 1];
      num = num.replace(/\D/g, '');
      num = num.slice(0, +upperLength + 1 || 9e9);
      if (card.format.global) {
        return (_ref = num.match(card.format)) != null ? _ref.join(' ') : void 0;
      } else {
        groups = card.format.exec(num);
        if (groups != null) {
          groups.shift();
        }
        return groups != null ? groups.join(' ') : void 0;
      }
    }
  };

  Payment.restrictNumeric = function(el) {
    return QJ.on(el, 'keypress', restrictNumeric);
  };

  Payment.cardExpiryVal = function(el) {
    return Payment.fns.cardExpiryVal(QJ.val(el));
  };

  Payment.formatCardCVC = function(el) {
    Payment.restrictNumeric(el);
    QJ.on(el, 'keypress', restrictCVC);
    return el;
  };

  Payment.formatCardExpiry = function(el) {
    Payment.restrictNumeric(el);
    QJ.on(el, 'keypress', restrictExpiry);
    QJ.on(el, 'keypress', formatExpiry);
    QJ.on(el, 'keypress', formatForwardSlash);
    QJ.on(el, 'keypress', formatForwardExpiry);
    QJ.on(el, 'keydown', formatBackExpiry);
    return el;
  };

  Payment.formatCardNumber = function(el) {
    Payment.restrictNumeric(el);
    QJ.on(el, 'keypress', restrictCardNumber);
    QJ.on(el, 'keypress', formatCardNumber);
    QJ.on(el, 'keydown', formatBackCardNumber);
    QJ.on(el, 'keyup', setCardType);
    QJ.on(el, 'paste', reFormatCardNumber);
    return el;
  };

  Payment.getCardArray = function() {
    return cards;
  };

  Payment.setCardArray = function(cardArray) {
    cards = cardArray;
    return true;
  };

  Payment.addToCardArray = function(cardObject) {
    return cards.push(cardObject);
  };

  Payment.removeFromCardArray = function(type) {
    var key, value;
    for (key in cards) {
      value = cards[key];
      if (value.type === type) {
        cards.splice(key, 1);
      }
    }
    return true;
  };

  return Payment;

})();

module.exports = Payment;

global.Payment = Payment;

}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"qj":4}],10:[function(require,module,exports){
module.exports = require('sassify')('.jp-card.jp-card-safari.jp-card-identified .jp-card-front:before, .jp-card.jp-card-safari.jp-card-identified .jp-card-back:before {   background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), -webkit-linear-gradient(-245deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%);   background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), linear-gradient(-25deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%); }  .jp-card.jp-card-ie-10.jp-card-flipped, .jp-card.jp-card-ie-11.jp-card-flipped {   -webkit-transform: 0deg;   -moz-transform: 0deg;   -ms-transform: 0deg;   -o-transform: 0deg;   transform: 0deg; }   .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-front, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-front {     -webkit-transform: rotateY(0deg);     -moz-transform: rotateY(0deg);     -ms-transform: rotateY(0deg);     -o-transform: rotateY(0deg);     transform: rotateY(0deg); }   .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-back, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-back {     -webkit-transform: rotateY(0deg);     -moz-transform: rotateY(0deg);     -ms-transform: rotateY(0deg);     -o-transform: rotateY(0deg);     transform: rotateY(0deg); }     .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-back:after, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-back:after {       left: 18%; }     .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-back .jp-card-cvc, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-back .jp-card-cvc {       -webkit-transform: rotateY(180deg);       -moz-transform: rotateY(180deg);       -ms-transform: rotateY(180deg);       -o-transform: rotateY(180deg);       transform: rotateY(180deg);       left: 5%; }     .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-back .jp-card-shiny, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-back .jp-card-shiny {       left: 84%; }       .jp-card.jp-card-ie-10.jp-card-flipped .jp-card-back .jp-card-shiny:after, .jp-card.jp-card-ie-11.jp-card-flipped .jp-card-back .jp-card-shiny:after {         left: -480%;         -webkit-transform: rotateY(180deg);         -moz-transform: rotateY(180deg);         -ms-transform: rotateY(180deg);         -o-transform: rotateY(180deg);         transform: rotateY(180deg); }  .jp-card.jp-card-ie-10.jp-card-amex .jp-card-back, .jp-card.jp-card-ie-11.jp-card-amex .jp-card-back {   display: none; }  .jp-card-logo {   height: 36px;   width: 60px;   font-style: italic; }   .jp-card-logo, .jp-card-logo:before, .jp-card-logo:after {     box-sizing: border-box; }  .jp-card-logo.jp-card-amex {   text-transform: uppercase;   font-size: 4px;   font-weight: bold;   color: white;   background-image: repeating-radial-gradient(circle at center, #FFF 1px, #999 2px);   background-image: repeating-radial-gradient(circle at center, #FFF 1px, #999 2px);   border: 1px solid #EEE; }   .jp-card-logo.jp-card-amex:before, .jp-card-logo.jp-card-amex:after {     width: 28px;     display: block;     position: absolute;     left: 16px; }   .jp-card-logo.jp-card-amex:before {     height: 28px;     content: "american";     top: 3px;     text-align: left;     padding-left: 2px;     padding-top: 11px;     background: #267AC3; }   .jp-card-logo.jp-card-amex:after {     content: "express";     bottom: 11px;     text-align: right;     padding-right: 2px; }  .jp-card.jp-card-amex.jp-card-flipped {   -webkit-transform: none;   -moz-transform: none;   -ms-transform: none;   -o-transform: none;   transform: none; }  .jp-card.jp-card-amex.jp-card-identified .jp-card-front:before, .jp-card.jp-card-amex.jp-card-identified .jp-card-back:before {   background-color: #108168; }  .jp-card.jp-card-amex.jp-card-identified .jp-card-front .jp-card-logo.jp-card-amex {   opacity: 1; }  .jp-card.jp-card-amex.jp-card-identified .jp-card-front .jp-card-cvc {   visibility: visible; }  .jp-card.jp-card-amex.jp-card-identified .jp-card-front:after {   opacity: 1; }  .jp-card-logo.jp-card-discover {   background: #FF6600;   color: #111;   text-transform: uppercase;   font-style: normal;   font-weight: bold;   font-size: 10px;   text-align: center;   overflow: hidden;   z-index: 1;   padding-top: 9px;   letter-spacing: .03em;   border: 1px solid #EEE; }   .jp-card-logo.jp-card-discover:before, .jp-card-logo.jp-card-discover:after {     content: " ";     display: block;     position: absolute; }   .jp-card-logo.jp-card-discover:before {     background: white;     width: 200px;     height: 200px;     border-radius: 200px;     bottom: -5%;     right: -80%;     z-index: -1; }   .jp-card-logo.jp-card-discover:after {     width: 8px;     height: 8px;     border-radius: 4px;     top: 10px;     left: 27px;     background-color: #FF6600;     background-image: -webkit-radial-gradient(#FF6600, #fff, , , , , , , , );     background-image: radial-gradient(  #FF6600, #fff, , , , , , , , );     content: "network";     font-size: 4px;     line-height: 24px;     text-indent: -7px; }  .jp-card .jp-card-front .jp-card-logo.jp-card-discover {   right: 12%;   top: 18%; }  .jp-card.jp-card-discover.jp-card-identified .jp-card-front:before, .jp-card.jp-card-discover.jp-card-identified .jp-card-back:before {   background-color: #86B8CF; }  .jp-card.jp-card-discover.jp-card-identified .jp-card-logo.jp-card-discover {   opacity: 1; }  .jp-card.jp-card-discover.jp-card-identified .jp-card-front:after {   -webkit-transition: 400ms;   -moz-transition: 400ms;   transition: 400ms;   content: " ";   display: block;   background-color: #FF6600;   background-image: -webkit-linear-gradient(#FF6600, #ffa366, #FF6600);   background-image: linear-gradient(#FF6600, #ffa366, #FF6600, , , , , , , );   height: 50px;   width: 50px;   border-radius: 25px;   position: absolute;   left: 100%;   top: 15%;   margin-left: -25px;   box-shadow: inset 1px 1px 3px 1px rgba(0, 0, 0, 0.5); }  .jp-card-logo.jp-card-visa {   background: white;   text-transform: uppercase;   color: #1A1876;   text-align: center;   font-weight: bold;   font-size: 15px;   line-height: 18px; }   .jp-card-logo.jp-card-visa:before, .jp-card-logo.jp-card-visa:after {     content: " ";     display: block;     width: 100%;     height: 25%; }   .jp-card-logo.jp-card-visa:before {     background: #1A1876; }   .jp-card-logo.jp-card-visa:after {     background: #E79800; }  .jp-card.jp-card-visa.jp-card-identified .jp-card-front:before, .jp-card.jp-card-visa.jp-card-identified .jp-card-back:before {   background-color: #191278; }  .jp-card.jp-card-visa.jp-card-identified .jp-card-logo.jp-card-visa {   opacity: 1; }  .jp-card-logo.jp-card-mastercard {   color: white;   font-weight: bold;   text-align: center;   font-size: 9px;   line-height: 36px;   z-index: 1;   text-shadow: 1px 1px rgba(0, 0, 0, 0.6); }   .jp-card-logo.jp-card-mastercard:before, .jp-card-logo.jp-card-mastercard:after {     content: " ";     display: block;     width: 36px;     top: 0;     position: absolute;     height: 36px;     border-radius: 18px; }   .jp-card-logo.jp-card-mastercard:before {     left: 0;     background: #FF0000;     z-index: -1; }   .jp-card-logo.jp-card-mastercard:after {     right: 0;     background: #FFAB00;     z-index: -2; }  .jp-card.jp-card-mastercard.jp-card-identified .jp-card-front .jp-card-logo.jp-card-mastercard, .jp-card.jp-card-mastercard.jp-card-identified .jp-card-back .jp-card-logo.jp-card-mastercard {   box-shadow: none; }  .jp-card.jp-card-mastercard.jp-card-identified .jp-card-front:before, .jp-card.jp-card-mastercard.jp-card-identified .jp-card-back:before {   background-color: #0061A8; }  .jp-card.jp-card-mastercard.jp-card-identified .jp-card-logo.jp-card-mastercard {   opacity: 1; }  .jp-card-logo.jp-card-maestro {   color: white;   font-weight: bold;   text-align: center;   font-size: 14px;   line-height: 36px;   z-index: 1;   text-shadow: 1px 1px rgba(0, 0, 0, 0.6); }   .jp-card-logo.jp-card-maestro:before, .jp-card-logo.jp-card-maestro:after {     content: " ";     display: block;     width: 36px;     top: 0;     position: absolute;     height: 36px;     border-radius: 18px; }   .jp-card-logo.jp-card-maestro:before {     left: 0;     background: #0064CB;     z-index: -1; }   .jp-card-logo.jp-card-maestro:after {     right: 0;     background: #CC0000;     z-index: -2; }  .jp-card.jp-card-maestro.jp-card-identified .jp-card-front .jp-card-logo.jp-card-maestro, .jp-card.jp-card-maestro.jp-card-identified .jp-card-back .jp-card-logo.jp-card-maestro {   box-shadow: none; }  .jp-card.jp-card-maestro.jp-card-identified .jp-card-front:before, .jp-card.jp-card-maestro.jp-card-identified .jp-card-back:before {   background-color: #0B2C5F; }  .jp-card.jp-card-maestro.jp-card-identified .jp-card-logo.jp-card-maestro {   opacity: 1; }  .jp-card-logo.jp-card-dankort {   width: 60px;   height: 36px;   padding: 3px;   border-radius: 8px;   border: #000000 1px solid;   background-color: #FFFFFF; }   .jp-card-logo.jp-card-dankort .dk {     position: relative;     width: 100%;     height: 100%;     overflow: hidden; }     .jp-card-logo.jp-card-dankort .dk:before {       background-color: #ED1C24;       content: \'\';       position: absolute;       width: 100%;       height: 100%;       display: block;       border-radius: 6px; }     .jp-card-logo.jp-card-dankort .dk:after {       content: \'\';       position: absolute;       top: 50%;       margin-top: -7.7px;       right: 0;       width: 0;       height: 0;       border-style: solid;       border-width: 7px 7px 10px 0;       border-color: transparent #ED1C24 transparent transparent;       z-index: 1; }   .jp-card-logo.jp-card-dankort .d, .jp-card-logo.jp-card-dankort .k {     position: absolute;     top: 50%;     width: 50%;     display: block;     height: 15.4px;     margin-top: -7.7px;     background: white; }   .jp-card-logo.jp-card-dankort .d {     left: 0;     border-radius: 0 8px 10px 0; }     .jp-card-logo.jp-card-dankort .d:before {       content: \'\';       position: absolute;       top: 50%;       left: 50%;       display: block;       background: #ED1C24;       border-radius: 2px 4px 6px 0px;       height: 5px;       width: 7px;       margin: -3px 0 0 -4px; }   .jp-card-logo.jp-card-dankort .k {     right: 0; }     .jp-card-logo.jp-card-dankort .k:before, .jp-card-logo.jp-card-dankort .k:after {       content: \'\';       position: absolute;       right: 50%;       width: 0;       height: 0;       border-style: solid;       margin-right: -1px; }     .jp-card-logo.jp-card-dankort .k:before {       top: 0;       border-width: 8px 5px 0 0;       border-color: #ED1C24 transparent transparent transparent; }     .jp-card-logo.jp-card-dankort .k:after {       bottom: 0;       border-width: 0 5px 8px 0;       border-color: transparent transparent #ED1C24 transparent; }  .jp-card.jp-card-dankort.jp-card-identified .jp-card-front:before, .jp-card.jp-card-dankort.jp-card-identified .jp-card-back:before {   background-color: #0055C7; }  .jp-card.jp-card-dankort.jp-card-identified .jp-card-logo.jp-card-dankort {   opacity: 1; }  .jp-card-container {   -webkit-perspective: 1000px;   -moz-perspective: 1000px;   perspective: 1000px;   width: 350px;   max-width: 100%;   height: 200px;   margin: auto;   z-index: 1;   position: relative; }  .jp-card {   font-family: "Helvetica Neue";   line-height: 1;   position: relative;   width: 100%;   height: 100%;   min-width: 315px;   border-radius: 10px;   -webkit-transform-style: preserve-3d;   -moz-transform-style: preserve-3d;   -ms-transform-style: preserve-3d;   -o-transform-style: preserve-3d;   transform-style: preserve-3d;   -webkit-transition: all 400ms linear;   -moz-transition: all 400ms linear;   transition: all 400ms linear; }   .jp-card > *, .jp-card > *:before, .jp-card > *:after {     -moz-box-sizing: border-box;     -webkit-box-sizing: border-box;     box-sizing: border-box;     font-family: inherit; }   .jp-card.jp-card-flipped {     -webkit-transform: rotateY(180deg);     -moz-transform: rotateY(180deg);     -ms-transform: rotateY(180deg);     -o-transform: rotateY(180deg);     transform: rotateY(180deg); }   .jp-card .jp-card-front, .jp-card .jp-card-back {     -webkit-backface-visibility: hidden;     backface-visibility: hidden;     -webkit-transform-style: preserve-3d;     -moz-transform-style: preserve-3d;     -ms-transform-style: preserve-3d;     -o-transform-style: preserve-3d;     transform-style: preserve-3d;     -webkit-transition: all 400ms linear;     -moz-transition: all 400ms linear;     transition: all 400ms linear;     width: 100%;     height: 100%;     position: absolute;     top: 0;     left: 0;     overflow: hidden;     border-radius: 10px;     background: #DDD; }     .jp-card .jp-card-front:before, .jp-card .jp-card-back:before {       content: " ";       display: block;       position: absolute;       width: 100%;       height: 100%;       top: 0;       left: 0;       opacity: 0;       border-radius: 10px;       -webkit-transition: all 400ms ease;       -moz-transition: all 400ms ease;       transition: all 400ms ease; }     .jp-card .jp-card-front:after, .jp-card .jp-card-back:after {       content: " ";       display: block; }     .jp-card .jp-card-front .jp-card-display, .jp-card .jp-card-back .jp-card-display {       color: white;       font-weight: normal;       opacity: 0.5;       -webkit-transition: opacity 400ms linear;       -moz-transition: opacity 400ms linear;       transition: opacity 400ms linear; }       .jp-card .jp-card-front .jp-card-display.jp-card-focused, .jp-card .jp-card-back .jp-card-display.jp-card-focused {         opacity: 1;         font-weight: 700; }     .jp-card .jp-card-front .jp-card-cvc, .jp-card .jp-card-back .jp-card-cvc {       font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;       font-size: 14px; }     .jp-card .jp-card-front .jp-card-shiny, .jp-card .jp-card-back .jp-card-shiny {       width: 50px;       height: 35px;       border-radius: 5px;       background: #CCC;       position: relative; }       .jp-card .jp-card-front .jp-card-shiny:before, .jp-card .jp-card-back .jp-card-shiny:before {         content: " ";         display: block;         width: 70%;         height: 60%;         border-top-right-radius: 5px;         border-bottom-right-radius: 5px;         background: #d9d9d9;         position: absolute;         top: 20%; }   .jp-card .jp-card-front .jp-card-logo {     position: absolute;     opacity: 0;     right: 5%;     top: 8%;     -webkit-transition: 400ms;     -moz-transition: 400ms;     transition: 400ms; }   .jp-card .jp-card-front .jp-card-lower {     width: 80%;     position: absolute;     left: 10%;     bottom: 30px; }     @media only screen and (max-width: 480px) {       .jp-card .jp-card-front .jp-card-lower {         width: 90%;         left: 5%; } }     .jp-card .jp-card-front .jp-card-lower .jp-card-cvc {       visibility: hidden;       float: right;       position: relative;       bottom: 5px; }     .jp-card .jp-card-front .jp-card-lower .jp-card-number {       font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;       font-size: 24px;       clear: both;       margin-bottom: 30px; }     .jp-card .jp-card-front .jp-card-lower .jp-card-expiry {       font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;       letter-spacing: 0em;       position: relative;       float: right;       width: 25%; }       .jp-card .jp-card-front .jp-card-lower .jp-card-expiry:before, .jp-card .jp-card-front .jp-card-lower .jp-card-expiry:after {         font-family: "Helvetica Neue";         font-weight: bold;         font-size: 7px;         white-space: pre;         display: block;         opacity: .5; }       .jp-card .jp-card-front .jp-card-lower .jp-card-expiry:before {         content: attr(data-before);         margin-bottom: 2px;         font-size: 7px;         text-transform: uppercase; }       .jp-card .jp-card-front .jp-card-lower .jp-card-expiry:after {         position: absolute;         content: attr(data-after);         text-align: right;         right: 100%;         margin-right: 5px;         margin-top: 2px;         bottom: 0; }     .jp-card .jp-card-front .jp-card-lower .jp-card-name {       text-transform: uppercase;       font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;       font-size: 20px;       max-height: 45px;       position: absolute;       bottom: 0;       width: 190px;       display: -webkit-box;       -webkit-line-clamp: 2;       -webkit-box-orient: horizontal;       overflow: hidden;       text-overflow: ellipsis; }   .jp-card .jp-card-back {     -webkit-transform: rotateY(180deg);     -moz-transform: rotateY(180deg);     -ms-transform: rotateY(180deg);     -o-transform: rotateY(180deg);     transform: rotateY(180deg); }     .jp-card .jp-card-back .jp-card-bar {       background-color: #444;       background-image: -webkit-linear-gradient(#444, #333);       background-image: linear-gradient(#444, #333, , , , , , , , );       width: 100%;       height: 20%;       position: absolute;       top: 10%; }     .jp-card .jp-card-back:after {       content: " ";       display: block;       background-color: #FFF;       background-image: -webkit-linear-gradient(#FFF, #FFF);       background-image: linear-gradient(#FFF, #FFF, , , , , , , , );       width: 80%;       height: 16%;       position: absolute;       top: 40%;       left: 2%; }     .jp-card .jp-card-back .jp-card-cvc {       position: absolute;       top: 40%;       left: 85%;       -webkit-transition-delay: 600ms;       -moz-transition-delay: 600ms;       transition-delay: 600ms; }     .jp-card .jp-card-back .jp-card-shiny {       position: absolute;       top: 66%;       left: 2%; }       .jp-card .jp-card-back .jp-card-shiny:after {         content: "This card has been issued by Jesse Pollak and is licensed for anyone to use anywhere for free.\AIt comes with no warranty.\A For support issues, please visit: github.com/jessepollak/card.";         position: absolute;         left: 120%;         top: 5%;         color: white;         font-size: 7px;         width: 230px;         opacity: .5; }   .jp-card.jp-card-identified {     box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); }     .jp-card.jp-card-identified .jp-card-front, .jp-card.jp-card-identified .jp-card-back {       background-color: #000;       background-color: rgba(0, 0, 0, 0.5); }       .jp-card.jp-card-identified .jp-card-front:before, .jp-card.jp-card-identified .jp-card-back:before {         -webkit-transition: all 400ms ease;         -moz-transition: all 400ms ease;         transition: all 400ms ease;         background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 70% 70%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 90% 20%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 15% 80%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), -webkit-linear-gradient(-245deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%);         background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 70% 70%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 90% 20%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-radial-gradient(circle at 15% 80%, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), linear-gradient(-25deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%);         opacity: 1; }       .jp-card.jp-card-identified .jp-card-front .jp-card-logo, .jp-card.jp-card-identified .jp-card-back .jp-card-logo {         box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.3); }     .jp-card.jp-card-identified.no-radial-gradient .jp-card-front:before, .jp-card.jp-card-identified.no-radial-gradient .jp-card-back:before {       background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), -webkit-linear-gradient(-245deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%);       background-image: repeating-linear-gradient(45deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.05) 1px, rgba(255, 255, 255, 0) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.03) 4px), repeating-linear-gradient(90deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), repeating-linear-gradient(210deg, rgba(255, 255, 255, 0) 1px, rgba(255, 255, 255, 0.03) 2px, rgba(255, 255, 255, 0.04) 3px, rgba(255, 255, 255, 0.05) 4px), linear-gradient(-25deg, rgba(255, 255, 255, 0) 50%, rgba(255, 255, 255, 0.2) 70%, rgba(255, 255, 255, 0) 90%); } ');;
},{"sassify":5}]},{},[8]);
/*jshint eqnull:true */
/*!
* jQuery Cookie Plugin v1.2
* https://github.com/carhartl/jquery-cookie
*
* Copyright 2011, Klaus Hartl
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://www.opensource.org/licenses/mit-license.php
* http://www.opensource.org/licenses/GPL-2.0
*/
(function ($, document, undefined) {

    var pluses = /\+/g;

    function raw(s) {
        return s;
    }

    function decoded(s) {
        return decodeURIComponent(s.replace(pluses, ' '));
    }

    $.cookie = function (key, value, options) {

        // key and at least value given, set cookie...
        if (value !== undefined && !/Object/.test(Object.prototype.toString.call(value))) {
            options = $.extend({}, $.cookie.defaults, options);

            if (value === null) {
                options.expires = -1;
            }

            if (typeof options.expires === 'number') {
                var days = options.expires, t = options.expires = new Date();
                t.setDate(t.getDate() + days);
            }

            value = String(value);

            return (document.cookie = [
				encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
				options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
				options.path ? '; path=' + options.path : '',
				options.domain ? '; domain=' + options.domain : '',
				options.secure ? '; secure' : ''
			].join(''));
        }

        // key and possibly options given, get cookie...
        options = value || $.cookie.defaults || {};
        var decode = options.raw ? raw : decoded;
        var cookies = document.cookie.split('; ');
        for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
            if (decode(parts.shift()) === key) {
                return decode(parts.join('='));
            }
        }

        return null;
    };

    $.cookie.defaults = {};

    $.removeCookie = function (key, options) {
        if ($.cookie(key, options) !== null) {
            $.cookie(key, null, options);
            return true;
        }
        return false;
    };

})(jQuery, document);
(function (jQuery) {

    var daysInWeek = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var shortMonthsInYear = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    var longMonthsInYear = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    var shortMonthsToNumber = [];
    shortMonthsToNumber["Jan"] = "01";
    shortMonthsToNumber["Feb"] = "02";
    shortMonthsToNumber["Mar"] = "03";
    shortMonthsToNumber["Apr"] = "04";
    shortMonthsToNumber["May"] = "05";
    shortMonthsToNumber["Jun"] = "06";
    shortMonthsToNumber["Jul"] = "07";
    shortMonthsToNumber["Aug"] = "08";
    shortMonthsToNumber["Sep"] = "09";
    shortMonthsToNumber["Oct"] = "10";
    shortMonthsToNumber["Nov"] = "11";
    shortMonthsToNumber["Dec"] = "12";

    jQuery.format = (function () {
        function strDay(value) {
            return daysInWeek[parseInt(value, 10)] || value;
        }

        function strMonth(value) {
            var monthArrayIndex = parseInt(value, 10) - 1;
            return shortMonthsInYear[monthArrayIndex] || value;
        }

        function strLongMonth(value) {
            var monthArrayIndex = parseInt(value, 10) - 1;
            return longMonthsInYear[monthArrayIndex] || value;
        }

        var parseMonth = function (value) {
            return shortMonthsToNumber[value] || value;
        };

        var parseTime = function (value) {
            var retValue = value;
            var millis = "";
            if (retValue.indexOf(".") !== -1) {
                var delimited = retValue.split('.');
                retValue = delimited[0];
                millis = delimited[1];
            }

            var values3 = retValue.split(":");

            if (values3.length === 3) {
                hour = values3[0];
                minute = values3[1];
                second = values3[2];

                return {
                    time: retValue,
                    hour: hour,
                    minute: minute,
                    second: second,
                    millis: millis
                };
            } else {
                return {
                    time: "",
                    hour: "",
                    minute: "",
                    second: "",
                    millis: ""
                };
            }
        };

        return {
            date: function (value, format) {
                /* 
                value = new java.util.Date()
                2009-12-18 10:54:50.546 
                */
                try {
                    var date = null;
                    var year = null;
                    var month = null;
                    var dayOfMonth = null;
                    var dayOfWeek = null;
                    var time = null;
                    if (typeof value == "number") {
                        return this.date(new Date(value), format);
                    } else if (typeof value.getFullYear == "function") {
                        year = value.getFullYear();
                        month = value.getMonth() + 1;
                        dayOfMonth = value.getDate();
                        dayOfWeek = value.getDay();
                        time = parseTime(value.toTimeString());
                    } else if (value.search(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.?\d{0,3}[-+]?\d{2}:?\d{2}/) != -1) { /* 2009-04-19T16:11:05+02:00 */
                        var values = value.split(/[T\+-]/);
                        year = values[0];
                        month = values[1];
                        dayOfMonth = values[2];
                        time = parseTime(values[3].split(".")[0]);
                        date = new Date(year, month - 1, dayOfMonth);
                        dayOfWeek = date.getDay();
                    } else {
                        var values = value.split(" ");
                        switch (values.length) {
                            case 6:
                                /* Wed Jan 13 10:43:41 CET 2010 */
                                year = values[5];
                                month = parseMonth(values[1]);
                                dayOfMonth = values[2];
                                time = parseTime(values[3]);
                                date = new Date(year, month - 1, dayOfMonth);
                                dayOfWeek = date.getDay();
                                break;
                            case 2:
                                /* 2009-12-18 10:54:50.546 */
                                var values2 = values[0].split("-");
                                year = values2[0];
                                month = values2[1];
                                dayOfMonth = values2[2];
                                time = parseTime(values[1]);
                                date = new Date(year, month - 1, dayOfMonth);
                                dayOfWeek = date.getDay();
                                break;
                            case 7:
                                /* Tue Mar 01 2011 12:01:42 GMT-0800 (PST) */
                            case 9:
                                /*added by Larry, for Fri Apr 08 2011 00:00:00 GMT+0800 (China Standard Time) */
                            case 10:
                                /* added by Larry, for Fri Apr 08 2011 00:00:00 GMT+0200 (W. Europe Daylight Time) */
                                year = values[3];
                                month = parseMonth(values[1]);
                                dayOfMonth = values[2];
                                time = parseTime(values[4]);
                                date = new Date(year, month - 1, dayOfMonth);
                                dayOfWeek = date.getDay();
                                break;
                            case 1:
                                /* added by Jonny, for 2012-02-07CET00:00:00 (Doctrine Entity -> Json Serializer) */
                                var values2 = values[0].split("");
                                year = values2[0] + values2[1] + values2[2] + values2[3];
                                month = values2[5] + values2[6];
                                dayOfMonth = values2[8] + values2[9];
                                time = parseTime(values2[13] + values2[14] + values2[15] + values2[16] + values2[17] + values2[18] + values2[19] + values2[20])
                                date = new Date(year, month - 1, dayOfMonth);
                                dayOfWeek = date.getDay();
                                break;
                            default:
                                return value;
                        }
                    }

                    var pattern = "";
                    var retValue = "";
                    var unparsedRest = "";
                    /*
                    Issue 1 - variable scope issue in format.date 
                    Thanks jakemonO
                    */
                    for (var i = 0; i < format.length; i++) {
                        var currentPattern = format.charAt(i);
                        pattern += currentPattern;
                        unparsedRest = "";
                        switch (pattern) {
                            case "ddd":
                                retValue += strDay(dayOfWeek);
                                pattern = "";
                                break;
                            case "dd":
                                if (format.charAt(i + 1) == "d") {
                                    break;
                                }
                                if (String(dayOfMonth).length === 1) {
                                    dayOfMonth = '0' + dayOfMonth;
                                }
                                retValue += dayOfMonth;
                                pattern = "";
                                break;
                            case "d":
                                if (format.charAt(i + 1) == "d") {
                                    break;
                                }
                                retValue += parseInt(dayOfMonth, 10);
                                pattern = "";
                                break;
                            case "MMMM":
                                retValue += strLongMonth(month);
                                pattern = "";
                                break;
                            case "MMM":
                                if (format.charAt(i + 1) === "M") {
                                    break;
                                }
                                retValue += strMonth(month);
                                pattern = "";
                                break;
                            case "MM":
                                if (format.charAt(i + 1) == "M") {
                                    break;
                                }
                                if (String(month).length === 1) {
                                    month = '0' + month;
                                }
                                retValue += month;
                                pattern = "";
                                break;
                            case "M":
                                if (format.charAt(i + 1) == "M") {
                                    break;
                                }
                                retValue += parseInt(month, 10);
                                pattern = "";
                                break;
                            case "yyyy":
                                retValue += year;
                                pattern = "";
                                break;
                            case "yy":
                                if (format.charAt(i + 1) == "y" && format.charAt(i + 2) == "y") {
                                    break;
                                }
                                retValue += String(year).slice(-2);
                                pattern = "";
                                break;
                            case "HH":
                                retValue += time.hour;
                                pattern = "";
                                break;
                            case "hh":
                                /* time.hour is "00" as string == is used instead of === */
                                var hour = (time.hour == 0 ? 12 : time.hour < 13 ? time.hour : time.hour - 12);
                                hour = String(hour).length == 1 ? '0' + hour : hour;
                                retValue += hour;
                                pattern = "";
                                break;
                            case "h":
                                if (format.charAt(i + 1) == "h") {
                                    break;
                                }
                                var hour = (time.hour == 0 ? 12 : time.hour < 13 ? time.hour : time.hour - 12);
                                retValue += parseInt(hour, 10);
                                // Fixing issue https://github.com/phstc/jquery-dateFormat/issues/21
                                // retValue = parseInt(retValue, 10);
                                pattern = "";
                                break;
                            case "mm":
                                retValue += time.minute;
                                pattern = "";
                                break;
                            case "ss":
                                /* ensure only seconds are added to the return string */
                                retValue += time.second.substring(0, 2);
                                pattern = "";
                                break;
                            case "SSS":
                                retValue += time.millis.substring(0, 3);
                                pattern = "";
                                break;
                            case "a":
                                retValue += time.hour >= 12 ? "PM" : "AM";
                                pattern = "";
                                break;
                            case " ":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            case "/":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            case ":":
                                retValue += currentPattern;
                                pattern = "";
                                break;
                            default:
                                if (pattern.length === 2 && pattern.indexOf("y") !== 0 && pattern != "SS") {
                                    retValue += pattern.substring(0, 1);
                                    pattern = pattern.substring(1, 2);
                                } else if ((pattern.length === 3 && pattern.indexOf("yyy") === -1)) {
                                    pattern = "";
                                } else {
                                    unparsedRest = pattern;
                                }
                        }
                    }
                    retValue += unparsedRest;
                    return retValue;
                } catch (e) {
                    //console.log(e);
                    return value;
                }
            }
        };
    } ());
} (jQuery));

jQuery.format.date.defaultShortDateFormat = "dd/MM/yyyy";
jQuery.format.date.defaultLongDateFormat = "dd/MM/yyyy hh:mm:ss";

jQuery(document).ready(function () {
    jQuery(".shortDateFormat").each(function (idx, elem) {
        if (jQuery(elem).is(":input")) {
            jQuery(elem).val(jQuery.format.date(jQuery(elem).val(), jQuery.format.date.defaultShortDateFormat));
        } else {
            jQuery(elem).text(jQuery.format.date(jQuery(elem).text(), jQuery.format.date.defaultShortDateFormat));
        }
    });
    jQuery(".longDateFormat").each(function (idx, elem) {
        if (jQuery(elem).is(":input")) {
            jQuery(elem).val(jQuery.format.date(jQuery(elem).val(), jQuery.format.date.defaultLongDateFormat));
        } else {
            jQuery(elem).text(jQuery.format.date(jQuery(elem).text(), jQuery.format.date.defaultLongDateFormat));
        }
    });
});
/**
* Version: 1.0 Alpha-1
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
/**
* Version: 1.0 Alpha-1 
* Build Date: 13-Nov-2007
* Copyright (c) 2006-2007, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* License: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/. 
* Website: http://www.datejs.com/ or http://www.coolite.com/datejs/
*/
Date.CultureInfo = {
    /* Culture Name */
    name: "en-AU",
    englishName: "English (Australia)",
    nativeName: "English (Australia)",

    /* Day Name Strings */
    dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
    abbreviatedDayNames: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
    shortestDayNames: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
    firstLetterDayNames: ["S", "M", "T", "W", "T", "F", "S"],

    /* Month Name Strings */
    monthNames: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
    abbreviatedMonthNames: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],

    /* AM/PM Designators */
    amDesignator: "AM",
    pmDesignator: "PM",

    firstDayOfWeek: 1,
    twoDigitYearMax: 2029,

    /**
    * The dateElementOrder is based on the order of the 
    * format specifiers in the formatPatterns.DatePattern. 
    *
    * Example:
    <pre>
    shortDatePattern    dateElementOrder
    ------------------  ---------------- 
    "M/d/yyyy"          "mdy"
    "dd/MM/yyyy"        "dmy"
    "yyyy-MM-dd"        "ymd"
    </pre>
    * The correct dateElementOrder is required by the parser to
    * determine the expected order of the date elements in the
    * string being parsed.
    * 
    * NOTE: It is VERY important this value be correct for each Culture.
    */
    dateElementOrder: "dmy",

    /* Standard date and time format patterns */
    formatPatterns: {
        shortDate: "d/MM/yyyy",
        longDate: "dddd, d MMMM yyyy",
        shortTime: "h:mm tt",
        longTime: "h:mm:ss tt",
        fullDateTime: "dddd, d MMMM yyyy h:mm:ss tt",
        sortableDateTime: "yyyy-MM-ddTHH:mm:ss",
        universalSortableDateTime: "yyyy-MM-dd HH:mm:ssZ",
        rfc1123: "ddd, dd MMM yyyy HH:mm:ss GMT",
        monthDay: "dd MMMM",
        yearMonth: "MMMM yyyy"
    },

    /**
    * NOTE: If a string format is not parsing correctly, but
    * you would expect it parse, the problem likely lies below. 
    * 
    * The following regex patterns control most of the string matching
    * within the parser.
    * 
    * The Month name and Day name patterns were automatically generated
    * and in general should be (mostly) correct. 
    *
    * Beyond the month and day name patterns are natural language strings.
    * Example: "next", "today", "months"
    *
    * These natural language string may NOT be correct for this culture. 
    * If they are not correct, please translate and edit this file
    * providing the correct regular expression pattern. 
    *
    * If you modify this file, please post your revised CultureInfo file
    * to the Datejs Discussions located at
    *     http://groups.google.com/group/date-js
    *
    * Please mark the subject with [CultureInfo]. Example:
    *    Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
    * 
    * We will add the modified patterns to the master source files.
    *
    * As well, please review the list of "Future Strings" section below. 
    */
    regexPatterns: {
        jan: /^jan(uary)?/i,
        feb: /^feb(ruary)?/i,
        mar: /^mar(ch)?/i,
        apr: /^apr(il)?/i,
        may: /^may/i,
        jun: /^jun(e)?/i,
        jul: /^jul(y)?/i,
        aug: /^aug(ust)?/i,
        sep: /^sep(t(ember)?)?/i,
        oct: /^oct(ober)?/i,
        nov: /^nov(ember)?/i,
        dec: /^dec(ember)?/i,

        sun: /^su(n(day)?)?/i,
        mon: /^mo(n(day)?)?/i,
        tue: /^tu(e(s(day)?)?)?/i,
        wed: /^we(d(nesday)?)?/i,
        thu: /^th(u(r(s(day)?)?)?)?/i,
        fri: /^fr(i(day)?)?/i,
        sat: /^sa(t(urday)?)?/i,

        future: /^next/i,
        past: /^last|past|prev(ious)?/i,
        add: /^(\+|after|from)/i,
        subtract: /^(\-|before|ago)/i,

        yesterday: /^yesterday/i,
        today: /^t(oday)?/i,
        tomorrow: /^tomorrow/i,
        now: /^n(ow)?/i,

        millisecond: /^ms|milli(second)?s?/i,
        second: /^sec(ond)?s?/i,
        minute: /^min(ute)?s?/i,
        hour: /^h(ou)?rs?/i,
        week: /^w(ee)?k/i,
        month: /^m(o(nth)?s?)?/i,
        day: /^d(ays?)?/i,
        year: /^y((ea)?rs?)?/i,

        shortMeridian: /^(a|p)/i,
        longMeridian: /^(a\.?m?\.?|p\.?m?\.?)/i,
        timezone: /^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt)/i,
        ordinalSuffix: /^\s*(st|nd|rd|th)/i,
        timeContext: /^\s*(\:|a|p)/i
    },

    abbreviatedTimeZoneStandard: { GMT: "-000", EST: "-0400", CST: "-0500", MST: "-0600", PST: "-0700" },
    abbreviatedTimeZoneDST: { GMT: "-000", EDT: "-0500", CDT: "-0600", MDT: "-0700", PDT: "-0800" }

};

/********************
** Future Strings **
********************
* 
* The following list of strings are not currently being used, but 
* may be incorporated later. We would appreciate any help translating
* the strings below.
* 
* If you modify this file, please post your revised CultureInfo file
* to the Datejs Discussions located at
*     http://groups.google.com/group/date-js
*
* Please mark the subject with [CultureInfo]. Example:
*    Subject: [CultureInfo] Translated "da-DK" Danish(Denmark)
*
* English Name        Translated
* ------------------  -----------------
* date                date
* time                time
* calendar            calendar
* show                show
* hourly              hourly
* daily               daily
* weekly              weekly
* bi-weekly           bi-weekly
* monthly             monthly
* bi-monthly          bi-monthly
* quarter             quarter
* quarterly           quarterly
* yearly              yearly
* annual              annual
* annually            annually
* annum               annum
* again               again
* between             between
* after               after
* from now            from now
* repeat              repeat
* times               times
* per                 per
*/

Date.getMonthNumberFromName = function (name) {
    var n = Date.CultureInfo.monthNames,
        m = Date.CultureInfo.abbreviatedMonthNames,
        s = name.toLowerCase();
    for (var i = 0; i < n.length; i++) {
        if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) {
            return i;
        }
    }
    return -1;
};
Date.getDayNumberFromName = function (name) {
    var n = Date.CultureInfo.dayNames,
        m = Date.CultureInfo.abbreviatedDayNames,
        o = Date.CultureInfo.shortestDayNames,
        s = name.toLowerCase();
    for (var i = 0; i < n.length; i++) {
        if (n[i].toLowerCase() == s || m[i].toLowerCase() == s) {
            return i;
        }
    }
    return -1;
};
Date.isLeapYear = function (year) {
    return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
};
Date.getDaysInMonth = function (year, month) {
    return [31, (Date.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
};
Date.getTimezoneOffset = function (s, dst) {
    return (dst || false) ? Date.CultureInfo.abbreviatedTimeZoneDST[s.toUpperCase()] : Date.CultureInfo.abbreviatedTimeZoneStandard[s.toUpperCase()];
};
Date.getTimezoneAbbreviation = function (offset, dst) {
    var n = (dst || false) ? Date.CultureInfo.abbreviatedTimeZoneDST : Date.CultureInfo.abbreviatedTimeZoneStandard,
        p;
    for (p in n) {
        if (n[p] === offset) {
            return p;
        }
    }
    return null;
};
Date.prototype.clone = function () {
    return new Date(this.getTime());
};
Date.prototype.compareTo = function (date) {
    if (isNaN(this)) {
        throw new Error(this);
    }
    if (date instanceof Date && !isNaN(date)) {
        return (this > date) ? 1 : (this < date) ? -1 : 0;
    } else {
        throw new TypeError(date);
    }
};
Date.prototype.equals = function (date) {
    return (this.compareTo(date) === 0);
};
Date.prototype.between = function (start, end) {
    var t = this.getTime();
    return t >= start.getTime() && t <= end.getTime();
};
Date.prototype.addMilliseconds = function (value) {
    this.setMilliseconds(this.getMilliseconds() + value);
    return this;
};
Date.prototype.addSeconds = function (value) {
    return this.addMilliseconds(value * 1000);
};
Date.prototype.addMinutes = function (value) {
    return this.addMilliseconds(value * 60000);
};
Date.prototype.addHours = function (value) {
    return this.addMilliseconds(value * 3600000);
};
Date.prototype.addDays = function (value) {
    return this.addMilliseconds(value * 86400000);
};
Date.prototype.addWeeks = function (value) {
    return this.addMilliseconds(value * 604800000);
};
Date.prototype.addMonths = function (value) {
    var n = this.getDate();
    this.setDate(1);
    this.setMonth(this.getMonth() + value);
    this.setDate(Math.min(n, this.getDaysInMonth()));
    return this;
};
Date.prototype.addYears = function (value) {
    return this.addMonths(value * 12);
};
Date.prototype.add = function (config) {
    if (typeof config == "number") {
        this._orient = config;
        return this;
    }
    var x = config;
    if (x.millisecond || x.milliseconds) {
        this.addMilliseconds(x.millisecond || x.milliseconds);
    }
    if (x.second || x.seconds) {
        this.addSeconds(x.second || x.seconds);
    }
    if (x.minute || x.minutes) {
        this.addMinutes(x.minute || x.minutes);
    }
    if (x.hour || x.hours) {
        this.addHours(x.hour || x.hours);
    }
    if (x.month || x.months) {
        this.addMonths(x.month || x.months);
    }
    if (x.year || x.years) {
        this.addYears(x.year || x.years);
    }
    if (x.day || x.days) {
        this.addDays(x.day || x.days);
    }
    return this;
};
Date._validate = function (value, min, max, name) {
    if (typeof value != "number") {
        throw new TypeError(value + " is not a Number.");
    } else if (value < min || value > max) {
        throw new RangeError(value + " is not a valid value for " + name + ".");
    }
    return true;
};
Date.validateMillisecond = function (n) {
    return Date._validate(n, 0, 999, "milliseconds");
};
Date.validateSecond = function (n) {
    return Date._validate(n, 0, 59, "seconds");
};
Date.validateMinute = function (n) {
    return Date._validate(n, 0, 59, "minutes");
};
Date.validateHour = function (n) {
    return Date._validate(n, 0, 23, "hours");
};
Date.validateDay = function (n, year, month) {
    return Date._validate(n, 1, Date.getDaysInMonth(year, month), "days");
};
Date.validateMonth = function (n) {
    return Date._validate(n, 0, 11, "months");
};
Date.validateYear = function (n) {
    return Date._validate(n, 1, 9999, "seconds");
};
Date.prototype.set = function (config) {
    var x = config;
    if (!x.millisecond && x.millisecond !== 0) {
        x.millisecond = -1;
    }
    if (!x.second && x.second !== 0) {
        x.second = -1;
    }
    if (!x.minute && x.minute !== 0) {
        x.minute = -1;
    }
    if (!x.hour && x.hour !== 0) {
        x.hour = -1;
    }
    if (!x.day && x.day !== 0) {
        x.day = -1;
    }
    if (!x.month && x.month !== 0) {
        x.month = -1;
    }
    if (!x.year && x.year !== 0) {
        x.year = -1;
    }
    if (x.millisecond != -1 && Date.validateMillisecond(x.millisecond)) {
        this.addMilliseconds(x.millisecond - this.getMilliseconds());
    }
    if (x.second != -1 && Date.validateSecond(x.second)) {
        this.addSeconds(x.second - this.getSeconds());
    }
    if (x.minute != -1 && Date.validateMinute(x.minute)) {
        this.addMinutes(x.minute - this.getMinutes());
    }
    if (x.hour != -1 && Date.validateHour(x.hour)) {
        this.addHours(x.hour - this.getHours());
    }
    if (x.month !== -1 && Date.validateMonth(x.month)) {
        this.addMonths(x.month - this.getMonth());
    }
    if (x.year != -1 && Date.validateYear(x.year)) {
        this.addYears(x.year - this.getFullYear());
    }
    if (x.day != -1 && Date.validateDay(x.day, this.getFullYear(), this.getMonth())) {
        this.addDays(x.day - this.getDate());
    }
    if (x.timezone) {
        this.setTimezone(x.timezone);
    }
    if (x.timezoneOffset) {
        this.setTimezoneOffset(x.timezoneOffset);
    }
    return this;
};
Date.prototype.clearTime = function () {
    this.setHours(0);
    this.setMinutes(0);
    this.setSeconds(0);
    this.setMilliseconds(0);
    return this;
};
Date.prototype.isLeapYear = function () {
    var y = this.getFullYear();
    return (((y % 4 === 0) && (y % 100 !== 0)) || (y % 400 === 0));
};
Date.prototype.isWeekday = function () {
    return !(this.is().sat() || this.is().sun());
};
Date.prototype.getDaysInMonth = function () {
    return Date.getDaysInMonth(this.getFullYear(), this.getMonth());
};
Date.prototype.moveToFirstDayOfMonth = function () {
    return this.set({
        day: 1
    });
};
Date.prototype.moveToLastDayOfMonth = function () {
    return this.set({
        day: this.getDaysInMonth()
    });
};
Date.prototype.moveToDayOfWeek = function (day, orient) {
    var diff = (day - this.getDay() + 7 * (orient || +1)) % 7;
    return this.addDays((diff === 0) ? diff += 7 * (orient || +1) : diff);
};
Date.prototype.moveToMonth = function (month, orient) {
    var diff = (month - this.getMonth() + 12 * (orient || +1)) % 12;
    return this.addMonths((diff === 0) ? diff += 12 * (orient || +1) : diff);
};
Date.prototype.getDayOfYear = function () {
    return Math.floor((this - new Date(this.getFullYear(), 0, 1)) / 86400000);
};
Date.prototype.getWeekOfYear = function (firstDayOfWeek) {
    var y = this.getFullYear(),
        m = this.getMonth(),
        d = this.getDate();
    var dow = firstDayOfWeek || Date.CultureInfo.firstDayOfWeek;
    var offset = 7 + 1 - new Date(y, 0, 1).getDay();
    if (offset == 8) {
        offset = 1;
    }
    var daynum = ((Date.UTC(y, m, d, 0, 0, 0) - Date.UTC(y, 0, 1, 0, 0, 0)) / 86400000) + 1;
    var w = Math.floor((daynum - offset + 7) / 7);
    if (w === dow) {
        y--;
        var prevOffset = 7 + 1 - new Date(y, 0, 1).getDay();
        if (prevOffset == 2 || prevOffset == 8) {
            w = 53;
        } else {
            w = 52;
        }
    }
    return w;
};
Date.prototype.isDST = function () {
    console.log('isDST');
    return this.toString().match(/(E|C|M|P)(S|D)T/)[2] == "D";
};
Date.prototype.getTimezone = function () {
    return Date.getTimezoneAbbreviation(this.getUTCOffset, this.isDST());
};
Date.prototype.setTimezoneOffset = function (s) {
    var here = this.getTimezoneOffset(),
        there = Number(s) * -6 / 10;
    this.addMinutes(there - here);
    return this;
};
Date.prototype.setTimezone = function (s) {
    return this.setTimezoneOffset(Date.getTimezoneOffset(s));
};
Date.prototype.getUTCOffset = function () {
    var n = this.getTimezoneOffset() * -10 / 6,
        r;
    if (n < 0) {
        r = (n - 10000).toString();
        return r[0] + r.substr(2);
    } else {
        r = (n + 10000).toString();
        return "+" + r.substr(1);
    }
};
Date.prototype.getDayName = function (abbrev) {
    return abbrev ? Date.CultureInfo.abbreviatedDayNames[this.getDay()] : Date.CultureInfo.dayNames[this.getDay()];
};
Date.prototype.getMonthName = function (abbrev) {
    return abbrev ? Date.CultureInfo.abbreviatedMonthNames[this.getMonth()] : Date.CultureInfo.monthNames[this.getMonth()];
};
Date.prototype._toString = Date.prototype.toString;
Date.prototype.toString = function (format) {
    var self = this;
    var p = function p(s) {
        return (s.toString().length == 1) ? "0" + s : s;
    };
    return format ? format.replace(/dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?/g, function (format) {
        switch (format) {
            case "hh":
                return p(self.getHours() < 13 ? self.getHours() : (self.getHours() - 12));
            case "h":
                return self.getHours() < 13 ? self.getHours() : (self.getHours() - 12);
            case "HH":
                return p(self.getHours());
            case "H":
                return self.getHours();
            case "mm":
                return p(self.getMinutes());
            case "m":
                return self.getMinutes();
            case "ss":
                return p(self.getSeconds());
            case "s":
                return self.getSeconds();
            case "yyyy":
                return self.getFullYear();
            case "yy":
                return self.getFullYear().toString().substring(2, 4);
            case "dddd":
                return self.getDayName();
            case "ddd":
                return self.getDayName(true);
            case "dd":
                return p(self.getDate());
            case "d":
                return self.getDate().toString();
            case "MMMM":
                return self.getMonthName();
            case "MMM":
                return self.getMonthName(true);
            case "MM":
                return p((self.getMonth() + 1));
            case "M":
                return self.getMonth() + 1;
            case "t":
                return self.getHours() < 12 ? Date.CultureInfo.amDesignator.substring(0, 1) : Date.CultureInfo.pmDesignator.substring(0, 1);
            case "tt":
                return self.getHours() < 12 ? Date.CultureInfo.amDesignator : Date.CultureInfo.pmDesignator;
            case "zzz":
            case "zz":
            case "z":
                return "";
        }
    }) : this._toString();
};
Date.now = function () {
    return new Date();
};
Date.today = function () {
    return Date.now().clearTime();
};
Date.prototype._orient = +1;
Date.prototype.next = function () {
    this._orient = +1;
    return this;
};
Date.prototype.last = Date.prototype.prev = Date.prototype.previous = function () {
    this._orient = -1;
    return this;
};
Date.prototype._is = false;
Date.prototype.is = function () {
    this._is = true;
    return this;
};
Number.prototype._dateElement = "day";
Number.prototype.fromNow = function () {
    var c = {};
    c[this._dateElement] = this;
    return Date.now().add(c);
};
Number.prototype.ago = function () {
    var c = {};
    c[this._dateElement] = this * -1;
    return Date.now().add(c);
};
(function () {
    var $D = Date.prototype,
        $N = Number.prototype;
    var dx = ("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),
        mx = ("january february march april may june july august september october november december").split(/\s/),
        px = ("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),
        de;
    var df = function (n) {
        return function () {
            if (this._is) {
                this._is = false;
                return this.getDay() == n;
            }
            return this.moveToDayOfWeek(n, this._orient);
        };
    };
    for (var i = 0; i < dx.length; i++) {
        $D[dx[i]] = $D[dx[i].substring(0, 3)] = df(i);
    }
    var mf = function (n) {
        return function () {
            if (this._is) {
                this._is = false;
                return this.getMonth() === n;
            }
            return this.moveToMonth(n, this._orient);
        };
    };
    for (var j = 0; j < mx.length; j++) {
        $D[mx[j]] = $D[mx[j].substring(0, 3)] = mf(j);
    }
    var ef = function (j) {
        return function () {
            if (j.substring(j.length - 1) != "s") {
                j += "s";
            }
            return this["add" + j](this._orient);
        };
    };
    var nf = function (n) {
        return function () {
            this._dateElement = n;
            return this;
        };
    };
    for (var k = 0; k < px.length; k++) {
        de = px[k].toLowerCase();
        $D[de] = $D[de + "s"] = ef(px[k]);
        $N[de] = $N[de + "s"] = nf(de);
    }
} ());
Date.prototype.toJSONString = function () {
    return this.toString("yyyy-MM-ddThh:mm:ssZ");
};
Date.prototype.toShortDateString = function () {
    return this.toString(Date.CultureInfo.formatPatterns.shortDatePattern);
};
Date.prototype.toLongDateString = function () {
    return this.toString(Date.CultureInfo.formatPatterns.longDatePattern);
};
Date.prototype.toShortTimeString = function () {
    return this.toString(Date.CultureInfo.formatPatterns.shortTimePattern);
};
Date.prototype.toLongTimeString = function () {
    return this.toString(Date.CultureInfo.formatPatterns.longTimePattern);
};
Date.prototype.getOrdinal = function () {
    switch (this.getDate()) {
        case 1:
        case 21:
        case 31:
            return "st";
        case 2:
        case 22:
            return "nd";
        case 3:
        case 23:
            return "rd";
        default:
            return "th";
    }
};
(function () {
    Date.Parsing = {
        Exception: function (s) {
            this.message = "Parse error at '" + s.substring(0, 10) + " ...'";
        }
    };
    var $P = Date.Parsing;
    var _ = $P.Operators = {
        rtoken: function (r) {
            return function (s) {
                var mx = s.match(r);
                if (mx) {
                    return ([mx[0], s.substring(mx[0].length)]);
                } else {
                    throw new $P.Exception(s);
                }
            };
        },
        token: function (s) {
            return function (s) {
                return _.rtoken(new RegExp("^\s*" + s + "\s*"))(s);
            };
        },
        stoken: function (s) {
            return _.rtoken(new RegExp("^" + s));
        },
        until: function (p) {
            return function (s) {
                var qx = [],
                    rx = null;
                while (s.length) {
                    try {
                        rx = p.call(this, s);
                    } catch (e) {
                        qx.push(rx[0]);
                        s = rx[1];
                        continue;
                    }
                    break;
                }
                return [qx, s];
            };
        },
        many: function (p) {
            return function (s) {
                var rx = [],
                    r = null;
                while (s.length) {
                    try {
                        r = p.call(this, s);
                    } catch (e) {
                        return [rx, s];
                    }
                    rx.push(r[0]);
                    s = r[1];
                }
                return [rx, s];
            };
        },
        optional: function (p) {
            return function (s) {
                var r = null;
                try {
                    r = p.call(this, s);
                } catch (e) {
                    return [null, s];
                }
                return [r[0], r[1]];
            };
        },
        not: function (p) {
            return function (s) {
                try {
                    p.call(this, s);
                } catch (e) {
                    return [null, s];
                }
                throw new $P.Exception(s);
            };
        },
        ignore: function (p) {
            return p ? function (s) {
                var r = null;
                r = p.call(this, s);
                return [null, r[1]];
            } : null;
        },
        product: function () {
            var px = arguments[0],
                qx = Array.prototype.slice.call(arguments, 1),
                rx = [];
            for (var i = 0; i < px.length; i++) {
                rx.push(_.each(px[i], qx));
            }
            return rx;
        },
        cache: function (rule) {
            var cache = {},
                r = null;
            return function (s) {
                try {
                    r = cache[s] = (cache[s] || rule.call(this, s));
                } catch (e) {
                    r = cache[s] = e;
                }
                if (r instanceof $P.Exception) {
                    throw r;
                } else {
                    return r;
                }
            };
        },
        any: function () {
            var px = arguments;
            return function (s) {
                var r = null;
                for (var i = 0; i < px.length; i++) {
                    if (px[i] == null) {
                        continue;
                    }
                    try {
                        r = (px[i].call(this, s));
                    } catch (e) {
                        r = null;
                    }
                    if (r) {
                        return r;
                    }
                }
                throw new $P.Exception(s);
            };
        },
        each: function () {
            var px = arguments;
            return function (s) {
                var rx = [],
                    r = null;
                for (var i = 0; i < px.length; i++) {
                    if (px[i] == null) {
                        continue;
                    }
                    try {
                        r = (px[i].call(this, s));
                    } catch (e) {
                        throw new $P.Exception(s);
                    }
                    rx.push(r[0]);
                    s = r[1];
                }
                return [rx, s];
            };
        },
        all: function () {
            var px = arguments,
                _ = _;
            return _.each(_.optional(px));
        },
        sequence: function (px, d, c) {
            d = d || _.rtoken(/^\s*/);
            c = c || null;
            if (px.length == 1) {
                return px[0];
            }
            return function (s) {
                var r = null,
                    q = null;
                var rx = [];
                for (var i = 0; i < px.length; i++) {
                    try {
                        r = px[i].call(this, s);
                    } catch (e) {
                        break;
                    }
                    rx.push(r[0]);
                    try {
                        q = d.call(this, r[1]);
                    } catch (ex) {
                        q = null;
                        break;
                    }
                    s = q[1];
                }
                if (!r) {
                    throw new $P.Exception(s);
                }
                if (q) {
                    throw new $P.Exception(q[1]);
                }
                if (c) {
                    try {
                        r = c.call(this, r[1]);
                    } catch (ey) {
                        throw new $P.Exception(r[1]);
                    }
                }
                return [rx, (r ? r[1] : s)];
            };
        },
        between: function (d1, p, d2) {
            d2 = d2 || d1;
            var _fn = _.each(_.ignore(d1), p, _.ignore(d2));
            return function (s) {
                var rx = _fn.call(this, s);
                return [
                    [rx[0][0], r[0][2]], rx[1]
                ];
            };
        },
        list: function (p, d, c) {
            d = d || _.rtoken(/^\s*/);
            c = c || null;
            return (p instanceof Array ? _.each(_.product(p.slice(0, -1), _.ignore(d)), p.slice(-1), _.ignore(c)) : _.each(_.many(_.each(p, _.ignore(d))), px, _.ignore(c)));
        },
        set: function (px, d, c) {
            d = d || _.rtoken(/^\s*/);
            c = c || null;
            return function (s) {
                var r = null,
                    p = null,
                    q = null,
                    rx = null,
                    best = [
                        [], s
                    ],
                    last = false;
                for (var i = 0; i < px.length; i++) {
                    q = null;
                    p = null;
                    r = null;
                    last = (px.length == 1);
                    try {
                        r = px[i].call(this, s);
                    } catch (e) {
                        continue;
                    }
                    rx = [
                        [r[0]], r[1]
                    ];
                    if (r[1].length > 0 && !last) {
                        try {
                            q = d.call(this, r[1]);
                        } catch (ex) {
                            last = true;
                        }
                    } else {
                        last = true;
                    }
                    if (!last && q[1].length === 0) {
                        last = true;
                    }
                    if (!last) {
                        var qx = [];
                        for (var j = 0; j < px.length; j++) {
                            if (i != j) {
                                qx.push(px[j]);
                            }
                        }
                        p = _.set(qx, d).call(this, q[1]);
                        if (p[0].length > 0) {
                            rx[0] = rx[0].concat(p[0]);
                            rx[1] = p[1];
                        }
                    }
                    if (rx[1].length < best[1].length) {
                        best = rx;
                    }
                    if (best[1].length === 0) {
                        break;
                    }
                }
                if (best[0].length === 0) {
                    return best;
                }
                if (c) {
                    try {
                        q = c.call(this, best[1]);
                    } catch (ey) {
                        throw new $P.Exception(best[1]);
                    }
                    best[1] = q[1];
                }
                return best;
            };
        },
        forward: function (gr, fname) {
            return function (s) {
                return gr[fname].call(this, s);
            };
        },
        replace: function (rule, repl) {
            return function (s) {
                var r = rule.call(this, s);
                return [repl, r[1]];
            };
        },
        process: function (rule, fn) {
            return function (s) {
                var r = rule.call(this, s);
                return [fn.call(this, r[0]), r[1]];
            };
        },
        min: function (min, rule) {
            return function (s) {
                var rx = rule.call(this, s);
                if (rx[0].length < min) {
                    throw new $P.Exception(s);
                }
                return rx;
            };
        }
    };
    var _generator = function (op) {
        return function () {
            var args = null,
                rx = [];
            if (arguments.length > 1) {
                args = Array.prototype.slice.call(arguments);
            } else if (arguments[0] instanceof Array) {
                args = arguments[0];
            }
            if (args) {
                for (var i = 0, px = args.shift(); i < px.length; i++) {
                    args.unshift(px[i]);
                    rx.push(op.apply(null, args));
                    args.shift();
                    return rx;
                }
            } else {
                return op.apply(null, arguments);
            }
        };
    };
    var gx = "optional not ignore cache".split(/\s/);
    for (var i = 0; i < gx.length; i++) {
        _[gx[i]] = _generator(_[gx[i]]);
    }
    var _vector = function (op) {
        return function () {
            if (arguments[0] instanceof Array) {
                return op.apply(null, arguments[0]);
            } else {
                return op.apply(null, arguments);
            }
        };
    };
    var vx = "each any all".split(/\s/);
    for (var j = 0; j < vx.length; j++) {
        _[vx[j]] = _vector(_[vx[j]]);
    }
} ());
(function () {
    var flattenAndCompact = function (ax) {
        var rx = [];
        for (var i = 0; i < ax.length; i++) {
            if (ax[i] instanceof Array) {
                rx = rx.concat(flattenAndCompact(ax[i]));
            } else {
                if (ax[i]) {
                    rx.push(ax[i]);
                }
            }
        }
        return rx;
    };
    Date.Grammar = {};
    Date.Translator = {
        hour: function (s) {
            return function () {
                this.hour = Number(s);
            };
        },
        minute: function (s) {
            return function () {
                this.minute = Number(s);
            };
        },
        second: function (s) {
            return function () {
                this.second = Number(s);
            };
        },
        meridian: function (s) {
            return function () {
                this.meridian = s.slice(0, 1).toLowerCase();
            };
        },
        timezone: function (s) {
            return function () {
                var n = s.replace(/[^\d\+\-]/g, "");
                if (n.length) {
                    this.timezoneOffset = Number(n);
                } else {
                    this.timezone = s.toLowerCase();
                }
            };
        },
        day: function (x) {
            var s = x[0];
            return function () {
                this.day = Number(s.match(/\d+/)[0]);
            };
        },
        month: function (s) {
            return function () {
                this.month = ((s.length == 3) ? Date.getMonthNumberFromName(s) : (Number(s) - 1));
            };
        },
        year: function (s) {
            return function () {
                var n = Number(s);
                this.year = ((s.length > 2) ? n : (n + (((n + 2000) < Date.CultureInfo.twoDigitYearMax) ? 2000 : 1900)));
            };
        },
        rday: function (s) {
            return function () {
                switch (s) {
                    case "yesterday":
                        this.days = -1;
                        break;
                    case "tomorrow":
                        this.days = 1;
                        break;
                    case "today":
                        this.days = 0;
                        break;
                    case "now":
                        this.days = 0;
                        this.now = true;
                        break;
                }
            };
        },
        finishExact: function (x) {
            x = (x instanceof Array) ? x : [x];
            var now = new Date();
            this.year = now.getFullYear();
            this.month = now.getMonth();
            this.day = 1;
            this.hour = 0;
            this.minute = 0;
            this.second = 0;
            for (var i = 0; i < x.length; i++) {
                if (x[i]) {
                    x[i].call(this);
                }
            }
            this.hour = (this.meridian == "p" && this.hour < 13) ? this.hour + 12 : this.hour;
            if (this.day > Date.getDaysInMonth(this.year, this.month)) {
                throw new RangeError(this.day + " is not a valid value for days.");
            }
            var r = new Date(this.year, this.month, this.day, this.hour, this.minute, this.second);
            if (this.timezone) {
                r.set({
                    timezone: this.timezone
                });
            } else if (this.timezoneOffset) {
                r.set({
                    timezoneOffset: this.timezoneOffset
                });
            }
            return r;
        },
        finish: function (x) {
            x = (x instanceof Array) ? flattenAndCompact(x) : [x];
            if (x.length === 0) {
                return null;
            }
            for (var i = 0; i < x.length; i++) {
                if (typeof x[i] == "function") {
                    x[i].call(this);
                }
            }
            if (this.now) {
                return new Date();
            }
            var today = Date.today();
            var method = null;
            var expression = !!(this.days != null || this.orient || this.operator);
            if (expression) {
                var gap, mod, orient;
                orient = ((this.orient == "past" || this.operator == "subtract") ? -1 : 1);
                if (this.weekday) {
                    this.unit = "day";
                    gap = (Date.getDayNumberFromName(this.weekday) - today.getDay());
                    mod = 7;
                    this.days = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
                }
                if (this.month) {
                    this.unit = "month";
                    gap = (this.month - today.getMonth());
                    mod = 12;
                    this.months = gap ? ((gap + (orient * mod)) % mod) : (orient * mod);
                    this.month = null;
                }
                if (!this.unit) {
                    this.unit = "day";
                }
                if (this[this.unit + "s"] == null || this.operator != null) {
                    if (!this.value) {
                        this.value = 1;
                    }
                    if (this.unit == "week") {
                        this.unit = "day";
                        this.value = this.value * 7;
                    }
                    this[this.unit + "s"] = this.value * orient;
                }
                return today.add(this);
            } else {
                if (this.meridian && this.hour) {
                    this.hour = (this.hour < 13 && this.meridian == "p") ? this.hour + 12 : this.hour;
                }
                if (this.weekday && !this.day) {
                    this.day = (today.addDays((Date.getDayNumberFromName(this.weekday) - today.getDay()))).getDate();
                }
                if (this.month && !this.day) {
                    this.day = 1;
                }
                return today.set(this);
            }
        }
    };
    var _ = Date.Parsing.Operators,
        g = Date.Grammar,
        t = Date.Translator,
        _fn;
    g.datePartDelimiter = _.rtoken(/^([\s\-\.\,\/\x27]+)/);
    g.timePartDelimiter = _.stoken(":");
    g.whiteSpace = _.rtoken(/^\s*/);
    g.generalDelimiter = _.rtoken(/^(([\s\,]|at|on)+)/);
    var _C = {};
    g.ctoken = function (keys) {
        var fn = _C[keys];
        if (!fn) {
            var c = Date.CultureInfo.regexPatterns;
            var kx = keys.split(/\s+/),
                px = [];
            for (var i = 0; i < kx.length; i++) {
                px.push(_.replace(_.rtoken(c[kx[i]]), kx[i]));
            }
            fn = _C[keys] = _.any.apply(null, px);
        }
        return fn;
    };
    g.ctoken2 = function (key) {
        return _.rtoken(Date.CultureInfo.regexPatterns[key]);
    };
    g.h = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/), t.hour));
    g.hh = _.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/), t.hour));
    g.H = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/), t.hour));
    g.HH = _.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/), t.hour));
    g.m = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.minute));
    g.mm = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.minute));
    g.s = _.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/), t.second));
    g.ss = _.cache(_.process(_.rtoken(/^[0-5][0-9]/), t.second));
    g.hms = _.cache(_.sequence([g.H, g.mm, g.ss], g.timePartDelimiter));
    g.t = _.cache(_.process(g.ctoken2("shortMeridian"), t.meridian));
    g.tt = _.cache(_.process(g.ctoken2("longMeridian"), t.meridian));
    g.z = _.cache(_.process(_.rtoken(/^(\+|\-)?\s*\d\d\d\d?/), t.timezone));
    g.zz = _.cache(_.process(_.rtoken(/^(\+|\-)\s*\d\d\d\d/), t.timezone));
    g.zzz = _.cache(_.process(g.ctoken2("timezone"), t.timezone));
    g.timeSuffix = _.each(_.ignore(g.whiteSpace), _.set([g.tt, g.zzz]));
    g.time = _.each(_.optional(_.ignore(_.stoken("T"))), g.hms, g.timeSuffix);
    g.d = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/), _.optional(g.ctoken2("ordinalSuffix"))), t.day));
    g.dd = _.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/), _.optional(g.ctoken2("ordinalSuffix"))), t.day));
    g.ddd = g.dddd = _.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"), function (s) {
        return function () {
            this.weekday = s;
        };
    }));
    g.M = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/), t.month));
    g.MM = _.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/), t.month));
    g.MMM = g.MMMM = _.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"), t.month));
    g.y = _.cache(_.process(_.rtoken(/^(\d\d?)/), t.year));
    g.yy = _.cache(_.process(_.rtoken(/^(\d\d)/), t.year));
    g.yyy = _.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/), t.year));
    g.yyyy = _.cache(_.process(_.rtoken(/^(\d\d\d\d)/), t.year));
    _fn = function () {
        return _.each(_.any.apply(null, arguments), _.not(g.ctoken2("timeContext")));
    };
    g.day = _fn(g.d, g.dd);
    g.month = _fn(g.M, g.MMM);
    g.year = _fn(g.yyyy, g.yy);
    g.orientation = _.process(g.ctoken("past future"), function (s) {
        return function () {
            this.orient = s;
        };
    });
    g.operator = _.process(g.ctoken("add subtract"), function (s) {
        return function () {
            this.operator = s;
        };
    });
    g.rday = _.process(g.ctoken("yesterday tomorrow today now"), t.rday);
    g.unit = _.process(g.ctoken("minute hour day week month year"), function (s) {
        return function () {
            this.unit = s;
        };
    });
    g.value = _.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/), function (s) {
        return function () {
            this.value = s.replace(/\D/g, "");
        };
    });
    g.expression = _.set([g.rday, g.operator, g.value, g.unit, g.orientation, g.ddd, g.MMM]);
    _fn = function () {
        return _.set(arguments, g.datePartDelimiter);
    };
    g.mdy = _fn(g.ddd, g.month, g.day, g.year);
    g.ymd = _fn(g.ddd, g.year, g.month, g.day);
    g.dmy = _fn(g.ddd, g.day, g.month, g.year);
    g.date = function (s) {
        return ((g[Date.CultureInfo.dateElementOrder] || g.mdy).call(this, s));
    };
    g.format = _.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/), function (fmt) {
        if (g[fmt]) {
            return g[fmt];
        } else {
            throw Date.Parsing.Exception(fmt);
        }
    }), _.process(_.rtoken(/^[^dMyhHmstz]+/), function (s) {
        return _.ignore(_.stoken(s));
    }))), function (rules) {
        return _.process(_.each.apply(null, rules), t.finishExact);
    });
    var _F = {};
    var _get = function (f) {
        return _F[f] = (_F[f] || g.format(f)[0]);
    };
    g.formats = function (fx) {
        if (fx instanceof Array) {
            var rx = [];
            for (var i = 0; i < fx.length; i++) {
                rx.push(_get(fx[i]));
            }
            return _.any.apply(null, rx);
        } else {
            return _get(fx);
        }
    };
    g._formats = g.formats(["yyyy-MM-ddTHH:mm:ss", "ddd, MMM dd, yyyy H:mm:ss tt", "ddd MMM d yyyy HH:mm:ss zzz", "d"]);
    g._start = _.process(_.set([g.date, g.time, g.expression], g.generalDelimiter, g.whiteSpace), t.finish);
    g.start = function (s) {
        try {
            var r = g._formats.call({}, s);
            if (r[1].length === 0) {
                return r;
            }
        } catch (e) { }
        return g._start.call({}, s);
    };
} ());
Date._parse = Date.parse;
Date.parse = function (s) {
    var r = null;
    if (!s) {
        return null;
    }
    try {
        r = Date.Grammar.start.call({}, s);
    } catch (e) {
        return null;
    }
    return ((r[1].length === 0) ? r[0] : null);
};
Date.getParseFunction = function (fx) {
    var fn = Date.Grammar.formats(fx);
    return function (s) {
        var r = null;
        try {
            r = fn.call({}, s);
        } catch (e) {
            return null;
        }
        return ((r[1].length === 0) ? r[0] : null);
    };
};
Date.parseExact = function (s, fx) {
    return Date.getParseFunction(fx)(s);
};
/*!
FileReader.js - v0.99
A lightweight wrapper for common FileReader usage.
Copyright 2014 Brian Grinstead - MIT License.
See http://github.com/bgrins/filereader.js for documentation.
*/

(function (window, document) {

    var FileReader = window.FileReader;
    var FileReaderSyncSupport = false;
    var workerScript = "self.addEventListener('message', function(e) { var data=e.data; try { var reader = new FileReaderSync; postMessage({ result: reader[data.readAs](data.file), extra: data.extra, file: data.file})} catch(e){ postMessage({ result:'error', extra:data.extra, file:data.file}); } }, false);";
    var syncDetectionScript = "onmessage = function(e) { postMessage(!!FileReaderSync); };";
    var fileReaderEvents = ['loadstart', 'progress', 'load', 'abort', 'error', 'loadend'];
    var sync = false;
    var FileReaderJS = window.FileReaderJS = {
        enabled: false,
        setupInput: setupInput,
        setupDrop: setupDrop,
        setupClipboard: setupClipboard,
        setSync: function (value) {
            sync = value;

            if (sync && !FileReaderSyncSupport) {
                checkFileReaderSyncSupport();
            }
        },
        getSync: function () {
            return sync && FileReaderSyncSupport;
        },
        output: [],
        opts: {
            dragClass: "drag",
            accept: false,
            readAsDefault: 'DataURL',
            readAsMap: {
            },
            on: {
                loadstart: noop,
                progress: noop,
                load: noop,
                abort: noop,
                error: noop,
                loadend: noop,
                skip: noop,
                groupstart: noop,
                groupend: noop,
                beforestart: noop
            }
        }
    };

    // Setup jQuery plugin (if available)
    if (typeof (jQuery) !== "undefined") {
        jQuery.fn.fileReaderJS = function (opts) {
            return this.each(function () {
                if (jQuery(this).is("input")) {
                    setupInput(this, opts);
                }
                else {
                    setupDrop(this, opts);
                }
            });
        };

        jQuery.fn.fileClipboard = function (opts) {
            return this.each(function () {
                setupClipboard(this, opts);
            });
        };
    }

    // Not all browsers support the FileReader interface. Return with the enabled bit = false.
    if (!FileReader) {
        return;
    }


    // makeWorker is a little wrapper for generating web workers from strings
    function makeWorker(script) {
        var URL = window.URL || window.webkitURL;
        var Blob = window.Blob;
        var Worker = window.Worker;

        if (!URL || !Blob || !Worker || !script) {
            return null;
        }

        var blob = new Blob([script]);
        var worker = new Worker(URL.createObjectURL(blob));
        return worker;
    }

    // setupClipboard: bind to clipboard events (intended for document.body)
    function setupClipboard(element, opts) {

        if (!FileReaderJS.enabled) {
            return;
        }
        var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);

        element.addEventListener("paste", onpaste, false);

        function onpaste(e) {
            var files = [];
            var clipboardData = e.clipboardData || {};
            var items = clipboardData.items || [];

            for (var i = 0; i < items.length; i++) {
                var file = items[i].getAsFile();

                if (file) {

                    // Create a fake file name for images from clipboard, since this data doesn't get sent
                    var matches = new RegExp("/\(.*\)").exec(file.type);
                    if (!file.name && matches) {
                        var extension = matches[1];
                        file.name = "clipboard" + i + "." + extension;
                    }

                    files.push(file);
                }
            }

            if (files.length) {
                processFileList(e, files, instanceOptions);
                e.preventDefault();
                e.stopPropagation();
            }
        }
    }

    // setupInput: bind the 'change' event to an input[type=file]
    function setupInput(input, opts) {

        if (!FileReaderJS.enabled) {
            return;
        }
        var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);

        input.addEventListener("change", inputChange, false);
        input.addEventListener("drop", inputDrop, false);

        function inputChange(e) {
            processFileList(e, input.files, instanceOptions);
        }

        function inputDrop(e) {
            e.stopPropagation();
            e.preventDefault();
            processFileList(e, e.dataTransfer.files, instanceOptions);
        }
    }

    // setupDrop: bind the 'drop' event for a DOM element
    function setupDrop(dropbox, opts) {

        if (!FileReaderJS.enabled) {
            return;
        }
        var instanceOptions = extend(extend({}, FileReaderJS.opts), opts);
        var dragClass = instanceOptions.dragClass;
        var initializedOnBody = false;

        // Bind drag events to the dropbox to add the class while dragging, and accept the drop data transfer.
        dropbox.addEventListener("dragenter", onlyWithFiles(dragenter), false);
        dropbox.addEventListener("dragleave", onlyWithFiles(dragleave), false);
        dropbox.addEventListener("dragover", onlyWithFiles(dragover), false);
        dropbox.addEventListener("drop", onlyWithFiles(drop), false);

        // Bind to body to prevent the dropbox events from firing when it was initialized on the page.
        document.body.addEventListener("dragstart", bodydragstart, true);
        document.body.addEventListener("dragend", bodydragend, true);
        document.body.addEventListener("drop", bodydrop, false);

        function bodydragend(e) {
            initializedOnBody = false;
        }

        function bodydragstart(e) {
            initializedOnBody = true;
        }

        function bodydrop(e) {
            if (e.dataTransfer.files && e.dataTransfer.files.length) {
                e.stopPropagation();
                e.preventDefault();
            }
        }

        function onlyWithFiles(fn) {
            return function () {
                if (!initializedOnBody) {
                    fn.apply(this, arguments);
                }
            };
        }

        function drop(e) {
            e.stopPropagation();
            e.preventDefault();
            if (dragClass) {
                removeClass(dropbox, dragClass);
            }
            processFileList(e, e.dataTransfer.files, instanceOptions);
        }

        function dragenter(e) {
            e.stopPropagation();
            e.preventDefault();
            if (dragClass) {
                addClass(dropbox, dragClass);
            }
        }

        function dragleave(e) {
            if (dragClass) {
                removeClass(dropbox, dragClass);
            }
        }

        function dragover(e) {
            e.stopPropagation();
            e.preventDefault();
            if (dragClass) {
                addClass(dropbox, dragClass);
            }
        }
    }

    // setupCustomFileProperties: modify the file object with extra properties
    function setupCustomFileProperties(files, groupID) {
        for (var i = 0; i < files.length; i++) {
            var file = files[i];
            file.extra = {
                nameNoExtension: file.name.substring(0, file.name.lastIndexOf('.')),
                extension: file.name.substring(file.name.lastIndexOf('.') + 1),
                fileID: i,
                uniqueID: getUniqueID(),
                groupID: groupID,
                prettySize: prettySize(file.size)
            };
        }
    }

    // getReadAsMethod: return method name for 'readAs*' - http://www.w3.org/TR/FileAPI/#reading-a-file
    function getReadAsMethod(type, readAsMap, readAsDefault) {
        for (var r in readAsMap) {
            if (type.match(new RegExp(r))) {
                return 'readAs' + readAsMap[r];
            }
        }
        return 'readAs' + readAsDefault;
    }

    // processFileList: read the files with FileReader, send off custom events.
    function processFileList(e, files, opts) {

        var filesLeft = files.length;
        var group = {
            groupID: getGroupID(),
            files: files,
            started: new Date()
        };

        function groupEnd() {
            group.ended = new Date();
            opts.on.groupend(group);
        }

        function groupFileDone() {
            if (--filesLeft === 0) {
                groupEnd();
            }
        }

        FileReaderJS.output.push(group);
        setupCustomFileProperties(files, group.groupID);

        opts.on.groupstart(group);

        // No files in group - end immediately
        if (!files.length) {
            groupEnd();
            return;
        }

        var supportsSync = sync && FileReaderSyncSupport;
        var syncWorker;

        // Only initialize the synchronous worker if the option is enabled - to prevent the overhead
        if (supportsSync) {
            syncWorker = makeWorker(workerScript);
            syncWorker.onmessage = function (e) {
                var file = e.data.file;
                var result = e.data.result;

                // Workers seem to lose the custom property on the file object.
                if (!file.extra) {
                    file.extra = e.data.extra;
                }

                file.extra.ended = new Date();

                // Call error or load event depending on success of the read from the worker.
                opts.on[result === "error" ? "error" : "load"]({ target: { result: result} }, file);
                groupFileDone();
            };
        }

        Array.prototype.forEach.call(files, function (file) {

            file.extra.started = new Date();

            if (opts.accept && !file.type.match(new RegExp(opts.accept))) {
                opts.on.skip(file);
                groupFileDone();
                return;
            }

            if (opts.on.beforestart(file) === false) {
                opts.on.skip(file);
                groupFileDone();
                return;
            }

            var readAs = getReadAsMethod(file.type, opts.readAsMap, opts.readAsDefault);

            if (syncWorker) {
                syncWorker.postMessage({
                    file: file,
                    extra: file.extra,
                    readAs: readAs
                });
            }
            else {

                var reader = new FileReader();
                reader.originalEvent = e;

                fileReaderEvents.forEach(function (eventName) {
                    reader['on' + eventName] = function (e) {
                        if (eventName == 'load' || eventName == 'error') {
                            file.extra.ended = new Date();
                        }
                        opts.on[eventName](reader.result, e, file);
                        if (eventName == 'loadend') {
                            groupFileDone();
                        }
                    };
                });

                reader[readAs](file);
            }
        });
    }

    // checkFileReaderSyncSupport: Create a temporary worker and see if FileReaderSync exists
    function checkFileReaderSyncSupport() {
        var worker = makeWorker(syncDetectionScript);
        if (worker) {
            worker.onmessage = function (e) {
                FileReaderSyncSupport = e.data;
            };
            worker.postMessage({});
        }
    }

    // noop: do nothing
    function noop() {

    }

    // extend: used to make deep copies of options object
    function extend(destination, source) {
        for (var property in source) {
            if (source[property] && source[property].constructor &&
                source[property].constructor === Object) {
                destination[property] = destination[property] || {};
                arguments.callee(destination[property], source[property]);
            }
            else {
                destination[property] = source[property];
            }
        }
        return destination;
    }

    // hasClass: does an element have the css class?
    function hasClass(el, name) {
        return new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)").test(el.className);
    }

    // addClass: add the css class for the element.
    function addClass(el, name) {
        if (!hasClass(el, name)) {
            el.className = el.className ? [el.className, name].join(' ') : name;
        }
    }

    // removeClass: remove the css class from the element.
    function removeClass(el, name) {
        if (hasClass(el, name)) {
            var c = el.className;
            el.className = c.replace(new RegExp("(?:^|\\s+)" + name + "(?:\\s+|$)", "g"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        }
    }

    // prettySize: convert bytes to a more readable string.
    function prettySize(bytes) {
        var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
        var e = Math.floor(Math.log(bytes) / Math.log(1024));
        return (bytes / Math.pow(1024, Math.floor(e))).toFixed(2) + " " + s[e];
    }

    // getGroupID: generate a unique int ID for groups.
    var getGroupID = (function (id) {
        return function () {
            return id++;
        };
    })(0);

    // getUniqueID: generate a unique int ID for files
    var getUniqueID = (function (id) {
        return function () {
            return id++;
        };
    })(0);

    // The interface is supported, bind the FileReaderJS callbacks
    FileReaderJS.enabled = true;

})(this, document);
/* Blob.js
* A Blob implementation.
* 2014-07-24
*
* By Eli Grey, http://eligrey.com
* By Devin Samarin, https://github.com/dsamarin
* License: X11/MIT
*   See https://github.com/eligrey/Blob.js/blob/master/LICENSE.md
*/

/*global self, unescape */
/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true,
plusplus: true */

/*! @source http://purl.eligrey.com/github/Blob.js/blob/master/Blob.js */

(function (view) {
    "use strict";

    view.URL = view.URL || view.webkitURL;

    if (view.Blob && view.URL) {
        try {
            new Blob;
            return;
        } catch (e) { }
    }

    // Internally we use a BlobBuilder implementation to base Blob off of
    // in order to support older browsers that only have BlobBuilder
    var BlobBuilder = view.BlobBuilder || view.WebKitBlobBuilder || view.MozBlobBuilder || (function (view) {
        var 
			  get_class = function (object) {
			      return Object.prototype.toString.call(object).match(/^\[object\s(.*)\]$/)[1];
			  }
			, FakeBlobBuilder = function BlobBuilder() {
			    this.data = [];
			}
			, FakeBlob = function Blob(data, type, encoding) {
			    this.data = data;
			    this.size = data.length;
			    this.type = type;
			    this.encoding = encoding;
			}
			, FBB_proto = FakeBlobBuilder.prototype
			, FB_proto = FakeBlob.prototype
			, FileReaderSync = view.FileReaderSync
			, FileException = function (type) {
			    this.code = this[this.name = type];
			}
			, file_ex_codes = (
				  "NOT_FOUND_ERR SECURITY_ERR ABORT_ERR NOT_READABLE_ERR ENCODING_ERR "
				+ "NO_MODIFICATION_ALLOWED_ERR INVALID_STATE_ERR SYNTAX_ERR"
			).split(" ")
			, file_ex_code = file_ex_codes.length
			, real_URL = view.URL || view.webkitURL || view
			, real_create_object_URL = real_URL.createObjectURL
			, real_revoke_object_URL = real_URL.revokeObjectURL
			, URL = real_URL
			, btoa = view.btoa
			, atob = view.atob

			, ArrayBuffer = view.ArrayBuffer
			, Uint8Array = view.Uint8Array

			, origin = /^[\w-]+:\/*\[?[\w\.:-]+\]?(?::[0-9]+)?/
		;
        FakeBlob.fake = FB_proto.fake = true;
        while (file_ex_code--) {
            FileException.prototype[file_ex_codes[file_ex_code]] = file_ex_code + 1;
        }
        // Polyfill URL
        if (!real_URL.createObjectURL) {
            URL = view.URL = function (uri) {
                var 
					  uri_info = document.createElementNS("http://www.w3.org/1999/xhtml", "a")
					, uri_origin
				;
                uri_info.href = uri;
                if (!("origin" in uri_info)) {
                    if (uri_info.protocol.toLowerCase() === "data:") {
                        uri_info.origin = null;
                    } else {
                        uri_origin = uri.match(origin);
                        uri_info.origin = uri_origin && uri_origin[1];
                    }
                }
                return uri_info;
            };
        }
        URL.createObjectURL = function (blob) {
            var 
				  type = blob.type
				, data_URI_header
			;
            if (type === null) {
                type = "application/octet-stream";
            }
            if (blob instanceof FakeBlob) {
                data_URI_header = "data:" + type;
                if (blob.encoding === "base64") {
                    return data_URI_header + ";base64," + blob.data;
                } else if (blob.encoding === "URI") {
                    return data_URI_header + "," + decodeURIComponent(blob.data);
                } if (btoa) {
                    return data_URI_header + ";base64," + btoa(blob.data);
                } else {
                    return data_URI_header + "," + encodeURIComponent(blob.data);
                }
            } else if (real_create_object_URL) {
                return real_create_object_URL.call(real_URL, blob);
            }
        };
        URL.revokeObjectURL = function (object_URL) {
            if (object_URL.substring(0, 5) !== "data:" && real_revoke_object_URL) {
                real_revoke_object_URL.call(real_URL, object_URL);
            }
        };
        FBB_proto.append = function (data/*, endings*/) {
            var bb = this.data;
            // decode data to a binary string
            if (Uint8Array && (data instanceof ArrayBuffer || data instanceof Uint8Array)) {
                var 
					  str = ""
					, buf = new Uint8Array(data)
					, i = 0
					, buf_len = buf.length
				;
                for (; i < buf_len; i++) {
                    str += String.fromCharCode(buf[i]);
                }
                bb.push(str);
            } else if (get_class(data) === "Blob" || get_class(data) === "File") {
                if (FileReaderSync) {
                    var fr = new FileReaderSync;
                    bb.push(fr.readAsBinaryString(data));
                } else {
                    // async FileReader won't work as BlobBuilder is sync
                    throw new FileException("NOT_READABLE_ERR");
                }
            } else if (data instanceof FakeBlob) {
                if (data.encoding === "base64" && atob) {
                    bb.push(atob(data.data));
                } else if (data.encoding === "URI") {
                    bb.push(decodeURIComponent(data.data));
                } else if (data.encoding === "raw") {
                    bb.push(data.data);
                }
            } else {
                if (typeof data !== "string") {
                    data += ""; // convert unsupported types to strings
                }
                // decode UTF-16 to binary string
                bb.push(unescape(encodeURIComponent(data)));
            }
        };
        FBB_proto.getBlob = function (type) {
            if (!arguments.length) {
                type = null;
            }
            return new FakeBlob(this.data.join(""), type, "raw");
        };
        FBB_proto.toString = function () {
            return "[object BlobBuilder]";
        };
        FB_proto.slice = function (start, end, type) {
            var args = arguments.length;
            if (args < 3) {
                type = null;
            }
            return new FakeBlob(
				  this.data.slice(start, args > 1 ? end : this.data.length)
				, type
				, this.encoding
			);
        };
        FB_proto.toString = function () {
            return "[object Blob]";
        };
        FB_proto.close = function () {
            this.size = 0;
            delete this.data;
        };
        return FakeBlobBuilder;
    } (view));

    view.Blob = function (blobParts, options) {
        var type = options ? (options.type || "") : "";
        var builder = new BlobBuilder();
        if (blobParts) {
            for (var i = 0, len = blobParts.length; i < len; i++) {
                builder.append(blobParts[i]);
            }
        }
        return builder.getBlob(type);
    };
} (typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this));

/* FileSaver.js
* A saveAs() FileSaver implementation.
* 2015-03-04
*
* By Eli Grey, http://eligrey.com
* License: X11/MIT
*   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
*/

/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */

var saveAs = saveAs
// IE 10+ (native saveAs)
  || (typeof navigator !== "undefined" &&
      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
// Everyone else
  || (function (view) {
      "use strict";
      // IE <10 is explicitly unsupported
      if (typeof navigator !== "undefined" &&
	    /MSIE [1-9]\./.test(navigator.userAgent)) {
          return;
      }
      var 
		  doc = view.document
      // only get URL when necessary in case Blob.js hasn't overridden it yet
		, get_URL = function () {
		    return view.URL || view.webkitURL || view;
		}
		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
		, can_use_save_link = "download" in save_link
		, click = function (node) {
		    var event = doc.createEvent("MouseEvents");
		    event.initMouseEvent(
				"click", true, false, view, 0, 0, 0, 0, 0
				, false, false, false, false, 0, null
			);
		    node.dispatchEvent(event);
		}
		, webkit_req_fs = view.webkitRequestFileSystem
		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
		, throw_outside = function (ex) {
		    (view.setImmediate || view.setTimeout)(function () {
		        throw ex;
		    }, 0);
		}
		, force_saveable_type = "application/octet-stream"
		, fs_min_size = 0
      // See https://code.google.com/p/chromium/issues/detail?id=375297#c7 and
      // https://github.com/eligrey/FileSaver.js/commit/485930a#commitcomment-8768047
      // for the reasoning behind the timeout and revocation flow
		, arbitrary_revoke_timeout = 500 // in ms
		, revoke = function (file) {
		    var revoker = function () {
		        if (typeof file === "string") { // file is an object URL
		            get_URL().revokeObjectURL(file);
		        } else { // file is a File
		            file.remove();
		        }
		    };
		    if (view.chrome) {
		        revoker();
		    } else {
		        setTimeout(revoker, arbitrary_revoke_timeout);
		    }
		}
		, dispatch = function (filesaver, event_types, event) {
		    event_types = [].concat(event_types);
		    var i = event_types.length;
		    while (i--) {
		        var listener = filesaver["on" + event_types[i]];
		        if (typeof listener === "function") {
		            try {
		                listener.call(filesaver, event || filesaver);
		            } catch (ex) {
		                throw_outside(ex);
		            }
		        }
		    }
		}
		, FileSaver = function (blob, name) {
		    // First try a.download, then web filesystem, then object URLs
		    var 
				  filesaver = this
				, type = blob.type
				, blob_changed = false
				, object_url
				, target_view
				, dispatch_all = function () {
				    dispatch(filesaver, "writestart progress write writeend".split(" "));
				}
		    // on any filesys errors revert to saving with object URLs
				, fs_error = function () {
				    // don't create more object URLs than needed
				    if (blob_changed || !object_url) {
				        object_url = get_URL().createObjectURL(blob);
				    }
				    if (target_view) {
				        target_view.location.href = object_url;
				    } else {
				        var new_tab = view.open(object_url, "_blank");
				        if (new_tab == undefined && typeof safari !== "undefined") {
				            //Apple do not allow window.open, see http://bit.ly/1kZffRI
				            view.location.href = object_url
				        }
				    }
				    filesaver.readyState = filesaver.DONE;
				    dispatch_all();
				    revoke(object_url);
				}
				, abortable = function (func) {
				    return function () {
				        if (filesaver.readyState !== filesaver.DONE) {
				            return func.apply(this, arguments);
				        }
				    };
				}
				, create_if_not_found = { create: true, exclusive: false }
				, slice
			;
		    filesaver.readyState = filesaver.INIT;
		    if (!name) {
		        name = "download";
		    }
		    if (can_use_save_link) {
		        object_url = get_URL().createObjectURL(blob);
		        save_link.href = object_url;
		        save_link.download = name;
		        click(save_link);
		        filesaver.readyState = filesaver.DONE;
		        dispatch_all();
		        revoke(object_url);
		        return;
		    }
		    // prepend BOM for UTF-8 XML and text/plain types
		    if (/^\s*(?:text\/(?:plain|xml)|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
		        blob = new Blob(["\ufeff", blob], { type: blob.type });
		    }
		    // Object and web filesystem URLs have a problem saving in Google Chrome when
		    // viewed in a tab, so I force save with application/octet-stream
		    // http://code.google.com/p/chromium/issues/detail?id=91158
		    // Update: Google errantly closed 91158, I submitted it again:
		    // https://code.google.com/p/chromium/issues/detail?id=389642
		    if (view.chrome && type && type !== force_saveable_type) {
		        slice = blob.slice || blob.webkitSlice;
		        blob = slice.call(blob, 0, blob.size, force_saveable_type);
		        blob_changed = true;
		    }
		    // Since I can't be sure that the guessed media type will trigger a download
		    // in WebKit, I append .download to the filename.
		    // https://bugs.webkit.org/show_bug.cgi?id=65440
		    if (webkit_req_fs && name !== "download") {
		        name += ".download";
		    }
		    if (type === force_saveable_type || webkit_req_fs) {
		        target_view = view;
		    }
		    if (!req_fs) {
		        fs_error();
		        return;
		    }
		    fs_min_size += blob.size;
		    req_fs(view.TEMPORARY, fs_min_size, abortable(function (fs) {
		        fs.root.getDirectory("saved", create_if_not_found, abortable(function (dir) {
		            var save = function () {
		                dir.getFile(name, create_if_not_found, abortable(function (file) {
		                    file.createWriter(abortable(function (writer) {
		                        writer.onwriteend = function (event) {
		                            target_view.location.href = file.toURL();
		                            filesaver.readyState = filesaver.DONE;
		                            dispatch(filesaver, "writeend", event);
		                            revoke(file);
		                        };
		                        writer.onerror = function () {
		                            var error = writer.error;
		                            if (error.code !== error.ABORT_ERR) {
		                                fs_error();
		                            }
		                        };
		                        "writestart progress write abort".split(" ").forEach(function (event) {
		                            writer["on" + event] = filesaver["on" + event];
		                        });
		                        writer.write(blob);
		                        filesaver.abort = function () {
		                            writer.abort();
		                            filesaver.readyState = filesaver.DONE;
		                        };
		                        filesaver.readyState = filesaver.WRITING;
		                    }), fs_error);
		                }), fs_error);
		            };
		            dir.getFile(name, { create: false }, abortable(function (file) {
		                // delete file if it already exists
		                file.remove();
		                save();
		            }), abortable(function (ex) {
		                if (ex.code === ex.NOT_FOUND_ERR) {
		                    save();
		                } else {
		                    fs_error();
		                }
		            }));
		        }), fs_error);
		    }), fs_error);
		}
		, FS_proto = FileSaver.prototype
		, saveAs = function (blob, name) {
		    return new FileSaver(blob, name);
		}
	;
      FS_proto.abort = function () {
          var filesaver = this;
          filesaver.readyState = filesaver.DONE;
          dispatch(filesaver, "abort");
      };
      FS_proto.readyState = FS_proto.INIT = 0;
      FS_proto.WRITING = 1;
      FS_proto.DONE = 2;

      FS_proto.error =
	FS_proto.onwritestart =
	FS_proto.onprogress =
	FS_proto.onwrite =
	FS_proto.onabort =
	FS_proto.onerror =
	FS_proto.onwriteend =
		null;

      return saveAs;
  } (
	   typeof self !== "undefined" && self
	|| typeof window !== "undefined" && window
	|| this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window

if (typeof module !== "undefined" && module.exports) {
    module.exports.saveAs = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
    define([], function () {
        return saveAs;
    });
}
/* global saveAs, Blob, BlobBuilder, console */
/* exported ics */

var ics = function () {
    'use strict';

    if (navigator.userAgent.indexOf('MSIE') > -1 && navigator.userAgent.indexOf('MSIE 10') == -1) {
        console.log('Unsupported Browser');
        return;
    }

    var SEPARATOR = (navigator.appVersion.indexOf('Win') !== -1) ? '\r\n' : '\n';
    var calendarEvents = [];
    var calendarStart = [
        'BEGIN:VCALENDAR',
        'VERSION:2.0'
    ].join(SEPARATOR);
    var calendarEnd = SEPARATOR + 'END:VCALENDAR';

    return {
        /**
         * Returns events array
         * @return {array} Events
         */
        'events': function () {
            return calendarEvents;
        },

        /**
         * Returns calendar
         * @return {string} Calendar in iCalendar format
         */
        'calendar': function () {
            return calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;
        },

        /**
         * Add event to the calendar
         * @param  {string} subject     Subject/Title of event
         * @param  {string} description Description of event
         * @param  {string} location    Location of event
         * @param  {string} begin       Beginning date of event
         * @param  {string} stop        Ending date of event
         */
        'addEvent': function (subject, description, location, begin, stop) {
            // I'm not in the mood to make these optional... So they are all required
            if (typeof subject === 'undefined' ||
                typeof description === 'undefined' ||
                typeof location === 'undefined' ||
                typeof begin === 'undefined' ||
                typeof stop === 'undefined'
            ) {
                return false;
            };

            //TODO add time and time zone? use moment to format?
            var start_date = new Date(begin);
            var end_date = new Date(stop);

            var start_year = ("0000" + (start_date.getFullYear().toString())).slice(-4);
            var start_month = ("00" + ((start_date.getMonth() + 1).toString())).slice(-2);
            var start_day = ("00" + ((start_date.getDate()).toString())).slice(-2);
            var start_hours = ("00" + (start_date.getHours().toString())).slice(-2);
            var start_minutes = ("00" + (start_date.getMinutes().toString())).slice(-2);
            var start_seconds = ("00" + (start_date.getMinutes().toString())).slice(-2);

            var end_year = ("0000" + (end_date.getFullYear().toString())).slice(-4);
            var end_month = ("00" + ((end_date.getMonth() + 1).toString())).slice(-2);
            var end_day = ("00" + ((end_date.getDate()).toString())).slice(-2);
            var end_hours = ("00" + (end_date.getHours().toString())).slice(-2);
            var end_minutes = ("00" + (end_date.getMinutes().toString())).slice(-2);
            var end_seconds = ("00" + (end_date.getMinutes().toString())).slice(-2);

            // Since some calendars don't add 0 second events, we need to remove time if there is none...
            var start_time = '';
            var end_time = '';
            if (start_minutes + start_seconds + end_minutes + end_seconds != 0) {
                start_time = 'T' + start_hours + start_minutes + start_seconds;
                end_time = 'T' + end_hours + end_minutes + end_seconds;
            }

            var start = start_year + start_month + start_day + start_time;
            var end = end_year + end_month + end_day + end_time;

            var calendarEvent = [
                'BEGIN:VEVENT',
                'CLASS:PUBLIC',
                'DESCRIPTION:' + description,
                'DTSTART;VALUE=DATE:' + start,
                'DTEND;VALUE=DATE:' + end,
                'LOCATION:' + location,
                'SUMMARY;LANGUAGE=en-us:' + subject,
                'TRANSP:TRANSPARENT',
                'END:VEVENT'
            ].join(SEPARATOR);

            calendarEvents.push(calendarEvent);
            return calendarEvent;
        },

        /**
         * Download calendar using the saveAs function from filesave.js
         * @param  {string} filename Filename
         * @param  {string} ext      Extention
         */
        'download': function (filename, ext) {
            if (calendarEvents.length < 1) {
                return false;
            }

            ext = (typeof ext !== 'undefined') ? ext : '.ics';
            filename = (typeof filename !== 'undefined') ? filename : 'calendar';
            var calendar = calendarStart + SEPARATOR + calendarEvents.join(SEPARATOR) + calendarEnd;

            var blob;
            if (navigator.userAgent.indexOf('MSIE 10') === -1) { // chrome or firefox
                blob = new Blob([calendar]);
            } else { // ie
                var bb = new BlobBuilder();
                bb.append(calendar);
                blob = bb.getBlob('text/x-vCalendar;charset=' + document.characterSet);
            }
            saveAs(blob, filename + ext);
            return calendar;
        }
    };
};
/**
* jQuery JSON plugin 2.4.0
*
* @author Brantley Harris, 2009-2011
* @author Timo Tijhof, 2011-2012
* @source This plugin is heavily influenced by MochiKit's serializeJSON, which is
*         copyrighted 2005 by Bob Ippolito.
* @source Brantley Harris wrote this plugin. It is based somewhat on the JSON.org
*         website's http://www.json.org/json2.js, which proclaims:
*         "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
*         I uphold.
* @license MIT License <http://www.opensource.org/licenses/mit-license.php>
*/

(function ($) {
    'use strict';

    var escape = /["\\\x00-\x1f\x7f-\x9f]/g,
		meta = {
		    '\b': '\\b',
		    '\t': '\\t',
		    '\n': '\\n',
		    '\f': '\\f',
		    '\r': '\\r',
		    '"': '\\"',
		    '\\': '\\\\'
		},
		hasOwn = Object.prototype.hasOwnProperty;

    /**
    * jQuery.toJSON
    * Converts the given argument into a JSON representation.
    *
    * @param o {Mixed} The json-serializable *thing* to be converted
    *
    * If an object has a toJSON prototype, that will be used to get the representation.
    * Non-integer/string keys are skipped in the object, as are keys that point to a
    * function.
    *
    */
    $.toJSON = typeof JSON === 'object' && JSON.stringify ? JSON.stringify : function (o) {
        if (o === null) {
            return 'null';
        }

        var pairs, k, name, val,
			type = $.type(o);

        if (type === 'undefined') {
            return undefined;
        }

        // Also covers instantiated Number and Boolean objects,
        // which are typeof 'object' but thanks to $.type, we
        // catch them here. I don't know whether it is right
        // or wrong that instantiated primitives are not
        // exported to JSON as an {"object":..}.
        // We choose this path because that's what the browsers did.
        if (type === 'number' || type === 'boolean') {
            return String(o);
        }
        if (type === 'string') {
            return $.quoteString(o);
        }
        if (typeof o.toJSON === 'function') {
            return $.toJSON(o.toJSON());
        }
        if (type === 'date') {
            var month = o.getUTCMonth() + 1,
				day = o.getUTCDate(),
				year = o.getUTCFullYear(),
				hours = o.getUTCHours(),
				minutes = o.getUTCMinutes(),
				seconds = o.getUTCSeconds(),
				milli = o.getUTCMilliseconds();

            if (month < 10) {
                month = '0' + month;
            }
            if (day < 10) {
                day = '0' + day;
            }
            if (hours < 10) {
                hours = '0' + hours;
            }
            if (minutes < 10) {
                minutes = '0' + minutes;
            }
            if (seconds < 10) {
                seconds = '0' + seconds;
            }
            if (milli < 100) {
                milli = '0' + milli;
            }
            if (milli < 10) {
                milli = '0' + milli;
            }
            return '"' + year + '-' + month + '-' + day + 'T' +
				hours + ':' + minutes + ':' + seconds +
				'.' + milli + 'Z"';
        }

        pairs = [];

        if ($.isArray(o)) {
            for (k = 0; k < o.length; k++) {
                pairs.push($.toJSON(o[k]) || 'null');
            }
            return '[' + pairs.join(',') + ']';
        }

        // Any other object (plain object, RegExp, ..)
        // Need to do typeof instead of $.type, because we also
        // want to catch non-plain objects.
        if (typeof o === 'object') {
            for (k in o) {
                // Only include own properties,
                // Filter out inherited prototypes
                if (hasOwn.call(o, k)) {
                    // Keys must be numerical or string. Skip others
                    type = typeof k;
                    if (type === 'number') {
                        name = '"' + k + '"';
                    } else if (type === 'string') {
                        name = $.quoteString(k);
                    } else {
                        continue;
                    }
                    type = typeof o[k];

                    // Invalid values like these return undefined
                    // from toJSON, however those object members
                    // shouldn't be included in the JSON string at all.
                    if (type !== 'function' && type !== 'undefined') {
                        val = $.toJSON(o[k]);
                        pairs.push(name + ':' + val);
                    }
                }
            }
            return '{' + pairs.join(',') + '}';
        }
    };

    /**
    * jQuery.evalJSON
    * Evaluates a given json string.
    *
    * @param str {String}
    */
    $.evalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) {
        /*jshint evil: true */
        return eval('(' + str + ')');
    };

    /**
    * jQuery.secureEvalJSON
    * Evals JSON in a way that is *more* secure.
    *
    * @param str {String}
    */
    $.secureEvalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) {
        var filtered =
			str
			.replace(/\\["\\\/bfnrtu]/g, '@')
			.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
			.replace(/(?:^|:|,)(?:\s*\[)+/g, '');

        if (/^[\],:{}\s]*$/.test(filtered)) {
            /*jshint evil: true */
            return eval('(' + str + ')');
        }
        throw new SyntaxError('Error parsing JSON, source is not valid.');
    };

    /**
    * jQuery.quoteString
    * Returns a string-repr of a string, escaping quotes intelligently.
    * Mostly a support function for toJSON.
    * Examples:
    * >>> jQuery.quoteString('apple')
    * "apple"
    *
    * >>> jQuery.quoteString('"Where are we going?", she asked.')
    * "\"Where are we going?\", she asked."
    */
    $.quoteString = function (str) {
        if (str.match(escape)) {
            return '"' + str.replace(escape, function (a) {
                var c = meta[a];
                if (typeof c === 'string') {
                    return c;
                }
                c = a.charCodeAt();
                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
            }) + '"';
        }
        return '"' + str + '"';
    };

} (jQuery));

!function (a, b) { "object" == typeof exports && "undefined" != typeof module ? module.exports = b() : "function" == typeof define && define.amd ? define(b) : a.moment = b() }(this, function () {
    "use strict"; function a() { return Wd.apply(null, arguments) } function b(a) { Wd = a } function c(a) { return a instanceof Array || "[object Array]" === Object.prototype.toString.call(a) } function d(a) { return a instanceof Date || "[object Date]" === Object.prototype.toString.call(a) } function e(a, b) { var c, d = []; for (c = 0; c < a.length; ++c) d.push(b(a[c], c)); return d } function f(a, b) { return Object.prototype.hasOwnProperty.call(a, b) } function g(a, b) { for (var c in b) f(b, c) && (a[c] = b[c]); return f(b, "toString") && (a.toString = b.toString), f(b, "valueOf") && (a.valueOf = b.valueOf), a } function h(a, b, c, d) { return Ia(a, b, c, d, !0).utc() } function i() { return { empty: !1, unusedTokens: [], unusedInput: [], overflow: -2, charsLeftOver: 0, nullInput: !1, invalidMonth: null, invalidFormat: !1, userInvalidated: !1, iso: !1 } } function j(a) { return null == a._pf && (a._pf = i()), a._pf } function k(a) { if (null == a._isValid) { var b = j(a); a._isValid = !(isNaN(a._d.getTime()) || !(b.overflow < 0) || b.empty || b.invalidMonth || b.invalidWeekday || b.nullInput || b.invalidFormat || b.userInvalidated), a._strict && (a._isValid = a._isValid && 0 === b.charsLeftOver && 0 === b.unusedTokens.length && void 0 === b.bigHour) } return a._isValid } function l(a) { var b = h(NaN); return null != a ? g(j(b), a) : j(b).userInvalidated = !0, b } function m(a) { return void 0 === a } function n(a, b) { var c, d, e; if (m(b._isAMomentObject) || (a._isAMomentObject = b._isAMomentObject), m(b._i) || (a._i = b._i), m(b._f) || (a._f = b._f), m(b._l) || (a._l = b._l), m(b._strict) || (a._strict = b._strict), m(b._tzm) || (a._tzm = b._tzm), m(b._isUTC) || (a._isUTC = b._isUTC), m(b._offset) || (a._offset = b._offset), m(b._pf) || (a._pf = j(b)), m(b._locale) || (a._locale = b._locale), Xd.length > 0) for (c in Xd) d = Xd[c], e = b[d], m(e) || (a[d] = e); return a } function o(b) { n(this, b), this._d = new Date(null != b._d ? b._d.getTime() : NaN), Yd === !1 && (Yd = !0, a.updateOffset(this), Yd = !1) } function p(a) { return a instanceof o || null != a && null != a._isAMomentObject } function q(a) { return 0 > a ? Math.ceil(a) : Math.floor(a) } function r(a) { var b = +a, c = 0; return 0 !== b && isFinite(b) && (c = q(b)), c } function s(a, b, c) { var d, e = Math.min(a.length, b.length), f = Math.abs(a.length - b.length), g = 0; for (d = 0; e > d; d++) (c && a[d] !== b[d] || !c && r(a[d]) !== r(b[d])) && g++; return g + f } function t(b) { a.suppressDeprecationWarnings === !1 && "undefined" != typeof console && console.warn && console.warn("Deprecation warning: " + b) } function u(a, b) { var c = !0; return g(function () { return c && (t(a + "\nArguments: " + Array.prototype.slice.call(arguments).join(", ") + "\n" + (new Error).stack), c = !1), b.apply(this, arguments) }, b) } function v(a, b) { Zd[a] || (t(b), Zd[a] = !0) } function w(a) { return a instanceof Function || "[object Function]" === Object.prototype.toString.call(a) } function x(a) { return "[object Object]" === Object.prototype.toString.call(a) } function y(a) { var b, c; for (c in a) b = a[c], w(b) ? this[c] = b : this["_" + c] = b; this._config = a, this._ordinalParseLenient = new RegExp(this._ordinalParse.source + "|" + /\d{1,2}/.source) } function z(a, b) { var c, d = g({}, a); for (c in b) f(b, c) && (x(a[c]) && x(b[c]) ? (d[c] = {}, g(d[c], a[c]), g(d[c], b[c])) : null != b[c] ? d[c] = b[c] : delete d[c]); return d } function A(a) { null != a && this.set(a) } function B(a) { return a ? a.toLowerCase().replace("_", "-") : a } function C(a) { for (var b, c, d, e, f = 0; f < a.length;) { for (e = B(a[f]).split("-"), b = e.length, c = B(a[f + 1]), c = c ? c.split("-") : null; b > 0;) { if (d = D(e.slice(0, b).join("-"))) return d; if (c && c.length >= b && s(e, c, !0) >= b - 1) break; b-- } f++ } return null } function D(a) { var b = null; if (!_d[a] && "undefined" != typeof module && module && module.exports) try { b = $d._abbr, require("./locale/" + a), E(b) } catch (c) { } return _d[a] } function E(a, b) { var c; return a && (c = m(b) ? H(a) : F(a, b), c && ($d = c)), $d._abbr } function F(a, b) { return null !== b ? (b.abbr = a, null != _d[a] ? (v("defineLocaleOverride", "use moment.updateLocale(localeName, config) to change an existing locale. moment.defineLocale(localeName, config) should only be used for creating a new locale"), b = z(_d[a]._config, b)) : null != b.parentLocale && (null != _d[b.parentLocale] ? b = z(_d[b.parentLocale]._config, b) : v("parentLocaleUndefined", "specified parentLocale is not defined yet")), _d[a] = new A(b), E(a), _d[a]) : (delete _d[a], null) } function G(a, b) { if (null != b) { var c; null != _d[a] && (b = z(_d[a]._config, b)), c = new A(b), c.parentLocale = _d[a], _d[a] = c, E(a) } else null != _d[a] && (null != _d[a].parentLocale ? _d[a] = _d[a].parentLocale : null != _d[a] && delete _d[a]); return _d[a] } function H(a) { var b; if (a && a._locale && a._locale._abbr && (a = a._locale._abbr), !a) return $d; if (!c(a)) { if (b = D(a)) return b; a = [a] } return C(a) } function I() { return Object.keys(_d) } function J(a, b) { var c = a.toLowerCase(); ae[c] = ae[c + "s"] = ae[b] = a } function K(a) { return "string" == typeof a ? ae[a] || ae[a.toLowerCase()] : void 0 } function L(a) { var b, c, d = {}; for (c in a) f(a, c) && (b = K(c), b && (d[b] = a[c])); return d } function M(b, c) { return function (d) { return null != d ? (O(this, b, d), a.updateOffset(this, c), this) : N(this, b) } } function N(a, b) { return a.isValid() ? a._d["get" + (a._isUTC ? "UTC" : "") + b]() : NaN } function O(a, b, c) { a.isValid() && a._d["set" + (a._isUTC ? "UTC" : "") + b](c) } function P(a, b) { var c; if ("object" == typeof a) for (c in a) this.set(c, a[c]); else if (a = K(a), w(this[a])) return this[a](b); return this } function Q(a, b, c) { var d = "" + Math.abs(a), e = b - d.length, f = a >= 0; return (f ? c ? "+" : "" : "-") + Math.pow(10, Math.max(0, e)).toString().substr(1) + d } function R(a, b, c, d) { var e = d; "string" == typeof d && (e = function () { return this[d]() }), a && (ee[a] = e), b && (ee[b[0]] = function () { return Q(e.apply(this, arguments), b[1], b[2]) }), c && (ee[c] = function () { return this.localeData().ordinal(e.apply(this, arguments), a) }) } function S(a) { return a.match(/\[[\s\S]/) ? a.replace(/^\[|\]$/g, "") : a.replace(/\\/g, "") } function T(a) { var b, c, d = a.match(be); for (b = 0, c = d.length; c > b; b++) ee[d[b]] ? d[b] = ee[d[b]] : d[b] = S(d[b]); return function (e) { var f = ""; for (b = 0; c > b; b++) f += d[b] instanceof Function ? d[b].call(e, a) : d[b]; return f } } function U(a, b) { return a.isValid() ? (b = V(b, a.localeData()), de[b] = de[b] || T(b), de[b](a)) : a.localeData().invalidDate() } function V(a, b) { function c(a) { return b.longDateFormat(a) || a } var d = 5; for (ce.lastIndex = 0; d >= 0 && ce.test(a) ;) a = a.replace(ce, c), ce.lastIndex = 0, d -= 1; return a } function W(a, b, c) { we[a] = w(b) ? b : function (a, d) { return a && c ? c : b } } function X(a, b) { return f(we, a) ? we[a](b._strict, b._locale) : new RegExp(Y(a)) } function Y(a) { return Z(a.replace("\\", "").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (a, b, c, d, e) { return b || c || d || e })) } function Z(a) { return a.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&") } function $(a, b) { var c, d = b; for ("string" == typeof a && (a = [a]), "number" == typeof b && (d = function (a, c) { c[b] = r(a) }), c = 0; c < a.length; c++) xe[a[c]] = d } function _(a, b) { $(a, function (a, c, d, e) { d._w = d._w || {}, b(a, d._w, d, e) }) } function aa(a, b, c) { null != b && f(xe, a) && xe[a](b, c._a, c, a) } function ba(a, b) { return new Date(Date.UTC(a, b + 1, 0)).getUTCDate() } function ca(a, b) { return c(this._months) ? this._months[a.month()] : this._months[He.test(b) ? "format" : "standalone"][a.month()] } function da(a, b) { return c(this._monthsShort) ? this._monthsShort[a.month()] : this._monthsShort[He.test(b) ? "format" : "standalone"][a.month()] } function ea(a, b, c) { var d, e, f; for (this._monthsParse || (this._monthsParse = [], this._longMonthsParse = [], this._shortMonthsParse = []), d = 0; 12 > d; d++) { if (e = h([2e3, d]), c && !this._longMonthsParse[d] && (this._longMonthsParse[d] = new RegExp("^" + this.months(e, "").replace(".", "") + "$", "i"), this._shortMonthsParse[d] = new RegExp("^" + this.monthsShort(e, "").replace(".", "") + "$", "i")), c || this._monthsParse[d] || (f = "^" + this.months(e, "") + "|^" + this.monthsShort(e, ""), this._monthsParse[d] = new RegExp(f.replace(".", ""), "i")), c && "MMMM" === b && this._longMonthsParse[d].test(a)) return d; if (c && "MMM" === b && this._shortMonthsParse[d].test(a)) return d; if (!c && this._monthsParse[d].test(a)) return d } } function fa(a, b) { var c; if (!a.isValid()) return a; if ("string" == typeof b) if (/^\d+$/.test(b)) b = r(b); else if (b = a.localeData().monthsParse(b), "number" != typeof b) return a; return c = Math.min(a.date(), ba(a.year(), b)), a._d["set" + (a._isUTC ? "UTC" : "") + "Month"](b, c), a } function ga(b) { return null != b ? (fa(this, b), a.updateOffset(this, !0), this) : N(this, "Month") } function ha() { return ba(this.year(), this.month()) } function ia(a) { return this._monthsParseExact ? (f(this, "_monthsRegex") || ka.call(this), a ? this._monthsShortStrictRegex : this._monthsShortRegex) : this._monthsShortStrictRegex && a ? this._monthsShortStrictRegex : this._monthsShortRegex } function ja(a) { return this._monthsParseExact ? (f(this, "_monthsRegex") || ka.call(this), a ? this._monthsStrictRegex : this._monthsRegex) : this._monthsStrictRegex && a ? this._monthsStrictRegex : this._monthsRegex } function ka() { function a(a, b) { return b.length - a.length } var b, c, d = [], e = [], f = []; for (b = 0; 12 > b; b++) c = h([2e3, b]), d.push(this.monthsShort(c, "")), e.push(this.months(c, "")), f.push(this.months(c, "")), f.push(this.monthsShort(c, "")); for (d.sort(a), e.sort(a), f.sort(a), b = 0; 12 > b; b++) d[b] = Z(d[b]), e[b] = Z(e[b]), f[b] = Z(f[b]); this._monthsRegex = new RegExp("^(" + f.join("|") + ")", "i"), this._monthsShortRegex = this._monthsRegex, this._monthsStrictRegex = new RegExp("^(" + e.join("|") + ")$", "i"), this._monthsShortStrictRegex = new RegExp("^(" + d.join("|") + ")$", "i") } function la(a) { var b, c = a._a; return c && -2 === j(a).overflow && (b = c[ze] < 0 || c[ze] > 11 ? ze : c[Ae] < 1 || c[Ae] > ba(c[ye], c[ze]) ? Ae : c[Be] < 0 || c[Be] > 24 || 24 === c[Be] && (0 !== c[Ce] || 0 !== c[De] || 0 !== c[Ee]) ? Be : c[Ce] < 0 || c[Ce] > 59 ? Ce : c[De] < 0 || c[De] > 59 ? De : c[Ee] < 0 || c[Ee] > 999 ? Ee : -1, j(a)._overflowDayOfYear && (ye > b || b > Ae) && (b = Ae), j(a)._overflowWeeks && -1 === b && (b = Fe), j(a)._overflowWeekday && -1 === b && (b = Ge), j(a).overflow = b), a } function ma(a) { var b, c, d, e, f, g, h = a._i, i = Me.exec(h) || Ne.exec(h); if (i) { for (j(a).iso = !0, b = 0, c = Pe.length; c > b; b++) if (Pe[b][1].exec(i[1])) { e = Pe[b][0], d = Pe[b][2] !== !1; break } if (null == e) return void (a._isValid = !1); if (i[3]) { for (b = 0, c = Qe.length; c > b; b++) if (Qe[b][1].exec(i[3])) { f = (i[2] || " ") + Qe[b][0]; break } if (null == f) return void (a._isValid = !1) } if (!d && null != f) return void (a._isValid = !1); if (i[4]) { if (!Oe.exec(i[4])) return void (a._isValid = !1); g = "Z" } a._f = e + (f || "") + (g || ""), Ba(a) } else a._isValid = !1 } function na(b) { var c = Re.exec(b._i); return null !== c ? void (b._d = new Date(+c[1])) : (ma(b), void (b._isValid === !1 && (delete b._isValid, a.createFromInputFallback(b)))) } function oa(a, b, c, d, e, f, g) { var h = new Date(a, b, c, d, e, f, g); return 100 > a && a >= 0 && isFinite(h.getFullYear()) && h.setFullYear(a), h } function pa(a) { var b = new Date(Date.UTC.apply(null, arguments)); return 100 > a && a >= 0 && isFinite(b.getUTCFullYear()) && b.setUTCFullYear(a), b } function qa(a) { return ra(a) ? 366 : 365 } function ra(a) { return a % 4 === 0 && a % 100 !== 0 || a % 400 === 0 } function sa() { return ra(this.year()) } function ta(a, b, c) { var d = 7 + b - c, e = (7 + pa(a, 0, d).getUTCDay() - b) % 7; return -e + d - 1 } function ua(a, b, c, d, e) { var f, g, h = (7 + c - d) % 7, i = ta(a, d, e), j = 1 + 7 * (b - 1) + h + i; return 0 >= j ? (f = a - 1, g = qa(f) + j) : j > qa(a) ? (f = a + 1, g = j - qa(a)) : (f = a, g = j), { year: f, dayOfYear: g } } function va(a, b, c) { var d, e, f = ta(a.year(), b, c), g = Math.floor((a.dayOfYear() - f - 1) / 7) + 1; return 1 > g ? (e = a.year() - 1, d = g + wa(e, b, c)) : g > wa(a.year(), b, c) ? (d = g - wa(a.year(), b, c), e = a.year() + 1) : (e = a.year(), d = g), { week: d, year: e } } function wa(a, b, c) { var d = ta(a, b, c), e = ta(a + 1, b, c); return (qa(a) - d + e) / 7 } function xa(a, b, c) { return null != a ? a : null != b ? b : c } function ya(b) { var c = new Date(a.now()); return b._useUTC ? [c.getUTCFullYear(), c.getUTCMonth(), c.getUTCDate()] : [c.getFullYear(), c.getMonth(), c.getDate()] } function za(a) { var b, c, d, e, f = []; if (!a._d) { for (d = ya(a), a._w && null == a._a[Ae] && null == a._a[ze] && Aa(a), a._dayOfYear && (e = xa(a._a[ye], d[ye]), a._dayOfYear > qa(e) && (j(a)._overflowDayOfYear = !0), c = pa(e, 0, a._dayOfYear), a._a[ze] = c.getUTCMonth(), a._a[Ae] = c.getUTCDate()), b = 0; 3 > b && null == a._a[b]; ++b) a._a[b] = f[b] = d[b]; for (; 7 > b; b++) a._a[b] = f[b] = null == a._a[b] ? 2 === b ? 1 : 0 : a._a[b]; 24 === a._a[Be] && 0 === a._a[Ce] && 0 === a._a[De] && 0 === a._a[Ee] && (a._nextDay = !0, a._a[Be] = 0), a._d = (a._useUTC ? pa : oa).apply(null, f), null != a._tzm && a._d.setUTCMinutes(a._d.getUTCMinutes() - a._tzm), a._nextDay && (a._a[Be] = 24) } } function Aa(a) { var b, c, d, e, f, g, h, i; b = a._w, null != b.GG || null != b.W || null != b.E ? (f = 1, g = 4, c = xa(b.GG, a._a[ye], va(Ja(), 1, 4).year), d = xa(b.W, 1), e = xa(b.E, 1), (1 > e || e > 7) && (i = !0)) : (f = a._locale._week.dow, g = a._locale._week.doy, c = xa(b.gg, a._a[ye], va(Ja(), f, g).year), d = xa(b.w, 1), null != b.d ? (e = b.d, (0 > e || e > 6) && (i = !0)) : null != b.e ? (e = b.e + f, (b.e < 0 || b.e > 6) && (i = !0)) : e = f), 1 > d || d > wa(c, f, g) ? j(a)._overflowWeeks = !0 : null != i ? j(a)._overflowWeekday = !0 : (h = ua(c, d, e, f, g), a._a[ye] = h.year, a._dayOfYear = h.dayOfYear) } function Ba(b) { if (b._f === a.ISO_8601) return void ma(b); b._a = [], j(b).empty = !0; var c, d, e, f, g, h = "" + b._i, i = h.length, k = 0; for (e = V(b._f, b._locale).match(be) || [], c = 0; c < e.length; c++) f = e[c], d = (h.match(X(f, b)) || [])[0], d && (g = h.substr(0, h.indexOf(d)), g.length > 0 && j(b).unusedInput.push(g), h = h.slice(h.indexOf(d) + d.length), k += d.length), ee[f] ? (d ? j(b).empty = !1 : j(b).unusedTokens.push(f), aa(f, d, b)) : b._strict && !d && j(b).unusedTokens.push(f); j(b).charsLeftOver = i - k, h.length > 0 && j(b).unusedInput.push(h), j(b).bigHour === !0 && b._a[Be] <= 12 && b._a[Be] > 0 && (j(b).bigHour = void 0), b._a[Be] = Ca(b._locale, b._a[Be], b._meridiem), za(b), la(b) } function Ca(a, b, c) { var d; return null == c ? b : null != a.meridiemHour ? a.meridiemHour(b, c) : null != a.isPM ? (d = a.isPM(c), d && 12 > b && (b += 12), d || 12 !== b || (b = 0), b) : b } function Da(a) { var b, c, d, e, f; if (0 === a._f.length) return j(a).invalidFormat = !0, void (a._d = new Date(NaN)); for (e = 0; e < a._f.length; e++) f = 0, b = n({}, a), null != a._useUTC && (b._useUTC = a._useUTC), b._f = a._f[e], Ba(b), k(b) && (f += j(b).charsLeftOver, f += 10 * j(b).unusedTokens.length, j(b).score = f, (null == d || d > f) && (d = f, c = b)); g(a, c || b) } function Ea(a) { if (!a._d) { var b = L(a._i); a._a = e([b.year, b.month, b.day || b.date, b.hour, b.minute, b.second, b.millisecond], function (a) { return a && parseInt(a, 10) }), za(a) } } function Fa(a) { var b = new o(la(Ga(a))); return b._nextDay && (b.add(1, "d"), b._nextDay = void 0), b } function Ga(a) { var b = a._i, e = a._f; return a._locale = a._locale || H(a._l), null === b || void 0 === e && "" === b ? l({ nullInput: !0 }) : ("string" == typeof b && (a._i = b = a._locale.preparse(b)), p(b) ? new o(la(b)) : (c(e) ? Da(a) : e ? Ba(a) : d(b) ? a._d = b : Ha(a), k(a) || (a._d = null), a)) } function Ha(b) { var f = b._i; void 0 === f ? b._d = new Date(a.now()) : d(f) ? b._d = new Date(+f) : "string" == typeof f ? na(b) : c(f) ? (b._a = e(f.slice(0), function (a) { return parseInt(a, 10) }), za(b)) : "object" == typeof f ? Ea(b) : "number" == typeof f ? b._d = new Date(f) : a.createFromInputFallback(b) } function Ia(a, b, c, d, e) { var f = {}; return "boolean" == typeof c && (d = c, c = void 0), f._isAMomentObject = !0, f._useUTC = f._isUTC = e, f._l = c, f._i = a, f._f = b, f._strict = d, Fa(f) } function Ja(a, b, c, d) { return Ia(a, b, c, d, !1) } function Ka(a, b) { var d, e; if (1 === b.length && c(b[0]) && (b = b[0]), !b.length) return Ja(); for (d = b[0], e = 1; e < b.length; ++e) (!b[e].isValid() || b[e][a](d)) && (d = b[e]); return d } function La() { var a = [].slice.call(arguments, 0); return Ka("isBefore", a) } function Ma() { var a = [].slice.call(arguments, 0); return Ka("isAfter", a) } function Na(a) { var b = L(a), c = b.year || 0, d = b.quarter || 0, e = b.month || 0, f = b.week || 0, g = b.day || 0, h = b.hour || 0, i = b.minute || 0, j = b.second || 0, k = b.millisecond || 0; this._milliseconds = +k + 1e3 * j + 6e4 * i + 36e5 * h, this._days = +g + 7 * f, this._months = +e + 3 * d + 12 * c, this._data = {}, this._locale = H(), this._bubble() } function Oa(a) { return a instanceof Na } function Pa(a, b) { R(a, 0, 0, function () { var a = this.utcOffset(), c = "+"; return 0 > a && (a = -a, c = "-"), c + Q(~~(a / 60), 2) + b + Q(~~a % 60, 2) }) } function Qa(a, b) { var c = (b || "").match(a) || [], d = c[c.length - 1] || [], e = (d + "").match(We) || ["-", 0, 0], f = +(60 * e[1]) + r(e[2]); return "+" === e[0] ? f : -f } function Ra(b, c) { var e, f; return c._isUTC ? (e = c.clone(), f = (p(b) || d(b) ? +b : +Ja(b)) - +e, e._d.setTime(+e._d + f), a.updateOffset(e, !1), e) : Ja(b).local() } function Sa(a) { return 15 * -Math.round(a._d.getTimezoneOffset() / 15) } function Ta(b, c) { var d, e = this._offset || 0; return this.isValid() ? null != b ? ("string" == typeof b ? b = Qa(te, b) : Math.abs(b) < 16 && (b = 60 * b), !this._isUTC && c && (d = Sa(this)), this._offset = b, this._isUTC = !0, null != d && this.add(d, "m"), e !== b && (!c || this._changeInProgress ? ib(this, cb(b - e, "m"), 1, !1) : this._changeInProgress || (this._changeInProgress = !0, a.updateOffset(this, !0), this._changeInProgress = null)), this) : this._isUTC ? e : Sa(this) : null != b ? this : NaN } function Ua(a, b) { return null != a ? ("string" != typeof a && (a = -a), this.utcOffset(a, b), this) : -this.utcOffset() } function Va(a) { return this.utcOffset(0, a) } function Wa(a) { return this._isUTC && (this.utcOffset(0, a), this._isUTC = !1, a && this.subtract(Sa(this), "m")), this } function Xa() { return this._tzm ? this.utcOffset(this._tzm) : "string" == typeof this._i && this.utcOffset(Qa(se, this._i)), this } function Ya(a) { return this.isValid() ? (a = a ? Ja(a).utcOffset() : 0, (this.utcOffset() - a) % 60 === 0) : !1 } function Za() { return this.utcOffset() > this.clone().month(0).utcOffset() || this.utcOffset() > this.clone().month(5).utcOffset() } function $a() { if (!m(this._isDSTShifted)) return this._isDSTShifted; var a = {}; if (n(a, this), a = Ga(a), a._a) { var b = a._isUTC ? h(a._a) : Ja(a._a); this._isDSTShifted = this.isValid() && s(a._a, b.toArray()) > 0 } else this._isDSTShifted = !1; return this._isDSTShifted } function _a() { return this.isValid() ? !this._isUTC : !1 } function ab() { return this.isValid() ? this._isUTC : !1 } function bb() { return this.isValid() ? this._isUTC && 0 === this._offset : !1 } function cb(a, b) { var c, d, e, g = a, h = null; return Oa(a) ? g = { ms: a._milliseconds, d: a._days, M: a._months } : "number" == typeof a ? (g = {}, b ? g[b] = a : g.milliseconds = a) : (h = Xe.exec(a)) ? (c = "-" === h[1] ? -1 : 1, g = { y: 0, d: r(h[Ae]) * c, h: r(h[Be]) * c, m: r(h[Ce]) * c, s: r(h[De]) * c, ms: r(h[Ee]) * c }) : (h = Ye.exec(a)) ? (c = "-" === h[1] ? -1 : 1, g = { y: db(h[2], c), M: db(h[3], c), w: db(h[4], c), d: db(h[5], c), h: db(h[6], c), m: db(h[7], c), s: db(h[8], c) }) : null == g ? g = {} : "object" == typeof g && ("from" in g || "to" in g) && (e = fb(Ja(g.from), Ja(g.to)), g = {}, g.ms = e.milliseconds, g.M = e.months), d = new Na(g), Oa(a) && f(a, "_locale") && (d._locale = a._locale), d } function db(a, b) { var c = a && parseFloat(a.replace(",", ".")); return (isNaN(c) ? 0 : c) * b } function eb(a, b) { var c = { milliseconds: 0, months: 0 }; return c.months = b.month() - a.month() + 12 * (b.year() - a.year()), a.clone().add(c.months, "M").isAfter(b) && --c.months, c.milliseconds = +b - +a.clone().add(c.months, "M"), c } function fb(a, b) { var c; return a.isValid() && b.isValid() ? (b = Ra(b, a), a.isBefore(b) ? c = eb(a, b) : (c = eb(b, a), c.milliseconds = -c.milliseconds, c.months = -c.months), c) : { milliseconds: 0, months: 0 } } function gb(a) { return 0 > a ? -1 * Math.round(-1 * a) : Math.round(a) } function hb(a, b) { return function (c, d) { var e, f; return null === d || isNaN(+d) || (v(b, "moment()." + b + "(period, number) is deprecated. Please use moment()." + b + "(number, period)."), f = c, c = d, d = f), c = "string" == typeof c ? +c : c, e = cb(c, d), ib(this, e, a), this } } function ib(b, c, d, e) { var f = c._milliseconds, g = gb(c._days), h = gb(c._months); b.isValid() && (e = null == e ? !0 : e, f && b._d.setTime(+b._d + f * d), g && O(b, "Date", N(b, "Date") + g * d), h && fa(b, N(b, "Month") + h * d), e && a.updateOffset(b, g || h)) } function jb(a, b) { var c = a || Ja(), d = Ra(c, this).startOf("day"), e = this.diff(d, "days", !0), f = -6 > e ? "sameElse" : -1 > e ? "lastWeek" : 0 > e ? "lastDay" : 1 > e ? "sameDay" : 2 > e ? "nextDay" : 7 > e ? "nextWeek" : "sameElse", g = b && (w(b[f]) ? b[f]() : b[f]); return this.format(g || this.localeData().calendar(f, this, Ja(c))) } function kb() { return new o(this) } function lb(a, b) { var c = p(a) ? a : Ja(a); return this.isValid() && c.isValid() ? (b = K(m(b) ? "millisecond" : b), "millisecond" === b ? +this > +c : +c < +this.clone().startOf(b)) : !1 } function mb(a, b) { var c = p(a) ? a : Ja(a); return this.isValid() && c.isValid() ? (b = K(m(b) ? "millisecond" : b), "millisecond" === b ? +c > +this : +this.clone().endOf(b) < +c) : !1 } function nb(a, b, c) { return this.isAfter(a, c) && this.isBefore(b, c) } function ob(a, b) { var c, d = p(a) ? a : Ja(a); return this.isValid() && d.isValid() ? (b = K(b || "millisecond"), "millisecond" === b ? +this === +d : (c = +d, +this.clone().startOf(b) <= c && c <= +this.clone().endOf(b))) : !1 } function pb(a, b) { return this.isSame(a, b) || this.isAfter(a, b) } function qb(a, b) { return this.isSame(a, b) || this.isBefore(a, b) } function rb(a, b, c) { var d, e, f, g; return this.isValid() ? (d = Ra(a, this), d.isValid() ? (e = 6e4 * (d.utcOffset() - this.utcOffset()), b = K(b), "year" === b || "month" === b || "quarter" === b ? (g = sb(this, d), "quarter" === b ? g /= 3 : "year" === b && (g /= 12)) : (f = this - d, g = "second" === b ? f / 1e3 : "minute" === b ? f / 6e4 : "hour" === b ? f / 36e5 : "day" === b ? (f - e) / 864e5 : "week" === b ? (f - e) / 6048e5 : f), c ? g : q(g)) : NaN) : NaN } function sb(a, b) { var c, d, e = 12 * (b.year() - a.year()) + (b.month() - a.month()), f = a.clone().add(e, "months"); return 0 > b - f ? (c = a.clone().add(e - 1, "months"), d = (b - f) / (f - c)) : (c = a.clone().add(e + 1, "months"), d = (b - f) / (c - f)), -(e + d) } function tb() { return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ") } function ub() { var a = this.clone().utc(); return 0 < a.year() && a.year() <= 9999 ? w(Date.prototype.toISOString) ? this.toDate().toISOString() : U(a, "YYYY-MM-DD[T]HH:mm:ss.SSS[Z]") : U(a, "YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]") } function vb(b) { var c = U(this, b || a.defaultFormat); return this.localeData().postformat(c) } function wb(a, b) { return this.isValid() && (p(a) && a.isValid() || Ja(a).isValid()) ? cb({ to: this, from: a }).locale(this.locale()).humanize(!b) : this.localeData().invalidDate() } function xb(a) { return this.from(Ja(), a) } function yb(a, b) { return this.isValid() && (p(a) && a.isValid() || Ja(a).isValid()) ? cb({ from: this, to: a }).locale(this.locale()).humanize(!b) : this.localeData().invalidDate() } function zb(a) { return this.to(Ja(), a) } function Ab(a) { var b; return void 0 === a ? this._locale._abbr : (b = H(a), null != b && (this._locale = b), this) } function Bb() { return this._locale } function Cb(a) { switch (a = K(a)) { case "year": this.month(0); case "quarter": case "month": this.date(1); case "week": case "isoWeek": case "day": this.hours(0); case "hour": this.minutes(0); case "minute": this.seconds(0); case "second": this.milliseconds(0) } return "week" === a && this.weekday(0), "isoWeek" === a && this.isoWeekday(1), "quarter" === a && this.month(3 * Math.floor(this.month() / 3)), this } function Db(a) { return a = K(a), void 0 === a || "millisecond" === a ? this : this.startOf(a).add(1, "isoWeek" === a ? "week" : a).subtract(1, "ms") } function Eb() { return +this._d - 6e4 * (this._offset || 0) } function Fb() { return Math.floor(+this / 1e3) } function Gb() { return this._offset ? new Date(+this) : this._d } function Hb() { var a = this; return [a.year(), a.month(), a.date(), a.hour(), a.minute(), a.second(), a.millisecond()] } function Ib() { var a = this; return { years: a.year(), months: a.month(), date: a.date(), hours: a.hours(), minutes: a.minutes(), seconds: a.seconds(), milliseconds: a.milliseconds() } } function Jb() { return this.isValid() ? this.toISOString() : null } function Kb() { return k(this) } function Lb() { return g({}, j(this)) } function Mb() { return j(this).overflow } function Nb() { return { input: this._i, format: this._f, locale: this._locale, isUTC: this._isUTC, strict: this._strict } } function Ob(a, b) { R(0, [a, a.length], 0, b) } function Pb(a) { return Tb.call(this, a, this.week(), this.weekday(), this.localeData()._week.dow, this.localeData()._week.doy) } function Qb(a) { return Tb.call(this, a, this.isoWeek(), this.isoWeekday(), 1, 4) } function Rb() { return wa(this.year(), 1, 4) } function Sb() { var a = this.localeData()._week; return wa(this.year(), a.dow, a.doy) } function Tb(a, b, c, d, e) { var f; return null == a ? va(this, d, e).year : (f = wa(a, d, e), b > f && (b = f), Ub.call(this, a, b, c, d, e)) } function Ub(a, b, c, d, e) { var f = ua(a, b, c, d, e), g = pa(f.year, 0, f.dayOfYear); return this.year(g.getUTCFullYear()), this.month(g.getUTCMonth()), this.date(g.getUTCDate()), this } function Vb(a) { return null == a ? Math.ceil((this.month() + 1) / 3) : this.month(3 * (a - 1) + this.month() % 3) } function Wb(a) { return va(a, this._week.dow, this._week.doy).week } function Xb() { return this._week.dow } function Yb() { return this._week.doy } function Zb(a) { var b = this.localeData().week(this); return null == a ? b : this.add(7 * (a - b), "d") } function $b(a) { var b = va(this, 1, 4).week; return null == a ? b : this.add(7 * (a - b), "d") } function _b(a, b) { return "string" != typeof a ? a : isNaN(a) ? (a = b.weekdaysParse(a), "number" == typeof a ? a : null) : parseInt(a, 10) } function ac(a, b) { return c(this._weekdays) ? this._weekdays[a.day()] : this._weekdays[this._weekdays.isFormat.test(b) ? "format" : "standalone"][a.day()] } function bc(a) { return this._weekdaysShort[a.day()] } function cc(a) { return this._weekdaysMin[a.day()] } function dc(a, b, c) { var d, e, f; for (this._weekdaysParse || (this._weekdaysParse = [], this._minWeekdaysParse = [], this._shortWeekdaysParse = [], this._fullWeekdaysParse = []), d = 0; 7 > d; d++) { if (e = Ja([2e3, 1]).day(d), c && !this._fullWeekdaysParse[d] && (this._fullWeekdaysParse[d] = new RegExp("^" + this.weekdays(e, "").replace(".", ".?") + "$", "i"), this._shortWeekdaysParse[d] = new RegExp("^" + this.weekdaysShort(e, "").replace(".", ".?") + "$", "i"), this._minWeekdaysParse[d] = new RegExp("^" + this.weekdaysMin(e, "").replace(".", ".?") + "$", "i")), this._weekdaysParse[d] || (f = "^" + this.weekdays(e, "") + "|^" + this.weekdaysShort(e, "") + "|^" + this.weekdaysMin(e, ""), this._weekdaysParse[d] = new RegExp(f.replace(".", ""), "i")), c && "dddd" === b && this._fullWeekdaysParse[d].test(a)) return d; if (c && "ddd" === b && this._shortWeekdaysParse[d].test(a)) return d; if (c && "dd" === b && this._minWeekdaysParse[d].test(a)) return d; if (!c && this._weekdaysParse[d].test(a)) return d } } function ec(a) { if (!this.isValid()) return null != a ? this : NaN; var b = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); return null != a ? (a = _b(a, this.localeData()), this.add(a - b, "d")) : b } function fc(a) { if (!this.isValid()) return null != a ? this : NaN; var b = (this.day() + 7 - this.localeData()._week.dow) % 7; return null == a ? b : this.add(a - b, "d") } function gc(a) { return this.isValid() ? null == a ? this.day() || 7 : this.day(this.day() % 7 ? a : a - 7) : null != a ? this : NaN } function hc(a) { var b = Math.round((this.clone().startOf("day") - this.clone().startOf("year")) / 864e5) + 1; return null == a ? b : this.add(a - b, "d") } function ic() { return this.hours() % 12 || 12 } function jc(a, b) { R(a, 0, 0, function () { return this.localeData().meridiem(this.hours(), this.minutes(), b) }) } function kc(a, b) { return b._meridiemParse } function lc(a) { return "p" === (a + "").toLowerCase().charAt(0) } function mc(a, b, c) { return a > 11 ? c ? "pm" : "PM" : c ? "am" : "AM" } function nc(a, b) { b[Ee] = r(1e3 * ("0." + a)) } function oc() { return this._isUTC ? "UTC" : "" } function pc() { return this._isUTC ? "Coordinated Universal Time" : "" } function qc(a) { return Ja(1e3 * a) } function rc() { return Ja.apply(null, arguments).parseZone() } function sc(a, b, c) { var d = this._calendar[a]; return w(d) ? d.call(b, c) : d } function tc(a) { var b = this._longDateFormat[a], c = this._longDateFormat[a.toUpperCase()]; return b || !c ? b : (this._longDateFormat[a] = c.replace(/MMMM|MM|DD|dddd/g, function (a) { return a.slice(1) }), this._longDateFormat[a]) } function uc() { return this._invalidDate } function vc(a) { return this._ordinal.replace("%d", a) } function wc(a) { return a } function xc(a, b, c, d) { var e = this._relativeTime[c]; return w(e) ? e(a, b, c, d) : e.replace(/%d/i, a) } function yc(a, b) { var c = this._relativeTime[a > 0 ? "future" : "past"]; return w(c) ? c(b) : c.replace(/%s/i, b) } function zc(a, b, c, d) { var e = H(), f = h().set(d, b); return e[c](f, a) } function Ac(a, b, c, d, e) { if ("number" == typeof a && (b = a, a = void 0), a = a || "", null != b) return zc(a, b, c, e); var f, g = []; for (f = 0; d > f; f++) g[f] = zc(a, f, c, e); return g } function Bc(a, b) { return Ac(a, b, "months", 12, "month") } function Cc(a, b) { return Ac(a, b, "monthsShort", 12, "month") } function Dc(a, b) { return Ac(a, b, "weekdays", 7, "day") } function Ec(a, b) { return Ac(a, b, "weekdaysShort", 7, "day") } function Fc(a, b) { return Ac(a, b, "weekdaysMin", 7, "day") } function Gc() { var a = this._data; return this._milliseconds = vf(this._milliseconds), this._days = vf(this._days), this._months = vf(this._months), a.milliseconds = vf(a.milliseconds), a.seconds = vf(a.seconds), a.minutes = vf(a.minutes), a.hours = vf(a.hours), a.months = vf(a.months), a.years = vf(a.years), this } function Hc(a, b, c, d) { var e = cb(b, c); return a._milliseconds += d * e._milliseconds, a._days += d * e._days, a._months += d * e._months, a._bubble() } function Ic(a, b) { return Hc(this, a, b, 1) } function Jc(a, b) { return Hc(this, a, b, -1) } function Kc(a) { return 0 > a ? Math.floor(a) : Math.ceil(a) } function Lc() { var a, b, c, d, e, f = this._milliseconds, g = this._days, h = this._months, i = this._data; return f >= 0 && g >= 0 && h >= 0 || 0 >= f && 0 >= g && 0 >= h || (f += 864e5 * Kc(Nc(h) + g), g = 0, h = 0), i.milliseconds = f % 1e3, a = q(f / 1e3), i.seconds = a % 60, b = q(a / 60), i.minutes = b % 60, c = q(b / 60), i.hours = c % 24, g += q(c / 24), e = q(Mc(g)), h += e, g -= Kc(Nc(e)), d = q(h / 12), h %= 12, i.days = g, i.months = h, i.years = d, this } function Mc(a) { return 4800 * a / 146097 } function Nc(a) { return 146097 * a / 4800 } function Oc(a) { var b, c, d = this._milliseconds; if (a = K(a), "month" === a || "year" === a) return b = this._days + d / 864e5, c = this._months + Mc(b), "month" === a ? c : c / 12; switch (b = this._days + Math.round(Nc(this._months)), a) { case "week": return b / 7 + d / 6048e5; case "day": return b + d / 864e5; case "hour": return 24 * b + d / 36e5; case "minute": return 1440 * b + d / 6e4; case "second": return 86400 * b + d / 1e3; case "millisecond": return Math.floor(864e5 * b) + d; default: throw new Error("Unknown unit " + a) } } function Pc() { return this._milliseconds + 864e5 * this._days + this._months % 12 * 2592e6 + 31536e6 * r(this._months / 12) } function Qc(a) { return function () { return this.as(a) } } function Rc(a) { return a = K(a), this[a + "s"]() } function Sc(a) { return function () { return this._data[a] } } function Tc() { return q(this.days() / 7) } function Uc(a, b, c, d, e) { return e.relativeTime(b || 1, !!c, a, d) } function Vc(a, b, c) { var d = cb(a).abs(), e = Lf(d.as("s")), f = Lf(d.as("m")), g = Lf(d.as("h")), h = Lf(d.as("d")), i = Lf(d.as("M")), j = Lf(d.as("y")), k = e < Mf.s && ["s", e] || 1 >= f && ["m"] || f < Mf.m && ["mm", f] || 1 >= g && ["h"] || g < Mf.h && ["hh", g] || 1 >= h && ["d"] || h < Mf.d && ["dd", h] || 1 >= i && ["M"] || i < Mf.M && ["MM", i] || 1 >= j && ["y"] || ["yy", j]; return k[2] = b, k[3] = +a > 0, k[4] = c, Uc.apply(null, k) } function Wc(a, b) { return void 0 === Mf[a] ? !1 : void 0 === b ? Mf[a] : (Mf[a] = b, !0) } function Xc(a) { var b = this.localeData(), c = Vc(this, !a, b); return a && (c = b.pastFuture(+this, c)), b.postformat(c) } function Yc() { var a, b, c, d = Nf(this._milliseconds) / 1e3, e = Nf(this._days), f = Nf(this._months); a = q(d / 60), b = q(a / 60), d %= 60, a %= 60, c = q(f / 12), f %= 12; var g = c, h = f, i = e, j = b, k = a, l = d, m = this.asSeconds(); return m ? (0 > m ? "-" : "") + "P" + (g ? g + "Y" : "") + (h ? h + "M" : "") + (i ? i + "D" : "") + (j || k || l ? "T" : "") + (j ? j + "H" : "") + (k ? k + "M" : "") + (l ? l + "S" : "") : "P0D" }
    //! moment.js locale configuration
    //! locale : belarusian (be)
    //! author : Dmitry Demidov : https://github.com/demidov91
    //! author: Praleska: http://praleska.pro/
    //! Author : Menelion Elensúle : https://github.com/Oire
    function Zc(a, b) { var c = a.split("_"); return b % 10 === 1 && b % 100 !== 11 ? c[0] : b % 10 >= 2 && 4 >= b % 10 && (10 > b % 100 || b % 100 >= 20) ? c[1] : c[2] } function $c(a, b, c) { var d = { mm: b ? "хвіліна_хвіліны_хвілін" : "хвіліну_хвіліны_хвілін", hh: b ? "гадзіна_гадзіны_гадзін" : "гадзіну_гадзіны_гадзін", dd: "дзень_дні_дзён", MM: "месяц_месяцы_месяцаў", yy: "год_гады_гадоў" }; return "m" === c ? b ? "хвіліна" : "хвіліну" : "h" === c ? b ? "гадзіна" : "гадзіну" : a + " " + Zc(d[c], +a) }
    //! moment.js locale configuration
    //! locale : breton (br)
    //! author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou
    function _c(a, b, c) { var d = { mm: "munutenn", MM: "miz", dd: "devezh" }; return a + " " + cd(d[c], a) } function ad(a) { switch (bd(a)) { case 1: case 3: case 4: case 5: case 9: return a + " bloaz"; default: return a + " vloaz" } } function bd(a) { return a > 9 ? bd(a % 10) : a } function cd(a, b) { return 2 === b ? dd(a) : a } function dd(a) { var b = { m: "v", b: "v", d: "z" }; return void 0 === b[a.charAt(0)] ? a : b[a.charAt(0)] + a.substring(1) }
    //! moment.js locale configuration
    //! locale : bosnian (bs)
    //! author : Nedim Cholich : https://github.com/frontyard
    //! based on (hr) translation by Bojan Marković
    function ed(a, b, c) { var d = a + " "; switch (c) { case "m": return b ? "jedna minuta" : "jedne minute"; case "mm": return d += 1 === a ? "minuta" : 2 === a || 3 === a || 4 === a ? "minute" : "minuta"; case "h": return b ? "jedan sat" : "jednog sata"; case "hh": return d += 1 === a ? "sat" : 2 === a || 3 === a || 4 === a ? "sata" : "sati"; case "dd": return d += 1 === a ? "dan" : "dana"; case "MM": return d += 1 === a ? "mjesec" : 2 === a || 3 === a || 4 === a ? "mjeseca" : "mjeseci"; case "yy": return d += 1 === a ? "godina" : 2 === a || 3 === a || 4 === a ? "godine" : "godina" } } function fd(a) { return a > 1 && 5 > a && 1 !== ~~(a / 10) } function gd(a, b, c, d) { var e = a + " "; switch (c) { case "s": return b || d ? "pár sekund" : "pár sekundami"; case "m": return b ? "minuta" : d ? "minutu" : "minutou"; case "mm": return b || d ? e + (fd(a) ? "minuty" : "minut") : e + "minutami"; break; case "h": return b ? "hodina" : d ? "hodinu" : "hodinou"; case "hh": return b || d ? e + (fd(a) ? "hodiny" : "hodin") : e + "hodinami"; break; case "d": return b || d ? "den" : "dnem"; case "dd": return b || d ? e + (fd(a) ? "dny" : "dní") : e + "dny"; break; case "M": return b || d ? "měsíc" : "měsícem"; case "MM": return b || d ? e + (fd(a) ? "měsíce" : "měsíců") : e + "měsíci"; break; case "y": return b || d ? "rok" : "rokem"; case "yy": return b || d ? e + (fd(a) ? "roky" : "let") : e + "lety" } }
    //! moment.js locale configuration
    //! locale : austrian german (de-at)
    //! author : lluchs : https://github.com/lluchs
    //! author: Menelion Elensúle: https://github.com/Oire
    //! author : Martin Groller : https://github.com/MadMG
    //! author : Mikolaj Dadela : https://github.com/mik01aj
    function hd(a, b, c, d) { var e = { m: ["eine Minute", "einer Minute"], h: ["eine Stunde", "einer Stunde"], d: ["ein Tag", "einem Tag"], dd: [a + " Tage", a + " Tagen"], M: ["ein Monat", "einem Monat"], MM: [a + " Monate", a + " Monaten"], y: ["ein Jahr", "einem Jahr"], yy: [a + " Jahre", a + " Jahren"] }; return b ? e[c][0] : e[c][1] }
    //! moment.js locale configuration
    //! locale : german (de)
    //! author : lluchs : https://github.com/lluchs
    //! author: Menelion Elensúle: https://github.com/Oire
    //! author : Mikolaj Dadela : https://github.com/mik01aj
    function id(a, b, c, d) { var e = { m: ["eine Minute", "einer Minute"], h: ["eine Stunde", "einer Stunde"], d: ["ein Tag", "einem Tag"], dd: [a + " Tage", a + " Tagen"], M: ["ein Monat", "einem Monat"], MM: [a + " Monate", a + " Monaten"], y: ["ein Jahr", "einem Jahr"], yy: [a + " Jahre", a + " Jahren"] }; return b ? e[c][0] : e[c][1] }
    //! moment.js locale configuration
    //! locale : estonian (et)
    //! author : Henry Kehlmann : https://github.com/madhenry
    //! improvements : Illimar Tambek : https://github.com/ragulka
    function jd(a, b, c, d) { var e = { s: ["mõne sekundi", "mõni sekund", "paar sekundit"], m: ["ühe minuti", "üks minut"], mm: [a + " minuti", a + " minutit"], h: ["ühe tunni", "tund aega", "üks tund"], hh: [a + " tunni", a + " tundi"], d: ["ühe päeva", "üks päev"], M: ["kuu aja", "kuu aega", "üks kuu"], MM: [a + " kuu", a + " kuud"], y: ["ühe aasta", "aasta", "üks aasta"], yy: [a + " aasta", a + " aastat"] }; return b ? e[c][2] ? e[c][2] : e[c][1] : d ? e[c][0] : e[c][1] } function kd(a, b, c, d) { var e = ""; switch (c) { case "s": return d ? "muutaman sekunnin" : "muutama sekunti"; case "m": return d ? "minuutin" : "minuutti"; case "mm": e = d ? "minuutin" : "minuuttia"; break; case "h": return d ? "tunnin" : "tunti"; case "hh": e = d ? "tunnin" : "tuntia"; break; case "d": return d ? "päivän" : "päivä"; case "dd": e = d ? "päivän" : "päivää"; break; case "M": return d ? "kuukauden" : "kuukausi"; case "MM": e = d ? "kuukauden" : "kuukautta"; break; case "y": return d ? "vuoden" : "vuosi"; case "yy": e = d ? "vuoden" : "vuotta" } return e = ld(a, d) + " " + e } function ld(a, b) { return 10 > a ? b ? kg[a] : jg[a] : a }
    //! moment.js locale configuration
    //! locale : hrvatski (hr)
    //! author : Bojan Marković : https://github.com/bmarkovic
    function md(a, b, c) { var d = a + " "; switch (c) { case "m": return b ? "jedna minuta" : "jedne minute"; case "mm": return d += 1 === a ? "minuta" : 2 === a || 3 === a || 4 === a ? "minute" : "minuta"; case "h": return b ? "jedan sat" : "jednog sata"; case "hh": return d += 1 === a ? "sat" : 2 === a || 3 === a || 4 === a ? "sata" : "sati"; case "dd": return d += 1 === a ? "dan" : "dana"; case "MM": return d += 1 === a ? "mjesec" : 2 === a || 3 === a || 4 === a ? "mjeseca" : "mjeseci"; case "yy": return d += 1 === a ? "godina" : 2 === a || 3 === a || 4 === a ? "godine" : "godina" } } function nd(a, b, c, d) { var e = a; switch (c) { case "s": return d || b ? "néhány másodperc" : "néhány másodperce"; case "m": return "egy" + (d || b ? " perc" : " perce"); case "mm": return e + (d || b ? " perc" : " perce"); case "h": return "egy" + (d || b ? " óra" : " órája"); case "hh": return e + (d || b ? " óra" : " órája"); case "d": return "egy" + (d || b ? " nap" : " napja"); case "dd": return e + (d || b ? " nap" : " napja"); case "M": return "egy" + (d || b ? " hónap" : " hónapja"); case "MM": return e + (d || b ? " hónap" : " hónapja"); case "y": return "egy" + (d || b ? " év" : " éve"); case "yy": return e + (d || b ? " év" : " éve") } return "" } function od(a) { return (a ? "" : "[múlt] ") + "[" + ug[this.day()] + "] LT[-kor]" }
    //! moment.js locale configuration
    //! locale : icelandic (is)
    //! author : Hinrik Örn Sigurðsson : https://github.com/hinrik
    function pd(a) { return a % 100 === 11 ? !0 : a % 10 === 1 ? !1 : !0 } function qd(a, b, c, d) { var e = a + " "; switch (c) { case "s": return b || d ? "nokkrar sekúndur" : "nokkrum sekúndum"; case "m": return b ? "mínúta" : "mínútu"; case "mm": return pd(a) ? e + (b || d ? "mínútur" : "mínútum") : b ? e + "mínúta" : e + "mínútu"; case "hh": return pd(a) ? e + (b || d ? "klukkustundir" : "klukkustundum") : e + "klukkustund"; case "d": return b ? "dagur" : d ? "dag" : "degi"; case "dd": return pd(a) ? b ? e + "dagar" : e + (d ? "daga" : "dögum") : b ? e + "dagur" : e + (d ? "dag" : "degi"); case "M": return b ? "mánuður" : d ? "mánuð" : "mánuði"; case "MM": return pd(a) ? b ? e + "mánuðir" : e + (d ? "mánuði" : "mánuðum") : b ? e + "mánuður" : e + (d ? "mánuð" : "mánuði"); case "y": return b || d ? "ár" : "ári"; case "yy": return pd(a) ? e + (b || d ? "ár" : "árum") : e + (b || d ? "ár" : "ári") } }
    //! moment.js locale configuration
    //! locale : Luxembourgish (lb)
    //! author : mweimerskirch : https://github.com/mweimerskirch, David Raison : https://github.com/kwisatz
    function rd(a, b, c, d) { var e = { m: ["eng Minutt", "enger Minutt"], h: ["eng Stonn", "enger Stonn"], d: ["een Dag", "engem Dag"], M: ["ee Mount", "engem Mount"], y: ["ee Joer", "engem Joer"] }; return b ? e[c][0] : e[c][1] } function sd(a) { var b = a.substr(0, a.indexOf(" ")); return ud(b) ? "a " + a : "an " + a } function td(a) { var b = a.substr(0, a.indexOf(" ")); return ud(b) ? "viru " + a : "virun " + a } function ud(a) { if (a = parseInt(a, 10), isNaN(a)) return !1; if (0 > a) return !0; if (10 > a) return a >= 4 && 7 >= a ? !0 : !1; if (100 > a) { var b = a % 10, c = a / 10; return ud(0 === b ? c : b) } if (1e4 > a) { for (; a >= 10;) a /= 10; return ud(a) } return a /= 1e3, ud(a) } function vd(a, b, c, d) { return b ? "kelios sekundės" : d ? "kelių sekundžių" : "kelias sekundes" } function wd(a, b, c, d) { return b ? yd(c)[0] : d ? yd(c)[1] : yd(c)[2] } function xd(a) { return a % 10 === 0 || a > 10 && 20 > a } function yd(a) { return wg[a].split("_") } function zd(a, b, c, d) { var e = a + " "; return 1 === a ? e + wd(a, b, c[0], d) : b ? e + (xd(a) ? yd(c)[1] : yd(c)[0]) : d ? e + yd(c)[1] : e + (xd(a) ? yd(c)[1] : yd(c)[2]) } function Ad(a, b, c) { return c ? b % 10 === 1 && 11 !== b ? a[2] : a[3] : b % 10 === 1 && 11 !== b ? a[0] : a[1] } function Bd(a, b, c) { return a + " " + Ad(xg[c], a, b) } function Cd(a, b, c) { return Ad(xg[c], a, b) } function Dd(a, b) { return b ? "dažas sekundes" : "dažām sekundēm" } function Ed(a, b, c, d) { var e = ""; if (b) switch (c) { case "s": e = "काही सेकंद"; break; case "m": e = "एक मिनिट"; break; case "mm": e = "%d मिनिटे"; break; case "h": e = "एक तास"; break; case "hh": e = "%d तास"; break; case "d": e = "एक दिवस"; break; case "dd": e = "%d दिवस"; break; case "M": e = "एक महिना"; break; case "MM": e = "%d महिने"; break; case "y": e = "एक वर्ष"; break; case "yy": e = "%d वर्षे" } else switch (c) { case "s": e = "काही सेकंदां"; break; case "m": e = "एका मिनिटा"; break; case "mm": e = "%d मिनिटां"; break; case "h": e = "एका तासा"; break; case "hh": e = "%d तासां"; break; case "d": e = "एका दिवसा"; break; case "dd": e = "%d दिवसां"; break; case "M": e = "एका महिन्या"; break; case "MM": e = "%d महिन्यां"; break; case "y": e = "एका वर्षा"; break; case "yy": e = "%d वर्षां" } return e.replace(/%d/i, a) } function Fd(a) { return 5 > a % 10 && a % 10 > 1 && ~~(a / 10) % 10 !== 1 } function Gd(a, b, c) { var d = a + " "; switch (c) { case "m": return b ? "minuta" : "minutę"; case "mm": return d + (Fd(a) ? "minuty" : "minut"); case "h": return b ? "godzina" : "godzinę"; case "hh": return d + (Fd(a) ? "godziny" : "godzin"); case "MM": return d + (Fd(a) ? "miesiące" : "miesięcy"); case "yy": return d + (Fd(a) ? "lata" : "lat") } }
    //! moment.js locale configuration
    //! locale : romanian (ro)
    //! author : Vlad Gurdiga : https://github.com/gurdiga
    //! author : Valentin Agachi : https://github.com/avaly
    function Hd(a, b, c) { var d = { mm: "minute", hh: "ore", dd: "zile", MM: "luni", yy: "ani" }, e = " "; return (a % 100 >= 20 || a >= 100 && a % 100 === 0) && (e = " de "), a + e + d[c] }
    //! moment.js locale configuration
    //! locale : russian (ru)
    //! author : Viktorminator : https://github.com/Viktorminator
    //! Author : Menelion Elensúle : https://github.com/Oire
    //! author : Коренберг Марк : https://github.com/socketpair
    function Id(a, b) { var c = a.split("_"); return b % 10 === 1 && b % 100 !== 11 ? c[0] : b % 10 >= 2 && 4 >= b % 10 && (10 > b % 100 || b % 100 >= 20) ? c[1] : c[2] } function Jd(a, b, c) { var d = { mm: b ? "минута_минуты_минут" : "минуту_минуты_минут", hh: "час_часа_часов", dd: "день_дня_дней", MM: "месяц_месяца_месяцев", yy: "год_года_лет" }; return "m" === c ? b ? "минута" : "минуту" : a + " " + Id(d[c], +a) } function Kd(a) { return a > 1 && 5 > a } function Ld(a, b, c, d) { var e = a + " "; switch (c) { case "s": return b || d ? "pár sekúnd" : "pár sekundami"; case "m": return b ? "minúta" : d ? "minútu" : "minútou"; case "mm": return b || d ? e + (Kd(a) ? "minúty" : "minút") : e + "minútami"; break; case "h": return b ? "hodina" : d ? "hodinu" : "hodinou"; case "hh": return b || d ? e + (Kd(a) ? "hodiny" : "hodín") : e + "hodinami"; break; case "d": return b || d ? "deň" : "dňom"; case "dd": return b || d ? e + (Kd(a) ? "dni" : "dní") : e + "dňami"; break; case "M": return b || d ? "mesiac" : "mesiacom"; case "MM": return b || d ? e + (Kd(a) ? "mesiace" : "mesiacov") : e + "mesiacmi"; break; case "y": return b || d ? "rok" : "rokom"; case "yy": return b || d ? e + (Kd(a) ? "roky" : "rokov") : e + "rokmi" } }
    //! moment.js locale configuration
    //! locale : slovenian (sl)
    //! author : Robert Sedovšek : https://github.com/sedovsek
    function Md(a, b, c, d) { var e = a + " "; switch (c) { case "s": return b || d ? "nekaj sekund" : "nekaj sekundami"; case "m": return b ? "ena minuta" : "eno minuto"; case "mm": return e += 1 === a ? b ? "minuta" : "minuto" : 2 === a ? b || d ? "minuti" : "minutama" : 5 > a ? b || d ? "minute" : "minutami" : b || d ? "minut" : "minutami"; case "h": return b ? "ena ura" : "eno uro"; case "hh": return e += 1 === a ? b ? "ura" : "uro" : 2 === a ? b || d ? "uri" : "urama" : 5 > a ? b || d ? "ure" : "urami" : b || d ? "ur" : "urami"; case "d": return b || d ? "en dan" : "enim dnem"; case "dd": return e += 1 === a ? b || d ? "dan" : "dnem" : 2 === a ? b || d ? "dni" : "dnevoma" : b || d ? "dni" : "dnevi"; case "M": return b || d ? "en mesec" : "enim mesecem"; case "MM": return e += 1 === a ? b || d ? "mesec" : "mesecem" : 2 === a ? b || d ? "meseca" : "mesecema" : 5 > a ? b || d ? "mesece" : "meseci" : b || d ? "mesecev" : "meseci"; case "y": return b || d ? "eno leto" : "enim letom"; case "yy": return e += 1 === a ? b || d ? "leto" : "letom" : 2 === a ? b || d ? "leti" : "letoma" : 5 > a ? b || d ? "leta" : "leti" : b || d ? "let" : "leti" } } function Nd(a) { var b = a; return b = -1 !== a.indexOf("jaj") ? b.slice(0, -3) + "leS" : -1 !== a.indexOf("jar") ? b.slice(0, -3) + "waQ" : -1 !== a.indexOf("DIS") ? b.slice(0, -3) + "nem" : b + " pIq" } function Od(a) { var b = a; return b = -1 !== a.indexOf("jaj") ? b.slice(0, -3) + "Hu’" : -1 !== a.indexOf("jar") ? b.slice(0, -3) + "wen" : -1 !== a.indexOf("DIS") ? b.slice(0, -3) + "ben" : b + " ret" } function Pd(a, b, c, d) { var e = Qd(a); switch (c) { case "mm": return e + " tup"; case "hh": return e + " rep"; case "dd": return e + " jaj"; case "MM": return e + " jar"; case "yy": return e + " DIS" } } function Qd(a) { var b = Math.floor(a % 1e3 / 100), c = Math.floor(a % 100 / 10), d = a % 10, e = ""; return b > 0 && (e += Sg[b] + "vatlh"), c > 0 && (e += ("" !== e ? " " : "") + Sg[c] + "maH"), d > 0 && (e += ("" !== e ? " " : "") + Sg[d]), "" === e ? "pagh" : e } function Rd(a, b, c, d) { var e = { s: ["viensas secunds", "'iensas secunds"], m: ["'n míut", "'iens míut"], mm: [a + " míuts", "" + a + " míuts"], h: ["'n þora", "'iensa þora"], hh: [a + " þoras", "" + a + " þoras"], d: ["'n ziua", "'iensa ziua"], dd: [a + " ziuas", "" + a + " ziuas"], M: ["'n mes", "'iens mes"], MM: [a + " mesen", "" + a + " mesen"], y: ["'n ar", "'iens ar"], yy: [a + " ars", "" + a + " ars"] }; return d ? e[c][0] : b ? e[c][0] : e[c][1] }
    //! moment.js locale configuration
    //! locale : ukrainian (uk)
    //! author : zemlanin : https://github.com/zemlanin
    //! Author : Menelion Elensúle : https://github.com/Oire
    function Sd(a, b) { var c = a.split("_"); return b % 10 === 1 && b % 100 !== 11 ? c[0] : b % 10 >= 2 && 4 >= b % 10 && (10 > b % 100 || b % 100 >= 20) ? c[1] : c[2] } function Td(a, b, c) { var d = { mm: b ? "хвилина_хвилини_хвилин" : "хвилину_хвилини_хвилин", hh: b ? "година_години_годин" : "годину_години_годин", dd: "день_дні_днів", MM: "місяць_місяці_місяців", yy: "рік_роки_років" }; return "m" === c ? b ? "хвилина" : "хвилину" : "h" === c ? b ? "година" : "годину" : a + " " + Sd(d[c], +a) } function Ud(a, b) { var c = { nominative: "неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"), accusative: "неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"), genitive: "неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_") }, d = /(\[[ВвУу]\]) ?dddd/.test(b) ? "accusative" : /\[?(?:минулої|наступної)? ?\] ?dddd/.test(b) ? "genitive" : "nominative"; return c[d][a.day()] } function Vd(a) { return function () { return a + "о" + (11 === this.hours() ? "б" : "") + "] LT" } } var Wd, Xd = a.momentProperties = [], Yd = !1, Zd = {}; a.suppressDeprecationWarnings = !1; var $d, _d = {}, ae = {}, be = /(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g, ce = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, de = {}, ee = {}, fe = /\d/, ge = /\d\d/, he = /\d{3}/, ie = /\d{4}/, je = /[+-]?\d{6}/, ke = /\d\d?/, le = /\d\d\d\d?/, me = /\d\d\d\d\d\d?/, ne = /\d{1,3}/, oe = /\d{1,4}/, pe = /[+-]?\d{1,6}/, qe = /\d+/, re = /[+-]?\d+/, se = /Z|[+-]\d\d:?\d\d/gi, te = /Z|[+-]\d\d(?::?\d\d)?/gi, ue = /[+-]?\d+(\.\d{1,3})?/, ve = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, we = {}, xe = {}, ye = 0, ze = 1, Ae = 2, Be = 3, Ce = 4, De = 5, Ee = 6, Fe = 7, Ge = 8; R("M", ["MM", 2], "Mo", function () { return this.month() + 1 }), R("MMM", 0, 0, function (a) { return this.localeData().monthsShort(this, a) }), R("MMMM", 0, 0, function (a) { return this.localeData().months(this, a) }), J("month", "M"), W("M", ke), W("MM", ke, ge), W("MMM", function (a, b) { return b.monthsShortRegex(a) }), W("MMMM", function (a, b) { return b.monthsRegex(a) }), $(["M", "MM"], function (a, b) { b[ze] = r(a) - 1 }), $(["MMM", "MMMM"], function (a, b, c, d) { var e = c._locale.monthsParse(a, d, c._strict); null != e ? b[ze] = e : j(c).invalidMonth = a }); var He = /D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/, Ie = "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), Je = "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), Ke = ve, Le = ve, Me = /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/, Ne = /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?/, Oe = /Z|[+-]\d\d(?::?\d\d)?/, Pe = [["YYYYYY-MM-DD", /[+-]\d{6}-\d\d-\d\d/], ["YYYY-MM-DD", /\d{4}-\d\d-\d\d/], ["GGGG-[W]WW-E", /\d{4}-W\d\d-\d/], ["GGGG-[W]WW", /\d{4}-W\d\d/, !1], ["YYYY-DDD", /\d{4}-\d{3}/], ["YYYY-MM", /\d{4}-\d\d/, !1], ["YYYYYYMMDD", /[+-]\d{10}/], ["YYYYMMDD", /\d{8}/], ["GGGG[W]WWE", /\d{4}W\d{3}/], ["GGGG[W]WW", /\d{4}W\d{2}/, !1], ["YYYYDDD", /\d{7}/]], Qe = [["HH:mm:ss.SSSS", /\d\d:\d\d:\d\d\.\d+/], ["HH:mm:ss,SSSS", /\d\d:\d\d:\d\d,\d+/], ["HH:mm:ss", /\d\d:\d\d:\d\d/], ["HH:mm", /\d\d:\d\d/], ["HHmmss.SSSS", /\d\d\d\d\d\d\.\d+/], ["HHmmss,SSSS", /\d\d\d\d\d\d,\d+/], ["HHmmss", /\d\d\d\d\d\d/], ["HHmm", /\d\d\d\d/], ["HH", /\d\d/]], Re = /^\/?Date\((\-?\d+)/i; a.createFromInputFallback = u("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.", function (a) { a._d = new Date(a._i + (a._useUTC ? " UTC" : "")) }), R("Y", 0, 0, function () { var a = this.year(); return 9999 >= a ? "" + a : "+" + a }), R(0, ["YY", 2], 0, function () { return this.year() % 100 }), R(0, ["YYYY", 4], 0, "year"), R(0, ["YYYYY", 5], 0, "year"), R(0, ["YYYYYY", 6, !0], 0, "year"), J("year", "y"), W("Y", re), W("YY", ke, ge), W("YYYY", oe, ie), W("YYYYY", pe, je), W("YYYYYY", pe, je), $(["YYYYY", "YYYYYY"], ye), $("YYYY", function (b, c) { c[ye] = 2 === b.length ? a.parseTwoDigitYear(b) : r(b) }), $("YY", function (b, c) { c[ye] = a.parseTwoDigitYear(b) }), $("Y", function (a, b) { b[ye] = parseInt(a, 10) }), a.parseTwoDigitYear = function (a) { return r(a) + (r(a) > 68 ? 1900 : 2e3) }; var Se = M("FullYear", !1); a.ISO_8601 = function () { }; var Te = u("moment().min is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548", function () { var a = Ja.apply(null, arguments); return this.isValid() && a.isValid() ? this > a ? this : a : l() }), Ue = u("moment().max is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548", function () { var a = Ja.apply(null, arguments); return this.isValid() && a.isValid() ? a > this ? this : a : l() }), Ve = function () { return Date.now ? Date.now() : +new Date }; Pa("Z", ":"), Pa("ZZ", ""), W("Z", te), W("ZZ", te), $(["Z", "ZZ"], function (a, b, c) { c._useUTC = !0, c._tzm = Qa(te, a) }); var We = /([\+\-]|\d\d)/gi; a.updateOffset = function () { }; var Xe = /^(\-)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?\d*)?$/, Ye = /^(-)?P(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)W)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?$/; cb.fn = Na.prototype; var Ze = hb(1, "add"), $e = hb(-1, "subtract"); a.defaultFormat = "YYYY-MM-DDTHH:mm:ssZ"; var _e = u("moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.", function (a) { return void 0 === a ? this.localeData() : this.locale(a) }); R(0, ["gg", 2], 0, function () { return this.weekYear() % 100 }), R(0, ["GG", 2], 0, function () { return this.isoWeekYear() % 100 }), Ob("gggg", "weekYear"), Ob("ggggg", "weekYear"), Ob("GGGG", "isoWeekYear"), Ob("GGGGG", "isoWeekYear"), J("weekYear", "gg"), J("isoWeekYear", "GG"), W("G", re), W("g", re), W("GG", ke, ge), W("gg", ke, ge), W("GGGG", oe, ie), W("gggg", oe, ie), W("GGGGG", pe, je), W("ggggg", pe, je), _(["gggg", "ggggg", "GGGG", "GGGGG"], function (a, b, c, d) { b[d.substr(0, 2)] = r(a) }), _(["gg", "GG"], function (b, c, d, e) { c[e] = a.parseTwoDigitYear(b) }), R("Q", 0, "Qo", "quarter"), J("quarter", "Q"), W("Q", fe), $("Q", function (a, b) { b[ze] = 3 * (r(a) - 1) }), R("w", ["ww", 2], "wo", "week"), R("W", ["WW", 2], "Wo", "isoWeek"), J("week", "w"), J("isoWeek", "W"), W("w", ke), W("ww", ke, ge), W("W", ke), W("WW", ke, ge), _(["w", "ww", "W", "WW"], function (a, b, c, d) { b[d.substr(0, 1)] = r(a) }); var af = { dow: 0, doy: 6 }; R("D", ["DD", 2], "Do", "date"), J("date", "D"), W("D", ke), W("DD", ke, ge), W("Do", function (a, b) { return a ? b._ordinalParse : b._ordinalParseLenient }), $(["D", "DD"], Ae), $("Do", function (a, b) { b[Ae] = r(a.match(ke)[0], 10) }); var bf = M("Date", !0); R("d", 0, "do", "day"), R("dd", 0, 0, function (a) { return this.localeData().weekdaysMin(this, a) }), R("ddd", 0, 0, function (a) { return this.localeData().weekdaysShort(this, a) }), R("dddd", 0, 0, function (a) { return this.localeData().weekdays(this, a) }), R("e", 0, 0, "weekday"), R("E", 0, 0, "isoWeekday"), J("day", "d"), J("weekday", "e"), J("isoWeekday", "E"), W("d", ke), W("e", ke), W("E", ke), W("dd", ve), W("ddd", ve), W("dddd", ve), _(["dd", "ddd", "dddd"], function (a, b, c, d) { var e = c._locale.weekdaysParse(a, d, c._strict); null != e ? b.d = e : j(c).invalidWeekday = a }), _(["d", "e", "E"], function (a, b, c, d) { b[d] = r(a) }); var cf = "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), df = "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), ef = "Su_Mo_Tu_We_Th_Fr_Sa".split("_"); R("DDD", ["DDDD", 3], "DDDo", "dayOfYear"), J("dayOfYear", "DDD"), W("DDD", ne), W("DDDD", he), $(["DDD", "DDDD"], function (a, b, c) { c._dayOfYear = r(a) }), R("H", ["HH", 2], 0, "hour"), R("h", ["hh", 2], 0, ic), R("hmm", 0, 0, function () { return "" + ic.apply(this) + Q(this.minutes(), 2) }), R("hmmss", 0, 0, function () { return "" + ic.apply(this) + Q(this.minutes(), 2) + Q(this.seconds(), 2) }), R("Hmm", 0, 0, function () { return "" + this.hours() + Q(this.minutes(), 2) }), R("Hmmss", 0, 0, function () { return "" + this.hours() + Q(this.minutes(), 2) + Q(this.seconds(), 2) }), jc("a", !0), jc("A", !1), J("hour", "h"), W("a", kc), W("A", kc), W("H", ke), W("h", ke), W("HH", ke, ge), W("hh", ke, ge), W("hmm", le), W("hmmss", me), W("Hmm", le), W("Hmmss", me), $(["H", "HH"], Be), $(["a", "A"], function (a, b, c) { c._isPm = c._locale.isPM(a), c._meridiem = a }), $(["h", "hh"], function (a, b, c) { b[Be] = r(a), j(c).bigHour = !0 }), $("hmm", function (a, b, c) { var d = a.length - 2; b[Be] = r(a.substr(0, d)), b[Ce] = r(a.substr(d)), j(c).bigHour = !0 }), $("hmmss", function (a, b, c) { var d = a.length - 4, e = a.length - 2; b[Be] = r(a.substr(0, d)), b[Ce] = r(a.substr(d, 2)), b[De] = r(a.substr(e)), j(c).bigHour = !0 }), $("Hmm", function (a, b, c) { var d = a.length - 2; b[Be] = r(a.substr(0, d)), b[Ce] = r(a.substr(d)) }), $("Hmmss", function (a, b, c) { var d = a.length - 4, e = a.length - 2; b[Be] = r(a.substr(0, d)), b[Ce] = r(a.substr(d, 2)), b[De] = r(a.substr(e)) }); var ff = /[ap]\.?m?\.?/i, gf = M("Hours", !0); R("m", ["mm", 2], 0, "minute"), J("minute", "m"), W("m", ke), W("mm", ke, ge), $(["m", "mm"], Ce); var hf = M("Minutes", !1); R("s", ["ss", 2], 0, "second"), J("second", "s"), W("s", ke), W("ss", ke, ge), $(["s", "ss"], De); var jf = M("Seconds", !1); R("S", 0, 0, function () { return ~~(this.millisecond() / 100) }), R(0, ["SS", 2], 0, function () { return ~~(this.millisecond() / 10) }), R(0, ["SSS", 3], 0, "millisecond"), R(0, ["SSSS", 4], 0, function () { return 10 * this.millisecond() }), R(0, ["SSSSS", 5], 0, function () { return 100 * this.millisecond() }), R(0, ["SSSSSS", 6], 0, function () { return 1e3 * this.millisecond() }), R(0, ["SSSSSSS", 7], 0, function () { return 1e4 * this.millisecond() }), R(0, ["SSSSSSSS", 8], 0, function () { return 1e5 * this.millisecond() }), R(0, ["SSSSSSSSS", 9], 0, function () { return 1e6 * this.millisecond() }), J("millisecond", "ms"), W("S", ne, fe), W("SS", ne, ge), W("SSS", ne, he); var kf; for (kf = "SSSS"; kf.length <= 9; kf += "S") W(kf, qe); for (kf = "S"; kf.length <= 9; kf += "S") $(kf, nc); var lf = M("Milliseconds", !1); R("z", 0, 0, "zoneAbbr"), R("zz", 0, 0, "zoneName"); var mf = o.prototype; mf.add = Ze, mf.calendar = jb, mf.clone = kb, mf.diff = rb, mf.endOf = Db, mf.format = vb, mf.from = wb, mf.fromNow = xb, mf.to = yb, mf.toNow = zb, mf.get = P, mf.invalidAt = Mb, mf.isAfter = lb, mf.isBefore = mb, mf.isBetween = nb, mf.isSame = ob, mf.isSameOrAfter = pb, mf.isSameOrBefore = qb, mf.isValid = Kb, mf.lang = _e, mf.locale = Ab, mf.localeData = Bb, mf.max = Ue, mf.min = Te, mf.parsingFlags = Lb, mf.set = P, mf.startOf = Cb, mf.subtract = $e, mf.toArray = Hb, mf.toObject = Ib, mf.toDate = Gb, mf.toISOString = ub, mf.toJSON = Jb, mf.toString = tb, mf.unix = Fb, mf.valueOf = Eb, mf.creationData = Nb, mf.year = Se, mf.isLeapYear = sa, mf.weekYear = Pb, mf.isoWeekYear = Qb, mf.quarter = mf.quarters = Vb, mf.month = ga, mf.daysInMonth = ha, mf.week = mf.weeks = Zb, mf.isoWeek = mf.isoWeeks = $b, mf.weeksInYear = Sb, mf.isoWeeksInYear = Rb, mf.date = bf, mf.day = mf.days = ec, mf.weekday = fc, mf.isoWeekday = gc, mf.dayOfYear = hc, mf.hour = mf.hours = gf, mf.minute = mf.minutes = hf, mf.second = mf.seconds = jf, mf.millisecond = mf.milliseconds = lf, mf.utcOffset = Ta, mf.utc = Va, mf.local = Wa, mf.parseZone = Xa, mf.hasAlignedHourOffset = Ya, mf.isDST = Za, mf.isDSTShifted = $a, mf.isLocal = _a, mf.isUtcOffset = ab, mf.isUtc = bb, mf.isUTC = bb, mf.zoneAbbr = oc, mf.zoneName = pc, mf.dates = u("dates accessor is deprecated. Use date instead.", bf), mf.months = u("months accessor is deprecated. Use month instead", ga), mf.years = u("years accessor is deprecated. Use year instead", Se), mf.zone = u("moment().zone is deprecated, use moment().utcOffset instead. https://github.com/moment/moment/issues/1779", Ua); var nf = mf, of = { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, pf = { LTS: "h:mm:ss A", LT: "h:mm A", L: "MM/DD/YYYY", LL: "MMMM D, YYYY", LLL: "MMMM D, YYYY h:mm A", LLLL: "dddd, MMMM D, YYYY h:mm A" }, qf = "Invalid date", rf = "%d", sf = /\d{1,2}/, tf = { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, uf = A.prototype; uf._calendar = of, uf.calendar = sc, uf._longDateFormat = pf, uf.longDateFormat = tc, uf._invalidDate = qf, uf.invalidDate = uc, uf._ordinal = rf, uf.ordinal = vc, uf._ordinalParse = sf, uf.preparse = wc, uf.postformat = wc, uf._relativeTime = tf, uf.relativeTime = xc, uf.pastFuture = yc, uf.set = y, uf.months = ca, uf._months = Ie, uf.monthsShort = da, uf._monthsShort = Je, uf.monthsParse = ea, uf._monthsRegex = Le, uf.monthsRegex = ja, uf._monthsShortRegex = Ke, uf.monthsShortRegex = ia, uf.week = Wb, uf._week = af, uf.firstDayOfYear = Yb, uf.firstDayOfWeek = Xb, uf.weekdays = ac, uf._weekdays = cf, uf.weekdaysMin = cc, uf._weekdaysMin = ef, uf.weekdaysShort = bc, uf._weekdaysShort = df, uf.weekdaysParse = dc, uf.isPM = lc, uf._meridiemParse = ff, uf.meridiem = mc, E("en", { ordinalParse: /\d{1,2}(th|st|nd|rd)/, ordinal: function (a) { var b = a % 10, c = 1 === r(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c } }), a.lang = u("moment.lang is deprecated. Use moment.locale instead.", E), a.langData = u("moment.langData is deprecated. Use moment.localeData instead.", H); var vf = Math.abs, wf = Qc("ms"), xf = Qc("s"), yf = Qc("m"), zf = Qc("h"), Af = Qc("d"), Bf = Qc("w"), Cf = Qc("M"), Df = Qc("y"), Ef = Sc("milliseconds"), Ff = Sc("seconds"), Gf = Sc("minutes"), Hf = Sc("hours"), If = Sc("days"), Jf = Sc("months"), Kf = Sc("years"), Lf = Math.round, Mf = { s: 45, m: 45, h: 22, d: 26, M: 11 }, Nf = Math.abs, Of = Na.prototype; Of.abs = Gc, Of.add = Ic, Of.subtract = Jc, Of.as = Oc, Of.asMilliseconds = wf, Of.asSeconds = xf, Of.asMinutes = yf, Of.asHours = zf, Of.asDays = Af, Of.asWeeks = Bf, Of.asMonths = Cf, Of.asYears = Df, Of.valueOf = Pc, Of._bubble = Lc, Of.get = Rc, Of.milliseconds = Ef, Of.seconds = Ff, Of.minutes = Gf, Of.hours = Hf, Of.days = If, Of.weeks = Tc, Of.months = Jf, Of.years = Kf, Of.humanize = Xc, Of.toISOString = Yc, Of.toString = Yc, Of.toJSON = Yc, Of.locale = Ab, Of.localeData = Bb, Of.toIsoString = u("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)", Yc), Of.lang = _e, R("X", 0, 0, "unix"), R("x", 0, 0, "valueOf"), W("x", re), W("X", ue), $("X", function (a, b, c) { c._d = new Date(1e3 * parseFloat(a, 10)) }), $("x", function (a, b, c) { c._d = new Date(r(a)) }),
    //! moment.js
    //! version : 2.12.0
    //! authors : Tim Wood, Iskren Chernev, Moment.js contributors
    //! license : MIT
    //! momentjs.com
    a.version = "2.12.0", b(Ja), a.fn = nf, a.min = La, a.max = Ma, a.now = Ve, a.utc = h, a.unix = qc, a.months = Bc, a.isDate = d, a.locale = E, a.invalid = l, a.duration = cb, a.isMoment = p, a.weekdays = Dc, a.parseZone = rc, a.localeData = H, a.isDuration = Oa, a.monthsShort = Cc, a.weekdaysMin = Fc, a.defineLocale = F, a.updateLocale = G, a.locales = I, a.weekdaysShort = Ec, a.normalizeUnits = K, a.relativeTimeThreshold = Wc, a.prototype = nf; var Pf = a, Qf = (Pf.defineLocale("af", { months: "Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"), monthsShort: "Jan_Feb_Mar_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"), weekdays: "Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"), weekdaysShort: "Son_Maa_Din_Woe_Don_Vry_Sat".split("_"), weekdaysMin: "So_Ma_Di_Wo_Do_Vr_Sa".split("_"), meridiemParse: /vm|nm/i, isPM: function (a) { return /^nm$/i.test(a) }, meridiem: function (a, b, c) { return 12 > a ? c ? "vm" : "VM" : c ? "nm" : "NM" }, longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Vandag om] LT", nextDay: "[Môre om] LT", nextWeek: "dddd [om] LT", lastDay: "[Gister om] LT", lastWeek: "[Laas] dddd [om] LT", sameElse: "L" }, relativeTime: { future: "oor %s", past: "%s gelede", s: "'n paar sekondes", m: "'n minuut", mm: "%d minute", h: "'n uur", hh: "%d ure", d: "'n dag", dd: "%d dae", M: "'n maand", MM: "%d maande", y: "'n jaar", yy: "%d jaar" }, ordinalParse: /\d{1,2}(ste|de)/, ordinal: function (a) { return a + (1 === a || 8 === a || a >= 20 ? "ste" : "de") }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("ar-ma", { months: "يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"), monthsShort: "يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"), weekdays: "الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"), weekdaysShort: "احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"), weekdaysMin: "ح_ن_ث_ر_خ_ج_س".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[اليوم على الساعة] LT", nextDay: "[غدا على الساعة] LT", nextWeek: "dddd [على الساعة] LT", lastDay: "[أمس على الساعة] LT", lastWeek: "dddd [على الساعة] LT", sameElse: "L" }, relativeTime: { future: "في %s", past: "منذ %s", s: "ثوان", m: "دقيقة", mm: "%d دقائق", h: "ساعة", hh: "%d ساعات", d: "يوم", dd: "%d أيام", M: "شهر", MM: "%d أشهر", y: "سنة", yy: "%d سنوات" }, week: { dow: 6, doy: 12 } }), { 1: "١", 2: "٢", 3: "٣", 4: "٤", 5: "٥", 6: "٦", 7: "٧", 8: "٨", 9: "٩", 0: "٠" }), Rf = { "١": "1", "٢": "2", "٣": "3", "٤": "4", "٥": "5", "٦": "6", "٧": "7", "٨": "8", "٩": "9", "٠": "0" }, Sf = (Pf.defineLocale("ar-sa", { months: "يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"), monthsShort: "يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"), weekdays: "الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"), weekdaysShort: "أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"), weekdaysMin: "ح_ن_ث_ر_خ_ج_س".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, meridiemParse: /ص|م/, isPM: function (a) { return "م" === a }, meridiem: function (a, b, c) { return 12 > a ? "ص" : "م" }, calendar: { sameDay: "[اليوم على الساعة] LT", nextDay: "[غدا على الساعة] LT", nextWeek: "dddd [على الساعة] LT", lastDay: "[أمس على الساعة] LT", lastWeek: "dddd [على الساعة] LT", sameElse: "L" }, relativeTime: { future: "في %s", past: "منذ %s", s: "ثوان", m: "دقيقة", mm: "%d دقائق", h: "ساعة", hh: "%d ساعات", d: "يوم", dd: "%d أيام", M: "شهر", MM: "%d أشهر", y: "سنة", yy: "%d سنوات" }, preparse: function (a) { return a.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (a) { return Rf[a] }).replace(/،/g, ",") }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Qf[a] }).replace(/,/g, "،") }, week: { dow: 6, doy: 12 } }), Pf.defineLocale("ar-tn", { months: "جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"), monthsShort: "جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"), weekdays: "الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"), weekdaysShort: "أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"), weekdaysMin: "ح_ن_ث_ر_خ_ج_س".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[اليوم على الساعة] LT", nextDay: "[غدا على الساعة] LT", nextWeek: "dddd [على الساعة] LT", lastDay: "[أمس على الساعة] LT", lastWeek: "dddd [على الساعة] LT", sameElse: "L" }, relativeTime: { future: "في %s", past: "منذ %s", s: "ثوان", m: "دقيقة", mm: "%d دقائق", h: "ساعة", hh: "%d ساعات", d: "يوم", dd: "%d أيام", M: "شهر", MM: "%d أشهر", y: "سنة", yy: "%d سنوات" }, week: { dow: 1, doy: 4 } }), { 1: "١", 2: "٢", 3: "٣", 4: "٤", 5: "٥", 6: "٦", 7: "٧", 8: "٨", 9: "٩", 0: "٠" }), Tf = { "١": "1", "٢": "2", "٣": "3", "٤": "4", "٥": "5", "٦": "6", "٧": "7", "٨": "8", "٩": "9", "٠": "0" }, Uf = function (a) { return 0 === a ? 0 : 1 === a ? 1 : 2 === a ? 2 : a % 100 >= 3 && 10 >= a % 100 ? 3 : a % 100 >= 11 ? 4 : 5 }, Vf = { s: ["أقل من ثانية", "ثانية واحدة", ["ثانيتان", "ثانيتين"], "%d ثوان", "%d ثانية", "%d ثانية"], m: ["أقل من دقيقة", "دقيقة واحدة", ["دقيقتان", "دقيقتين"], "%d دقائق", "%d دقيقة", "%d دقيقة"], h: ["أقل من ساعة", "ساعة واحدة", ["ساعتان", "ساعتين"], "%d ساعات", "%d ساعة", "%d ساعة"], d: ["أقل من يوم", "يوم واحد", ["يومان", "يومين"], "%d أيام", "%d يومًا", "%d يوم"], M: ["أقل من شهر", "شهر واحد", ["شهران", "شهرين"], "%d أشهر", "%d شهرا", "%d شهر"], y: ["أقل من عام", "عام واحد", ["عامان", "عامين"], "%d أعوام", "%d عامًا", "%d عام"] }, Wf = function (a) { return function (b, c, d, e) { var f = Uf(b), g = Vf[a][Uf(b)]; return 2 === f && (g = g[c ? 0 : 1]), g.replace(/%d/i, b) } }, Xf = ["كانون الثاني يناير", "شباط فبراير", "آذار مارس", "نيسان أبريل", "أيار مايو", "حزيران يونيو", "تموز يوليو", "آب أغسطس", "أيلول سبتمبر", "تشرين الأول أكتوبر", "تشرين الثاني نوفمبر", "كانون الأول ديسمبر"], Yf = (Pf.defineLocale("ar", { months: Xf, monthsShort: Xf, weekdays: "الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"), weekdaysShort: "أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"), weekdaysMin: "ح_ن_ث_ر_خ_ج_س".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "D/‏M/‏YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, meridiemParse: /ص|م/, isPM: function (a) { return "م" === a }, meridiem: function (a, b, c) { return 12 > a ? "ص" : "م" }, calendar: { sameDay: "[اليوم عند الساعة] LT", nextDay: "[غدًا عند الساعة] LT", nextWeek: "dddd [عند الساعة] LT", lastDay: "[أمس عند الساعة] LT", lastWeek: "dddd [عند الساعة] LT", sameElse: "L" }, relativeTime: { future: "بعد %s", past: "منذ %s", s: Wf("s"), m: Wf("m"), mm: Wf("m"), h: Wf("h"), hh: Wf("h"), d: Wf("d"), dd: Wf("d"), M: Wf("M"), MM: Wf("M"), y: Wf("y"), yy: Wf("y") }, preparse: function (a) { return a.replace(/\u200f/g, "").replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (a) { return Tf[a] }).replace(/،/g, ",") }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Sf[a] }).replace(/,/g, "،") }, week: { dow: 6, doy: 12 } }), { 1: "-inci", 5: "-inci", 8: "-inci", 70: "-inci", 80: "-inci", 2: "-nci", 7: "-nci", 20: "-nci", 50: "-nci", 3: "-üncü", 4: "-üncü", 100: "-üncü", 6: "-ncı", 9: "-uncu", 10: "-uncu", 30: "-uncu", 60: "-ıncı", 90: "-ıncı" }), Zf = (Pf.defineLocale("az", { months: "yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"), monthsShort: "yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"), weekdays: "Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"), weekdaysShort: "Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"), weekdaysMin: "Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[bugün saat] LT", nextDay: "[sabah saat] LT", nextWeek: "[gələn həftə] dddd [saat] LT", lastDay: "[dünən] LT", lastWeek: "[keçən həftə] dddd [saat] LT", sameElse: "L" }, relativeTime: { future: "%s sonra", past: "%s əvvəl", s: "birneçə saniyyə", m: "bir dəqiqə", mm: "%d dəqiqə", h: "bir saat", hh: "%d saat", d: "bir gün", dd: "%d gün", M: "bir ay", MM: "%d ay", y: "bir il", yy: "%d il" }, meridiemParse: /gecə|səhər|gündüz|axşam/, isPM: function (a) { return /^(gündüz|axşam)$/.test(a) }, meridiem: function (a, b, c) { return 4 > a ? "gecə" : 12 > a ? "səhər" : 17 > a ? "gündüz" : "axşam" }, ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/, ordinal: function (a) { if (0 === a) return a + "-ıncı"; var b = a % 10, c = a % 100 - b, d = a >= 100 ? 100 : null; return a + (Yf[b] || Yf[c] || Yf[d]) }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("be", { months: { format: "студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"), standalone: "студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_") }, monthsShort: "студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"), weekdays: { format: "нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"), standalone: "нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"), isFormat: /\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/ }, weekdaysShort: "нд_пн_ат_ср_чц_пт_сб".split("_"), weekdaysMin: "нд_пн_ат_ср_чц_пт_сб".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY г.", LLL: "D MMMM YYYY г., HH:mm", LLLL: "dddd, D MMMM YYYY г., HH:mm" }, calendar: { sameDay: "[Сёння ў] LT", nextDay: "[Заўтра ў] LT", lastDay: "[Учора ў] LT", nextWeek: function () { return "[У] dddd [ў] LT" }, lastWeek: function () { switch (this.day()) { case 0: case 3: case 5: case 6: return "[У мінулую] dddd [ў] LT"; case 1: case 2: case 4: return "[У мінулы] dddd [ў] LT" } }, sameElse: "L" }, relativeTime: { future: "праз %s", past: "%s таму", s: "некалькі секунд", m: $c, mm: $c, h: $c, hh: $c, d: "дзень", dd: $c, M: "месяц", MM: $c, y: "год", yy: $c }, meridiemParse: /ночы|раніцы|дня|вечара/, isPM: function (a) { return /^(дня|вечара)$/.test(a) }, meridiem: function (a, b, c) { return 4 > a ? "ночы" : 12 > a ? "раніцы" : 17 > a ? "дня" : "вечара" }, ordinalParse: /\d{1,2}-(і|ы|га)/, ordinal: function (a, b) { switch (b) { case "M": case "d": case "DDD": case "w": case "W": return a % 10 !== 2 && a % 10 !== 3 || a % 100 === 12 || a % 100 === 13 ? a + "-ы" : a + "-і"; case "D": return a + "-га"; default: return a } }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("bg", { months: "януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"), monthsShort: "янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"), weekdays: "неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"), weekdaysShort: "нед_пон_вто_сря_чет_пет_съб".split("_"), weekdaysMin: "нд_пн_вт_ср_чт_пт_сб".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "D.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY H:mm", LLLL: "dddd, D MMMM YYYY H:mm" }, calendar: { sameDay: "[Днес в] LT", nextDay: "[Утре в] LT", nextWeek: "dddd [в] LT", lastDay: "[Вчера в] LT", lastWeek: function () { switch (this.day()) { case 0: case 3: case 6: return "[В изминалата] dddd [в] LT"; case 1: case 2: case 4: case 5: return "[В изминалия] dddd [в] LT" } }, sameElse: "L" }, relativeTime: { future: "след %s", past: "преди %s", s: "няколко секунди", m: "минута", mm: "%d минути", h: "час", hh: "%d часа", d: "ден", dd: "%d дни", M: "месец", MM: "%d месеца", y: "година", yy: "%d години" }, ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, ordinal: function (a) { var b = a % 10, c = a % 100; return 0 === a ? a + "-ев" : 0 === c ? a + "-ен" : c > 10 && 20 > c ? a + "-ти" : 1 === b ? a + "-ви" : 2 === b ? a + "-ри" : 7 === b || 8 === b ? a + "-ми" : a + "-ти" }, week: { dow: 1, doy: 7 } }), { 1: "১", 2: "২", 3: "৩", 4: "৪", 5: "৫", 6: "৬", 7: "৭", 8: "৮", 9: "৯", 0: "০" }), $f = { "১": "1", "২": "2", "৩": "3", "৪": "4", "৫": "5", "৬": "6", "৭": "7", "৮": "8", "৯": "9", "০": "0" }, _f = (Pf.defineLocale("bn", { months: "জানুয়ারী_ফেবুয়ারী_মার্চ_এপ্রিল_মে_জুন_জুলাই_অগাস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"), monthsShort: "জানু_ফেব_মার্চ_এপর_মে_জুন_জুল_অগ_সেপ্ট_অক্টো_নভ_ডিসেম্".split("_"), weekdays: "রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পত্তিবার_শুক্রবার_শনিবার".split("_"), weekdaysShort: "রবি_সোম_মঙ্গল_বুধ_বৃহস্পত্তি_শুক্র_শনি".split("_"), weekdaysMin: "রব_সম_মঙ্গ_বু_ব্রিহ_শু_শনি".split("_"), longDateFormat: { LT: "A h:mm সময়", LTS: "A h:mm:ss সময়", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm সময়", LLLL: "dddd, D MMMM YYYY, A h:mm সময়" }, calendar: { sameDay: "[আজ] LT", nextDay: "[আগামীকাল] LT", nextWeek: "dddd, LT", lastDay: "[গতকাল] LT", lastWeek: "[গত] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s পরে", past: "%s আগে", s: "কয়েক সেকেন্ড", m: "এক মিনিট", mm: "%d মিনিট", h: "এক ঘন্টা", hh: "%d ঘন্টা", d: "এক দিন", dd: "%d দিন", M: "এক মাস", MM: "%d মাস", y: "এক বছর", yy: "%d বছর" }, preparse: function (a) { return a.replace(/[১২৩৪৫৬৭৮৯০]/g, function (a) { return $f[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Zf[a] }) }, meridiemParse: /রাত|সকাল|দুপুর|বিকাল|রাত/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "রাত" === b && a >= 4 || "দুপুর" === b && 5 > a || "বিকাল" === b ? a + 12 : a }, meridiem: function (a, b, c) { return 4 > a ? "রাত" : 10 > a ? "সকাল" : 17 > a ? "দুপুর" : 20 > a ? "বিকাল" : "রাত" }, week: { dow: 0, doy: 6 } }), { 1: "༡", 2: "༢", 3: "༣", 4: "༤", 5: "༥", 6: "༦", 7: "༧", 8: "༨", 9: "༩", 0: "༠" }), ag = { "༡": "1", "༢": "2", "༣": "3", "༤": "4", "༥": "5", "༦": "6", "༧": "7", "༨": "8", "༩": "9", "༠": "0" }, bg = (Pf.defineLocale("bo", { months: "ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"), monthsShort: "ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"), weekdays: "གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"), weekdaysShort: "ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"), weekdaysMin: "ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"), longDateFormat: { LT: "A h:mm", LTS: "A h:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm", LLLL: "dddd, D MMMM YYYY, A h:mm" }, calendar: { sameDay: "[དི་རིང] LT", nextDay: "[སང་ཉིན] LT", nextWeek: "[བདུན་ཕྲག་རྗེས་མ], LT", lastDay: "[ཁ་སང] LT", lastWeek: "[བདུན་ཕྲག་མཐའ་མ] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s ལ་", past: "%s སྔན་ལ", s: "ལམ་སང", m: "སྐར་མ་གཅིག", mm: "%d སྐར་མ", h: "ཆུ་ཚོད་གཅིག", hh: "%d ཆུ་ཚོད", d: "ཉིན་གཅིག", dd: "%d ཉིན་", M: "ཟླ་བ་གཅིག", MM: "%d ཟླ་བ", y: "ལོ་གཅིག", yy: "%d ལོ" }, preparse: function (a) { return a.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (a) { return ag[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return _f[a] }) }, meridiemParse: /མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "མཚན་མོ" === b && a >= 4 || "ཉིན་གུང" === b && 5 > a || "དགོང་དག" === b ? a + 12 : a }, meridiem: function (a, b, c) { return 4 > a ? "མཚན་མོ" : 10 > a ? "ཞོགས་ཀས" : 17 > a ? "ཉིན་གུང" : 20 > a ? "དགོང་དག" : "མཚན་མོ" }, week: { dow: 0, doy: 6 } }), Pf.defineLocale("br", { months: "Genver_C'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"), monthsShort: "Gen_C'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"), weekdays: "Sul_Lun_Meurzh_Merc'her_Yaou_Gwener_Sadorn".split("_"), weekdaysShort: "Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"), weekdaysMin: "Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"), longDateFormat: { LT: "h[e]mm A", LTS: "h[e]mm:ss A", L: "DD/MM/YYYY", LL: "D [a viz] MMMM YYYY", LLL: "D [a viz] MMMM YYYY h[e]mm A", LLLL: "dddd, D [a viz] MMMM YYYY h[e]mm A" }, calendar: { sameDay: "[Hiziv da] LT", nextDay: "[Warc'hoazh da] LT", nextWeek: "dddd [da] LT", lastDay: "[Dec'h da] LT", lastWeek: "dddd [paset da] LT", sameElse: "L" }, relativeTime: { future: "a-benn %s", past: "%s 'zo", s: "un nebeud segondennoù", m: "ur vunutenn", mm: _c, h: "un eur", hh: "%d eur", d: "un devezh", dd: _c, M: "ur miz", MM: _c, y: "ur bloaz", yy: ad }, ordinalParse: /\d{1,2}(añ|vet)/, ordinal: function (a) { var b = 1 === a ? "añ" : "vet"; return a + b }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("bs", { months: "januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"), monthsShort: "jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"), weekdays: "nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"), weekdaysShort: "ned._pon._uto._sri._čet._pet._sub.".split("_"), weekdaysMin: "ne_po_ut_sr_če_pe_su".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[danas u] LT", nextDay: "[sutra u] LT", nextWeek: function () { switch (this.day()) { case 0: return "[u] [nedjelju] [u] LT"; case 3: return "[u] [srijedu] [u] LT"; case 6: return "[u] [subotu] [u] LT"; case 1: case 2: case 4: case 5: return "[u] dddd [u] LT" } }, lastDay: "[jučer u] LT", lastWeek: function () { switch (this.day()) { case 0: case 3: return "[prošlu] dddd [u] LT"; case 6: return "[prošle] [subote] [u] LT"; case 1: case 2: case 4: case 5: return "[prošli] dddd [u] LT" } }, sameElse: "L" }, relativeTime: { future: "za %s", past: "prije %s", s: "par sekundi", m: ed, mm: ed, h: ed, hh: ed, d: "dan", dd: ed, M: "mjesec", MM: ed, y: "godinu", yy: ed }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), Pf.defineLocale("ca", { months: "gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"), monthsShort: "gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.".split("_"), weekdays: "diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"), weekdaysShort: "dg._dl._dt._dc._dj._dv._ds.".split("_"), weekdaysMin: "Dg_Dl_Dt_Dc_Dj_Dv_Ds".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY H:mm", LLLL: "dddd D MMMM YYYY H:mm" }, calendar: { sameDay: function () { return "[avui a " + (1 !== this.hours() ? "les" : "la") + "] LT" }, nextDay: function () { return "[demà a " + (1 !== this.hours() ? "les" : "la") + "] LT" }, nextWeek: function () { return "dddd [a " + (1 !== this.hours() ? "les" : "la") + "] LT" }, lastDay: function () { return "[ahir a " + (1 !== this.hours() ? "les" : "la") + "] LT" }, lastWeek: function () { return "[el] dddd [passat a " + (1 !== this.hours() ? "les" : "la") + "] LT" }, sameElse: "L" }, relativeTime: { future: "en %s", past: "fa %s", s: "uns segons", m: "un minut", mm: "%d minuts", h: "una hora", hh: "%d hores", d: "un dia", dd: "%d dies", M: "un mes", MM: "%d mesos", y: "un any", yy: "%d anys" }, ordinalParse: /\d{1,2}(r|n|t|è|a)/, ordinal: function (a, b) { var c = 1 === a ? "r" : 2 === a ? "n" : 3 === a ? "r" : 4 === a ? "t" : "è"; return ("w" === b || "W" === b) && (c = "a"), a + c }, week: { dow: 1, doy: 4 } }), "leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_")), cg = "led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_"), dg = (Pf.defineLocale("cs", { months: bg, monthsShort: cg, monthsParse: function (a, b) { var c, d = []; for (c = 0; 12 > c; c++) d[c] = new RegExp("^" + a[c] + "$|^" + b[c] + "$", "i"); return d }(bg, cg), shortMonthsParse: function (a) { var b, c = []; for (b = 0; 12 > b; b++) c[b] = new RegExp("^" + a[b] + "$", "i"); return c }(cg), longMonthsParse: function (a) { var b, c = []; for (b = 0; 12 > b; b++) c[b] = new RegExp("^" + a[b] + "$", "i"); return c }(bg), weekdays: "neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"), weekdaysShort: "ne_po_út_st_čt_pá_so".split("_"), weekdaysMin: "ne_po_út_st_čt_pá_so".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd D. MMMM YYYY H:mm" }, calendar: { sameDay: "[dnes v] LT", nextDay: "[zítra v] LT", nextWeek: function () { switch (this.day()) { case 0: return "[v neděli v] LT"; case 1: case 2: return "[v] dddd [v] LT"; case 3: return "[ve středu v] LT"; case 4: return "[ve čtvrtek v] LT"; case 5: return "[v pátek v] LT"; case 6: return "[v sobotu v] LT" } }, lastDay: "[včera v] LT", lastWeek: function () { switch (this.day()) { case 0: return "[minulou neděli v] LT"; case 1: case 2: return "[minulé] dddd [v] LT"; case 3: return "[minulou středu v] LT"; case 4: case 5: return "[minulý] dddd [v] LT"; case 6: return "[minulou sobotu v] LT" } }, sameElse: "L" }, relativeTime: { future: "za %s", past: "před %s", s: gd, m: gd, mm: gd, h: gd, hh: gd, d: gd, dd: gd, M: gd, MM: gd, y: gd, yy: gd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("cv", { months: "кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"), monthsShort: "кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"), weekdays: "вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"), weekdaysShort: "выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"), weekdaysMin: "вр_тн_ыт_юн_кҫ_эр_шм".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD-MM-YYYY", LL: "YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]", LLL: "YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm", LLLL: "dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm" }, calendar: { sameDay: "[Паян] LT [сехетре]", nextDay: "[Ыран] LT [сехетре]", lastDay: "[Ӗнер] LT [сехетре]", nextWeek: "[Ҫитес] dddd LT [сехетре]", lastWeek: "[Иртнӗ] dddd LT [сехетре]", sameElse: "L" }, relativeTime: { future: function (a) { var b = /сехет$/i.exec(a) ? "рен" : /ҫул$/i.exec(a) ? "тан" : "ран"; return a + b }, past: "%s каялла", s: "пӗр-ик ҫеккунт", m: "пӗр минут", mm: "%d минут", h: "пӗр сехет", hh: "%d сехет", d: "пӗр кун", dd: "%d кун", M: "пӗр уйӑх", MM: "%d уйӑх", y: "пӗр ҫул", yy: "%d ҫул" }, ordinalParse: /\d{1,2}-мӗш/, ordinal: "%d-мӗш", week: { dow: 1, doy: 7 } }), Pf.defineLocale("cy", { months: "Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"), monthsShort: "Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"), weekdays: "Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"), weekdaysShort: "Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"), weekdaysMin: "Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Heddiw am] LT", nextDay: "[Yfory am] LT", nextWeek: "dddd [am] LT", lastDay: "[Ddoe am] LT", lastWeek: "dddd [diwethaf am] LT", sameElse: "L" }, relativeTime: { future: "mewn %s", past: "%s yn ôl", s: "ychydig eiliadau", m: "munud", mm: "%d munud", h: "awr", hh: "%d awr", d: "diwrnod", dd: "%d diwrnod", M: "mis", MM: "%d mis", y: "blwyddyn", yy: "%d flynedd" }, ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/, ordinal: function (a) { var b = a, c = "", d = ["", "af", "il", "ydd", "ydd", "ed", "ed", "ed", "fed", "fed", "fed", "eg", "fed", "eg", "eg", "fed", "eg", "eg", "fed", "eg", "fed"]; return b > 20 ? c = 40 === b || 50 === b || 60 === b || 80 === b || 100 === b ? "fed" : "ain" : b > 0 && (c = d[b]), a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("da", { months: "januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"), monthsShort: "jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"), weekdays: "søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"), weekdaysShort: "søn_man_tir_ons_tor_fre_lør".split("_"), weekdaysMin: "sø_ma_ti_on_to_fr_lø".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY HH:mm", LLLL: "dddd [d.] D. MMMM YYYY HH:mm" }, calendar: { sameDay: "[I dag kl.] LT", nextDay: "[I morgen kl.] LT", nextWeek: "dddd [kl.] LT", lastDay: "[I går kl.] LT", lastWeek: "[sidste] dddd [kl] LT", sameElse: "L" }, relativeTime: { future: "om %s", past: "%s siden", s: "få sekunder", m: "et minut", mm: "%d minutter", h: "en time", hh: "%d timer", d: "en dag", dd: "%d dage", M: "en måned", MM: "%d måneder", y: "et år", yy: "%d år" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("de-at", { months: "Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"), monthsShort: "Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"), weekdays: "Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"), weekdaysShort: "So._Mo._Di._Mi._Do._Fr._Sa.".split("_"), weekdaysMin: "So_Mo_Di_Mi_Do_Fr_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY HH:mm", LLLL: "dddd, D. MMMM YYYY HH:mm" }, calendar: { sameDay: "[heute um] LT [Uhr]", sameElse: "L", nextDay: "[morgen um] LT [Uhr]", nextWeek: "dddd [um] LT [Uhr]", lastDay: "[gestern um] LT [Uhr]", lastWeek: "[letzten] dddd [um] LT [Uhr]" }, relativeTime: { future: "in %s", past: "vor %s", s: "ein paar Sekunden", m: hd, mm: "%d Minuten", h: hd, hh: "%d Stunden", d: hd, dd: hd, M: hd, MM: hd, y: hd, yy: hd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("de", { months: "Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"), monthsShort: "Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"), weekdays: "Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"), weekdaysShort: "So._Mo._Di._Mi._Do._Fr._Sa.".split("_"), weekdaysMin: "So_Mo_Di_Mi_Do_Fr_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY HH:mm", LLLL: "dddd, D. MMMM YYYY HH:mm" }, calendar: { sameDay: "[heute um] LT [Uhr]", sameElse: "L", nextDay: "[morgen um] LT [Uhr]", nextWeek: "dddd [um] LT [Uhr]", lastDay: "[gestern um] LT [Uhr]", lastWeek: "[letzten] dddd [um] LT [Uhr]" }, relativeTime: { future: "in %s", past: "vor %s", s: "ein paar Sekunden", m: id, mm: "%d Minuten", h: id, hh: "%d Stunden", d: id, dd: id, M: id, MM: id, y: id, yy: id }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), ["ޖެނުއަރީ", "ފެބްރުއަރީ", "މާރިޗު", "އޭޕްރީލު", "މޭ", "ޖޫން", "ޖުލައި", "އޯގަސްޓު", "ސެޕްޓެމްބަރު", "އޮކްޓޯބަރު", "ނޮވެމްބަރު", "ޑިސެމްބަރު"]), eg = ["އާދިއްތަ", "ހޯމަ", "އަންގާރަ", "ބުދަ", "ބުރާސްފަތި", "ހުކުރު", "ހޮނިހިރު"], fg = (Pf.defineLocale("dv", { months: dg, monthsShort: dg, weekdays: eg, weekdaysShort: eg, weekdaysMin: "އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "D/M/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, meridiemParse: /މކ|މފ/, isPM: function (a) { return "މފ" === a }, meridiem: function (a, b, c) { return 12 > a ? "މކ" : "މފ" }, calendar: { sameDay: "[މިއަދު] LT", nextDay: "[މާދަމާ] LT", nextWeek: "dddd LT", lastDay: "[އިއްޔެ] LT", lastWeek: "[ފާއިތުވި] dddd LT", sameElse: "L" }, relativeTime: { future: "ތެރޭގައި %s", past: "ކުރިން %s", s: "ސިކުންތުކޮޅެއް", m: "މިނިޓެއް", mm: "މިނިޓު %d", h: "ގަޑިއިރެއް", hh: "ގަޑިއިރު %d", d: "ދުވަހެއް", dd: "ދުވަސް %d", M: "މަހެއް", MM: "މަސް %d", y: "އަހަރެއް", yy: "އަހަރު %d" }, preparse: function (a) { return a.replace(/،/g, ",") }, postformat: function (a) { return a.replace(/,/g, "،") }, week: { dow: 7, doy: 12 } }), Pf.defineLocale("el", { monthsNominativeEl: "Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"), monthsGenitiveEl: "Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"), months: function (a, b) { return /D/.test(b.substring(0, b.indexOf("MMMM"))) ? this._monthsGenitiveEl[a.month()] : this._monthsNominativeEl[a.month()] }, monthsShort: "Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"), weekdays: "Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"), weekdaysShort: "Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"), weekdaysMin: "Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"), meridiem: function (a, b, c) { return a > 11 ? c ? "μμ" : "ΜΜ" : c ? "πμ" : "ΠΜ" }, isPM: function (a) { return "μ" === (a + "").toLowerCase()[0] }, meridiemParse: /[ΠΜ]\.?Μ?\.?/i, longDateFormat: { LT: "h:mm A", LTS: "h:mm:ss A", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY h:mm A", LLLL: "dddd, D MMMM YYYY h:mm A" }, calendarEl: { sameDay: "[Σήμερα {}] LT", nextDay: "[Αύριο {}] LT", nextWeek: "dddd [{}] LT", lastDay: "[Χθες {}] LT", lastWeek: function () { switch (this.day()) { case 6: return "[το προηγούμενο] dddd [{}] LT"; default: return "[την προηγούμενη] dddd [{}] LT" } }, sameElse: "L" }, calendar: function (a, b) { var c = this._calendarEl[a], d = b && b.hours(); return w(c) && (c = c.apply(b)), c.replace("{}", d % 12 === 1 ? "στη" : "στις") }, relativeTime: { future: "σε %s", past: "%s πριν", s: "λίγα δευτερόλεπτα", m: "ένα λεπτό", mm: "%d λεπτά", h: "μία ώρα", hh: "%d ώρες", d: "μία μέρα", dd: "%d μέρες", M: "ένας μήνας", MM: "%d μήνες", y: "ένας χρόνος", yy: "%d χρόνια" }, ordinalParse: /\d{1,2}η/, ordinal: "%dη", week: { dow: 1, doy: 4 } }), Pf.defineLocale("en-au", { months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), longDateFormat: { LT: "h:mm A", LTS: "h:mm:ss A", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY h:mm A", LLLL: "dddd, D MMMM YYYY h:mm A" }, calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, ordinalParse: /\d{1,2}(st|nd|rd|th)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("en-ca", { months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), longDateFormat: { LT: "h:mm A", LTS: "h:mm:ss A", L: "YYYY-MM-DD", LL: "MMMM D, YYYY", LLL: "MMMM D, YYYY h:mm A", LLLL: "dddd, MMMM D, YYYY h:mm A" }, calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, ordinalParse: /\d{1,2}(st|nd|rd|th)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c } }), Pf.defineLocale("en-gb", { months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, ordinalParse: /\d{1,2}(st|nd|rd|th)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("en-ie", { months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD-MM-YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, ordinalParse: /\d{1,2}(st|nd|rd|th)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("en-nz", { months: "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), monthsShort: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), weekdays: "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), weekdaysShort: "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), weekdaysMin: "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), longDateFormat: { LT: "h:mm A", LTS: "h:mm:ss A", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY h:mm A", LLLL: "dddd, D MMMM YYYY h:mm A" }, calendar: { sameDay: "[Today at] LT", nextDay: "[Tomorrow at] LT", nextWeek: "dddd [at] LT", lastDay: "[Yesterday at] LT", lastWeek: "[Last] dddd [at] LT", sameElse: "L" }, relativeTime: { future: "in %s", past: "%s ago", s: "a few seconds", m: "a minute", mm: "%d minutes", h: "an hour", hh: "%d hours", d: "a day", dd: "%d days", M: "a month", MM: "%d months", y: "a year", yy: "%d years" }, ordinalParse: /\d{1,2}(st|nd|rd|th)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "th" : 1 === b ? "st" : 2 === b ? "nd" : 3 === b ? "rd" : "th"; return a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("eo", {
        months: "januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),
        monthsShort: "jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec".split("_"), weekdays: "Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato".split("_"), weekdaysShort: "Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab".split("_"), weekdaysMin: "Di_Lu_Ma_Me_Ĵa_Ve_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY-MM-DD", LL: "D[-an de] MMMM, YYYY", LLL: "D[-an de] MMMM, YYYY HH:mm", LLLL: "dddd, [la] D[-an de] MMMM, YYYY HH:mm" }, meridiemParse: /[ap]\.t\.m/i, isPM: function (a) { return "p" === a.charAt(0).toLowerCase() }, meridiem: function (a, b, c) { return a > 11 ? c ? "p.t.m." : "P.T.M." : c ? "a.t.m." : "A.T.M." }, calendar: { sameDay: "[Hodiaŭ je] LT", nextDay: "[Morgaŭ je] LT", nextWeek: "dddd [je] LT", lastDay: "[Hieraŭ je] LT", lastWeek: "[pasinta] dddd [je] LT", sameElse: "L" }, relativeTime: { future: "je %s", past: "antaŭ %s", s: "sekundoj", m: "minuto", mm: "%d minutoj", h: "horo", hh: "%d horoj", d: "tago", dd: "%d tagoj", M: "monato", MM: "%d monatoj", y: "jaro", yy: "%d jaroj" }, ordinalParse: /\d{1,2}a/, ordinal: "%da", week: { dow: 1, doy: 7 }
    }), "ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_")), gg = "ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"), hg = (Pf.defineLocale("es", { months: "enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"), monthsShort: function (a, b) { return /-MMM-/.test(b) ? gg[a.month()] : fg[a.month()] }, weekdays: "domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"), weekdaysShort: "dom._lun._mar._mié._jue._vie._sáb.".split("_"), weekdaysMin: "do_lu_ma_mi_ju_vi_sá".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD/MM/YYYY", LL: "D [de] MMMM [de] YYYY", LLL: "D [de] MMMM [de] YYYY H:mm", LLLL: "dddd, D [de] MMMM [de] YYYY H:mm" }, calendar: { sameDay: function () { return "[hoy a la" + (1 !== this.hours() ? "s" : "") + "] LT" }, nextDay: function () { return "[mañana a la" + (1 !== this.hours() ? "s" : "") + "] LT" }, nextWeek: function () { return "dddd [a la" + (1 !== this.hours() ? "s" : "") + "] LT" }, lastDay: function () { return "[ayer a la" + (1 !== this.hours() ? "s" : "") + "] LT" }, lastWeek: function () { return "[el] dddd [pasado a la" + (1 !== this.hours() ? "s" : "") + "] LT" }, sameElse: "L" }, relativeTime: { future: "en %s", past: "hace %s", s: "unos segundos", m: "un minuto", mm: "%d minutos", h: "una hora", hh: "%d horas", d: "un día", dd: "%d días", M: "un mes", MM: "%d meses", y: "un año", yy: "%d años" }, ordinalParse: /\d{1,2}º/, ordinal: "%dº", week: { dow: 1, doy: 4 } }), Pf.defineLocale("et", { months: "jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"), monthsShort: "jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"), weekdays: "pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"), weekdaysShort: "P_E_T_K_N_R_L".split("_"), weekdaysMin: "P_E_T_K_N_R_L".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[Täna,] LT", nextDay: "[Homme,] LT", nextWeek: "[Järgmine] dddd LT", lastDay: "[Eile,] LT", lastWeek: "[Eelmine] dddd LT", sameElse: "L" }, relativeTime: { future: "%s pärast", past: "%s tagasi", s: jd, m: jd, mm: jd, h: jd, hh: jd, d: jd, dd: "%d päeva", M: jd, MM: jd, y: jd, yy: jd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("eu", { months: "urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"), monthsShort: "urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"), weekdays: "igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"), weekdaysShort: "ig._al._ar._az._og._ol._lr.".split("_"), weekdaysMin: "ig_al_ar_az_og_ol_lr".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY-MM-DD", LL: "YYYY[ko] MMMM[ren] D[a]", LLL: "YYYY[ko] MMMM[ren] D[a] HH:mm", LLLL: "dddd, YYYY[ko] MMMM[ren] D[a] HH:mm", l: "YYYY-M-D", ll: "YYYY[ko] MMM D[a]", lll: "YYYY[ko] MMM D[a] HH:mm", llll: "ddd, YYYY[ko] MMM D[a] HH:mm" }, calendar: { sameDay: "[gaur] LT[etan]", nextDay: "[bihar] LT[etan]", nextWeek: "dddd LT[etan]", lastDay: "[atzo] LT[etan]", lastWeek: "[aurreko] dddd LT[etan]", sameElse: "L" }, relativeTime: { future: "%s barru", past: "duela %s", s: "segundo batzuk", m: "minutu bat", mm: "%d minutu", h: "ordu bat", hh: "%d ordu", d: "egun bat", dd: "%d egun", M: "hilabete bat", MM: "%d hilabete", y: "urte bat", yy: "%d urte" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), { 1: "۱", 2: "۲", 3: "۳", 4: "۴", 5: "۵", 6: "۶", 7: "۷", 8: "۸", 9: "۹", 0: "۰" }), ig = { "۱": "1", "۲": "2", "۳": "3", "۴": "4", "۵": "5", "۶": "6", "۷": "7", "۸": "8", "۹": "9", "۰": "0" }, jg = (Pf.defineLocale("fa", { months: "ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"), monthsShort: "ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"), weekdays: "یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"), weekdaysShort: "یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"), weekdaysMin: "ی_د_س_چ_پ_ج_ش".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, meridiemParse: /قبل از ظهر|بعد از ظهر/, isPM: function (a) { return /بعد از ظهر/.test(a) }, meridiem: function (a, b, c) { return 12 > a ? "قبل از ظهر" : "بعد از ظهر" }, calendar: { sameDay: "[امروز ساعت] LT", nextDay: "[فردا ساعت] LT", nextWeek: "dddd [ساعت] LT", lastDay: "[دیروز ساعت] LT", lastWeek: "dddd [پیش] [ساعت] LT", sameElse: "L" }, relativeTime: { future: "در %s", past: "%s پیش", s: "چندین ثانیه", m: "یک دقیقه", mm: "%d دقیقه", h: "یک ساعت", hh: "%d ساعت", d: "یک روز", dd: "%d روز", M: "یک ماه", MM: "%d ماه", y: "یک سال", yy: "%d سال" }, preparse: function (a) { return a.replace(/[۰-۹]/g, function (a) { return ig[a] }).replace(/،/g, ",") }, postformat: function (a) { return a.replace(/\d/g, function (a) { return hg[a] }).replace(/,/g, "،") }, ordinalParse: /\d{1,2}م/, ordinal: "%dم", week: { dow: 6, doy: 12 } }), "nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" ")), kg = ["nolla", "yhden", "kahden", "kolmen", "neljän", "viiden", "kuuden", jg[7], jg[8], jg[9]], lg = (Pf.defineLocale("fi", { months: "tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"), monthsShort: "tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"), weekdays: "sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"), weekdaysShort: "su_ma_ti_ke_to_pe_la".split("_"), weekdaysMin: "su_ma_ti_ke_to_pe_la".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD.MM.YYYY", LL: "Do MMMM[ta] YYYY", LLL: "Do MMMM[ta] YYYY, [klo] HH.mm", LLLL: "dddd, Do MMMM[ta] YYYY, [klo] HH.mm", l: "D.M.YYYY", ll: "Do MMM YYYY", lll: "Do MMM YYYY, [klo] HH.mm", llll: "ddd, Do MMM YYYY, [klo] HH.mm" }, calendar: { sameDay: "[tänään] [klo] LT", nextDay: "[huomenna] [klo] LT", nextWeek: "dddd [klo] LT", lastDay: "[eilen] [klo] LT", lastWeek: "[viime] dddd[na] [klo] LT", sameElse: "L" }, relativeTime: { future: "%s päästä", past: "%s sitten", s: kd, m: kd, mm: kd, h: kd, hh: kd, d: kd, dd: kd, M: kd, MM: kd, y: kd, yy: kd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("fo", { months: "januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"), monthsShort: "jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"), weekdays: "sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"), weekdaysShort: "sun_mán_týs_mik_hós_frí_ley".split("_"), weekdaysMin: "su_má_tý_mi_hó_fr_le".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D. MMMM, YYYY HH:mm" }, calendar: { sameDay: "[Í dag kl.] LT", nextDay: "[Í morgin kl.] LT", nextWeek: "dddd [kl.] LT", lastDay: "[Í gjár kl.] LT", lastWeek: "[síðstu] dddd [kl] LT", sameElse: "L" }, relativeTime: { future: "um %s", past: "%s síðani", s: "fá sekund", m: "ein minutt", mm: "%d minuttir", h: "ein tími", hh: "%d tímar", d: "ein dagur", dd: "%d dagar", M: "ein mánaði", MM: "%d mánaðir", y: "eitt ár", yy: "%d ár" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("fr-ca", { months: "janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"), monthsShort: "janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"), weekdays: "dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"), weekdaysShort: "dim._lun._mar._mer._jeu._ven._sam.".split("_"), weekdaysMin: "Di_Lu_Ma_Me_Je_Ve_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY-MM-DD", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Aujourd'hui à] LT", nextDay: "[Demain à] LT", nextWeek: "dddd [à] LT", lastDay: "[Hier à] LT", lastWeek: "dddd [dernier à] LT", sameElse: "L" }, relativeTime: { future: "dans %s", past: "il y a %s", s: "quelques secondes", m: "une minute", mm: "%d minutes", h: "une heure", hh: "%d heures", d: "un jour", dd: "%d jours", M: "un mois", MM: "%d mois", y: "un an", yy: "%d ans" }, ordinalParse: /\d{1,2}(er|e)/, ordinal: function (a) { return a + (1 === a ? "er" : "e") } }), Pf.defineLocale("fr-ch", { months: "janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"), monthsShort: "janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"), weekdays: "dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"), weekdaysShort: "dim._lun._mar._mer._jeu._ven._sam.".split("_"), weekdaysMin: "Di_Lu_Ma_Me_Je_Ve_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Aujourd'hui à] LT", nextDay: "[Demain à] LT", nextWeek: "dddd [à] LT", lastDay: "[Hier à] LT", lastWeek: "dddd [dernier à] LT", sameElse: "L" }, relativeTime: { future: "dans %s", past: "il y a %s", s: "quelques secondes", m: "une minute", mm: "%d minutes", h: "une heure", hh: "%d heures", d: "un jour", dd: "%d jours", M: "un mois", MM: "%d mois", y: "un an", yy: "%d ans" }, ordinalParse: /\d{1,2}(er|e)/, ordinal: function (a) { return a + (1 === a ? "er" : "e") }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("fr", { months: "janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"), monthsShort: "janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"), weekdays: "dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"), weekdaysShort: "dim._lun._mar._mer._jeu._ven._sam.".split("_"), weekdaysMin: "Di_Lu_Ma_Me_Je_Ve_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Aujourd'hui à] LT", nextDay: "[Demain à] LT", nextWeek: "dddd [à] LT", lastDay: "[Hier à] LT", lastWeek: "dddd [dernier à] LT", sameElse: "L" }, relativeTime: { future: "dans %s", past: "il y a %s", s: "quelques secondes", m: "une minute", mm: "%d minutes", h: "une heure", hh: "%d heures", d: "un jour", dd: "%d jours", M: "un mois", MM: "%d mois", y: "un an", yy: "%d ans" }, ordinalParse: /\d{1,2}(er|)/, ordinal: function (a) { return a + (1 === a ? "er" : "") }, week: { dow: 1, doy: 4 } }), "jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_")), mg = "jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"), ng = (Pf.defineLocale("fy", { months: "jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"), monthsShort: function (a, b) { return /-MMM-/.test(b) ? mg[a.month()] : lg[a.month()] }, weekdays: "snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"), weekdaysShort: "si._mo._ti._wo._to._fr._so.".split("_"), weekdaysMin: "Si_Mo_Ti_Wo_To_Fr_So".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD-MM-YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[hjoed om] LT", nextDay: "[moarn om] LT", nextWeek: "dddd [om] LT", lastDay: "[juster om] LT", lastWeek: "[ôfrûne] dddd [om] LT", sameElse: "L" }, relativeTime: { future: "oer %s", past: "%s lyn", s: "in pear sekonden", m: "ien minút", mm: "%d minuten", h: "ien oere", hh: "%d oeren", d: "ien dei", dd: "%d dagen", M: "ien moanne", MM: "%d moannen", y: "ien jier", yy: "%d jierren" }, ordinalParse: /\d{1,2}(ste|de)/, ordinal: function (a) { return a + (1 === a || 8 === a || a >= 20 ? "ste" : "de") }, week: { dow: 1, doy: 4 } }), ["Am Faoilleach", "An Gearran", "Am Màrt", "An Giblean", "An Cèitean", "An t-Ògmhios", "An t-Iuchar", "An Lùnastal", "An t-Sultain", "An Dàmhair", "An t-Samhain", "An Dùbhlachd"]), og = ["Faoi", "Gear", "Màrt", "Gibl", "Cèit", "Ògmh", "Iuch", "Lùn", "Sult", "Dàmh", "Samh", "Dùbh"], pg = ["Didòmhnaich", "Diluain", "Dimàirt", "Diciadain", "Diardaoin", "Dihaoine", "Disathairne"], qg = ["Did", "Dil", "Dim", "Dic", "Dia", "Dih", "Dis"], rg = ["Dò", "Lu", "Mà", "Ci", "Ar", "Ha", "Sa"], sg = (Pf.defineLocale("gd", { months: ng, monthsShort: og, monthsParseExact: !0, weekdays: pg, weekdaysShort: qg, weekdaysMin: rg, longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[An-diugh aig] LT", nextDay: "[A-màireach aig] LT", nextWeek: "dddd [aig] LT", lastDay: "[An-dè aig] LT", lastWeek: "dddd [seo chaidh] [aig] LT", sameElse: "L" }, relativeTime: { future: "ann an %s", past: "bho chionn %s", s: "beagan diogan", m: "mionaid", mm: "%d mionaidean", h: "uair", hh: "%d uairean", d: "latha", dd: "%d latha", M: "mìos", MM: "%d mìosan", y: "bliadhna", yy: "%d bliadhna" }, ordinalParse: /\d{1,2}(d|na|mh)/, ordinal: function (a) { var b = 1 === a ? "d" : a % 10 === 2 ? "na" : "mh"; return a + b }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("gl", { months: "Xaneiro_Febreiro_Marzo_Abril_Maio_Xuño_Xullo_Agosto_Setembro_Outubro_Novembro_Decembro".split("_"), monthsShort: "Xan._Feb._Mar._Abr._Mai._Xuñ._Xul._Ago._Set._Out._Nov._Dec.".split("_"), weekdays: "Domingo_Luns_Martes_Mércores_Xoves_Venres_Sábado".split("_"), weekdaysShort: "Dom._Lun._Mar._Mér._Xov._Ven._Sáb.".split("_"), weekdaysMin: "Do_Lu_Ma_Mé_Xo_Ve_Sá".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY H:mm", LLLL: "dddd D MMMM YYYY H:mm" }, calendar: { sameDay: function () { return "[hoxe " + (1 !== this.hours() ? "ás" : "á") + "] LT" }, nextDay: function () { return "[mañá " + (1 !== this.hours() ? "ás" : "á") + "] LT" }, nextWeek: function () { return "dddd [" + (1 !== this.hours() ? "ás" : "a") + "] LT" }, lastDay: function () { return "[onte " + (1 !== this.hours() ? "á" : "a") + "] LT" }, lastWeek: function () { return "[o] dddd [pasado " + (1 !== this.hours() ? "ás" : "a") + "] LT" }, sameElse: "L" }, relativeTime: { future: function (a) { return "uns segundos" === a ? "nuns segundos" : "en " + a }, past: "hai %s", s: "uns segundos", m: "un minuto", mm: "%d minutos", h: "unha hora", hh: "%d horas", d: "un día", dd: "%d días", M: "un mes", MM: "%d meses", y: "un ano", yy: "%d anos" }, ordinalParse: /\d{1,2}º/, ordinal: "%dº", week: { dow: 1, doy: 7 } }), Pf.defineLocale("he", { months: "ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"), monthsShort: "ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"), weekdays: "ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"), weekdaysShort: "א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"), weekdaysMin: "א_ב_ג_ד_ה_ו_ש".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D [ב]MMMM YYYY", LLL: "D [ב]MMMM YYYY HH:mm", LLLL: "dddd, D [ב]MMMM YYYY HH:mm", l: "D/M/YYYY", ll: "D MMM YYYY", lll: "D MMM YYYY HH:mm", llll: "ddd, D MMM YYYY HH:mm" }, calendar: { sameDay: "[היום ב־]LT", nextDay: "[מחר ב־]LT", nextWeek: "dddd [בשעה] LT", lastDay: "[אתמול ב־]LT", lastWeek: "[ביום] dddd [האחרון בשעה] LT", sameElse: "L" }, relativeTime: { future: "בעוד %s", past: "לפני %s", s: "מספר שניות", m: "דקה", mm: "%d דקות", h: "שעה", hh: function (a) { return 2 === a ? "שעתיים" : a + " שעות" }, d: "יום", dd: function (a) { return 2 === a ? "יומיים" : a + " ימים" }, M: "חודש", MM: function (a) { return 2 === a ? "חודשיים" : a + " חודשים" }, y: "שנה", yy: function (a) { return 2 === a ? "שנתיים" : a % 10 === 0 && 10 !== a ? a + " שנה" : a + " שנים" } }, meridiemParse: /אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i, isPM: function (a) { return /^(אחה"צ|אחרי הצהריים|בערב)$/.test(a) }, meridiem: function (a, b, c) { return 5 > a ? "לפנות בוקר" : 10 > a ? "בבוקר" : 12 > a ? c ? 'לפנה"צ' : "לפני הצהריים" : 18 > a ? c ? 'אחה"צ' : "אחרי הצהריים" : "בערב" } }), { 1: "१", 2: "२", 3: "३", 4: "४", 5: "५", 6: "६", 7: "७", 8: "८", 9: "९", 0: "०" }), tg = { "१": "1", "२": "2", "३": "3", "४": "4", "५": "5", "६": "6", "७": "7", "८": "8", "९": "9", "०": "0" }, ug = (Pf.defineLocale("hi", { months: "जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"), monthsShort: "जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"), weekdays: "रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"), weekdaysShort: "रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"), weekdaysMin: "र_सो_मं_बु_गु_शु_श".split("_"), longDateFormat: { LT: "A h:mm बजे", LTS: "A h:mm:ss बजे", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm बजे", LLLL: "dddd, D MMMM YYYY, A h:mm बजे" }, calendar: { sameDay: "[आज] LT", nextDay: "[कल] LT", nextWeek: "dddd, LT", lastDay: "[कल] LT", lastWeek: "[पिछले] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s में", past: "%s पहले", s: "कुछ ही क्षण", m: "एक मिनट", mm: "%d मिनट", h: "एक घंटा", hh: "%d घंटे", d: "एक दिन", dd: "%d दिन", M: "एक महीने", MM: "%d महीने", y: "एक वर्ष", yy: "%d वर्ष" }, preparse: function (a) { return a.replace(/[१२३४५६७८९०]/g, function (a) { return tg[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return sg[a] }) }, meridiemParse: /रात|सुबह|दोपहर|शाम/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "रात" === b ? 4 > a ? a : a + 12 : "सुबह" === b ? a : "दोपहर" === b ? a >= 10 ? a : a + 12 : "शाम" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 4 > a ? "रात" : 10 > a ? "सुबह" : 17 > a ? "दोपहर" : 20 > a ? "शाम" : "रात" }, week: { dow: 0, doy: 6 } }), Pf.defineLocale("hr", { months: { format: "siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"), standalone: "siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_") }, monthsShort: "sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"), weekdays: "nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"), weekdaysShort: "ned._pon._uto._sri._čet._pet._sub.".split("_"), weekdaysMin: "ne_po_ut_sr_če_pe_su".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[danas u] LT", nextDay: "[sutra u] LT", nextWeek: function () { switch (this.day()) { case 0: return "[u] [nedjelju] [u] LT"; case 3: return "[u] [srijedu] [u] LT"; case 6: return "[u] [subotu] [u] LT"; case 1: case 2: case 4: case 5: return "[u] dddd [u] LT" } }, lastDay: "[jučer u] LT", lastWeek: function () { switch (this.day()) { case 0: case 3: return "[prošlu] dddd [u] LT"; case 6: return "[prošle] [subote] [u] LT"; case 1: case 2: case 4: case 5: return "[prošli] dddd [u] LT" } }, sameElse: "L" }, relativeTime: { future: "za %s", past: "prije %s", s: "par sekundi", m: md, mm: md, h: md, hh: md, d: "dan", dd: md, M: "mjesec", MM: md, y: "godinu", yy: md }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), "vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ")), vg = (Pf.defineLocale("hu", { months: "január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"), monthsShort: "jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec".split("_"), weekdays: "vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"), weekdaysShort: "vas_hét_kedd_sze_csüt_pén_szo".split("_"), weekdaysMin: "v_h_k_sze_cs_p_szo".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "YYYY.MM.DD.", LL: "YYYY. MMMM D.", LLL: "YYYY. MMMM D. H:mm", LLLL: "YYYY. MMMM D., dddd H:mm" }, meridiemParse: /de|du/i, isPM: function (a) { return "u" === a.charAt(1).toLowerCase() }, meridiem: function (a, b, c) { return 12 > a ? c === !0 ? "de" : "DE" : c === !0 ? "du" : "DU" }, calendar: { sameDay: "[ma] LT[-kor]", nextDay: "[holnap] LT[-kor]", nextWeek: function () { return od.call(this, !0) }, lastDay: "[tegnap] LT[-kor]", lastWeek: function () { return od.call(this, !1) }, sameElse: "L" }, relativeTime: { future: "%s múlva", past: "%s", s: nd, m: nd, mm: nd, h: nd, hh: nd, d: nd, dd: nd, M: nd, MM: nd, y: nd, yy: nd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), Pf.defineLocale("hy-am", { months: { format: "հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"), standalone: "հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_") }, monthsShort: "հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"), weekdays: "կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"), weekdaysShort: "կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"), weekdaysMin: "կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY թ.", LLL: "D MMMM YYYY թ., HH:mm", LLLL: "dddd, D MMMM YYYY թ., HH:mm" }, calendar: { sameDay: "[այսօր] LT", nextDay: "[վաղը] LT", lastDay: "[երեկ] LT", nextWeek: function () { return "dddd [օրը ժամը] LT" }, lastWeek: function () { return "[անցած] dddd [օրը ժամը] LT" }, sameElse: "L" }, relativeTime: { future: "%s հետո", past: "%s առաջ", s: "մի քանի վայրկյան", m: "րոպե", mm: "%d րոպե", h: "ժամ", hh: "%d ժամ", d: "օր", dd: "%d օր", M: "ամիս", MM: "%d ամիս", y: "տարի", yy: "%d տարի" }, meridiemParse: /գիշերվա|առավոտվա|ցերեկվա|երեկոյան/, isPM: function (a) { return /^(ցերեկվա|երեկոյան)$/.test(a) }, meridiem: function (a) { return 4 > a ? "գիշերվա" : 12 > a ? "առավոտվա" : 17 > a ? "ցերեկվա" : "երեկոյան" }, ordinalParse: /\d{1,2}|\d{1,2}-(ին|րդ)/, ordinal: function (a, b) { switch (b) { case "DDD": case "w": case "W": case "DDDo": return 1 === a ? a + "-ին" : a + "-րդ"; default: return a } }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("id", { months: "Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"), monthsShort: "Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des".split("_"), weekdays: "Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"), weekdaysShort: "Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"), weekdaysMin: "Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY [pukul] HH.mm", LLLL: "dddd, D MMMM YYYY [pukul] HH.mm" }, meridiemParse: /pagi|siang|sore|malam/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "pagi" === b ? a : "siang" === b ? a >= 11 ? a : a + 12 : "sore" === b || "malam" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 11 > a ? "pagi" : 15 > a ? "siang" : 19 > a ? "sore" : "malam" }, calendar: { sameDay: "[Hari ini pukul] LT", nextDay: "[Besok pukul] LT", nextWeek: "dddd [pukul] LT", lastDay: "[Kemarin pukul] LT", lastWeek: "dddd [lalu pukul] LT", sameElse: "L" }, relativeTime: { future: "dalam %s", past: "%s yang lalu", s: "beberapa detik", m: "semenit", mm: "%d menit", h: "sejam", hh: "%d jam", d: "sehari", dd: "%d hari", M: "sebulan", MM: "%d bulan", y: "setahun", yy: "%d tahun" }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("is", { months: "janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"), monthsShort: "jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"), weekdays: "sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"), weekdaysShort: "sun_mán_þri_mið_fim_fös_lau".split("_"), weekdaysMin: "Su_Má_Þr_Mi_Fi_Fö_La".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY [kl.] H:mm", LLLL: "dddd, D. MMMM YYYY [kl.] H:mm" }, calendar: { sameDay: "[í dag kl.] LT", nextDay: "[á morgun kl.] LT", nextWeek: "dddd [kl.] LT", lastDay: "[í gær kl.] LT", lastWeek: "[síðasta] dddd [kl.] LT", sameElse: "L" }, relativeTime: { future: "eftir %s", past: "fyrir %s síðan", s: qd, m: qd, mm: qd, h: "klukkustund", hh: qd, d: qd, dd: qd, M: qd, MM: qd, y: qd, yy: qd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("it", { months: "gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"), monthsShort: "gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"), weekdays: "Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato".split("_"), weekdaysShort: "Dom_Lun_Mar_Mer_Gio_Ven_Sab".split("_"), weekdaysMin: "Do_Lu_Ma_Me_Gi_Ve_Sa".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Oggi alle] LT", nextDay: "[Domani alle] LT", nextWeek: "dddd [alle] LT", lastDay: "[Ieri alle] LT", lastWeek: function () { switch (this.day()) { case 0: return "[la scorsa] dddd [alle] LT"; default: return "[lo scorso] dddd [alle] LT" } }, sameElse: "L" }, relativeTime: { future: function (a) { return (/^[0-9].+$/.test(a) ? "tra" : "in") + " " + a }, past: "%s fa", s: "alcuni secondi", m: "un minuto", mm: "%d minuti", h: "un'ora", hh: "%d ore", d: "un giorno", dd: "%d giorni", M: "un mese", MM: "%d mesi", y: "un anno", yy: "%d anni" }, ordinalParse: /\d{1,2}º/, ordinal: "%dº", week: { dow: 1, doy: 4 } }), Pf.defineLocale("ja", { months: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"), monthsShort: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"), weekdays: "日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"), weekdaysShort: "日_月_火_水_木_金_土".split("_"), weekdaysMin: "日_月_火_水_木_金_土".split("_"), longDateFormat: { LT: "Ah時m分", LTS: "Ah時m分s秒", L: "YYYY/MM/DD", LL: "YYYY年M月D日", LLL: "YYYY年M月D日Ah時m分", LLLL: "YYYY年M月D日Ah時m分 dddd" }, meridiemParse: /午前|午後/i, isPM: function (a) { return "午後" === a }, meridiem: function (a, b, c) { return 12 > a ? "午前" : "午後" }, calendar: { sameDay: "[今日] LT", nextDay: "[明日] LT", nextWeek: "[来週]dddd LT", lastDay: "[昨日] LT", lastWeek: "[前週]dddd LT", sameElse: "L" }, ordinalParse: /\d{1,2}日/, ordinal: function (a, b) { switch (b) { case "d": case "D": case "DDD": return a + "日"; default: return a } }, relativeTime: { future: "%s後", past: "%s前", s: "数秒", m: "1分", mm: "%d分", h: "1時間", hh: "%d時間", d: "1日", dd: "%d日", M: "1ヶ月", MM: "%dヶ月", y: "1年", yy: "%d年" } }), Pf.defineLocale("jv", { months: "Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"), monthsShort: "Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"), weekdays: "Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"), weekdaysShort: "Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"), weekdaysMin: "Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY [pukul] HH.mm", LLLL: "dddd, D MMMM YYYY [pukul] HH.mm" }, meridiemParse: /enjing|siyang|sonten|ndalu/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "enjing" === b ? a : "siyang" === b ? a >= 11 ? a : a + 12 : "sonten" === b || "ndalu" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 11 > a ? "enjing" : 15 > a ? "siyang" : 19 > a ? "sonten" : "ndalu" }, calendar: { sameDay: "[Dinten puniko pukul] LT", nextDay: "[Mbenjang pukul] LT", nextWeek: "dddd [pukul] LT", lastDay: "[Kala wingi pukul] LT", lastWeek: "dddd [kepengker pukul] LT", sameElse: "L" }, relativeTime: { future: "wonten ing %s", past: "%s ingkang kepengker", s: "sawetawis detik", m: "setunggal menit", mm: "%d menit", h: "setunggal jam", hh: "%d jam", d: "sedinten", dd: "%d dinten", M: "sewulan", MM: "%d wulan", y: "setaun", yy: "%d taun" }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("ka", { months: { standalone: "იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"), format: "იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს".split("_") }, monthsShort: "იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"), weekdays: { standalone: "კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"), format: "კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"), isFormat: /(წინა|შემდეგ)/ }, weekdaysShort: "კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"), weekdaysMin: "კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"), longDateFormat: { LT: "h:mm A", LTS: "h:mm:ss A", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY h:mm A", LLLL: "dddd, D MMMM YYYY h:mm A" }, calendar: { sameDay: "[დღეს] LT[-ზე]", nextDay: "[ხვალ] LT[-ზე]", lastDay: "[გუშინ] LT[-ზე]", nextWeek: "[შემდეგ] dddd LT[-ზე]", lastWeek: "[წინა] dddd LT-ზე", sameElse: "L" }, relativeTime: { future: function (a) { return /(წამი|წუთი|საათი|წელი)/.test(a) ? a.replace(/ი$/, "ში") : a + "ში" }, past: function (a) { return /(წამი|წუთი|საათი|დღე|თვე)/.test(a) ? a.replace(/(ი|ე)$/, "ის წინ") : /წელი/.test(a) ? a.replace(/წელი$/, "წლის წინ") : void 0 }, s: "რამდენიმე წამი", m: "წუთი", mm: "%d წუთი", h: "საათი", hh: "%d საათი", d: "დღე", dd: "%d დღე", M: "თვე", MM: "%d თვე", y: "წელი", yy: "%d წელი" }, ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/, ordinal: function (a) { return 0 === a ? a : 1 === a ? a + "-ლი" : 20 > a || 100 >= a && a % 20 === 0 || a % 100 === 0 ? "მე-" + a : a + "-ე" }, week: { dow: 1, doy: 7 } }), { 0: "-ші", 1: "-ші", 2: "-ші", 3: "-ші", 4: "-ші", 5: "-ші", 6: "-шы", 7: "-ші", 8: "-ші", 9: "-шы", 10: "-шы", 20: "-шы", 30: "-шы", 40: "-шы", 50: "-ші", 60: "-шы", 70: "-ші", 80: "-ші", 90: "-шы", 100: "-ші" }), wg = (Pf.defineLocale("kk", { months: "Қаңтар_Ақпан_Наурыз_Сәуір_Мамыр_Маусым_Шілде_Тамыз_Қыркүйек_Қазан_Қараша_Желтоқсан".split("_"), monthsShort: "Қаң_Ақп_Нау_Сәу_Мам_Мау_Шіл_Там_Қыр_Қаз_Қар_Жел".split("_"), weekdays: "Жексенбі_Дүйсенбі_Сейсенбі_Сәрсенбі_Бейсенбі_Жұма_Сенбі".split("_"), weekdaysShort: "Жек_Дүй_Сей_Сәр_Бей_Жұм_Сен".split("_"), weekdaysMin: "Жк_Дй_Сй_Ср_Бй_Жм_Сн".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Бүгін сағат] LT", nextDay: "[Ертең сағат] LT", nextWeek: "dddd [сағат] LT", lastDay: "[Кеше сағат] LT", lastWeek: "[Өткен аптаның] dddd [сағат] LT", sameElse: "L" }, relativeTime: { future: "%s ішінде", past: "%s бұрын", s: "бірнеше секунд", m: "бір минут", mm: "%d минут", h: "бір сағат", hh: "%d сағат", d: "бір күн", dd: "%d күн", M: "бір ай", MM: "%d ай", y: "бір жыл", yy: "%d жыл" }, ordinalParse: /\d{1,2}-(ші|шы)/, ordinal: function (a) { var b = a % 10, c = a >= 100 ? 100 : null; return a + (vg[a] || vg[b] || vg[c]) }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("km", { months: "មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"), monthsShort: "មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"), weekdays: "អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"), weekdaysShort: "អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"), weekdaysMin: "អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[ថ្ងៃនេះ ម៉ោង] LT", nextDay: "[ស្អែក ម៉ោង] LT", nextWeek: "dddd [ម៉ោង] LT", lastDay: "[ម្សិលមិញ ម៉ោង] LT", lastWeek: "dddd [សប្តាហ៍មុន] [ម៉ោង] LT", sameElse: "L" }, relativeTime: { future: "%sទៀត", past: "%sមុន", s: "ប៉ុន្មានវិនាទី", m: "មួយនាទី", mm: "%d នាទី", h: "មួយម៉ោង", hh: "%d ម៉ោង", d: "មួយថ្ងៃ", dd: "%d ថ្ងៃ", M: "មួយខែ", MM: "%d ខែ", y: "មួយឆ្នាំ", yy: "%d ឆ្នាំ" }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("ko", { months: "1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"), monthsShort: "1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"), weekdays: "일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"), weekdaysShort: "일_월_화_수_목_금_토".split("_"), weekdaysMin: "일_월_화_수_목_금_토".split("_"), longDateFormat: { LT: "A h시 m분", LTS: "A h시 m분 s초", L: "YYYY.MM.DD", LL: "YYYY년 MMMM D일", LLL: "YYYY년 MMMM D일 A h시 m분", LLLL: "YYYY년 MMMM D일 dddd A h시 m분" }, calendar: { sameDay: "오늘 LT", nextDay: "내일 LT", nextWeek: "dddd LT", lastDay: "어제 LT", lastWeek: "지난주 dddd LT", sameElse: "L" }, relativeTime: { future: "%s 후", past: "%s 전", s: "몇초", ss: "%d초", m: "일분", mm: "%d분", h: "한시간", hh: "%d시간", d: "하루", dd: "%d일", M: "한달", MM: "%d달", y: "일년", yy: "%d년" }, ordinalParse: /\d{1,2}일/, ordinal: "%d일", meridiemParse: /오전|오후/, isPM: function (a) { return "오후" === a }, meridiem: function (a, b, c) { return 12 > a ? "오전" : "오후" } }), Pf.defineLocale("lb", { months: "Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"), monthsShort: "Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"), weekdays: "Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"), weekdaysShort: "So._Mé._Dë._Më._Do._Fr._Sa.".split("_"), weekdaysMin: "So_Mé_Dë_Më_Do_Fr_Sa".split("_"), longDateFormat: { LT: "H:mm [Auer]", LTS: "H:mm:ss [Auer]", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm [Auer]", LLLL: "dddd, D. MMMM YYYY H:mm [Auer]" }, calendar: { sameDay: "[Haut um] LT", sameElse: "L", nextDay: "[Muer um] LT", nextWeek: "dddd [um] LT", lastDay: "[Gëschter um] LT", lastWeek: function () { switch (this.day()) { case 2: case 4: return "[Leschten] dddd [um] LT"; default: return "[Leschte] dddd [um] LT" } } }, relativeTime: { future: sd, past: td, s: "e puer Sekonnen", m: rd, mm: "%d Minutten", h: rd, hh: "%d Stonnen", d: rd, dd: "%d Deeg", M: rd, MM: "%d Méint", y: rd, yy: "%d Joer" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("lo", {
        months: "ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"), monthsShort: "ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"), weekdays: "ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"), weekdaysShort: "ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"), weekdaysMin: "ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "ວັນdddd D MMMM YYYY HH:mm" }, meridiemParse: /ຕອນເຊົ້າ|ຕອນແລງ/,
        isPM: function (a) { return "ຕອນແລງ" === a }, meridiem: function (a, b, c) { return 12 > a ? "ຕອນເຊົ້າ" : "ຕອນແລງ" }, calendar: { sameDay: "[ມື້ນີ້ເວລາ] LT", nextDay: "[ມື້ອື່ນເວລາ] LT", nextWeek: "[ວັນ]dddd[ໜ້າເວລາ] LT", lastDay: "[ມື້ວານນີ້ເວລາ] LT", lastWeek: "[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT", sameElse: "L" }, relativeTime: { future: "ອີກ %s", past: "%sຜ່ານມາ", s: "ບໍ່ເທົ່າໃດວິນາທີ", m: "1 ນາທີ", mm: "%d ນາທີ", h: "1 ຊົ່ວໂມງ", hh: "%d ຊົ່ວໂມງ", d: "1 ມື້", dd: "%d ມື້", M: "1 ເດືອນ", MM: "%d ເດືອນ", y: "1 ປີ", yy: "%d ປີ" }, ordinalParse: /(ທີ່)\d{1,2}/, ordinal: function (a) { return "ທີ່" + a }
    }), { m: "minutė_minutės_minutę", mm: "minutės_minučių_minutes", h: "valanda_valandos_valandą", hh: "valandos_valandų_valandas", d: "diena_dienos_dieną", dd: "dienos_dienų_dienas", M: "mėnuo_mėnesio_mėnesį", MM: "mėnesiai_mėnesių_mėnesius", y: "metai_metų_metus", yy: "metai_metų_metus" }), xg = (Pf.defineLocale("lt", { months: { format: "sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"), standalone: "sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_") }, monthsShort: "sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"), weekdays: { format: "sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"), standalone: "sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"), isFormat: /dddd HH:mm/ }, weekdaysShort: "Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"), weekdaysMin: "S_P_A_T_K_Pn_Š".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY-MM-DD", LL: "YYYY [m.] MMMM D [d.]", LLL: "YYYY [m.] MMMM D [d.], HH:mm [val.]", LLLL: "YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]", l: "YYYY-MM-DD", ll: "YYYY [m.] MMMM D [d.]", lll: "YYYY [m.] MMMM D [d.], HH:mm [val.]", llll: "YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]" }, calendar: { sameDay: "[Šiandien] LT", nextDay: "[Rytoj] LT", nextWeek: "dddd LT", lastDay: "[Vakar] LT", lastWeek: "[Praėjusį] dddd LT", sameElse: "L" }, relativeTime: { future: "po %s", past: "prieš %s", s: vd, m: wd, mm: zd, h: wd, hh: zd, d: wd, dd: zd, M: wd, MM: zd, y: wd, yy: zd }, ordinalParse: /\d{1,2}-oji/, ordinal: function (a) { return a + "-oji" }, week: { dow: 1, doy: 4 } }), { m: "minūtes_minūtēm_minūte_minūtes".split("_"), mm: "minūtes_minūtēm_minūte_minūtes".split("_"), h: "stundas_stundām_stunda_stundas".split("_"), hh: "stundas_stundām_stunda_stundas".split("_"), d: "dienas_dienām_diena_dienas".split("_"), dd: "dienas_dienām_diena_dienas".split("_"), M: "mēneša_mēnešiem_mēnesis_mēneši".split("_"), MM: "mēneša_mēnešiem_mēnesis_mēneši".split("_"), y: "gada_gadiem_gads_gadi".split("_"), yy: "gada_gadiem_gads_gadi".split("_") }), yg = (Pf.defineLocale("lv", { months: "janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"), monthsShort: "jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"), weekdays: "svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"), weekdaysShort: "Sv_P_O_T_C_Pk_S".split("_"), weekdaysMin: "Sv_P_O_T_C_Pk_S".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY.", LL: "YYYY. [gada] D. MMMM", LLL: "YYYY. [gada] D. MMMM, HH:mm", LLLL: "YYYY. [gada] D. MMMM, dddd, HH:mm" }, calendar: { sameDay: "[Šodien pulksten] LT", nextDay: "[Rīt pulksten] LT", nextWeek: "dddd [pulksten] LT", lastDay: "[Vakar pulksten] LT", lastWeek: "[Pagājušā] dddd [pulksten] LT", sameElse: "L" }, relativeTime: { future: "pēc %s", past: "pirms %s", s: Dd, m: Cd, mm: Bd, h: Cd, hh: Bd, d: Cd, dd: Bd, M: Cd, MM: Bd, y: Cd, yy: Bd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), { words: { m: ["jedan minut", "jednog minuta"], mm: ["minut", "minuta", "minuta"], h: ["jedan sat", "jednog sata"], hh: ["sat", "sata", "sati"], dd: ["dan", "dana", "dana"], MM: ["mjesec", "mjeseca", "mjeseci"], yy: ["godina", "godine", "godina"] }, correctGrammaticalCase: function (a, b) { return 1 === a ? b[0] : a >= 2 && 4 >= a ? b[1] : b[2] }, translate: function (a, b, c) { var d = yg.words[c]; return 1 === c.length ? b ? d[0] : d[1] : a + " " + yg.correctGrammaticalCase(a, d) } }), zg = (Pf.defineLocale("me", { months: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"], monthsShort: ["jan.", "feb.", "mar.", "apr.", "maj", "jun", "jul", "avg.", "sep.", "okt.", "nov.", "dec."], weekdays: ["nedjelja", "ponedjeljak", "utorak", "srijeda", "četvrtak", "petak", "subota"], weekdaysShort: ["ned.", "pon.", "uto.", "sri.", "čet.", "pet.", "sub."], weekdaysMin: ["ne", "po", "ut", "sr", "če", "pe", "su"], longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[danas u] LT", nextDay: "[sjutra u] LT", nextWeek: function () { switch (this.day()) { case 0: return "[u] [nedjelju] [u] LT"; case 3: return "[u] [srijedu] [u] LT"; case 6: return "[u] [subotu] [u] LT"; case 1: case 2: case 4: case 5: return "[u] dddd [u] LT" } }, lastDay: "[juče u] LT", lastWeek: function () { var a = ["[prošle] [nedjelje] [u] LT", "[prošlog] [ponedjeljka] [u] LT", "[prošlog] [utorka] [u] LT", "[prošle] [srijede] [u] LT", "[prošlog] [četvrtka] [u] LT", "[prošlog] [petka] [u] LT", "[prošle] [subote] [u] LT"]; return a[this.day()] }, sameElse: "L" }, relativeTime: { future: "za %s", past: "prije %s", s: "nekoliko sekundi", m: yg.translate, mm: yg.translate, h: yg.translate, hh: yg.translate, d: "dan", dd: yg.translate, M: "mjesec", MM: yg.translate, y: "godinu", yy: yg.translate }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), Pf.defineLocale("mk", { months: "јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"), monthsShort: "јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"), weekdays: "недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"), weekdaysShort: "нед_пон_вто_сре_чет_пет_саб".split("_"), weekdaysMin: "нe_пo_вт_ср_че_пе_сa".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "D.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY H:mm", LLLL: "dddd, D MMMM YYYY H:mm" }, calendar: { sameDay: "[Денес во] LT", nextDay: "[Утре во] LT", nextWeek: "[Во] dddd [во] LT", lastDay: "[Вчера во] LT", lastWeek: function () { switch (this.day()) { case 0: case 3: case 6: return "[Изминатата] dddd [во] LT"; case 1: case 2: case 4: case 5: return "[Изминатиот] dddd [во] LT" } }, sameElse: "L" }, relativeTime: { future: "после %s", past: "пред %s", s: "неколку секунди", m: "минута", mm: "%d минути", h: "час", hh: "%d часа", d: "ден", dd: "%d дена", M: "месец", MM: "%d месеци", y: "година", yy: "%d години" }, ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/, ordinal: function (a) { var b = a % 10, c = a % 100; return 0 === a ? a + "-ев" : 0 === c ? a + "-ен" : c > 10 && 20 > c ? a + "-ти" : 1 === b ? a + "-ви" : 2 === b ? a + "-ри" : 7 === b || 8 === b ? a + "-ми" : a + "-ти" }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("ml", { months: "ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"), monthsShort: "ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"), weekdays: "ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"), weekdaysShort: "ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"), weekdaysMin: "ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"), longDateFormat: { LT: "A h:mm -നു", LTS: "A h:mm:ss -നു", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm -നു", LLLL: "dddd, D MMMM YYYY, A h:mm -നു" }, calendar: { sameDay: "[ഇന്ന്] LT", nextDay: "[നാളെ] LT", nextWeek: "dddd, LT", lastDay: "[ഇന്നലെ] LT", lastWeek: "[കഴിഞ്ഞ] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s കഴിഞ്ഞ്", past: "%s മുൻപ്", s: "അൽപ നിമിഷങ്ങൾ", m: "ഒരു മിനിറ്റ്", mm: "%d മിനിറ്റ്", h: "ഒരു മണിക്കൂർ", hh: "%d മണിക്കൂർ", d: "ഒരു ദിവസം", dd: "%d ദിവസം", M: "ഒരു മാസം", MM: "%d മാസം", y: "ഒരു വർഷം", yy: "%d വർഷം" }, meridiemParse: /രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i, meridiemHour: function (a, b) { return 12 === a && (a = 0), "രാത്രി" === b && a >= 4 || "ഉച്ച കഴിഞ്ഞ്" === b || "വൈകുന്നേരം" === b ? a + 12 : a }, meridiem: function (a, b, c) { return 4 > a ? "രാത്രി" : 12 > a ? "രാവിലെ" : 17 > a ? "ഉച്ച കഴിഞ്ഞ്" : 20 > a ? "വൈകുന്നേരം" : "രാത്രി" } }), { 1: "१", 2: "२", 3: "३", 4: "४", 5: "५", 6: "६", 7: "७", 8: "८", 9: "९", 0: "०" }), Ag = { "१": "1", "२": "2", "३": "3", "४": "4", "५": "5", "६": "6", "७": "7", "८": "8", "९": "9", "०": "0" }, Bg = (Pf.defineLocale("mr", { months: "जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"), monthsShort: "जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"), weekdays: "रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"), weekdaysShort: "रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"), weekdaysMin: "र_सो_मं_बु_गु_शु_श".split("_"), longDateFormat: { LT: "A h:mm वाजता", LTS: "A h:mm:ss वाजता", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm वाजता", LLLL: "dddd, D MMMM YYYY, A h:mm वाजता" }, calendar: { sameDay: "[आज] LT", nextDay: "[उद्या] LT", nextWeek: "dddd, LT", lastDay: "[काल] LT", lastWeek: "[मागील] dddd, LT", sameElse: "L" }, relativeTime: { future: "%sमध्ये", past: "%sपूर्वी", s: Ed, m: Ed, mm: Ed, h: Ed, hh: Ed, d: Ed, dd: Ed, M: Ed, MM: Ed, y: Ed, yy: Ed }, preparse: function (a) { return a.replace(/[१२३४५६७८९०]/g, function (a) { return Ag[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return zg[a] }) }, meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "रात्री" === b ? 4 > a ? a : a + 12 : "सकाळी" === b ? a : "दुपारी" === b ? a >= 10 ? a : a + 12 : "सायंकाळी" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 4 > a ? "रात्री" : 10 > a ? "सकाळी" : 17 > a ? "दुपारी" : 20 > a ? "सायंकाळी" : "रात्री" }, week: { dow: 0, doy: 6 } }), Pf.defineLocale("ms-my", { months: "Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"), monthsShort: "Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"), weekdays: "Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"), weekdaysShort: "Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"), weekdaysMin: "Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY [pukul] HH.mm", LLLL: "dddd, D MMMM YYYY [pukul] HH.mm" }, meridiemParse: /pagi|tengahari|petang|malam/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "pagi" === b ? a : "tengahari" === b ? a >= 11 ? a : a + 12 : "petang" === b || "malam" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 11 > a ? "pagi" : 15 > a ? "tengahari" : 19 > a ? "petang" : "malam" }, calendar: { sameDay: "[Hari ini pukul] LT", nextDay: "[Esok pukul] LT", nextWeek: "dddd [pukul] LT", lastDay: "[Kelmarin pukul] LT", lastWeek: "dddd [lepas pukul] LT", sameElse: "L" }, relativeTime: { future: "dalam %s", past: "%s yang lepas", s: "beberapa saat", m: "seminit", mm: "%d minit", h: "sejam", hh: "%d jam", d: "sehari", dd: "%d hari", M: "sebulan", MM: "%d bulan", y: "setahun", yy: "%d tahun" }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("ms", { months: "Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"), monthsShort: "Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"), weekdays: "Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"), weekdaysShort: "Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"), weekdaysMin: "Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY [pukul] HH.mm", LLLL: "dddd, D MMMM YYYY [pukul] HH.mm" }, meridiemParse: /pagi|tengahari|petang|malam/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "pagi" === b ? a : "tengahari" === b ? a >= 11 ? a : a + 12 : "petang" === b || "malam" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 11 > a ? "pagi" : 15 > a ? "tengahari" : 19 > a ? "petang" : "malam" }, calendar: { sameDay: "[Hari ini pukul] LT", nextDay: "[Esok pukul] LT", nextWeek: "dddd [pukul] LT", lastDay: "[Kelmarin pukul] LT", lastWeek: "dddd [lepas pukul] LT", sameElse: "L" }, relativeTime: { future: "dalam %s", past: "%s yang lepas", s: "beberapa saat", m: "seminit", mm: "%d minit", h: "sejam", hh: "%d jam", d: "sehari", dd: "%d hari", M: "sebulan", MM: "%d bulan", y: "setahun", yy: "%d tahun" }, week: { dow: 1, doy: 7 } }), { 1: "၁", 2: "၂", 3: "၃", 4: "၄", 5: "၅", 6: "၆", 7: "၇", 8: "၈", 9: "၉", 0: "၀" }), Cg = { "၁": "1", "၂": "2", "၃": "3", "၄": "4", "၅": "5", "၆": "6", "၇": "7", "၈": "8", "၉": "9", "၀": "0" }, Dg = (Pf.defineLocale("my", { months: "ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"), monthsShort: "ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"), weekdays: "တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"), weekdaysShort: "နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"), weekdaysMin: "နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[ယနေ.] LT [မှာ]", nextDay: "[မနက်ဖြန်] LT [မှာ]", nextWeek: "dddd LT [မှာ]", lastDay: "[မနေ.က] LT [မှာ]", lastWeek: "[ပြီးခဲ့သော] dddd LT [မှာ]", sameElse: "L" }, relativeTime: { future: "လာမည့် %s မှာ", past: "လွန်ခဲ့သော %s က", s: "စက္ကန်.အနည်းငယ်", m: "တစ်မိနစ်", mm: "%d မိနစ်", h: "တစ်နာရီ", hh: "%d နာရီ", d: "တစ်ရက်", dd: "%d ရက်", M: "တစ်လ", MM: "%d လ", y: "တစ်နှစ်", yy: "%d နှစ်" }, preparse: function (a) { return a.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (a) { return Cg[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Bg[a] }) }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("nb", { months: "januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"), monthsShort: "jan._feb._mars_april_mai_juni_juli_aug._sep._okt._nov._des.".split("_"), weekdays: "søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"), weekdaysShort: "sø._ma._ti._on._to._fr._lø.".split("_"), weekdaysMin: "sø_ma_ti_on_to_fr_lø".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY [kl.] HH:mm", LLLL: "dddd D. MMMM YYYY [kl.] HH:mm" }, calendar: { sameDay: "[i dag kl.] LT", nextDay: "[i morgen kl.] LT", nextWeek: "dddd [kl.] LT", lastDay: "[i går kl.] LT", lastWeek: "[forrige] dddd [kl.] LT", sameElse: "L" }, relativeTime: { future: "om %s", past: "for %s siden", s: "noen sekunder", m: "ett minutt", mm: "%d minutter", h: "en time", hh: "%d timer", d: "en dag", dd: "%d dager", M: "en måned", MM: "%d måneder", y: "ett år", yy: "%d år" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), { 1: "१", 2: "२", 3: "३", 4: "४", 5: "५", 6: "६", 7: "७", 8: "८", 9: "९", 0: "०" }), Eg = { "१": "1", "२": "2", "३": "3", "४": "4", "५": "5", "६": "6", "७": "7", "८": "8", "९": "9", "०": "0" }, Fg = (Pf.defineLocale("ne", { months: "जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"), monthsShort: "जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"), weekdays: "आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"), weekdaysShort: "आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"), weekdaysMin: "आ._सो._मं._बु._बि._शु._श.".split("_"), longDateFormat: { LT: "Aको h:mm बजे", LTS: "Aको h:mm:ss बजे", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, Aको h:mm बजे", LLLL: "dddd, D MMMM YYYY, Aको h:mm बजे" }, preparse: function (a) { return a.replace(/[१२३४५६७८९०]/g, function (a) { return Eg[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Dg[a] }) }, meridiemParse: /राति|बिहान|दिउँसो|साँझ/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "राति" === b ? 4 > a ? a : a + 12 : "बिहान" === b ? a : "दिउँसो" === b ? a >= 10 ? a : a + 12 : "साँझ" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 3 > a ? "राति" : 12 > a ? "बिहान" : 16 > a ? "दिउँसो" : 20 > a ? "साँझ" : "राति" }, calendar: { sameDay: "[आज] LT", nextDay: "[भोलि] LT", nextWeek: "[आउँदो] dddd[,] LT", lastDay: "[हिजो] LT", lastWeek: "[गएको] dddd[,] LT", sameElse: "L" }, relativeTime: { future: "%sमा", past: "%s अगाडि", s: "केही क्षण", m: "एक मिनेट", mm: "%d मिनेट", h: "एक घण्टा", hh: "%d घण्टा", d: "एक दिन", dd: "%d दिन", M: "एक महिना", MM: "%d महिना", y: "एक बर्ष", yy: "%d बर्ष" }, week: { dow: 0, doy: 6 } }), "jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_")), Gg = "jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"), Hg = (Pf.defineLocale("nl", { months: "januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"), monthsShort: function (a, b) { return /-MMM-/.test(b) ? Gg[a.month()] : Fg[a.month()] }, weekdays: "zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"), weekdaysShort: "zo._ma._di._wo._do._vr._za.".split("_"), weekdaysMin: "Zo_Ma_Di_Wo_Do_Vr_Za".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD-MM-YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[vandaag om] LT", nextDay: "[morgen om] LT", nextWeek: "dddd [om] LT", lastDay: "[gisteren om] LT", lastWeek: "[afgelopen] dddd [om] LT", sameElse: "L" }, relativeTime: { future: "over %s", past: "%s geleden", s: "een paar seconden", m: "één minuut", mm: "%d minuten", h: "één uur", hh: "%d uur", d: "één dag", dd: "%d dagen", M: "één maand", MM: "%d maanden", y: "één jaar", yy: "%d jaar" }, ordinalParse: /\d{1,2}(ste|de)/, ordinal: function (a) { return a + (1 === a || 8 === a || a >= 20 ? "ste" : "de") }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("nn", { months: "januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"), monthsShort: "jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"), weekdays: "sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"), weekdaysShort: "sun_mån_tys_ons_tor_fre_lau".split("_"), weekdaysMin: "su_må_ty_on_to_fr_lø".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY [kl.] H:mm", LLLL: "dddd D. MMMM YYYY [kl.] HH:mm" }, calendar: { sameDay: "[I dag klokka] LT", nextDay: "[I morgon klokka] LT", nextWeek: "dddd [klokka] LT", lastDay: "[I går klokka] LT", lastWeek: "[Føregåande] dddd [klokka] LT", sameElse: "L" }, relativeTime: { future: "om %s", past: "for %s sidan", s: "nokre sekund", m: "eit minutt", mm: "%d minutt", h: "ein time", hh: "%d timar", d: "ein dag", dd: "%d dagar", M: "ein månad", MM: "%d månader", y: "eit år", yy: "%d år" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), { 1: "੧", 2: "੨", 3: "੩", 4: "੪", 5: "੫", 6: "੬", 7: "੭", 8: "੮", 9: "੯", 0: "੦" }), Ig = { "੧": "1", "੨": "2", "੩": "3", "੪": "4", "੫": "5", "੬": "6", "੭": "7", "੮": "8", "੯": "9", "੦": "0" }, Jg = (Pf.defineLocale("pa-in", { months: "ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"), monthsShort: "ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"), weekdays: "ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"), weekdaysShort: "ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"), weekdaysMin: "ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"), longDateFormat: { LT: "A h:mm ਵਜੇ", LTS: "A h:mm:ss ਵਜੇ", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm ਵਜੇ", LLLL: "dddd, D MMMM YYYY, A h:mm ਵਜੇ" }, calendar: { sameDay: "[ਅਜ] LT", nextDay: "[ਕਲ] LT", nextWeek: "dddd, LT", lastDay: "[ਕਲ] LT", lastWeek: "[ਪਿਛਲੇ] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s ਵਿੱਚ", past: "%s ਪਿਛਲੇ", s: "ਕੁਝ ਸਕਿੰਟ", m: "ਇਕ ਮਿੰਟ", mm: "%d ਮਿੰਟ", h: "ਇੱਕ ਘੰਟਾ", hh: "%d ਘੰਟੇ", d: "ਇੱਕ ਦਿਨ", dd: "%d ਦਿਨ", M: "ਇੱਕ ਮਹੀਨਾ", MM: "%d ਮਹੀਨੇ", y: "ਇੱਕ ਸਾਲ", yy: "%d ਸਾਲ" }, preparse: function (a) { return a.replace(/[੧੨੩੪੫੬੭੮੯੦]/g, function (a) { return Ig[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Hg[a] }) }, meridiemParse: /ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "ਰਾਤ" === b ? 4 > a ? a : a + 12 : "ਸਵੇਰ" === b ? a : "ਦੁਪਹਿਰ" === b ? a >= 10 ? a : a + 12 : "ਸ਼ਾਮ" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 4 > a ? "ਰਾਤ" : 10 > a ? "ਸਵੇਰ" : 17 > a ? "ਦੁਪਹਿਰ" : 20 > a ? "ਸ਼ਾਮ" : "ਰਾਤ" }, week: { dow: 0, doy: 6 } }), "styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_")), Kg = "stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"), Lg = (Pf.defineLocale("pl", { months: function (a, b) { return "" === b ? "(" + Kg[a.month()] + "|" + Jg[a.month()] + ")" : /D MMMM/.test(b) ? Kg[a.month()] : Jg[a.month()] }, monthsShort: "sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"), weekdays: "niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"), weekdaysShort: "nie_pon_wt_śr_czw_pt_sb".split("_"), weekdaysMin: "Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Dziś o] LT", nextDay: "[Jutro o] LT", nextWeek: "[W] dddd [o] LT", lastDay: "[Wczoraj o] LT", lastWeek: function () { switch (this.day()) { case 0: return "[W zeszłą niedzielę o] LT"; case 3: return "[W zeszłą środę o] LT"; case 6: return "[W zeszłą sobotę o] LT"; default: return "[W zeszły] dddd [o] LT" } }, sameElse: "L" }, relativeTime: { future: "za %s", past: "%s temu", s: "kilka sekund", m: Gd, mm: Gd, h: Gd, hh: Gd, d: "1 dzień", dd: "%d dni", M: "miesiąc", MM: Gd, y: "rok", yy: Gd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("pt-br", { months: "Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"), monthsShort: "Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"), weekdays: "Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"), weekdaysShort: "Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"), weekdaysMin: "Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D [de] MMMM [de] YYYY", LLL: "D [de] MMMM [de] YYYY [às] HH:mm", LLLL: "dddd, D [de] MMMM [de] YYYY [às] HH:mm" }, calendar: { sameDay: "[Hoje às] LT", nextDay: "[Amanhã às] LT", nextWeek: "dddd [às] LT", lastDay: "[Ontem às] LT", lastWeek: function () { return 0 === this.day() || 6 === this.day() ? "[Último] dddd [às] LT" : "[Última] dddd [às] LT" }, sameElse: "L" }, relativeTime: { future: "em %s", past: "%s atrás", s: "poucos segundos", m: "um minuto", mm: "%d minutos", h: "uma hora", hh: "%d horas", d: "um dia", dd: "%d dias", M: "um mês", MM: "%d meses", y: "um ano", yy: "%d anos" }, ordinalParse: /\d{1,2}º/, ordinal: "%dº" }), Pf.defineLocale("pt", { months: "Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro".split("_"), monthsShort: "Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"), weekdays: "Domingo_Segunda-Feira_Terça-Feira_Quarta-Feira_Quinta-Feira_Sexta-Feira_Sábado".split("_"), weekdaysShort: "Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"), weekdaysMin: "Dom_2ª_3ª_4ª_5ª_6ª_Sáb".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D [de] MMMM [de] YYYY", LLL: "D [de] MMMM [de] YYYY HH:mm", LLLL: "dddd, D [de] MMMM [de] YYYY HH:mm" }, calendar: { sameDay: "[Hoje às] LT", nextDay: "[Amanhã às] LT", nextWeek: "dddd [às] LT", lastDay: "[Ontem às] LT", lastWeek: function () { return 0 === this.day() || 6 === this.day() ? "[Último] dddd [às] LT" : "[Última] dddd [às] LT" }, sameElse: "L" }, relativeTime: { future: "em %s", past: "há %s", s: "segundos", m: "um minuto", mm: "%d minutos", h: "uma hora", hh: "%d horas", d: "um dia", dd: "%d dias", M: "um mês", MM: "%d meses", y: "um ano", yy: "%d anos" }, ordinalParse: /\d{1,2}º/, ordinal: "%dº", week: { dow: 1, doy: 4 } }), Pf.defineLocale("ro", { months: "ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"), monthsShort: "ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"), weekdays: "duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"), weekdaysShort: "Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"), weekdaysMin: "Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY H:mm", LLLL: "dddd, D MMMM YYYY H:mm" }, calendar: { sameDay: "[azi la] LT", nextDay: "[mâine la] LT", nextWeek: "dddd [la] LT", lastDay: "[ieri la] LT", lastWeek: "[fosta] dddd [la] LT", sameElse: "L" }, relativeTime: { future: "peste %s", past: "%s în urmă", s: "câteva secunde", m: "un minut", mm: Hd, h: "o oră", hh: Hd, d: "o zi", dd: Hd, M: "o lună", MM: Hd, y: "un an", yy: Hd }, week: { dow: 1, doy: 7 } }), [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i]), Mg = (Pf.defineLocale("ru", { months: { format: "января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"), standalone: "январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_") }, monthsShort: { format: "янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек".split("_"), standalone: "янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_") }, weekdays: { standalone: "воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"), format: "воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"), isFormat: /\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/ }, weekdaysShort: "вс_пн_вт_ср_чт_пт_сб".split("_"), weekdaysMin: "вс_пн_вт_ср_чт_пт_сб".split("_"), monthsParse: Lg, longMonthsParse: Lg, shortMonthsParse: Lg, longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY г.", LLL: "D MMMM YYYY г., HH:mm", LLLL: "dddd, D MMMM YYYY г., HH:mm" }, calendar: { sameDay: "[Сегодня в] LT", nextDay: "[Завтра в] LT", lastDay: "[Вчера в] LT", nextWeek: function (a) { if (a.week() === this.week()) return 2 === this.day() ? "[Во] dddd [в] LT" : "[В] dddd [в] LT"; switch (this.day()) { case 0: return "[В следующее] dddd [в] LT"; case 1: case 2: case 4: return "[В следующий] dddd [в] LT"; case 3: case 5: case 6: return "[В следующую] dddd [в] LT" } }, lastWeek: function (a) { if (a.week() === this.week()) return 2 === this.day() ? "[Во] dddd [в] LT" : "[В] dddd [в] LT"; switch (this.day()) { case 0: return "[В прошлое] dddd [в] LT"; case 1: case 2: case 4: return "[В прошлый] dddd [в] LT"; case 3: case 5: case 6: return "[В прошлую] dddd [в] LT" } }, sameElse: "L" }, relativeTime: { future: "через %s", past: "%s назад", s: "несколько секунд", m: Jd, mm: Jd, h: "час", hh: Jd, d: "день", dd: Jd, M: "месяц", MM: Jd, y: "год", yy: Jd }, meridiemParse: /ночи|утра|дня|вечера/i, isPM: function (a) { return /^(дня|вечера)$/.test(a) }, meridiem: function (a, b, c) { return 4 > a ? "ночи" : 12 > a ? "утра" : 17 > a ? "дня" : "вечера" }, ordinalParse: /\d{1,2}-(й|го|я)/, ordinal: function (a, b) { switch (b) { case "M": case "d": case "DDD": return a + "-й"; case "D": return a + "-го"; case "w": case "W": return a + "-я"; default: return a } }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("se", { months: "ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"), monthsShort: "ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"), weekdays: "sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"), weekdaysShort: "sotn_vuos_maŋ_gask_duor_bear_láv".split("_"), weekdaysMin: "s_v_m_g_d_b_L".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "MMMM D. [b.] YYYY", LLL: "MMMM D. [b.] YYYY [ti.] HH:mm", LLLL: "dddd, MMMM D. [b.] YYYY [ti.] HH:mm" }, calendar: { sameDay: "[otne ti] LT", nextDay: "[ihttin ti] LT", nextWeek: "dddd [ti] LT", lastDay: "[ikte ti] LT", lastWeek: "[ovddit] dddd [ti] LT", sameElse: "L" }, relativeTime: { future: "%s geažes", past: "maŋit %s", s: "moadde sekunddat", m: "okta minuhta", mm: "%d minuhtat", h: "okta diimmu", hh: "%d diimmut", d: "okta beaivi", dd: "%d beaivvit", M: "okta mánnu", MM: "%d mánut", y: "okta jahki", yy: "%d jagit" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("si", { months: "ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"), monthsShort: "ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"), weekdays: "ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"), weekdaysShort: "ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"), weekdaysMin: "ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"), longDateFormat: { LT: "a h:mm", LTS: "a h:mm:ss", L: "YYYY/MM/DD", LL: "YYYY MMMM D", LLL: "YYYY MMMM D, a h:mm", LLLL: "YYYY MMMM D [වැනි] dddd, a h:mm:ss" }, calendar: { sameDay: "[අද] LT[ට]", nextDay: "[හෙට] LT[ට]", nextWeek: "dddd LT[ට]", lastDay: "[ඊයේ] LT[ට]", lastWeek: "[පසුගිය] dddd LT[ට]", sameElse: "L" }, relativeTime: { future: "%sකින්", past: "%sකට පෙර", s: "තත්පර කිහිපය", m: "මිනිත්තුව", mm: "මිනිත්තු %d", h: "පැය", hh: "පැය %d", d: "දිනය", dd: "දින %d", M: "මාසය", MM: "මාස %d", y: "වසර", yy: "වසර %d" }, ordinalParse: /\d{1,2} වැනි/, ordinal: function (a) { return a + " වැනි" }, meridiemParse: /පෙර වරු|පස් වරු|පෙ.ව|ප.ව./, isPM: function (a) { return "ප.ව." === a || "පස් වරු" === a }, meridiem: function (a, b, c) { return a > 11 ? c ? "ප.ව." : "පස් වරු" : c ? "පෙ.ව." : "පෙර වරු" } }), "január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_")), Ng = "jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_"), Og = (Pf.defineLocale("sk", { months: Mg, monthsShort: Ng, weekdays: "nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"), weekdaysShort: "ne_po_ut_st_št_pi_so".split("_"), weekdaysMin: "ne_po_ut_st_št_pi_so".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD.MM.YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd D. MMMM YYYY H:mm" }, calendar: { sameDay: "[dnes o] LT", nextDay: "[zajtra o] LT", nextWeek: function () { switch (this.day()) { case 0: return "[v nedeľu o] LT"; case 1: case 2: return "[v] dddd [o] LT"; case 3: return "[v stredu o] LT"; case 4: return "[vo štvrtok o] LT"; case 5: return "[v piatok o] LT"; case 6: return "[v sobotu o] LT" } }, lastDay: "[včera o] LT", lastWeek: function () { switch (this.day()) { case 0: return "[minulú nedeľu o] LT"; case 1: case 2: return "[minulý] dddd [o] LT"; case 3: return "[minulú stredu o] LT"; case 4: case 5: return "[minulý] dddd [o] LT"; case 6: return "[minulú sobotu o] LT" } }, sameElse: "L" }, relativeTime: { future: "za %s", past: "pred %s", s: Ld, m: Ld, mm: Ld, h: Ld, hh: Ld, d: Ld, dd: Ld, M: Ld, MM: Ld, y: Ld, yy: Ld }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("sl", { months: "januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"), monthsShort: "jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"), weekdays: "nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"), weekdaysShort: "ned._pon._tor._sre._čet._pet._sob.".split("_"), weekdaysMin: "ne_po_to_sr_če_pe_so".split("_"), longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[danes ob] LT", nextDay: "[jutri ob] LT", nextWeek: function () { switch (this.day()) { case 0: return "[v] [nedeljo] [ob] LT"; case 3: return "[v] [sredo] [ob] LT"; case 6: return "[v] [soboto] [ob] LT"; case 1: case 2: case 4: case 5: return "[v] dddd [ob] LT" } }, lastDay: "[včeraj ob] LT", lastWeek: function () { switch (this.day()) { case 0: return "[prejšnjo] [nedeljo] [ob] LT"; case 3: return "[prejšnjo] [sredo] [ob] LT"; case 6: return "[prejšnjo] [soboto] [ob] LT"; case 1: case 2: case 4: case 5: return "[prejšnji] dddd [ob] LT" } }, sameElse: "L" }, relativeTime: { future: "čez %s", past: "pred %s", s: Md, m: Md, mm: Md, h: Md, hh: Md, d: Md, dd: Md, M: Md, MM: Md, y: Md, yy: Md }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), Pf.defineLocale("sq", { months: "Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"), monthsShort: "Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"), weekdays: "E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"), weekdaysShort: "Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"), weekdaysMin: "D_H_Ma_Më_E_P_Sh".split("_"), meridiemParse: /PD|MD/, isPM: function (a) { return "M" === a.charAt(0) }, meridiem: function (a, b, c) { return 12 > a ? "PD" : "MD" }, longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Sot në] LT", nextDay: "[Nesër në] LT", nextWeek: "dddd [në] LT", lastDay: "[Dje në] LT", lastWeek: "dddd [e kaluar në] LT", sameElse: "L" }, relativeTime: { future: "në %s", past: "%s më parë", s: "disa sekonda", m: "një minutë", mm: "%d minuta", h: "një orë", hh: "%d orë", d: "një ditë", dd: "%d ditë", M: "një muaj", MM: "%d muaj", y: "një vit", yy: "%d vite" }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), { words: { m: ["један минут", "једне минуте"], mm: ["минут", "минуте", "минута"], h: ["један сат", "једног сата"], hh: ["сат", "сата", "сати"], dd: ["дан", "дана", "дана"], MM: ["месец", "месеца", "месеци"], yy: ["година", "године", "година"] }, correctGrammaticalCase: function (a, b) { return 1 === a ? b[0] : a >= 2 && 4 >= a ? b[1] : b[2] }, translate: function (a, b, c) { var d = Og.words[c]; return 1 === c.length ? b ? d[0] : d[1] : a + " " + Og.correctGrammaticalCase(a, d) } }), Pg = (Pf.defineLocale("sr-cyrl", {
        months: ["јануар", "фебруар", "март", "април", "мај", "јун", "јул", "август", "септембар", "октобар", "новембар", "децембар"], monthsShort: ["јан.", "феб.", "мар.", "апр.", "мај", "јун", "јул", "авг.", "сеп.", "окт.", "нов.", "дец."], weekdays: ["недеља", "понедељак", "уторак", "среда", "четвртак", "петак", "субота"], weekdaysShort: ["нед.", "пон.", "уто.", "сре.", "чет.", "пет.", "суб."], weekdaysMin: ["не", "по", "ут", "ср", "че", "пе", "су"], longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: {
            sameDay: "[данас у] LT", nextDay: "[сутра у] LT", nextWeek: function () { switch (this.day()) { case 0: return "[у] [недељу] [у] LT"; case 3: return "[у] [среду] [у] LT"; case 6: return "[у] [суботу] [у] LT"; case 1: case 2: case 4: case 5: return "[у] dddd [у] LT" } }, lastDay: "[јуче у] LT", lastWeek: function () {
                var a = ["[прошле] [недеље] [у] LT", "[прошлог] [понедељка] [у] LT", "[прошлог] [уторка] [у] LT", "[прошле] [среде] [у] LT", "[прошлог] [четвртка] [у] LT", "[прошлог] [петка] [у] LT", "[прошле] [суботе] [у] LT"];
                return a[this.day()]
            }, sameElse: "L"
        }, relativeTime: { future: "за %s", past: "пре %s", s: "неколико секунди", m: Og.translate, mm: Og.translate, h: Og.translate, hh: Og.translate, d: "дан", dd: Og.translate, M: "месец", MM: Og.translate, y: "годину", yy: Og.translate }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 }
    }), { words: { m: ["jedan minut", "jedne minute"], mm: ["minut", "minute", "minuta"], h: ["jedan sat", "jednog sata"], hh: ["sat", "sata", "sati"], dd: ["dan", "dana", "dana"], MM: ["mesec", "meseca", "meseci"], yy: ["godina", "godine", "godina"] }, correctGrammaticalCase: function (a, b) { return 1 === a ? b[0] : a >= 2 && 4 >= a ? b[1] : b[2] }, translate: function (a, b, c) { var d = Pg.words[c]; return 1 === c.length ? b ? d[0] : d[1] : a + " " + Pg.correctGrammaticalCase(a, d) } }), Qg = (Pf.defineLocale("sr", { months: ["januar", "februar", "mart", "april", "maj", "jun", "jul", "avgust", "septembar", "oktobar", "novembar", "decembar"], monthsShort: ["jan.", "feb.", "mar.", "apr.", "maj", "jun", "jul", "avg.", "sep.", "okt.", "nov.", "dec."], weekdays: ["nedelja", "ponedeljak", "utorak", "sreda", "četvrtak", "petak", "subota"], weekdaysShort: ["ned.", "pon.", "uto.", "sre.", "čet.", "pet.", "sub."], weekdaysMin: ["ne", "po", "ut", "sr", "če", "pe", "su"], longDateFormat: { LT: "H:mm", LTS: "H:mm:ss", L: "DD. MM. YYYY", LL: "D. MMMM YYYY", LLL: "D. MMMM YYYY H:mm", LLLL: "dddd, D. MMMM YYYY H:mm" }, calendar: { sameDay: "[danas u] LT", nextDay: "[sutra u] LT", nextWeek: function () { switch (this.day()) { case 0: return "[u] [nedelju] [u] LT"; case 3: return "[u] [sredu] [u] LT"; case 6: return "[u] [subotu] [u] LT"; case 1: case 2: case 4: case 5: return "[u] dddd [u] LT" } }, lastDay: "[juče u] LT", lastWeek: function () { var a = ["[prošle] [nedelje] [u] LT", "[prošlog] [ponedeljka] [u] LT", "[prošlog] [utorka] [u] LT", "[prošle] [srede] [u] LT", "[prošlog] [četvrtka] [u] LT", "[prošlog] [petka] [u] LT", "[prošle] [subote] [u] LT"]; return a[this.day()] }, sameElse: "L" }, relativeTime: { future: "za %s", past: "pre %s", s: "nekoliko sekundi", m: Pg.translate, mm: Pg.translate, h: Pg.translate, hh: Pg.translate, d: "dan", dd: Pg.translate, M: "mesec", MM: Pg.translate, y: "godinu", yy: Pg.translate }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 7 } }), Pf.defineLocale("sv", { months: "januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"), monthsShort: "jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"), weekdays: "söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"), weekdaysShort: "sön_mån_tis_ons_tor_fre_lör".split("_"), weekdaysMin: "sö_må_ti_on_to_fr_lö".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "YYYY-MM-DD", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[Idag] LT", nextDay: "[Imorgon] LT", lastDay: "[Igår] LT", nextWeek: "[På] dddd LT", lastWeek: "[I] dddd[s] LT", sameElse: "L" }, relativeTime: { future: "om %s", past: "för %s sedan", s: "några sekunder", m: "en minut", mm: "%d minuter", h: "en timme", hh: "%d timmar", d: "en dag", dd: "%d dagar", M: "en månad", MM: "%d månader", y: "ett år", yy: "%d år" }, ordinalParse: /\d{1,2}(e|a)/, ordinal: function (a) { var b = a % 10, c = 1 === ~~(a % 100 / 10) ? "e" : 1 === b ? "a" : 2 === b ? "a" : "e"; return a + c }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("sw", { months: "Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"), monthsShort: "Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"), weekdays: "Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"), weekdaysShort: "Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"), weekdaysMin: "J2_J3_J4_J5_Al_Ij_J1".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[leo saa] LT", nextDay: "[kesho saa] LT", nextWeek: "[wiki ijayo] dddd [saat] LT", lastDay: "[jana] LT", lastWeek: "[wiki iliyopita] dddd [saat] LT", sameElse: "L" }, relativeTime: { future: "%s baadaye", past: "tokea %s", s: "hivi punde", m: "dakika moja", mm: "dakika %d", h: "saa limoja", hh: "masaa %d", d: "siku moja", dd: "masiku %d", M: "mwezi mmoja", MM: "miezi %d", y: "mwaka mmoja", yy: "miaka %d" }, week: { dow: 1, doy: 7 } }), { 1: "௧", 2: "௨", 3: "௩", 4: "௪", 5: "௫", 6: "௬", 7: "௭", 8: "௮", 9: "௯", 0: "௦" }), Rg = { "௧": "1", "௨": "2", "௩": "3", "௪": "4", "௫": "5", "௬": "6", "௭": "7", "௮": "8", "௯": "9", "௦": "0" }, Sg = (Pf.defineLocale("ta", { months: "ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"), monthsShort: "ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"), weekdays: "ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"), weekdaysShort: "ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"), weekdaysMin: "ஞா_தி_செ_பு_வி_வெ_ச".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, HH:mm", LLLL: "dddd, D MMMM YYYY, HH:mm" }, calendar: { sameDay: "[இன்று] LT", nextDay: "[நாளை] LT", nextWeek: "dddd, LT", lastDay: "[நேற்று] LT", lastWeek: "[கடந்த வாரம்] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s இல்", past: "%s முன்", s: "ஒரு சில விநாடிகள்", m: "ஒரு நிமிடம்", mm: "%d நிமிடங்கள்", h: "ஒரு மணி நேரம்", hh: "%d மணி நேரம்", d: "ஒரு நாள்", dd: "%d நாட்கள்", M: "ஒரு மாதம்", MM: "%d மாதங்கள்", y: "ஒரு வருடம்", yy: "%d ஆண்டுகள்" }, ordinalParse: /\d{1,2}வது/, ordinal: function (a) { return a + "வது" }, preparse: function (a) { return a.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (a) { return Rg[a] }) }, postformat: function (a) { return a.replace(/\d/g, function (a) { return Qg[a] }) }, meridiemParse: /யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/, meridiem: function (a, b, c) { return 2 > a ? " யாமம்" : 6 > a ? " வைகறை" : 10 > a ? " காலை" : 14 > a ? " நண்பகல்" : 18 > a ? " எற்பாடு" : 22 > a ? " மாலை" : " யாமம்" }, meridiemHour: function (a, b) { return 12 === a && (a = 0), "யாமம்" === b ? 2 > a ? a : a + 12 : "வைகறை" === b || "காலை" === b ? a : "நண்பகல்" === b && a >= 10 ? a : a + 12 }, week: { dow: 0, doy: 6 } }), Pf.defineLocale("te", { months: "జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జూలై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"), monthsShort: "జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జూలై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"), weekdays: "ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"), weekdaysShort: "ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"), weekdaysMin: "ఆ_సో_మం_బు_గు_శు_శ".split("_"), longDateFormat: { LT: "A h:mm", LTS: "A h:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY, A h:mm", LLLL: "dddd, D MMMM YYYY, A h:mm" }, calendar: { sameDay: "[నేడు] LT", nextDay: "[రేపు] LT", nextWeek: "dddd, LT", lastDay: "[నిన్న] LT", lastWeek: "[గత] dddd, LT", sameElse: "L" }, relativeTime: { future: "%s లో", past: "%s క్రితం", s: "కొన్ని క్షణాలు", m: "ఒక నిమిషం", mm: "%d నిమిషాలు", h: "ఒక గంట", hh: "%d గంటలు", d: "ఒక రోజు", dd: "%d రోజులు", M: "ఒక నెల", MM: "%d నెలలు", y: "ఒక సంవత్సరం", yy: "%d సంవత్సరాలు" }, ordinalParse: /\d{1,2}వ/, ordinal: "%dవ", meridiemParse: /రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "రాత్రి" === b ? 4 > a ? a : a + 12 : "ఉదయం" === b ? a : "మధ్యాహ్నం" === b ? a >= 10 ? a : a + 12 : "సాయంత్రం" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { return 4 > a ? "రాత్రి" : 10 > a ? "ఉదయం" : 17 > a ? "మధ్యాహ్నం" : 20 > a ? "సాయంత్రం" : "రాత్రి" }, week: { dow: 0, doy: 6 } }), Pf.defineLocale("th", { months: "มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"), monthsShort: "มกรา_กุมภา_มีนา_เมษา_พฤษภา_มิถุนา_กรกฎา_สิงหา_กันยา_ตุลา_พฤศจิกา_ธันวา".split("_"), weekdays: "อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"), weekdaysShort: "อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"), weekdaysMin: "อา._จ._อ._พ._พฤ._ศ._ส.".split("_"), longDateFormat: { LT: "H นาฬิกา m นาที", LTS: "H นาฬิกา m นาที s วินาที", L: "YYYY/MM/DD", LL: "D MMMM YYYY", LLL: "D MMMM YYYY เวลา H นาฬิกา m นาที", LLLL: "วันddddที่ D MMMM YYYY เวลา H นาฬิกา m นาที" }, meridiemParse: /ก่อนเที่ยง|หลังเที่ยง/, isPM: function (a) { return "หลังเที่ยง" === a }, meridiem: function (a, b, c) { return 12 > a ? "ก่อนเที่ยง" : "หลังเที่ยง" }, calendar: { sameDay: "[วันนี้ เวลา] LT", nextDay: "[พรุ่งนี้ เวลา] LT", nextWeek: "dddd[หน้า เวลา] LT", lastDay: "[เมื่อวานนี้ เวลา] LT", lastWeek: "[วัน]dddd[ที่แล้ว เวลา] LT", sameElse: "L" }, relativeTime: { future: "อีก %s", past: "%sที่แล้ว", s: "ไม่กี่วินาที", m: "1 นาที", mm: "%d นาที", h: "1 ชั่วโมง", hh: "%d ชั่วโมง", d: "1 วัน", dd: "%d วัน", M: "1 เดือน", MM: "%d เดือน", y: "1 ปี", yy: "%d ปี" } }), Pf.defineLocale("tl-ph", { months: "Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"), monthsShort: "Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"), weekdays: "Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"), weekdaysShort: "Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"), weekdaysMin: "Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "MM/D/YYYY", LL: "MMMM D, YYYY", LLL: "MMMM D, YYYY HH:mm", LLLL: "dddd, MMMM DD, YYYY HH:mm" }, calendar: { sameDay: "[Ngayon sa] LT", nextDay: "[Bukas sa] LT", nextWeek: "dddd [sa] LT", lastDay: "[Kahapon sa] LT", lastWeek: "dddd [huling linggo] LT", sameElse: "L" }, relativeTime: { future: "sa loob ng %s", past: "%s ang nakalipas", s: "ilang segundo", m: "isang minuto", mm: "%d minuto", h: "isang oras", hh: "%d oras", d: "isang araw", dd: "%d araw", M: "isang buwan", MM: "%d buwan", y: "isang taon", yy: "%d taon" }, ordinalParse: /\d{1,2}/, ordinal: function (a) { return a }, week: { dow: 1, doy: 4 } }), "pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_")), Tg = (Pf.defineLocale("tlh", { months: "tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"), monthsShort: "jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"), weekdays: "lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"), weekdaysShort: "lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"), weekdaysMin: "lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[DaHjaj] LT", nextDay: "[wa’leS] LT", nextWeek: "LLL", lastDay: "[wa’Hu’] LT", lastWeek: "LLL", sameElse: "L" }, relativeTime: { future: Nd, past: Od, s: "puS lup", m: "wa’ tup", mm: Pd, h: "wa’ rep", hh: Pd, d: "wa’ jaj", dd: Pd, M: "wa’ jar", MM: Pd, y: "wa’ DIS", yy: Pd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), { 1: "'inci", 5: "'inci", 8: "'inci", 70: "'inci", 80: "'inci", 2: "'nci", 7: "'nci", 20: "'nci", 50: "'nci", 3: "'üncü", 4: "'üncü", 100: "'üncü", 6: "'ncı", 9: "'uncu", 10: "'uncu", 30: "'uncu", 60: "'ıncı", 90: "'ıncı" }), Ug = (Pf.defineLocale("tr", { months: "Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"), monthsShort: "Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"), weekdays: "Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"), weekdaysShort: "Paz_Pts_Sal_Çar_Per_Cum_Cts".split("_"), weekdaysMin: "Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd, D MMMM YYYY HH:mm" }, calendar: { sameDay: "[bugün saat] LT", nextDay: "[yarın saat] LT", nextWeek: "[haftaya] dddd [saat] LT", lastDay: "[dün] LT", lastWeek: "[geçen hafta] dddd [saat] LT", sameElse: "L" }, relativeTime: { future: "%s sonra", past: "%s önce", s: "birkaç saniye", m: "bir dakika", mm: "%d dakika", h: "bir saat", hh: "%d saat", d: "bir gün", dd: "%d gün", M: "bir ay", MM: "%d ay", y: "bir yıl", yy: "%d yıl" }, ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/, ordinal: function (a) { if (0 === a) return a + "'ıncı"; var b = a % 10, c = a % 100 - b, d = a >= 100 ? 100 : null; return a + (Tg[b] || Tg[c] || Tg[d]) }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("tzl", { months: "Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"), monthsShort: "Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"), weekdays: "Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"), weekdaysShort: "Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"), weekdaysMin: "Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"), longDateFormat: { LT: "HH.mm", LTS: "HH.mm.ss", L: "DD.MM.YYYY", LL: "D. MMMM [dallas] YYYY", LLL: "D. MMMM [dallas] YYYY HH.mm", LLLL: "dddd, [li] D. MMMM [dallas] YYYY HH.mm" }, meridiemParse: /d\'o|d\'a/i, isPM: function (a) { return "d'o" === a.toLowerCase() }, meridiem: function (a, b, c) { return a > 11 ? c ? "d'o" : "D'O" : c ? "d'a" : "D'A" }, calendar: { sameDay: "[oxhi à] LT", nextDay: "[demà à] LT", nextWeek: "dddd [à] LT", lastDay: "[ieiri à] LT", lastWeek: "[sür el] dddd [lasteu à] LT", sameElse: "L" }, relativeTime: { future: "osprei %s", past: "ja%s", s: Rd, m: Rd, mm: Rd, h: Rd, hh: Rd, d: Rd, dd: Rd, M: Rd, MM: Rd, y: Rd, yy: Rd }, ordinalParse: /\d{1,2}\./, ordinal: "%d.", week: { dow: 1, doy: 4 } }), Pf.defineLocale("tzm-latn", { months: "innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"), monthsShort: "innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"), weekdays: "asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"), weekdaysShort: "asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"), weekdaysMin: "asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[asdkh g] LT", nextDay: "[aska g] LT", nextWeek: "dddd [g] LT", lastDay: "[assant g] LT", lastWeek: "dddd [g] LT", sameElse: "L" }, relativeTime: { future: "dadkh s yan %s", past: "yan %s", s: "imik", m: "minuḍ", mm: "%d minuḍ", h: "saɛa", hh: "%d tassaɛin", d: "ass", dd: "%d ossan", M: "ayowr", MM: "%d iyyirn", y: "asgas", yy: "%d isgasn" }, week: { dow: 6, doy: 12 } }), Pf.defineLocale("tzm", { months: "ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"), monthsShort: "ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"), weekdays: "ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"), weekdaysShort: "ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"), weekdaysMin: "ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "dddd D MMMM YYYY HH:mm" }, calendar: { sameDay: "[ⴰⵙⴷⵅ ⴴ] LT", nextDay: "[ⴰⵙⴽⴰ ⴴ] LT", nextWeek: "dddd [ⴴ] LT", lastDay: "[ⴰⵚⴰⵏⵜ ⴴ] LT", lastWeek: "dddd [ⴴ] LT", sameElse: "L" }, relativeTime: { future: "ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s", past: "ⵢⴰⵏ %s", s: "ⵉⵎⵉⴽ", m: "ⵎⵉⵏⵓⴺ", mm: "%d ⵎⵉⵏⵓⴺ", h: "ⵙⴰⵄⴰ", hh: "%d ⵜⴰⵙⵙⴰⵄⵉⵏ", d: "ⴰⵙⵙ", dd: "%d oⵙⵙⴰⵏ", M: "ⴰⵢoⵓⵔ", MM: "%d ⵉⵢⵢⵉⵔⵏ", y: "ⴰⵙⴳⴰⵙ", yy: "%d ⵉⵙⴳⴰⵙⵏ" }, week: { dow: 6, doy: 12 } }), Pf.defineLocale("uk", { months: { format: "січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"), standalone: "січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_") }, monthsShort: "січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"), weekdays: Ud, weekdaysShort: "нд_пн_вт_ср_чт_пт_сб".split("_"), weekdaysMin: "нд_пн_вт_ср_чт_пт_сб".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD.MM.YYYY", LL: "D MMMM YYYY р.", LLL: "D MMMM YYYY р., HH:mm", LLLL: "dddd, D MMMM YYYY р., HH:mm" }, calendar: { sameDay: Vd("[Сьогодні "), nextDay: Vd("[Завтра "), lastDay: Vd("[Вчора "), nextWeek: Vd("[У] dddd ["), lastWeek: function () { switch (this.day()) { case 0: case 3: case 5: case 6: return Vd("[Минулої] dddd [").call(this); case 1: case 2: case 4: return Vd("[Минулого] dddd [").call(this) } }, sameElse: "L" }, relativeTime: { future: "за %s", past: "%s тому", s: "декілька секунд", m: Td, mm: Td, h: "годину", hh: Td, d: "день", dd: Td, M: "місяць", MM: Td, y: "рік", yy: Td }, meridiemParse: /ночі|ранку|дня|вечора/, isPM: function (a) { return /^(дня|вечора)$/.test(a) }, meridiem: function (a, b, c) { return 4 > a ? "ночі" : 12 > a ? "ранку" : 17 > a ? "дня" : "вечора" }, ordinalParse: /\d{1,2}-(й|го)/, ordinal: function (a, b) { switch (b) { case "M": case "d": case "DDD": case "w": case "W": return a + "-й"; case "D": return a + "-го"; default: return a } }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("uz", { months: "январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"), monthsShort: "янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"), weekdays: "Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"), weekdaysShort: "Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"), weekdaysMin: "Як_Ду_Се_Чо_Па_Жу_Ша".split("_"), longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM YYYY", LLL: "D MMMM YYYY HH:mm", LLLL: "D MMMM YYYY, dddd HH:mm" }, calendar: { sameDay: "[Бугун соат] LT [да]", nextDay: "[Эртага] LT [да]", nextWeek: "dddd [куни соат] LT [да]", lastDay: "[Кеча соат] LT [да]", lastWeek: "[Утган] dddd [куни соат] LT [да]", sameElse: "L" }, relativeTime: { future: "Якин %s ичида", past: "Бир неча %s олдин", s: "фурсат", m: "бир дакика", mm: "%d дакика", h: "бир соат", hh: "%d соат", d: "бир кун", dd: "%d кун", M: "бир ой", MM: "%d ой", y: "бир йил", yy: "%d йил" }, week: { dow: 1, doy: 7 } }), Pf.defineLocale("vi", { months: "tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"), monthsShort: "Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12".split("_"), weekdays: "chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"), weekdaysShort: "CN_T2_T3_T4_T5_T6_T7".split("_"), weekdaysMin: "CN_T2_T3_T4_T5_T6_T7".split("_"), meridiemParse: /sa|ch/i, isPM: function (a) { return /^ch$/i.test(a) }, meridiem: function (a, b, c) { return 12 > a ? c ? "sa" : "SA" : c ? "ch" : "CH" }, longDateFormat: { LT: "HH:mm", LTS: "HH:mm:ss", L: "DD/MM/YYYY", LL: "D MMMM [năm] YYYY", LLL: "D MMMM [năm] YYYY HH:mm", LLLL: "dddd, D MMMM [năm] YYYY HH:mm", l: "DD/M/YYYY", ll: "D MMM YYYY", lll: "D MMM YYYY HH:mm", llll: "ddd, D MMM YYYY HH:mm" }, calendar: { sameDay: "[Hôm nay lúc] LT", nextDay: "[Ngày mai lúc] LT", nextWeek: "dddd [tuần tới lúc] LT", lastDay: "[Hôm qua lúc] LT", lastWeek: "dddd [tuần rồi lúc] LT", sameElse: "L" }, relativeTime: { future: "%s tới", past: "%s trước", s: "vài giây", m: "một phút", mm: "%d phút", h: "một giờ", hh: "%d giờ", d: "một ngày", dd: "%d ngày", M: "một tháng", MM: "%d tháng", y: "một năm", yy: "%d năm" }, ordinalParse: /\d{1,2}/, ordinal: function (a) { return a }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("zh-cn", { months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"), monthsShort: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"), weekdays: "星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"), weekdaysShort: "周日_周一_周二_周三_周四_周五_周六".split("_"), weekdaysMin: "日_一_二_三_四_五_六".split("_"), longDateFormat: { LT: "Ah点mm分", LTS: "Ah点m分s秒", L: "YYYY-MM-DD", LL: "YYYY年MMMD日", LLL: "YYYY年MMMD日Ah点mm分", LLLL: "YYYY年MMMD日ddddAh点mm分", l: "YYYY-MM-DD", ll: "YYYY年MMMD日", lll: "YYYY年MMMD日Ah点mm分", llll: "YYYY年MMMD日ddddAh点mm分" }, meridiemParse: /凌晨|早上|上午|中午|下午|晚上/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "凌晨" === b || "早上" === b || "上午" === b ? a : "下午" === b || "晚上" === b ? a + 12 : a >= 11 ? a : a + 12 }, meridiem: function (a, b, c) { var d = 100 * a + b; return 600 > d ? "凌晨" : 900 > d ? "早上" : 1130 > d ? "上午" : 1230 > d ? "中午" : 1800 > d ? "下午" : "晚上" }, calendar: { sameDay: function () { return 0 === this.minutes() ? "[今天]Ah[点整]" : "[今天]LT" }, nextDay: function () { return 0 === this.minutes() ? "[明天]Ah[点整]" : "[明天]LT" }, lastDay: function () { return 0 === this.minutes() ? "[昨天]Ah[点整]" : "[昨天]LT" }, nextWeek: function () { var a, b; return a = Pf().startOf("week"), b = this.unix() - a.unix() >= 604800 ? "[下]" : "[本]", 0 === this.minutes() ? b + "dddAh点整" : b + "dddAh点mm" }, lastWeek: function () { var a, b; return a = Pf().startOf("week"), b = this.unix() < a.unix() ? "[上]" : "[本]", 0 === this.minutes() ? b + "dddAh点整" : b + "dddAh点mm" }, sameElse: "LL" }, ordinalParse: /\d{1,2}(日|月|周)/, ordinal: function (a, b) { switch (b) { case "d": case "D": case "DDD": return a + "日"; case "M": return a + "月"; case "w": case "W": return a + "周"; default: return a } }, relativeTime: { future: "%s内", past: "%s前", s: "几秒", m: "1 分钟", mm: "%d 分钟", h: "1 小时", hh: "%d 小时", d: "1 天", dd: "%d 天", M: "1 个月", MM: "%d 个月", y: "1 年", yy: "%d 年" }, week: { dow: 1, doy: 4 } }), Pf.defineLocale("zh-tw", { months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"), monthsShort: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"), weekdays: "星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"), weekdaysShort: "週日_週一_週二_週三_週四_週五_週六".split("_"), weekdaysMin: "日_一_二_三_四_五_六".split("_"), longDateFormat: { LT: "Ah點mm分", LTS: "Ah點m分s秒", L: "YYYY年MMMD日", LL: "YYYY年MMMD日", LLL: "YYYY年MMMD日Ah點mm分", LLLL: "YYYY年MMMD日ddddAh點mm分", l: "YYYY年MMMD日", ll: "YYYY年MMMD日", lll: "YYYY年MMMD日Ah點mm分", llll: "YYYY年MMMD日ddddAh點mm分" }, meridiemParse: /早上|上午|中午|下午|晚上/, meridiemHour: function (a, b) { return 12 === a && (a = 0), "早上" === b || "上午" === b ? a : "中午" === b ? a >= 11 ? a : a + 12 : "下午" === b || "晚上" === b ? a + 12 : void 0 }, meridiem: function (a, b, c) { var d = 100 * a + b; return 900 > d ? "早上" : 1130 > d ? "上午" : 1230 > d ? "中午" : 1800 > d ? "下午" : "晚上" }, calendar: { sameDay: "[今天]LT", nextDay: "[明天]LT", nextWeek: "[下]ddddLT", lastDay: "[昨天]LT", lastWeek: "[上]ddddLT", sameElse: "L" }, ordinalParse: /\d{1,2}(日|月|週)/, ordinal: function (a, b) { switch (b) { case "d": case "D": case "DDD": return a + "日"; case "M": return a + "月"; case "w": case "W": return a + "週"; default: return a } }, relativeTime: { future: "%s內", past: "%s前", s: "幾秒", m: "一分鐘", mm: "%d分鐘", h: "一小時", hh: "%d小時", d: "一天", dd: "%d天", M: "一個月", MM: "%d個月", y: "一年", yy: "%d年" } }), Pf); return Ug.locale("en"), Ug
});
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS = CryptoJS || function (g, j) {
    var e = {}, d = e.lib = {}, m = function () { }, n = d.Base = { extend: function (a) { m.prototype = this; var c = new m; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () { c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } },
q = d.WordArray = n.extend({ init: function (a, c) { a = this.words = a || []; this.sigBytes = c != j ? c : 4 * a.length }, toString: function (a) { return (a || l).stringify(this) }, concat: function (a) { var c = this.words, p = a.words, f = this.sigBytes; a = a.sigBytes; this.clamp(); if (f % 4) for (var b = 0; b < a; b++) c[f + b >>> 2] |= (p[b >>> 2] >>> 24 - 8 * (b % 4) & 255) << 24 - 8 * ((f + b) % 4); else if (65535 < p.length) for (b = 0; b < a; b += 4) c[f + b >>> 2] = p[b >>> 2]; else c.push.apply(c, p); this.sigBytes += a; return this }, clamp: function () {
    var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 <<
32 - 8 * (c % 4); a.length = g.ceil(c / 4)
}, clone: function () { var a = n.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], b = 0; b < a; b += 4) c.push(4294967296 * g.random() | 0); return new q.init(c, a) } 
}), b = e.enc = {}, l = b.Hex = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], f = 0; f < a; f++) { var d = c[f >>> 2] >>> 24 - 8 * (f % 4) & 255; b.push((d >>> 4).toString(16)); b.push((d & 15).toString(16)) } return b.join("") }, parse: function (a) {
    for (var c = a.length, b = [], f = 0; f < c; f += 2) b[f >>> 3] |= parseInt(a.substr(f,
2), 16) << 24 - 4 * (f % 8); return new q.init(b, c / 2)
} 
}, k = b.Latin1 = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], f = 0; f < a; f++) b.push(String.fromCharCode(c[f >>> 2] >>> 24 - 8 * (f % 4) & 255)); return b.join("") }, parse: function (a) { for (var c = a.length, b = [], f = 0; f < c; f++) b[f >>> 2] |= (a.charCodeAt(f) & 255) << 24 - 8 * (f % 4); return new q.init(b, c) } }, h = b.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(k.stringify(a))) } catch (b) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return k.parse(unescape(encodeURIComponent(a))) } },
u = d.BufferedBlockAlgorithm = n.extend({ reset: function () { this._data = new q.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = h.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var b = this._data, d = b.words, f = b.sigBytes, l = this.blockSize, e = f / (4 * l), e = a ? g.ceil(e) : g.max((e | 0) - this._minBufferSize, 0); a = e * l; f = g.min(4 * a, f); if (a) { for (var h = 0; h < a; h += l) this._doProcessBlock(d, h); h = d.splice(0, a); b.sigBytes -= f } return new q.init(h, f) }, clone: function () {
    var a = n.clone.call(this);
    a._data = this._data.clone(); return a
}, _minBufferSize: 0
}); d.Hasher = u.extend({ cfg: n.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { u.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (b, d) { return (new a.init(d)).finalize(b) } }, _createHmacHelper: function (a) {
    return function (b, d) {
        return (new w.HMAC.init(a,
d)).finalize(b)
    } 
} 
}); var w = e.algo = {}; return e
} (Math);
(function () {
    var g = CryptoJS, j = g.lib, e = j.WordArray, d = j.Hasher, m = [], j = g.algo.SHA1 = d.extend({ _doReset: function () { this._hash = new e.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (d, e) {
        for (var b = this._hash.words, l = b[0], k = b[1], h = b[2], g = b[3], j = b[4], a = 0; 80 > a; a++) {
            if (16 > a) m[a] = d[e + a] | 0; else { var c = m[a - 3] ^ m[a - 8] ^ m[a - 14] ^ m[a - 16]; m[a] = c << 1 | c >>> 31 } c = (l << 5 | l >>> 27) + j + m[a]; c = 20 > a ? c + ((k & h | ~k & g) + 1518500249) : 40 > a ? c + ((k ^ h ^ g) + 1859775393) : 60 > a ? c + ((k & h | k & g | h & g) - 1894007588) : c + ((k ^ h ^
g) - 899497514); j = g; g = h; h = k << 30 | k >>> 2; k = l; l = c
        } b[0] = b[0] + l | 0; b[1] = b[1] + k | 0; b[2] = b[2] + h | 0; b[3] = b[3] + g | 0; b[4] = b[4] + j | 0
    }, _doFinalize: function () { var d = this._data, e = d.words, b = 8 * this._nDataBytes, l = 8 * d.sigBytes; e[l >>> 5] |= 128 << 24 - l % 32; e[(l + 64 >>> 9 << 4) + 14] = Math.floor(b / 4294967296); e[(l + 64 >>> 9 << 4) + 15] = b; d.sigBytes = 4 * e.length; this._process(); return this._hash }, clone: function () { var e = d.clone.call(this); e._hash = this._hash.clone(); return e } 
    }); g.SHA1 = d._createHelper(j); g.HmacSHA1 = d._createHmacHelper(j)
})();
(function () {
    var g = CryptoJS, j = g.enc.Utf8; g.algo.HMAC = g.lib.Base.extend({ init: function (e, d) { e = this._hasher = new e.init; "string" == typeof d && (d = j.parse(d)); var g = e.blockSize, n = 4 * g; d.sigBytes > n && (d = e.finalize(d)); d.clamp(); for (var q = this._oKey = d.clone(), b = this._iKey = d.clone(), l = q.words, k = b.words, h = 0; h < g; h++) l[h] ^= 1549556828, k[h] ^= 909522486; q.sigBytes = b.sigBytes = n; this.reset() }, reset: function () { var e = this._hasher; e.reset(); e.update(this._iKey) }, update: function (e) { this._hasher.update(e); return this }, finalize: function (e) {
        var d =
this._hasher; e = d.finalize(e); d.reset(); return d.finalize(this._oKey.clone().concat(e))
    } 
    })
})();
(function () {
    var g = CryptoJS, j = g.lib, e = j.Base, d = j.WordArray, j = g.algo, m = j.HMAC, n = j.PBKDF2 = e.extend({ cfg: e.extend({ keySize: 4, hasher: j.SHA1, iterations: 1 }), init: function (d) { this.cfg = this.cfg.extend(d) }, compute: function (e, b) {
        for (var g = this.cfg, k = m.create(g.hasher, e), h = d.create(), j = d.create([1]), n = h.words, a = j.words, c = g.keySize, g = g.iterations; n.length < c; ) {
            var p = k.update(b).finalize(j); k.reset(); for (var f = p.words, v = f.length, s = p, t = 1; t < g; t++) { s = k.finalize(s); k.reset(); for (var x = s.words, r = 0; r < v; r++) f[r] ^= x[r] } h.concat(p);
            a[0]++
        } h.sigBytes = 4 * c; return h
    } 
    }); g.PBKDF2 = function (d, b, e) { return n.create(e).compute(d, b) } 
})();

/*!
* jQuery scrollintoview() plugin and :scrollable selector filter
*
* Version 1.8 (14 Jul 2011)
* Requires jQuery 1.4 or newer
*
* Copyright (c) 2011 Robert Koritnik
* Licensed under the terms of the MIT license
* http://www.opensource.org/licenses/mit-license.php
*/

(function ($) {
    var converter = {
        vertical: { x: false, y: true },
        horizontal: { x: true, y: false },
        both: { x: true, y: true },
        x: { x: true, y: false },
        y: { x: false, y: true }
    };

    var settings = {
        duration: "fast",
        direction: "both"
    };

    var rootrx = /^(?:html)$/i;

    // gets border dimensions
    var borders = function (domElement, styles) {
        styles = styles || (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(domElement, null) : domElement.currentStyle);
        var px = document.defaultView && document.defaultView.getComputedStyle ? true : false;
        var b = {
            top: (parseFloat(px ? styles.borderTopWidth : $.css(domElement, "borderTopWidth")) || 0),
            left: (parseFloat(px ? styles.borderLeftWidth : $.css(domElement, "borderLeftWidth")) || 0),
            bottom: (parseFloat(px ? styles.borderBottomWidth : $.css(domElement, "borderBottomWidth")) || 0),
            right: (parseFloat(px ? styles.borderRightWidth : $.css(domElement, "borderRightWidth")) || 0)
        };
        return {
            top: b.top,
            left: b.left,
            bottom: b.bottom,
            right: b.right,
            vertical: b.top + b.bottom,
            horizontal: b.left + b.right
        };
    };

    var dimensions = function ($element) {
        var win = $(window);
        var isRoot = rootrx.test($element[0].nodeName);
        return {
            border: isRoot ? { top: 0, left: 0, bottom: 0, right: 0} : borders($element[0]),
            scroll: {
                top: (isRoot ? win : $element).scrollTop(),
                left: (isRoot ? win : $element).scrollLeft()
            },
            scrollbar: {
                right: isRoot ? 0 : $element.innerWidth() - $element[0].clientWidth,
                bottom: isRoot ? 0 : $element.innerHeight() - $element[0].clientHeight
            },
            rect: (function () {
                var r = $element[0].getBoundingClientRect();
                return {
                    top: isRoot ? 0 : r.top,
                    left: isRoot ? 0 : r.left,
                    bottom: isRoot ? $element[0].clientHeight : r.bottom,
                    right: isRoot ? $element[0].clientWidth : r.right
                };
            })()
        };
    };

    $.fn.extend({
        scrollintoview: function (options) {
            /// <summary>Scrolls the first element in the set into view by scrolling its closest scrollable parent.</summary>
            /// <param name="options" type="Object">Additional options that can configure scrolling:
            ///        duration (default: "fast") - jQuery animation speed (can be a duration string or number of milliseconds)
            ///        direction (default: "both") - select possible scrollings ("vertical" or "y", "horizontal" or "x", "both")
            ///        complete (default: none) - a function to call when scrolling completes (called in context of the DOM element being scrolled)
            /// </param>
            /// <return type="jQuery">Returns the same jQuery set that this function was run on.</return>

            options = $.extend({}, settings, options);
            options.direction = converter[typeof (options.direction) === "string" && options.direction.toLowerCase()] || converter.both;

            var dirStr = "";
            if (options.direction.x === true) dirStr = "horizontal";
            if (options.direction.y === true) dirStr = dirStr ? "both" : "vertical";

            var el = this.eq(0);
            var scroller = el.closest(":scrollable(" + dirStr + ")");

            // check if there's anything to scroll in the first place
            if (scroller.length > 0) {
                scroller = scroller.eq(0);

                var dim = {
                    e: dimensions(el),
                    s: dimensions(scroller)
                };

                var rel = {
                    top: dim.e.rect.top - (dim.s.rect.top + dim.s.border.top),
                    bottom: dim.s.rect.bottom - dim.s.border.bottom - dim.s.scrollbar.bottom - dim.e.rect.bottom,
                    left: dim.e.rect.left - (dim.s.rect.left + dim.s.border.left),
                    right: dim.s.rect.right - dim.s.border.right - dim.s.scrollbar.right - dim.e.rect.right
                };

                var animOptions = {};

                // vertical scroll
                if (options.direction.y === true) {
                    if (rel.top < 0) {
                        animOptions.scrollTop = dim.s.scroll.top + rel.top;
                    }
                    else if (rel.top > 0 && rel.bottom < 0) {
                        animOptions.scrollTop = dim.s.scroll.top + Math.min(rel.top, -rel.bottom);
                    }
                }

                // horizontal scroll
                if (options.direction.x === true) {
                    if (rel.left < 0) {
                        animOptions.scrollLeft = dim.s.scroll.left + rel.left;
                    }
                    else if (rel.left > 0 && rel.right < 0) {
                        animOptions.scrollLeft = dim.s.scroll.left + Math.min(rel.left, -rel.right);
                    }
                }

                // scroll if needed
                if (!$.isEmptyObject(animOptions)) {
                    if (rootrx.test(scroller[0].nodeName)) {
                        scroller = $("html,body");
                    }
                    scroller
						.animate(animOptions, options.duration)
						.eq(0) // we want function to be called just once (ref. "html,body")
						.queue(function (next) {
						    $.isFunction(options.complete) && options.complete.call(scroller[0]);
						    next();
						});
                }
                else {
                    // when there's nothing to scroll, just call the "complete" function
                    $.isFunction(options.complete) && options.complete.call(scroller[0]);
                }
            }

            // return set back
            return this;
        }
    });

    var scrollValue = {
        auto: true,
        scroll: true,
        visible: false,
        hidden: false
    };

    $.extend($.expr[":"], {
        scrollable: function (element, index, meta, stack) {
            var direction = converter[typeof (meta[3]) === "string" && meta[3].toLowerCase()] || converter.both;
            var styles = (document.defaultView && document.defaultView.getComputedStyle ? document.defaultView.getComputedStyle(element, null) : element.currentStyle);
            var overflow = {
                x: scrollValue[styles.overflowX.toLowerCase()] || false,
                y: scrollValue[styles.overflowY.toLowerCase()] || false,
                isRoot: rootrx.test(element.nodeName)
            };

            // check if completely unscrollable (exclude HTML element because it's special)
            if (!overflow.x && !overflow.y && !overflow.isRoot) {
                return false;
            }

            var size = {
                height: {
                    scroll: element.scrollHeight,
                    client: element.clientHeight
                },
                width: {
                    scroll: element.scrollWidth,
                    client: element.clientWidth
                },
                // check overflow.x/y because iPad (and possibly other tablets) don't dislay scrollbars
                scrollableX: function () {
                    return (overflow.x || overflow.isRoot) && this.width.scroll > this.width.client;
                },
                scrollableY: function () {
                    return (overflow.y || overflow.isRoot) && this.height.scroll > this.height.client;
                }
            };
            return direction.y && size.scrollableY() || direction.x && size.scrollableX();
        }
    });
})(jQuery);
// Cross-broswer implementation of text ranges and selections
// documentation: http://bililite.com/blog/2011/01/17/cross-browser-text-ranges-and-selections/
// Version: 2.6
// Copyright (c) 2013 Daniel Wachsstock
// MIT license:
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

(function(){

// a bit of weirdness with IE11: using 'focus' is flaky, even if I'm not bubbling, as far as I can tell.
var focusEvent = 'onfocusin' in document.createElement('input') ? 'focusin' : 'focus';

// IE11 normalize is buggy (http://connect.microsoft.com/IE/feedback/details/809424/node-normalize-removes-text-if-dashes-are-present)
var n = document.createElement('div');
n.appendChild(document.createTextNode('x-'));
n.appendChild(document.createTextNode('x'));
n.normalize();
var canNormalize = n.firstChild.length == 3;


bililiteRange = function(el, debug){
	var ret;
	if (debug){
		ret = new NothingRange(); // Easier to force it to use the no-selection type than to try to find an old browser
	}else if (window.getSelection && el.setSelectionRange){
		// Standards. Element is an input or textarea 
		// note that some input elements do not allow selections
		try{
			el.selectionStart; // even getting the selection in such an element will throw
			ret = new InputRange();
		}catch(e){
			ret = new NothingRange();
		}
	}else if (window.getSelection){
		// Standards, with any other kind of element
		ret = new W3CRange();
	}else if (document.selection){
		// Internet Explorer
		ret = new IERange();
	}else{
		// doesn't support selection
		ret = new NothingRange();
	}
	ret._el = el;
	// determine parent document, as implemented by John McLear <john@mclear.co.uk>
	ret._doc = el.ownerDocument;
	ret._win = 'defaultView' in ret._doc ? ret._doc.defaultView : ret._doc.parentWindow;
	ret._textProp = textProp(el);
	ret._bounds = [0, ret.length()];
	//  There's no way to detect whether a focus event happened as a result of a click (which should change the selection)
	// or as a result of a keyboard event (a tab in) or a script  action (el.focus()). So we track it globally, which is a hack, and is likely to fail
	// in edge cases (right-clicks, drag-n-drop), and is vulnerable to a lower-down handler preventing bubbling.
	// I just don't know a better way.
	// I'll hack my event-listening code below, rather than create an entire new bilililiteRange, potentially before the DOM has loaded
	if (!('bililiteRangeMouseDown' in ret._doc)){
		var _doc = {_el: ret._doc};
		ret._doc.bililiteRangeMouseDown = false;
		bililiteRange.fn.listen.call(_doc, 'mousedown', function() {
			ret._doc.bililiteRangeMouseDown = true;
		});
		bililiteRange.fn.listen.call(_doc, 'mouseup', function() {
			ret._doc.bililiteRangeMouseDown = false;
		});
	}
	// note that bililiteRangeSelection is an array, which means that copying it only copies the address, which points to the original.
	// make sure that we never let it (always do return [bililiteRangeSelection[0], bililiteRangeSelection[1]]), which means never returning
	// this._bounds directly
	if (!('bililiteRangeSelection' in el)){
		// start tracking the selection
		function trackSelection(evt){
			if (evt && evt.which == 9){
				// do tabs my way, by restoring the selection
				// there's a flash of the browser's selection, but I don't see a way of avoiding that
				ret._nativeSelect(ret._nativeRange(el.bililiteRangeSelection));
			}else{
				el.bililiteRangeSelection = ret._nativeSelection();
			}
		}
		trackSelection();
		// only IE does this right and allows us to grab the selection before blurring
		if ('onbeforedeactivate' in el){
			ret.listen('beforedeactivate', trackSelection);
		}else{
			// with standards-based browsers, have to listen for every user interaction
			ret.listen('mouseup', trackSelection).listen('keyup', trackSelection);
		}
		ret.listen(focusEvent, function(){
			// restore the correct selection when the element comes into focus (mouse clicks change the position of the selection)
			// Note that Firefox will not fire the focus event until the window/tab is active even if el.focus() is called
			// https://bugzilla.mozilla.org/show_bug.cgi?id=566671
			if (!ret._doc.bililiteRangeMouseDown){
				ret._nativeSelect(ret._nativeRange(el.bililiteRangeSelection));
			}
		});
	}
	if (!('oninput' in el)){
		// give IE8 a chance. Note that this still fails in IE11, which has has oninput on contenteditable elements but does not 
		// dispatch input events. See http://connect.microsoft.com/IE/feedback/details/794285/ie10-11-input-event-does-not-fire-on-div-with-contenteditable-set
		// TODO: revisit this when I have IE11 running on my development machine
		var inputhack = function() {ret.dispatch({type: 'input'}) };
		ret.listen('keyup', inputhack);
		ret.listen('cut', inputhack);
		ret.listen('paste', inputhack);
		ret.listen('drop', inputhack);
		el.oninput = 'patched';
	}
	return ret;
}

function textProp(el){
	// returns the property that contains the text of the element
	// note that for <body> elements the text attribute represents the obsolete text color, not the textContent.
	// we document that these routines do not work for <body> elements so that should not be relevant
	if (typeof el.value != 'undefined') return 'value';
	if (typeof el.text != 'undefined') return 'text';
	if (typeof el.textContent != 'undefined') return 'textContent';
	return 'innerText';
}

// base class
function Range(){}
Range.prototype = {
	length: function() {
		return this._el[this._textProp].replace(/\r/g, '').length; // need to correct for IE's CrLf weirdness
	},
	bounds: function(s){
		if (bililiteRange.bounds[s]){
			this._bounds = bililiteRange.bounds[s].apply(this);
		}else if (s){
			this._bounds = s; // don't do error checking now; things may change at a moment's notice
		}else{
			var b = [
				Math.max(0, Math.min (this.length(), this._bounds[0])),
				Math.max(0, Math.min (this.length(), this._bounds[1]))
			];
			b[1] = Math.max(b[0], b[1]);
			return b; // need to constrain it to fit
		}
		return this; // allow for chaining
	},
	select: function(){
		var b = this._el.bililiteRangeSelection = this.bounds();
		if (this._el === this._doc.activeElement){
			// only actually select if this element is active!
			this._nativeSelect(this._nativeRange(b));
		}
		this.dispatch({type: 'select'});
		return this; // allow for chaining
	},
	text: function(text, select){
		if (arguments.length){
			var bounds = this.bounds(), el = this._el;
			// signal the input per DOM 3 input events, http://www.w3.org/TR/DOM-Level-3-Events/#h4_events-inputevents
			// we add another field, bounds, which are the bounds of the original text before being changed.
			this.dispatch({type: 'beforeinput', data: text, bounds: bounds});
			this._nativeSetText(text, this._nativeRange(bounds));
			if (select == 'start'){
				this.bounds ([bounds[0], bounds[0]]);
			}else if (select == 'end'){
				this.bounds ([bounds[0]+text.length, bounds[0]+text.length]);
			}else if (select == 'all'){
				this.bounds ([bounds[0], bounds[0]+text.length]);
			}
			this.dispatch({type: 'input', data: text, bounds: bounds});
			return this; // allow for chaining
		}else{
			return this._nativeGetText(this._nativeRange(this.bounds())).replace(/\r/g, ''); // need to correct for IE's CrLf weirdness
		}
	},
	insertEOL: function (){
		this._nativeEOL();
		this._bounds = [this._bounds[0]+1, this._bounds[0]+1]; // move past the EOL marker
		return this;
	},
	sendkeys: function (text){
		var self = this;
		this.data().sendkeysOriginalText = this.text();
		this.data().sendkeysBounds = undefined;
		function simplechar (rng, c){
			if (/^{[^}]*}$/.test(c)) c = c.slice(1,-1);	// deal with unknown {key}s
			for (var i =0; i < c.length; ++i){
				var x = c.charCodeAt(i);
				rng.dispatch({type: 'keypress', keyCode: x, which: x, charCode: x});
			}
			rng.text(c, 'end');
		}
		text.replace(/{[^}]*}|[^{]+|{/g, function(part){
			(bililiteRange.sendkeys[part] || simplechar)(self, part, simplechar);
		});
		this.bounds(this.data().sendkeysBounds);
		this.dispatch({type: 'sendkeys', which: text});
		return this;
	},
	top: function(){
		return this._nativeTop(this._nativeRange(this.bounds()));
	},
	scrollIntoView: function(scroller){
		var top = this.top();
		// scroll into position if necessary
		if (this._el.scrollTop > top || this._el.scrollTop+this._el.clientHeight < top){
			if (scroller){
				scroller.call(this._el, top);
			}else{
				this._el.scrollTop = top;
			}
		}
		return this;
	},
	wrap: function (n){
		this._nativeWrap(n, this._nativeRange(this.bounds()));
		return this;
	},
	selection: function(text){
		if (arguments.length){
			return this.bounds('selection').text(text, 'end').select();
		}else{
			return this.bounds('selection').text();
		}
	},
	clone: function(){
		return bililiteRange(this._el).bounds(this.bounds());
	},
	all: function(text){
		if (arguments.length){
			this.dispatch ({type: 'beforeinput', data: text});
			this._el[this._textProp] = text;
			this.dispatch ({type: 'input', data: text});
			return this;
		}else{
			return this._el[this._textProp].replace(/\r/g, ''); // need to correct for IE's CrLf weirdness
		}
	},
	element: function() { return this._el },
	// includes a quickie polyfill for CustomEvent for IE that isn't perfect but works for me
	// IE10 allows custom events but not "new CustomEvent"; have to do it the old-fashioned way
	dispatch: function(opts){
		opts = opts || {};
		var event = document.createEvent ? document.createEvent('CustomEvent') : this._doc.createEventObject();
		event.initCustomEvent && event.initCustomEvent(opts.type, !!opts.bubbles, !!opts.cancelable, opts.detail);
		for (var key in opts) event[key] = opts[key];
		// dispatch event asynchronously (in the sense of on the next turn of the event loop; still should be fired in order of dispatch
		var el = this._el;
		setTimeout(function(){
			try {
				el.dispatchEvent ? el.dispatchEvent(event) : el.fireEvent("on" + opts.type, document.createEventObject());
				}catch(e){
				// IE8 will not let me fire custom events at all. Call them directly
					var listeners = el['listen'+opts.type];
					if (listeners) for (var i = 0; i < listeners.length; ++i){
						listeners[i].call(el, event);
					}
				}
		}, 0);
		return this;
	},
	listen: function (type, func){
		var el = this._el;
		if (el.addEventListener){
			el.addEventListener(type, func);
		}else{
			el.attachEvent("on" + type, func);
			// IE8 can't even handle custom events created with createEventObject  (though it permits attachEvent), so we have to make our own
			var listeners = el['listen'+type] = el['listen'+type] || [];
			listeners.push(func);
		}
		return this;
	},
	dontlisten: function (type, func){
		var el = this._el;
		if (el.removeEventListener){
			el.removeEventListener(type, func);
		}else try{
			el.detachEvent("on" + type, func);
		}catch(e){
			var listeners = el['listen'+type];
			if (listeners) for (var i = 0; i < listeners.length; ++i){
				if (listeners[i] === func) listeners[i] = function(){}; // replace with a noop
			}
		}
		return this;
	}
};

// allow extensions ala jQuery
bililiteRange.fn = Range.prototype; // to allow monkey patching
bililiteRange.extend = function(fns){
	for (fn in fns) Range.prototype[fn] = fns[fn];
};

//bounds functions
bililiteRange.bounds = {
	all: function() { return [0, this.length()] },
	start: function () { return [0,0] },
	end: function () { return [this.length(), this.length()] },
	selection: function(){
		if (this._el === this._doc.activeElement){
			this.bounds ('all'); // first select the whole thing for constraining
			return this._nativeSelection();
		}else{
			return this._el.bililiteRangeSelection;
		}
	}
};

// sendkeys functions
bililiteRange.sendkeys = {
	'{enter}': function (rng){
		simplechar(rng, '\n');
		rng.insertEOL();
	},
	'{tab}': function (rng, c, simplechar){
		simplechar(rng, '\t'); // useful for inserting what would be whitespace
	},
	'{newline}': function (rng, c, simplechar){
		simplechar(rng, '\n'); // useful for inserting what would be whitespace (and if I don't want to use insertEOL, which does some fancy things)
	},
	'{backspace}': function (rng){
		var b = rng.bounds();
		if (b[0] == b[1]) rng.bounds([b[0]-1, b[0]]); // no characters selected; it's just an insertion point. Remove the previous character
		rng.text('', 'end'); // delete the characters and update the selection
	},
	'{del}': function (rng){
		var b = rng.bounds();
		if (b[0] == b[1]) rng.bounds([b[0], b[0]+1]); // no characters selected; it's just an insertion point. Remove the next character
		rng.text('', 'end'); // delete the characters and update the selection
	},
	'{rightarrow}':  function (rng){
		var b = rng.bounds();
		if (b[0] == b[1]) ++b[1]; // no characters selected; it's just an insertion point. Move to the right
		rng.bounds([b[1], b[1]]);
	},
	'{leftarrow}': function (rng){
		var b = rng.bounds();
		if (b[0] == b[1]) --b[0]; // no characters selected; it's just an insertion point. Move to the left
		rng.bounds([b[0], b[0]]);
	},
	'{selectall}' : function (rng){
		rng.bounds('all');
	},
	'{selection}': function (rng){
		// insert the characters without the sendkeys processing
		var s = rng.data().sendkeysOriginalText;
		for (var i =0; i < s.length; ++i){
			var x = s.charCodeAt(i);
			rng.dispatch({type: 'keypress', keyCode: x, which: x, charCode: x});
		}
		rng.text(s, 'end');
	},
	'{mark}' : function (rng){
		rng.data().sendkeysBounds = rng.bounds();
	}
};
// Synonyms from the proposed DOM standard (http://www.w3.org/TR/DOM-Level-3-Events-key/)
bililiteRange.sendkeys['{Enter}'] = bililiteRange.sendkeys['{enter}'];
bililiteRange.sendkeys['{Backspace}'] = bililiteRange.sendkeys['{backspace}'];
bililiteRange.sendkeys['{Delete}'] = bililiteRange.sendkeys['{del}'];
bililiteRange.sendkeys['{ArrowRight}'] = bililiteRange.sendkeys['{rightarrow}'];
bililiteRange.sendkeys['{ArrowLeft}'] = bililiteRange.sendkeys['{leftarrow}'];

function IERange(){}
IERange.prototype = new Range();
IERange.prototype._nativeRange = function (bounds){
	var rng;
	if (this._el.tagName == 'INPUT'){
		// IE 8 is very inconsistent; textareas have createTextRange but it doesn't work
		rng = this._el.createTextRange();
	}else{
		rng = this._doc.body.createTextRange ();
		rng.moveToElementText(this._el);
	}
	if (bounds){
		if (bounds[1] < 0) bounds[1] = 0; // IE tends to run elements out of bounds
		if (bounds[0] > this.length()) bounds[0] = this.length();
		if (bounds[1] < rng.text.replace(/\r/g, '').length){ // correct for IE's CrLf weirdness
			// block-display elements have an invisible, uncounted end of element marker, so we move an extra one and use the current length of the range
			rng.moveEnd ('character', -1);
			rng.moveEnd ('character', bounds[1]-rng.text.replace(/\r/g, '').length);
		}
		if (bounds[0] > 0) rng.moveStart('character', bounds[0]);
	}
	return rng;					
};
IERange.prototype._nativeSelect = function (rng){
	rng.select();
};
IERange.prototype._nativeSelection = function (){
	// returns [start, end] for the selection constrained to be in element
	var rng = this._nativeRange(); // range of the element to constrain to
	var len = this.length();
	var sel = this._doc.selection.createRange();
	try{
		return [
			iestart(sel, rng),
			ieend (sel, rng)
		];
	}catch (e){
		// TODO: determine if this is still necessary, since we only call _nativeSelection if _el is active
		// IE gets upset sometimes about comparing text to input elements, but the selections cannot overlap, so make a best guess
		return (sel.parentElement().sourceIndex < this._el.sourceIndex) ? [0,0] : [len, len];
	}
};
IERange.prototype._nativeGetText = function (rng){
	return rng.text;
};
IERange.prototype._nativeSetText = function (text, rng){
	rng.text = text;
};
IERange.prototype._nativeEOL = function(){
	if ('value' in this._el){
		this.text('\n'); // for input and textarea, insert it straight
	}else{
		this._nativeRange(this.bounds()).pasteHTML('\n<br/>');
	}
};
IERange.prototype._nativeTop = function(rng){
	var startrng = this._nativeRange([0,0]);
	return rng.boundingTop - startrng.boundingTop;
}
IERange.prototype._nativeWrap = function(n, rng) {
	// hacky to use string manipulation but I don't see another way to do it.
	var div = document.createElement('div');
	div.appendChild(n);
	// insert the existing range HTML after the first tag
	var html = div.innerHTML.replace('><', '>'+rng.htmlText+'<');
	rng.pasteHTML(html);
};

// IE internals
function iestart(rng, constraint){
	// returns the position (in character) of the start of rng within constraint. If it's not in constraint, returns 0 if it's before, length if it's after
	var len = constraint.text.replace(/\r/g, '').length; // correct for IE's CrLf weirdness
	if (rng.compareEndPoints ('StartToStart', constraint) <= 0) return 0; // at or before the beginning
	if (rng.compareEndPoints ('StartToEnd', constraint) >= 0) return len;
	for (var i = 0; rng.compareEndPoints ('StartToStart', constraint) > 0; ++i, rng.moveStart('character', -1));
	return i;
}
function ieend (rng, constraint){
	// returns the position (in character) of the end of rng within constraint. If it's not in constraint, returns 0 if it's before, length if it's after
	var len = constraint.text.replace(/\r/g, '').length; // correct for IE's CrLf weirdness
	if (rng.compareEndPoints ('EndToEnd', constraint) >= 0) return len; // at or after the end
	if (rng.compareEndPoints ('EndToStart', constraint) <= 0) return 0;
	for (var i = 0; rng.compareEndPoints ('EndToStart', constraint) > 0; ++i, rng.moveEnd('character', -1));
	return i;
}

// an input element in a standards document. "Native Range" is just the bounds array
function InputRange(){}
InputRange.prototype = new Range();
InputRange.prototype._nativeRange = function(bounds) {
	return bounds || [0, this.length()];
};
InputRange.prototype._nativeSelect = function (rng){
	this._el.setSelectionRange(rng[0], rng[1]);
};
InputRange.prototype._nativeSelection = function(){
	return [this._el.selectionStart, this._el.selectionEnd];
};
InputRange.prototype._nativeGetText = function(rng){
	return this._el.value.substring(rng[0], rng[1]);
};
InputRange.prototype._nativeSetText = function(text, rng){
	var val = this._el.value;
	this._el.value = val.substring(0, rng[0]) + text + val.substring(rng[1]);
};
InputRange.prototype._nativeEOL = function(){
	this.text('\n');
};
InputRange.prototype._nativeTop = function(rng){
	// I can't remember where I found this clever hack to find the location of text in a text area
	var clone = this._el.cloneNode(true);
	clone.style.visibility = 'hidden';
	clone.style.position = 'absolute';
	this._el.parentNode.insertBefore(clone, this._el);
	clone.style.height = '1px';
	clone.value = this._el.value.slice(0, rng[0]);
	var top = clone.scrollHeight;
	// this gives the bottom of the text, so we have to subtract the height of a single line
	clone.value = 'X';
	top -= clone.scrollHeight;
	clone.parentNode.removeChild(clone);
	return top;
}
InputRange.prototype._nativeWrap = function() {throw new Error("Cannot wrap in a text element")};

function W3CRange(){}
W3CRange.prototype = new Range();
W3CRange.prototype._nativeRange = function (bounds){
	var rng = this._doc.createRange();
	rng.selectNodeContents(this._el);
	if (bounds){
		w3cmoveBoundary (rng, bounds[0], true, this._el);
		rng.collapse (true);
		w3cmoveBoundary (rng, bounds[1]-bounds[0], false, this._el);
	}
	return rng;					
};
W3CRange.prototype._nativeSelect = function (rng){
	this._win.getSelection().removeAllRanges();
	this._win.getSelection().addRange (rng);
};
W3CRange.prototype._nativeSelection = function (){
	// returns [start, end] for the selection constrained to be in element
	var rng = this._nativeRange(); // range of the element to constrain to
	if (this._win.getSelection().rangeCount == 0) return [this.length(), this.length()]; // append to the end
	var sel = this._win.getSelection().getRangeAt(0);
	return [
		w3cstart(sel, rng),
		w3cend (sel, rng)
	];
	}
W3CRange.prototype._nativeGetText = function (rng){
	return String.prototype.slice.apply(this._el.textContent, this.bounds());
	// return rng.toString(); // this fails in IE11 since it insists on inserting \r's before \n's in Ranges. node.textContent works as expected
};
W3CRange.prototype._nativeSetText = function (text, rng){
	rng.deleteContents();
	rng.insertNode (this._doc.createTextNode(text));
	if (canNormalize) this._el.normalize(); // merge the text with the surrounding text
};
W3CRange.prototype._nativeEOL = function(){
	var rng = this._nativeRange(this.bounds());
	rng.deleteContents();
	var br = this._doc.createElement('br');
	br.setAttribute ('_moz_dirty', ''); // for Firefox
	rng.insertNode (br);
	rng.insertNode (this._doc.createTextNode('\n'));
	rng.collapse (false);
};
W3CRange.prototype._nativeTop = function(rng){
	if (this.length == 0) return 0; // no text, no scrolling
	if (rng.toString() == ''){
		var textnode = this._doc.createTextNode('X');
		rng.insertNode (textnode);
	}
	var startrng = this._nativeRange([0,1]);
	var top = rng.getBoundingClientRect().top - startrng.getBoundingClientRect().top;
	if (textnode) textnode.parentNode.removeChild(textnode);
	return top;
}
W3CRange.prototype._nativeWrap = function(n, rng) {
	rng.surroundContents(n);
};

// W3C internals
function nextnode (node, root){
	//  in-order traversal
	// we've already visited node, so get kids then siblings
	if (node.firstChild) return node.firstChild;
	if (node.nextSibling) return node.nextSibling;
	if (node===root) return null;
	while (node.parentNode){
		// get uncles
		node = node.parentNode;
		if (node == root) return null;
		if (node.nextSibling) return node.nextSibling;
	}
	return null;
}
function w3cmoveBoundary (rng, n, bStart, el){
	// move the boundary (bStart == true ? start : end) n characters forward, up to the end of element el. Forward only!
	// if the start is moved after the end, then an exception is raised
	if (n <= 0) return;
	var node = rng[bStart ? 'startContainer' : 'endContainer'];
	if (node.nodeType == 3){
	  // we may be starting somewhere into the text
	  n += rng[bStart ? 'startOffset' : 'endOffset'];
	}
	while (node){
		if (node.nodeType == 3){
			var length = node.nodeValue.length;
			if (n <= length){
				rng[bStart ? 'setStart' : 'setEnd'](node, n);
				// special case: if we end next to a <br>, include that node.
				if (n == length){
					// skip past zero-length text nodes
					for (var next = nextnode (node, el); next && next.nodeType==3 && next.nodeValue.length == 0; next = nextnode(next, el)){
						rng[bStart ? 'setStartAfter' : 'setEndAfter'](next);
					}
					if (next && next.nodeType == 1 && next.nodeName == "BR") rng[bStart ? 'setStartAfter' : 'setEndAfter'](next);
				}
				return;
			}else{
				rng[bStart ? 'setStartAfter' : 'setEndAfter'](node); // skip past this one
				n -= length; // and eat these characters
			}
		}
		node = nextnode (node, el);
	}
}
var     START_TO_START                 = 0; // from the w3c definitions
var     START_TO_END                   = 1;
var     END_TO_END                     = 2;
var     END_TO_START                   = 3;
// from the Mozilla documentation, for range.compareBoundaryPoints(how, sourceRange)
// -1, 0, or 1, indicating whether the corresponding boundary-point of range is respectively before, equal to, or after the corresponding boundary-point of sourceRange. 
    // * Range.END_TO_END compares the end boundary-point of sourceRange to the end boundary-point of range.
    // * Range.END_TO_START compares the end boundary-point of sourceRange to the start boundary-point of range.
    // * Range.START_TO_END compares the start boundary-point of sourceRange to the end boundary-point of range.
    // * Range.START_TO_START compares the start boundary-point of sourceRange to the start boundary-point of range. 
function w3cstart(rng, constraint){
	if (rng.compareBoundaryPoints (START_TO_START, constraint) <= 0) return 0; // at or before the beginning
	if (rng.compareBoundaryPoints (END_TO_START, constraint) >= 0) return constraint.toString().length;
	rng = rng.cloneRange(); // don't change the original
	rng.setEnd (constraint.endContainer, constraint.endOffset); // they now end at the same place
	return constraint.toString().replace(/\r/g, '').length - rng.toString().replace(/\r/g, '').length;
}
function w3cend (rng, constraint){
	if (rng.compareBoundaryPoints (END_TO_END, constraint) >= 0) return constraint.toString().length; // at or after the end
	if (rng.compareBoundaryPoints (START_TO_END, constraint) <= 0) return 0;
	rng = rng.cloneRange(); // don't change the original
	rng.setStart (constraint.startContainer, constraint.startOffset); // they now start at the same place
	return rng.toString().replace(/\r/g, '').length;
}

function NothingRange(){}
NothingRange.prototype = new Range();
NothingRange.prototype._nativeRange = function(bounds) {
	return bounds || [0,this.length()];
};
NothingRange.prototype._nativeSelect = function (rng){ // do nothing
};
NothingRange.prototype._nativeSelection = function(){
	return [0,0];
};
NothingRange.prototype._nativeGetText = function (rng){
	return this._el[this._textProp].substring(rng[0], rng[1]);
};
NothingRange.prototype._nativeSetText = function (text, rng){
	var val = this._el[this._textProp];
	this._el[this._textProp] = val.substring(0, rng[0]) + text + val.substring(rng[1]);
};
NothingRange.prototype._nativeEOL = function(){
	this.text('\n');
};
NothingRange.prototype._nativeTop = function(){
	return 0;
};
NothingRange.prototype._nativeWrap = function() {throw new Error("Wrapping not implemented")};


// data for elements, similar to jQuery data, but allows for monitoring with custom events
var data = []; // to avoid attaching javascript objects to DOM elements, to avoid memory leaks
bililiteRange.fn.data = function(){
	var index = this.element().bililiteRangeData;
	if (index == undefined){
		index = this.element().bililiteRangeData = data.length;
		data[index] = new Data(this);
	}
	return data[index];
}
try {
	Object.defineProperty({},'foo',{}); // IE8 will throw an error
	var Data = function(rng) {
		// we use JSON.stringify to display the data values. To make some of those non-enumerable, we have to use properties
		Object.defineProperty(this, 'values', {
			value: {}
		});
		Object.defineProperty(this, 'sourceRange', {
			value: rng
		});
		Object.defineProperty(this, 'toJSON', {
			value: function(){
				var ret = {};
				for (var i in Data.prototype) if (i in this.values) ret[i] = this.values[i];
				return ret;
			}
		});
		// to display all the properties (not just those changed), use JSON.stringify(state.all)
		Object.defineProperty(this, 'all', {
			get: function(){
				var ret = {};
				for (var i in Data.prototype) ret[i] = this[i];
				return ret;
			}
		});
	}

	Data.prototype = {};
	Object.defineProperty(Data.prototype, 'values', {
		value: {}
	});
	Object.defineProperty(Data.prototype, 'monitored', {
		value: {}
	});
	
	bililiteRange.data = function (name, newdesc){
		newdesc = newdesc || {};
		var desc = Object.getOwnPropertyDescriptor(Data.prototype, name) || {};
		if ('enumerable' in newdesc) desc.enumerable = !!newdesc.enumerable;
		if (!('enumerable' in desc)) desc.enumerable = true; // default
		if ('value' in newdesc) Data.prototype.values[name] = newdesc.value;
		if ('monitored' in newdesc) Data.prototype.monitored[name] = newdesc.monitored;
		desc.configurable = true;
		desc.get = function (){
			if (name in this.values) return this.values[name];
			return Data.prototype.values[name];
		};
		desc.set = function (value){
			this.values[name] = value;
			if (Data.prototype.monitored[name]) this.sourceRange.dispatch({
				type: 'bililiteRangeData',
				bubbles: true,
				detail: {name: name, value: value}
			});
		}
		Object.defineProperty(Data.prototype, name, desc);
	}
}catch(err){
	// if we can't set object property properties, just use old-fashioned properties
  Data = function(rng){ this.sourceRange = rng };
	Data.prototype = {};
	bililiteRange.data = function(name, newdesc){
		if ('value' in newdesc) Data.prototype[name] = newdesc.value;
	}
}

})();

// Polyfill for forEach, per Mozilla documentation. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Polyfill
if (!Array.prototype.forEach)
{
  Array.prototype.forEach = function(fun /*, thisArg */)
  {
    "use strict";

    if (this === void 0 || this === null)
      throw new TypeError();

    var t = Object(this);
    var len = t.length >>> 0;
    if (typeof fun !== "function")
      throw new TypeError();

    var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
    for (var i = 0; i < len; i++)
    {
      if (i in t)
        fun.call(thisArg, t[i], i, t);
    }
  };
}
// insert characters in a textarea or text input field
// special characters are enclosed in {}; use {{} for the { character itself
// documentation: http://bililite.com/blog/2008/08/20/the-fnsendkeys-plugin/
// Version: 4
// Copyright (c) 2013 Daniel Wachsstock
// MIT license:
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

(function($){

$.fn.sendkeys = function (x){
	x = x.replace(/([^{])\n/g, '$1{enter}'); // turn line feeds into explicit break insertions, but not if escaped
	return this.each( function(){
		bililiteRange(this).bounds('selection').sendkeys(x).select();
		this.focus();
	});
}; // sendkeys

// add a default handler for keydowns so that we can send keystrokes, even though code-generated events 
// are untrusted (http://www.w3.org/TR/DOM-Level-3-Events/#trusted-events)
// documentation of special event handlers is at http://learn.jquery.com/events/event-extensions/
$.event.special.keydown = $.event.special.keydown || {};
$.event.special.keydown._default = function (evt){
	if (evt.isTrusted) return false;
	if (evt.ctrlKey || evt.altKey || evt.metaKey) return false; // only deal with printable characters. This may be a false assumption
	if (evt.key == null) return false; // nothing to print. Use the keymap plugin to set this 
	var target = evt.target;
	if (target.isContentEditable || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA') {
		// only insert into editable elements
		var key = evt.key;
		if (key.length > 1 && key.charAt(0) != '{') key = '{'+key+'}'; // sendkeys notation
		$(target).sendkeys(key);
		return true;
	}
	return false;
}
})(jQuery)
/*
CryptoJS v3.1.2
code.google.com/p/crypto-js
(c) 2009-2013 by Jeff Mott. All rights reserved.
code.google.com/p/crypto-js/wiki/License
*/
var CryptoJS = CryptoJS || function (e, m) {
    var p = {}, j = p.lib = {}, l = function () { }, f = j.Base = { extend: function (a) { l.prototype = this; var c = new l; a && c.mixIn(a); c.hasOwnProperty("init") || (c.init = function () { c.$super.init.apply(this, arguments) }); c.init.prototype = c; c.$super = this; return c }, create: function () { var a = this.extend(); a.init.apply(a, arguments); return a }, init: function () { }, mixIn: function (a) { for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]); a.hasOwnProperty("toString") && (this.toString = a.toString) }, clone: function () { return this.init.prototype.extend(this) } },
n = j.WordArray = f.extend({ init: function (a, c) { a = this.words = a || []; this.sigBytes = c != m ? c : 4 * a.length }, toString: function (a) { return (a || h).stringify(this) }, concat: function (a) { var c = this.words, q = a.words, d = this.sigBytes; a = a.sigBytes; this.clamp(); if (d % 4) for (var b = 0; b < a; b++) c[d + b >>> 2] |= (q[b >>> 2] >>> 24 - 8 * (b % 4) & 255) << 24 - 8 * ((d + b) % 4); else if (65535 < q.length) for (b = 0; b < a; b += 4) c[d + b >>> 2] = q[b >>> 2]; else c.push.apply(c, q); this.sigBytes += a; return this }, clamp: function () {
    var a = this.words, c = this.sigBytes; a[c >>> 2] &= 4294967295 <<
32 - 8 * (c % 4); a.length = e.ceil(c / 4)
}, clone: function () { var a = f.clone.call(this); a.words = this.words.slice(0); return a }, random: function (a) { for (var c = [], b = 0; b < a; b += 4) c.push(4294967296 * e.random() | 0); return new n.init(c, a) } 
}), b = p.enc = {}, h = b.Hex = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], d = 0; d < a; d++) { var f = c[d >>> 2] >>> 24 - 8 * (d % 4) & 255; b.push((f >>> 4).toString(16)); b.push((f & 15).toString(16)) } return b.join("") }, parse: function (a) {
    for (var c = a.length, b = [], d = 0; d < c; d += 2) b[d >>> 3] |= parseInt(a.substr(d,
2), 16) << 24 - 4 * (d % 8); return new n.init(b, c / 2)
} 
}, g = b.Latin1 = { stringify: function (a) { var c = a.words; a = a.sigBytes; for (var b = [], d = 0; d < a; d++) b.push(String.fromCharCode(c[d >>> 2] >>> 24 - 8 * (d % 4) & 255)); return b.join("") }, parse: function (a) { for (var c = a.length, b = [], d = 0; d < c; d++) b[d >>> 2] |= (a.charCodeAt(d) & 255) << 24 - 8 * (d % 4); return new n.init(b, c) } }, r = b.Utf8 = { stringify: function (a) { try { return decodeURIComponent(escape(g.stringify(a))) } catch (c) { throw Error("Malformed UTF-8 data"); } }, parse: function (a) { return g.parse(unescape(encodeURIComponent(a))) } },
k = j.BufferedBlockAlgorithm = f.extend({ reset: function () { this._data = new n.init; this._nDataBytes = 0 }, _append: function (a) { "string" == typeof a && (a = r.parse(a)); this._data.concat(a); this._nDataBytes += a.sigBytes }, _process: function (a) { var c = this._data, b = c.words, d = c.sigBytes, f = this.blockSize, h = d / (4 * f), h = a ? e.ceil(h) : e.max((h | 0) - this._minBufferSize, 0); a = h * f; d = e.min(4 * a, d); if (a) { for (var g = 0; g < a; g += f) this._doProcessBlock(b, g); g = b.splice(0, a); c.sigBytes -= d } return new n.init(g, d) }, clone: function () {
    var a = f.clone.call(this);
    a._data = this._data.clone(); return a
}, _minBufferSize: 0
}); j.Hasher = k.extend({ cfg: f.extend(), init: function (a) { this.cfg = this.cfg.extend(a); this.reset() }, reset: function () { k.reset.call(this); this._doReset() }, update: function (a) { this._append(a); this._process(); return this }, finalize: function (a) { a && this._append(a); return this._doFinalize() }, blockSize: 16, _createHelper: function (a) { return function (c, b) { return (new a.init(b)).finalize(c) } }, _createHmacHelper: function (a) {
    return function (b, f) {
        return (new s.HMAC.init(a,
f)).finalize(b)
    } 
} 
}); var s = p.algo = {}; return p
} (Math);
(function () {
    var e = CryptoJS, m = e.lib, p = m.WordArray, j = m.Hasher, l = [], m = e.algo.SHA1 = j.extend({ _doReset: function () { this._hash = new p.init([1732584193, 4023233417, 2562383102, 271733878, 3285377520]) }, _doProcessBlock: function (f, n) {
        for (var b = this._hash.words, h = b[0], g = b[1], e = b[2], k = b[3], j = b[4], a = 0; 80 > a; a++) {
            if (16 > a) l[a] = f[n + a] | 0; else { var c = l[a - 3] ^ l[a - 8] ^ l[a - 14] ^ l[a - 16]; l[a] = c << 1 | c >>> 31 } c = (h << 5 | h >>> 27) + j + l[a]; c = 20 > a ? c + ((g & e | ~g & k) + 1518500249) : 40 > a ? c + ((g ^ e ^ k) + 1859775393) : 60 > a ? c + ((g & e | g & k | e & k) - 1894007588) : c + ((g ^ e ^
k) - 899497514); j = k; k = e; e = g << 30 | g >>> 2; g = h; h = c
        } b[0] = b[0] + h | 0; b[1] = b[1] + g | 0; b[2] = b[2] + e | 0; b[3] = b[3] + k | 0; b[4] = b[4] + j | 0
    }, _doFinalize: function () { var f = this._data, e = f.words, b = 8 * this._nDataBytes, h = 8 * f.sigBytes; e[h >>> 5] |= 128 << 24 - h % 32; e[(h + 64 >>> 9 << 4) + 14] = Math.floor(b / 4294967296); e[(h + 64 >>> 9 << 4) + 15] = b; f.sigBytes = 4 * e.length; this._process(); return this._hash }, clone: function () { var e = j.clone.call(this); e._hash = this._hash.clone(); return e } 
    }); e.SHA1 = j._createHelper(m); e.HmacSHA1 = j._createHmacHelper(m)
})();

(function ($) {

    /**
    * Copyright 2012, Digital Fusion
    * Licensed under the MIT license.
    * http://teamdf.com/jquery-plugins/license/
    *
    * @author Sam Sehnert
    * @desc A small plugin that checks whether elements are within
    *       the user visible viewport of a web browser.
    *       only accounts for vertical position, not horizontal.
    */
    var $w = $(window);
    $.fn.visible = function (partial, hidden, direction) {

        if (this.length < 1)
            return;

        var $t = this.length > 1 ? this.eq(0) : this,
            t = $t.get(0),
            vpWidth = $w.width(),
            vpHeight = $w.height(),
            direction = (direction) ? direction : 'both',
            clientSize = hidden === true ? t.offsetWidth * t.offsetHeight : true;

        if (typeof t.getBoundingClientRect === 'function') {

            // Use this native browser method, if available.
            var rec = t.getBoundingClientRect(),
                tViz = rec.top >= 0 && rec.top < vpHeight,
                bViz = rec.bottom > 0 && rec.bottom <= vpHeight,
                lViz = rec.left >= 0 && rec.left < vpWidth,
                rViz = rec.right > 0 && rec.right <= vpWidth,
                vVisible = partial ? tViz || bViz : tViz && bViz,
                hVisible = partial ? lViz || rViz : lViz && rViz;

            if (direction === 'both')
                return clientSize && vVisible && hVisible;
            else if (direction === 'vertical')
                return clientSize && vVisible;
            else if (direction === 'horizontal')
                return clientSize && hVisible;
        } else {

            var viewTop = $w.scrollTop(),
                viewBottom = viewTop + vpHeight,
                viewLeft = $w.scrollLeft(),
                viewRight = viewLeft + vpWidth,
                offset = $t.offset(),
                _top = offset.top,
                _bottom = _top + $t.height(),
                _left = offset.left,
                _right = _left + $t.width(),
                compareTop = partial === true ? _bottom : _top,
                compareBottom = partial === true ? _top : _bottom,
                compareLeft = partial === true ? _right : _left,
                compareRight = partial === true ? _left : _right;

            if (direction === 'both')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop)) && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
            else if (direction === 'vertical')
                return !!clientSize && ((compareBottom <= viewBottom) && (compareTop >= viewTop));
            else if (direction === 'horizontal')
                return !!clientSize && ((compareRight <= viewRight) && (compareLeft >= viewLeft));
        }
    };

})(jQuery);
/*!
Waypoints - 4.0.0
Copyright © 2011-2015 Caleb Troughton
Licensed under the MIT license.
https://github.com/imakewebthings/waypoints/blog/master/licenses.txt
*/
!function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.invokeAll("enable")},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical);t&&e&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s],l=o.oldScroll<a.triggerPoint,h=o.newScroll>=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=y+l-f,h=w<s.oldScroll,p=d.triggerPoint>=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}();
/**
* Boxy 0.1.4 - Facebook-style dialog, with frills
*
* (c) 2008 Jason Frame
* Licensed under the MIT License (LICENSE)
*/

/*
* jQuery plugin
*
* Options:
*   message: confirmation message for form submit hook (default: "Please confirm:")
* 
* Any other options - e.g. 'clone' - will be passed onto the boxy constructor (or
* Boxy.load for AJAX operations)
*/
jQuery.fn.boxy = function (options) {
    options = options || {};
    return this.each(function () {
        var node = this.nodeName.toLowerCase(), self = this;
        if (node == 'a') {
            jQuery(this).click(function () {
                var active = Boxy.linkedTo(this),
                    href = this.getAttribute('href'),
                    localOptions = jQuery.extend({ actuator: this, title: this.title }, options);

                if (href.match(/(&|\?)boxy\.modal/)) localOptions.modal = true;

                if (active) {
                    active.show();
                } else if (href.indexOf('#') >= 0) {
                    var content = jQuery(href.substr(href.indexOf('#'))),
                        newContent = content.clone(true);
                    content.remove();
                    localOptions.unloadOnHide = false;
                    new Boxy(newContent, localOptions);
                } else if (href.match(/\.(jpe?g|png|gif|bmp)($|\?)/i)) {
                    localOptions.unloadOnHide = true;
                    Boxy.loadImage(this.href, localOptions);
                } else { // fall back to AJAX; could do with a same-origin check
                    if (!localOptions.cache) localOptions.unloadOnHide = true;
                    Boxy.load(this.href, localOptions);
                }

                return false;
            });
        } else if (node == 'form') {
            jQuery(this).bind('submit.boxy', function () {
                Boxy.confirm(options.message || 'Please confirm:', function () {
                    jQuery(self).unbind('submit.boxy').submit();
                });
                return false;
            });
        }
    });
};

//
// Boxy Class

function Boxy(element, options) {

    this.boxy = jQuery(Boxy.WRAPPER);
    jQuery.data(this.boxy[0], 'boxy', this);

    this.visible = false;
    this.options = jQuery.extend({}, Boxy.DEFAULTS, options || {});

    if (this.options.modal) {
        this.options = jQuery.extend(this.options, { center: true, draggable: false });
    }

    // options.actuator == DOM element that opened this boxy
    // association will be automatically deleted when this boxy is remove()d
    if (this.options.actuator) {
        jQuery.data(this.options.actuator, 'active.boxy', this);
    }

    this.setContent(element || "<div></div>");
    this._setupTitleBar();

    this.getToolbar().append(this.options.toolbar);

    this.boxy.css('display', 'none').appendTo(document.body);
    this.toTop();

    if (this.options.fixed) {
        if (Boxy.IE6) {
            this.options.fixed = false; // IE6 doesn't support fixed positioning
        } else {
            this.boxy.addClass('fixed');
        }
    }

    if (this.options.center && Boxy._u(this.options.x, this.options.y)) {
        this.center();
    } else {
        this.moveTo(
            Boxy._u(this.options.x) ? Boxy.DEFAULT_X : this.options.x,
            Boxy._u(this.options.y) ? Boxy.DEFAULT_Y : this.options.y
        );
    }

    if (this.options.show) this.show();

};

Boxy.EF = function () { };

jQuery.extend(Boxy, {

    WRAPPER: "<table cellspacing='0' cellpadding='0' border='0' class='boxy-wrapper app-boxy-wrapper'>" +
        "<tr><td class='boxy-inner'></td></tr><tr><td class='boxy-bottom' style='background-color: White;'></td></tr>" +                
        "</table>",

    DEFAULTS: {
        title: null,           // titlebar text. titlebar will not be visible if not set.
        closeable: true,           // display close link in titlebar?
        draggable: true,           // can this dialog be dragged?
        clone: false,          // clone content prior to insertion into dialog?
        actuator: null,           // element which opened this dialog
        center: true,           // center dialog in viewport?
        show: true,           // show dialog immediately?
        modal: false,          // make dialog modal?
        fixed: true,           // use fixed positioning, if supported? absolute positioning used otherwise
        closeText: '[close]',      // text to use for default close link
        unloadOnHide: false,          // should this dialog be removed from the DOM after being hidden?
        clickToFront: false,          // bring dialog to foreground on any click (not just titlebar)?
        behaviours: Boxy.EF,        // function used to apply behaviours to all content embedded in dialog.
        afterDrop: Boxy.EF,        // callback fired after dialog is dropped. executes in context of Boxy instance.
        afterShow: Boxy.EF,        // callback fired after dialog becomes visible. executes in context of Boxy instance.
        afterHide: Boxy.EF,        // callback fired after dialog is hidden. executed in context of Boxy instance.
        beforeUnload: Boxy.EF,        // callback fired after dialog is unloaded. executed in context of Boxy instance.
        afterUnload: Boxy.EF,
        beforeHide: Boxy.EF,
        hideFade: false,
        hideShrink: 'vertical',
        toolbar: ''
    },

    IE6: (jQuery.browser.msie && jQuery.browser.version < 7),
    DEFAULT_X: 50,
    DEFAULT_Y: 50,
    MODAL_OPACITY: 0.7,
    zIndex: 29000,
    dragConfigured: false, // only set up one drag handler for all boxys
    resizeConfigured: false,
    dragging: null,

    // load a URL and display in boxy
    // url - url to load
    // options keys (any not listed below are passed to boxy constructor)
    //   type: HTTP method, default: GET
    //   cache: cache retrieved content? default: false
    //   filter: jQuery selector used to filter remote content
    load: function (url, options) {

        options = options || {};

        var ajax = {
            url: url, type: 'GET', dataType: 'html', cache: false, success: function (html) {
                html = jQuery(html);
                if (options.filter) html = jQuery(options.filter, html);
                new Boxy(html, options);
            }
        };

        jQuery.each(['type', 'cache'], function () {
            if (this in options) {
                ajax[this] = options[this];
                delete options[this];
            }
        });

        jQuery.ajax(ajax);

    },

    loadImage: function (url, options) {
        var img = new Image();
        img.onload = function () {
            new Boxy($('<div class="boxy-image-wrapper"/>').append(this), options);
        };
        img.src = url;
    },

    // allows you to get a handle to the containing boxy instance of any element
    // e.g. <a href='#' onclick='alert(Boxy.get(this));'>inspect!</a>.
    // this returns the actual instance of the boxy 'class', not just a DOM element.
    // Boxy.get(this).hide() would be valid, for instance.
    get: function (ele) {
        var p = jQuery(ele).parents('.boxy-wrapper');
        return p.length ? jQuery.data(p[0], 'boxy') : null;
    },

    // returns the boxy instance which has been linked to a given element via the
    // 'actuator' constructor option.
    linkedTo: function (ele) {
        return jQuery.data(ele, 'active.boxy');
    },

    // displays an alert box with a given message, calling optional callback
    // after dismissal.
    alert: function (message, callback, options) {
        return Boxy.ask(message, ['OK'], callback, options);
    },

    // displays an alert box with a given message, calling after callback iff
    // user selects OK.
    confirm: function (message, after, options) {
        return Boxy.ask(message, ['OK', 'Cancel'], function (response) {
            if (response == 'OK') after();
        }, options);
    },

    // asks a question with multiple responses presented as buttons
    // selected item is returned to a callback method.
    // answers may be either an array or a hash. if it's an array, the
    // the callback will received the selected value. if it's a hash,
    // you'll get the corresponding key.
    ask: function (question, answers, callback, options) {

        options = jQuery.extend({ modal: true, closeable: false },
                                options || {},
                                { show: true, unloadOnHide: true });

        var body = jQuery('<div></div>').append(jQuery('<div class="question"></div>').html(question));

        var buttons = jQuery('<form class="answers"></form>');
        buttons.html(jQuery.map(Boxy._values(answers), function (v) {
            return "<input type='button' value='" + v + "' />";
        }).join(' '));

        jQuery('input[type=button]', buttons).click(function () {
            var clicked = this;
            Boxy.get(this).hide(function () {
                if (callback) {
                    jQuery.each(answers, function (i, val) {
                        if (val == clicked.value) {
                            callback(answers instanceof Array ? val : i);
                            return false;
                        }
                    });
                }
            });
        });

        body.append(buttons);

        new Boxy(body, options);

    },

    // returns true if a modal boxy is visible, false otherwise
    isModalVisible: function () {
        return jQuery('.boxy-modal-blackout').length > 0;
    },

    _u: function () {
        for (var i = 0; i < arguments.length; i++)
            if (typeof arguments[i] != 'undefined') return false;
        return true;
    },

    _values: function (t) {
        if (t instanceof Array) return t;
        var o = [];
        for (var k in t) o.push(t[k]);
        return o;
    },

    _handleResize: function (evt) {
        jQuery('.boxy-modal-blackout').css('display', 'none')
                                      .css(Boxy._cssForOverlay())
                                      .css('display', 'block');
    },

    _handleDrag: function (evt) {
        var d;
        if (d = Boxy.dragging) {
            d[0].boxy.css({ left: evt.pageX - d[1], top: evt.pageY - d[2] });
        }
    },

    _nextZ: function () {
        return Boxy.zIndex++;
    },

    _viewport: function () {
        var d = document.documentElement, b = document.body, w = window;
        return jQuery.extend(
            jQuery.browser.msie ?
                { left: b.scrollLeft || d.scrollLeft, top: b.scrollTop || d.scrollTop} :
                { left: w.pageXOffset, top: w.pageYOffset },
            !Boxy._u(w.innerWidth) ?
                { width: w.innerWidth, height: w.innerHeight} :
                (!Boxy._u(d) && !Boxy._u(d.clientWidth) && d.clientWidth != 0 ?
                    { width: d.clientWidth, height: d.clientHeight} :
                    { width: b.clientWidth, height: b.clientHeight }));
    },

    _setupModalResizing: function () {
        if (!Boxy.resizeConfigured) {
            var w = jQuery(window).resize(Boxy._handleResize);
            if (Boxy.IE6) w.scroll(Boxy._handleResize);
            Boxy.resizeConfigured = true;
        }
    },

    _cssForOverlay: function () {
        if (Boxy.IE6) {
            return Boxy._viewport();
        } else {
            return { width: '100%', height: jQuery(document).height() };
        }
    }

});

Boxy.prototype = {

    // Returns the size of this boxy instance without displaying it.
    // Do not use this method if boxy is already visible, use getSize() instead.
    estimateSize: function () {
        this.boxy.css({ visibility: 'hidden', display: 'block' });
        var dims = this.getSize();
        this.boxy.css('display', 'none').css('visibility', 'visible');
        return dims;
    },

    // Returns the dimensions of the entire boxy dialog as [width,height]
    getSize: function () {
        return [this.boxy.width(), this.boxy.height()];
    },

    // Returns the dimensions of the content region as [width,height]
    getContentSize: function () {
        var c = this.getContent();
        return [c.width(), c.height()];
    },

    // Returns the position of this dialog as [x,y]
    getPosition: function () {
        var b = this.boxy[0];
        return [b.offsetLeft, b.offsetTop];
    },

    // Returns the center point of this dialog as [x,y]
    getCenter: function () {
        var p = this.getPosition();
        var s = this.getSize();
        return [Math.floor(p[0] + s[0] / 2), Math.floor(p[1] + s[1] / 2)];
    },

    // Returns a jQuery object wrapping the inner boxy region.
    // Not much reason to use this, you're probably more interested in getContent()
    getInner: function () {
        return jQuery('.boxy-inner', this.boxy);
    },

    // Returns a jQuery object wrapping the boxy content region.
    // This is the user-editable content area (i.e. excludes titlebar)
    getContent: function () {
        return jQuery('.boxy-content', this.boxy);
    },

    getToolbar: function () {
        return jQuery('.boxy-bottom', this.boxy);
    },

    // Replace dialog content
    setContent: function (newContent) {
        newContent = jQuery(newContent).css({ display: 'block' }).addClass('boxy-content');
        if (this.options.clone) newContent = newContent.clone(true);
        this.getContent().remove();
        this.getInner().append(newContent);
        this._setupDefaultBehaviours(newContent);
        this.options.behaviours.call(this, newContent);
        return this;
    },

    // Move this dialog to some position, funnily enough
    moveTo: function (x, y) {
        this.moveToX(x).moveToY(y);
        return this;
    },

    // Move this dialog (x-coord only)
    moveToX: function (x) {
        if (typeof x == 'number') this.boxy.css({ left: (x < 0 ? 0 : x) });
        else this.centerX();
        return this;
    },

    // Move this dialog (y-coord only)
    moveToY: function (y) {
        if (typeof y == 'number') this.boxy.css({ top: (y < 0 ? 0 : y) });
        else this.centerY();
        return this;
    },

    // Move this dialog so that it is centered at (x,y)
    centerAt: function (x, y) {
        var s = this[this.visible ? 'getSize' : 'estimateSize']();
        if (typeof x == 'number') this.moveToX(x - s[0] / 2);
        if (typeof y == 'number') this.moveToY(y - s[1] / 2);
        return this;
    },

    centerAtX: function (x) {
        return this.centerAt(x, null);
    },

    centerAtY: function (y) {
        return this.centerAt(null, y);
    },

    // Center this dialog in the viewport
    // axis is optional, can be 'x', 'y'.
    center: function (axis) {
        var v = Boxy._viewport();
        var o = this.options.fixed ? [0, 0] : [v.left, v.top];
        if (!axis || axis == 'x') this.centerAt(o[0] + v.width / 2, null);
        if (!axis || axis == 'y') this.centerAt(null, o[1] + v.height / 2);
        return this;
    },

    // Center this dialog in the viewport (x-coord only)
    centerX: function () {
        return this.center('x');
    },

    // Center this dialog in the viewport (y-coord only)
    centerY: function () {
        return this.center('y');
    },

    // Resize the content region to a specific size
    resize: function (width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        this.boxy.css({ left: bounds[0], top: bounds[1] });
        this.getContent().css({ width: bounds[2], height: bounds[3] });
        if (after) after(this);
        return this;
    },

    // Tween the content region to a specific size
    tween: function (width, height, after) {
        if (!this.visible) return;
        var bounds = this._getBoundsForResize(width, height);
        var self = this;
        this.boxy.stop().animate({ left: bounds[0], top: bounds[1] });
        this.getContent().stop().animate({ width: bounds[2], height: bounds[3] }, function () {
            if (after) after(self);
        });
        return this;
    },

    // Returns true if this dialog is visible, false otherwise
    isVisible: function () {
        return this.visible;
    },

    // Make this boxy instance visible
    show: function () {
        if (this.visible) return;
        if (this.options.modal) {
            var self = this;
            Boxy._setupModalResizing();
            this.modalBlackout = jQuery('<div class="boxy-modal-blackout"></div>')
                .css(jQuery.extend(Boxy._cssForOverlay(), {
                    zIndex: Boxy._nextZ(), opacity: Boxy.MODAL_OPACITY
                })).appendTo(document.body);
            this.toTop();
            if (this.options.closeable) {
                jQuery(document.body).bind('keypress.boxy', function (evt) {
                    var key = evt.which || evt.keyCode;
                    if (key == 27) {
                        self.hide();
                        jQuery(document.body).unbind('keypress.boxy');
                    }
                });
            }
        }
        this.getInner().stop().css({ width: '', height: '' });
        this.boxy.stop().css({ opacity: 1 }).show();
        this.visible = true;
        //this.boxy.find('.close:first').focus();
        this._fire('afterShow');
        return this;
    },

    // Hide this boxy instance
    hide: function (after, closeclicked) {

        if (!this.visible) return;

        if (this._fire('beforeHide', closeclicked) == false)
            return;

        var self = this;

        if (this.options.modal) {
            jQuery(document.body).unbind('keypress.boxy');
            this.modalBlackout.animate({ opacity: 0 }, function () {
                jQuery(this).remove();
            });
        }

        var target = { boxy: {}, inner: {} },
			tween = 0,
			hideComplete = function () {
			    self.boxy.css({ display: 'none' });
			    self.visible = false;
			    self._fire('afterHide');
			    if (after) after(self);
			    if (self.options.unloadOnHide) self.unload();
			};

        if (this.options.hideShrink) {
            var inner = this.getInner(), hs = this.options.hideShrink, pos = this.getPosition();
            tween |= 1;
            if (hs === true || hs == 'vertical') {
                target.inner.height = 0;
                target.boxy.top = pos[1] + inner.height() / 2;
            }
            if (hs === true || hs == 'horizontal') {
                target.inner.width = 0;
                target.boxy.left = pos[0] + inner.width() / 2;
            }
        }

        if (this.options.hideFade) {
            tween |= 2;
            target.boxy.opacity = 0;
        }

        if (tween) {
            if (tween & 1) inner.stop().animate(target.inner, 300);
            this.boxy.stop().animate(target.boxy, 300, hideComplete);
        } else {
            hideComplete();
        }

        return this;

    },

    toggle: function () {
        this[this.visible ? 'hide' : 'show']();
        return this;
    },

    hideAndUnload: function (after) {
        this.options.unloadOnHide = true;
        this.hide(after);
        return this;
    },

    unload: function () {
        if (this._fire('beforeUnload') == false)
            return;
        if (this.options.modal) {
            jQuery(document.body).unbind('keypress.boxy');
            if (this.modalBlackout)
                this.modalBlackout.animate({ opacity: 0 }, function () {
                    jQuery(this).remove();
                });
        }
        this.boxy.remove();
        this._fire('afterUnload');
        if (this.options.actuator) {
            jQuery.data(this.options.actuator, 'active.boxy', false);
        }
    },

    // Move this dialog box above all other boxy instances
    toTop: function () {
        this.boxy.css({ zIndex: Boxy._nextZ() });
        return this;
    },

    // Returns the title of this dialog
    getTitle: function () {
        return jQuery('> .title-bar h2', this.getInner()).html();
    },

    // Sets the title of this dialog
    setTitle: function (t) {
        jQuery('> .title-bar h2', this.getInner()).html(t);
        return this;
    },

    //
    // Don't touch these privates

    _getBoundsForResize: function (width, height) {
        var csize = this.getContentSize();
        var delta = [width - csize[0], height - csize[1]];
        var p = this.getPosition();
        return [Math.max(p[0] - delta[0] / 2, 0),
                Math.max(p[1] - delta[1] / 2, 0), width, height];
    },

    _setupTitleBar: function () {
        if (this.options.title) {
            var self = this;
			
            var tb = null;
            if(Application.IsInMobile()){
                tb = jQuery("<div class='title-bar navbar navbar-inner'></div>").html(
                    (this.options.closeable?"<div id='closebtn"+this.options.id+"' class='menu-icon' data-ripple>" + this.options.closeText + "</div>":"") +
                    "<h2 class='navbar-brand' style='width: calc(100vw - 100px);margin: 0px;'>" + this.options.title + "</h2>" +
                    "<div id='okbtn"+this.options.id+"' class='menu-icon' style='float: right' data-ripple><i class='mdi mdi-check' style='font-size: 30px'></i></div>"
                );
            }else{
                tb = jQuery("<div class='title-bar ui-header ui-bar-a ui-dialog-titlebar ui-widget-header app-boxy-titlebar'></div>").html("<h2 class='app-boxy-title' style='display: inline-block; max-width: "+(UI.MagicWidth()-20)+"px;'>" + this.options.title + "</h2>");
                if (this.options.closeable) {
                    tb.append(jQuery('<a class="close mdi mdi-close" style="cursor: pointer;display: inline-block;float: right;font-size: 20px;line-height: 35px;margin-right: 10px;color: white;"></a>'));
                }
            }
           
            if (this.options.draggable) {
                tb[0].onselectstart = function () { return false; };
                tb[0].unselectable = 'on';
                tb[0].style.MozUserSelect = 'none';
                if (!Boxy.dragConfigured) {
                    jQuery(document).mousemove(Boxy._handleDrag);
                    Boxy.dragConfigured = true;
                }
                tb.mousedown(function (evt) {
                    self.toTop();
                    Boxy.dragging = [self, evt.pageX - self.boxy[0].offsetLeft, evt.pageY - self.boxy[0].offsetTop];
                    jQuery(this).addClass('dragging');
                }).mouseup(function () {
                    jQuery(this).removeClass('dragging');
                    Boxy.dragging = null;
                    self._fire('afterDrop');
                });
            }
            this.getInner().prepend(tb);
            this._setupDefaultBehaviours(tb);
        }
    },

    _setupDefaultBehaviours: function (root) {
        var self = this;
        if (this.options.clickToFront) {
            root.click(function () { self.toTop(); });
        }
        jQuery('.close', root).click(function (e) {
			$handleclick(e); //Liveapp v4
            self.hide(null,true);
            return false;
        }).mousedown(function (evt) { evt.stopPropagation(); });
        jQuery('.save', root).click(function () {
            self.options.onSave();
            return false;
        }).mousedown(function (evt) { evt.stopPropagation(); });
        jQuery('.addnext', root).click(function () {
            self.options.addNext();
            return false;
        }).mousedown(function (evt) { evt.stopPropagation(); });
    },

    _fire: function (event, arg1) {
        return this.options[event].call(this, arg1);
    }

};
(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module unless amdModuleId is set
        define('Chartist', [], function () {
            return (root['Chartist'] = factory());
        });
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        root['Chartist'] = factory();
    }
}(this, function () {

    /* Chartist.js 0.11.0
     * Copyright © 2017 Gion Kunz
     * Free to use under either the WTFPL license or the MIT license.
     * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-WTFPL
     * https://raw.githubusercontent.com/gionkunz/chartist-js/master/LICENSE-MIT
     */
    /**
     * The core module of Chartist that is mainly providing static functions and higher level functions for chart modules.
     *
     * @module Chartist.Core
     */
    var Chartist = {
        version: '0.11.0'
    };

    (function (window, document, Chartist) {
        'use strict';

        /**
         * This object contains all namespaces used within Chartist.
         *
         * @memberof Chartist.Core
         * @type {{svg: string, xmlns: string, xhtml: string, xlink: string, ct: string}}
         */
        Chartist.namespaces = {
            svg: 'http://www.w3.org/2000/svg',
            xmlns: 'http://www.w3.org/2000/xmlns/',
            xhtml: 'http://www.w3.org/1999/xhtml',
            xlink: 'http://www.w3.org/1999/xlink',
            ct: 'http://gionkunz.github.com/chartist-js/ct'
        };

        /**
         * Helps to simplify functional style code
         *
         * @memberof Chartist.Core
         * @param {*} n This exact value will be returned by the noop function
         * @return {*} The same value that was provided to the n parameter
         */
        Chartist.noop = function (n) {
            return n;
        };

        /**
         * Generates a-z from a number 0 to 26
         *
         * @memberof Chartist.Core
         * @param {Number} n A number from 0 to 26 that will result in a letter a-z
         * @return {String} A character from a-z based on the input number n
         */
        Chartist.alphaNumerate = function (n) {
            // Limit to a-z
            return String.fromCharCode(97 + n % 26);
        };

        /**
         * Simple recursive object extend
         *
         * @memberof Chartist.Core
         * @param {Object} target Target object where the source will be merged into
         * @param {Object...} sources This object (objects) will be merged into target and then target is returned
         * @return {Object} An object that has the same reference as target but is extended and merged with the properties of source
         */
        Chartist.extend = function (target) {
            var i, source, sourceProp;
            target = target || {};

            for (i = 1; i < arguments.length; i++) {
                source = arguments[i];
                for (var prop in source) {
                    sourceProp = source[prop];
                    if (typeof sourceProp === 'object' && sourceProp !== null && !(sourceProp instanceof Array)) {
                        target[prop] = Chartist.extend(target[prop], sourceProp);
                    } else {
                        target[prop] = sourceProp;
                    }
                }
            }

            return target;
        };

        /**
         * Replaces all occurrences of subStr in str with newSubStr and returns a new string.
         *
         * @memberof Chartist.Core
         * @param {String} str
         * @param {String} subStr
         * @param {String} newSubStr
         * @return {String}
         */
        Chartist.replaceAll = function (str, subStr, newSubStr) {
            return str.replace(new RegExp(subStr, 'g'), newSubStr);
        };

        /**
         * Converts a number to a string with a unit. If a string is passed then this will be returned unmodified.
         *
         * @memberof Chartist.Core
         * @param {Number} value
         * @param {String} unit
         * @return {String} Returns the passed number value with unit.
         */
        Chartist.ensureUnit = function (value, unit) {
            if (typeof value === 'number') {
                value = value + unit;
            }

            return value;
        };

        /**
         * Converts a number or string to a quantity object.
         *
         * @memberof Chartist.Core
         * @param {String|Number} input
         * @return {Object} Returns an object containing the value as number and the unit as string.
         */
        Chartist.quantity = function (input) {
            if (typeof input === 'string') {
                var match = (/^(\d+)\s*(.*)$/g).exec(input);
                return {
                    value: +match[1],
                    unit: match[2] || undefined
                };
            }
            return { value: input };
        };

        /**
         * This is a wrapper around document.querySelector that will return the query if it's already of type Node
         *
         * @memberof Chartist.Core
         * @param {String|Node} query The query to use for selecting a Node or a DOM node that will be returned directly
         * @return {Node}
         */
        Chartist.querySelector = function (query) {
            return query instanceof Node ? query : document.querySelector(query);
        };

        /**
         * Functional style helper to produce array with given length initialized with undefined values
         *
         * @memberof Chartist.Core
         * @param length
         * @return {Array}
         */
        Chartist.times = function (length) {
            return Array.apply(null, new Array(length));
        };

        /**
         * Sum helper to be used in reduce functions
         *
         * @memberof Chartist.Core
         * @param previous
         * @param current
         * @return {*}
         */
        Chartist.sum = function (previous, current) {
            return previous + (current ? current : 0);
        };

        /**
         * Multiply helper to be used in `Array.map` for multiplying each value of an array with a factor.
         *
         * @memberof Chartist.Core
         * @param {Number} factor
         * @returns {Function} Function that can be used in `Array.map` to multiply each value in an array
         */
        Chartist.mapMultiply = function (factor) {
            return function (num) {
                return num * factor;
            };
        };

        /**
         * Add helper to be used in `Array.map` for adding a addend to each value of an array.
         *
         * @memberof Chartist.Core
         * @param {Number} addend
         * @returns {Function} Function that can be used in `Array.map` to add a addend to each value in an array
         */
        Chartist.mapAdd = function (addend) {
            return function (num) {
                return num + addend;
            };
        };

        /**
         * Map for multi dimensional arrays where their nested arrays will be mapped in serial. The output array will have the length of the largest nested array. The callback function is called with variable arguments where each argument is the nested array value (or undefined if there are no more values).
         *
         * @memberof Chartist.Core
         * @param arr
         * @param cb
         * @return {Array}
         */
        Chartist.serialMap = function (arr, cb) {
            var result = [],
                length = Math.max.apply(null, arr.map(function (e) {
                    return e.length;
                }));

            Chartist.times(length).forEach(function (e, index) {
                var args = arr.map(function (e) {
                    return e[index];
                });

                result[index] = cb.apply(null, args);
            });

            return result;
        };

        /**
         * This helper function can be used to round values with certain precision level after decimal. This is used to prevent rounding errors near float point precision limit.
         *
         * @memberof Chartist.Core
         * @param {Number} value The value that should be rounded with precision
         * @param {Number} [digits] The number of digits after decimal used to do the rounding
         * @returns {number} Rounded value
         */
        Chartist.roundWithPrecision = function (value, digits) {
            var precision = Math.pow(10, digits || Chartist.precision);
            return Math.round(value * precision) / precision;
        };

        /**
         * Precision level used internally in Chartist for rounding. If you require more decimal places you can increase this number.
         *
         * @memberof Chartist.Core
         * @type {number}
         */
        Chartist.precision = 8;

        /**
         * A map with characters to escape for strings to be safely used as attribute values.
         *
         * @memberof Chartist.Core
         * @type {Object}
         */
        Chartist.escapingMap = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&quot;',
            '\'': '&#039;'
        };

        /**
         * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap.
         * If called with null or undefined the function will return immediately with null or undefined.
         *
         * @memberof Chartist.Core
         * @param {Number|String|Object} data
         * @return {String}
         */
        Chartist.serialize = function (data) {
            if (data === null || data === undefined) {
                return data;
            } else if (typeof data === 'number') {
                data = '' + data;
            } else if (typeof data === 'object') {
                data = JSON.stringify({ data: data });
            }

            return Object.keys(Chartist.escapingMap).reduce(function (result, key) {
                return Chartist.replaceAll(result, key, Chartist.escapingMap[key]);
            }, data);
        };

        /**
         * This function de-serializes a string previously serialized with Chartist.serialize. The string will always be unescaped using Chartist.escapingMap before it's returned. Based on the input value the return type can be Number, String or Object. JSON.parse is used with try / catch to see if the unescaped string can be parsed into an Object and this Object will be returned on success.
         *
         * @memberof Chartist.Core
         * @param {String} data
         * @return {String|Number|Object}
         */
        Chartist.deserialize = function (data) {
            if (typeof data !== 'string') {
                return data;
            }

            data = Object.keys(Chartist.escapingMap).reduce(function (result, key) {
                return Chartist.replaceAll(result, Chartist.escapingMap[key], key);
            }, data);

            try {
                data = JSON.parse(data);
                data = data.data !== undefined ? data.data : data;
            } catch (e) { }

            return data;
        };

        /**
         * Create or reinitialize the SVG element for the chart
         *
         * @memberof Chartist.Core
         * @param {Node} container The containing DOM Node object that will be used to plant the SVG element
         * @param {String} width Set the width of the SVG element. Default is 100%
         * @param {String} height Set the height of the SVG element. Default is 100%
         * @param {String} className Specify a class to be added to the SVG element
         * @return {Object} The created/reinitialized SVG element
         */
        Chartist.createSvg = function (container, width, height, className) {
            var svg;

            width = width || '100%';
            height = height || '100%';

            // Check if there is a previous SVG element in the container that contains the Chartist XML namespace and remove it
            // Since the DOM API does not support namespaces we need to manually search the returned list http://www.w3.org/TR/selectors-api/
            Array.prototype.slice.call(container.querySelectorAll('svg')).filter(function filterChartistSvgObjects(svg) {
                return svg.getAttributeNS(Chartist.namespaces.xmlns, 'ct');
            }).forEach(function removePreviousElement(svg) {
                container.removeChild(svg);
            });

            // Create svg object with width and height or use 100% as default
            svg = new Chartist.Svg('svg').attr({
                width: width,
                height: height
            }).addClass(className);

            svg._node.style.width = width;
            svg._node.style.height = height;

            // Add the DOM node to our container
            container.appendChild(svg._node);

            return svg;
        };

        /**
         * Ensures that the data object passed as second argument to the charts is present and correctly initialized.
         *
         * @param  {Object} data The data object that is passed as second argument to the charts
         * @return {Object} The normalized data object
         */
        Chartist.normalizeData = function (data, reverse, multi) {
            var labelCount;
            var output = {
                raw: data,
                normalized: {}
            };

            // Check if we should generate some labels based on existing series data
            output.normalized.series = Chartist.getDataArray({
                series: data.series || []
            }, reverse, multi);

            // If all elements of the normalized data array are arrays we're dealing with
            // multi series data and we need to find the largest series if they are un-even
            if (output.normalized.series.every(function (value) {
                return value instanceof Array;
            })) {
                // Getting the series with the the most elements
                labelCount = Math.max.apply(null, output.normalized.series.map(function (series) {
                    return series.length;
                }));
            } else {
                // We're dealing with Pie data so we just take the normalized array length
                labelCount = output.normalized.series.length;
            }

            output.normalized.labels = (data.labels || []).slice();
            // Padding the labels to labelCount with empty strings
            Array.prototype.push.apply(
              output.normalized.labels,
              Chartist.times(Math.max(0, labelCount - output.normalized.labels.length)).map(function () {
                  return '';
              })
            );

            if (reverse) {
                Chartist.reverseData(output.normalized);
            }

            return output;
        };

        /**
         * This function safely checks if an objects has an owned property.
         *
         * @param {Object} object The object where to check for a property
         * @param {string} property The property name
         * @returns {boolean} Returns true if the object owns the specified property
         */
        Chartist.safeHasProperty = function (object, property) {
            return object !== null &&
              typeof object === 'object' &&
              object.hasOwnProperty(property);
        };

        /**
         * Checks if a value is considered a hole in the data series.
         *
         * @param {*} value
         * @returns {boolean} True if the value is considered a data hole
         */
        Chartist.isDataHoleValue = function (value) {
            return value === null ||
              value === undefined ||
              (typeof value === 'number' && isNaN(value));
        };

        /**
         * Reverses the series, labels and series data arrays.
         *
         * @memberof Chartist.Core
         * @param data
         */
        Chartist.reverseData = function (data) {
            data.labels.reverse();
            data.series.reverse();
            for (var i = 0; i < data.series.length; i++) {
                if (typeof (data.series[i]) === 'object' && data.series[i].data !== undefined) {
                    data.series[i].data.reverse();
                } else if (data.series[i] instanceof Array) {
                    data.series[i].reverse();
                }
            }
        };

        /**
         * Convert data series into plain array
         *
         * @memberof Chartist.Core
         * @param {Object} data The series object that contains the data to be visualized in the chart
         * @param {Boolean} [reverse] If true the whole data is reversed by the getDataArray call. This will modify the data object passed as first parameter. The labels as well as the series order is reversed. The whole series data arrays are reversed too.
         * @param {Boolean} [multi] Create a multi dimensional array from a series data array where a value object with `x` and `y` values will be created.
         * @return {Array} A plain array that contains the data to be visualized in the chart
         */
        Chartist.getDataArray = function (data, reverse, multi) {
            // Recursively walks through nested arrays and convert string values to numbers and objects with value properties
            // to values. Check the tests in data core -> data normalization for a detailed specification of expected values
            function recursiveConvert(value) {
                if (Chartist.safeHasProperty(value, 'value')) {
                    // We are dealing with value object notation so we need to recurse on value property
                    return recursiveConvert(value.value);
                } else if (Chartist.safeHasProperty(value, 'data')) {
                    // We are dealing with series object notation so we need to recurse on data property
                    return recursiveConvert(value.data);
                } else if (value instanceof Array) {
                    // Data is of type array so we need to recurse on the series
                    return value.map(recursiveConvert);
                } else if (Chartist.isDataHoleValue(value)) {
                    // We're dealing with a hole in the data and therefore need to return undefined
                    // We're also returning undefined for multi value output
                    return undefined;
                } else {
                    // We need to prepare multi value output (x and y data)
                    if (multi) {
                        var multiValue = {};

                        // Single series value arrays are assumed to specify the Y-Axis value
                        // For example: [1, 2] => [{x: undefined, y: 1}, {x: undefined, y: 2}]
                        // If multi is a string then it's assumed that it specified which dimension should be filled as default
                        if (typeof multi === 'string') {
                            multiValue[multi] = Chartist.getNumberOrUndefined(value);
                        } else {
                            multiValue.y = Chartist.getNumberOrUndefined(value);
                        }

                        multiValue.x = value.hasOwnProperty('x') ? Chartist.getNumberOrUndefined(value.x) : multiValue.x;
                        multiValue.y = value.hasOwnProperty('y') ? Chartist.getNumberOrUndefined(value.y) : multiValue.y;

                        return multiValue;

                    } else {
                        // We can return simple data
                        return Chartist.getNumberOrUndefined(value);
                    }
                }
            }

            return data.series.map(recursiveConvert);
        };

        /**
         * Converts a number into a padding object.
         *
         * @memberof Chartist.Core
         * @param {Object|Number} padding
         * @param {Number} [fallback] This value is used to fill missing values if a incomplete padding object was passed
         * @returns {Object} Returns a padding object containing top, right, bottom, left properties filled with the padding number passed in as argument. If the argument is something else than a number (presumably already a correct padding object) then this argument is directly returned.
         */
        Chartist.normalizePadding = function (padding, fallback) {
            fallback = fallback || 0;

            return typeof padding === 'number' ? {
                top: padding,
                right: padding,
                bottom: padding,
                left: padding
            } : {
                top: typeof padding.top === 'number' ? padding.top : fallback,
                right: typeof padding.right === 'number' ? padding.right : fallback,
                bottom: typeof padding.bottom === 'number' ? padding.bottom : fallback,
                left: typeof padding.left === 'number' ? padding.left : fallback
            };
        };

        Chartist.getMetaData = function (series, index) {
            var value = series.data ? series.data[index] : series[index];
            return value ? value.meta : undefined;
        };

        /**
         * Calculate the order of magnitude for the chart scale
         *
         * @memberof Chartist.Core
         * @param {Number} value The value Range of the chart
         * @return {Number} The order of magnitude
         */
        Chartist.orderOfMagnitude = function (value) {
            return Math.floor(Math.log(Math.abs(value)) / Math.LN10);
        };

        /**
         * Project a data length into screen coordinates (pixels)
         *
         * @memberof Chartist.Core
         * @param {Object} axisLength The svg element for the chart
         * @param {Number} length Single data value from a series array
         * @param {Object} bounds All the values to set the bounds of the chart
         * @return {Number} The projected data length in pixels
         */
        Chartist.projectLength = function (axisLength, length, bounds) {
            return length / bounds.range * axisLength;
        };

        /**
         * Get the height of the area in the chart for the data series
         *
         * @memberof Chartist.Core
         * @param {Object} svg The svg element for the chart
         * @param {Object} options The Object that contains all the optional values for the chart
         * @return {Number} The height of the area in the chart for the data series
         */
        Chartist.getAvailableHeight = function (svg, options) {
            return Math.max((Chartist.quantity(options.height).value || svg.height()) - (options.chartPadding.top + options.chartPadding.bottom) - options.axisX.offset, 0);
        };

        /**
         * Get highest and lowest value of data array. This Array contains the data that will be visualized in the chart.
         *
         * @memberof Chartist.Core
         * @param {Array} data The array that contains the data to be visualized in the chart
         * @param {Object} options The Object that contains the chart options
         * @param {String} dimension Axis dimension 'x' or 'y' used to access the correct value and high / low configuration
         * @return {Object} An object that contains the highest and lowest value that will be visualized on the chart.
         */
        Chartist.getHighLow = function (data, options, dimension) {
            // TODO: Remove workaround for deprecated global high / low config. Axis high / low configuration is preferred
            options = Chartist.extend({}, options, dimension ? options['axis' + dimension.toUpperCase()] : {});

            var highLow = {
                high: options.high === undefined ? -Number.MAX_VALUE : +options.high,
                low: options.low === undefined ? Number.MAX_VALUE : +options.low
            };
            var findHigh = options.high === undefined;
            var findLow = options.low === undefined;

            // Function to recursively walk through arrays and find highest and lowest number
            function recursiveHighLow(data) {
                if (data === undefined) {
                    return undefined;
                } else if (data instanceof Array) {
                    for (var i = 0; i < data.length; i++) {
                        recursiveHighLow(data[i]);
                    }
                } else {
                    var value = dimension ? +data[dimension] : +data;

                    if (findHigh && value > highLow.high) {
                        highLow.high = value;
                    }

                    if (findLow && value < highLow.low) {
                        highLow.low = value;
                    }
                }
            }

            // Start to find highest and lowest number recursively
            if (findHigh || findLow) {
                recursiveHighLow(data);
            }

            // Overrides of high / low based on reference value, it will make sure that the invisible reference value is
            // used to generate the chart. This is useful when the chart always needs to contain the position of the
            // invisible reference value in the view i.e. for bipolar scales.
            if (options.referenceValue || options.referenceValue === 0) {
                highLow.high = Math.max(options.referenceValue, highLow.high);
                highLow.low = Math.min(options.referenceValue, highLow.low);
            }

            // If high and low are the same because of misconfiguration or flat data (only the same value) we need
            // to set the high or low to 0 depending on the polarity
            if (highLow.high <= highLow.low) {
                // If both values are 0 we set high to 1
                if (highLow.low === 0) {
                    highLow.high = 1;
                } else if (highLow.low < 0) {
                    // If we have the same negative value for the bounds we set bounds.high to 0
                    highLow.high = 0;
                } else if (highLow.high > 0) {
                    // If we have the same positive value for the bounds we set bounds.low to 0
                    highLow.low = 0;
                } else {
                    // If data array was empty, values are Number.MAX_VALUE and -Number.MAX_VALUE. Set bounds to prevent errors
                    highLow.high = 1;
                    highLow.low = 0;
                }
            }

            return highLow;
        };

        /**
         * Checks if a value can be safely coerced to a number. This includes all values except null which result in finite numbers when coerced. This excludes NaN, since it's not finite.
         *
         * @memberof Chartist.Core
         * @param value
         * @returns {Boolean}
         */
        Chartist.isNumeric = function (value) {
            return value === null ? false : isFinite(value);
        };

        /**
         * Returns true on all falsey values except the numeric value 0.
         *
         * @memberof Chartist.Core
         * @param value
         * @returns {boolean}
         */
        Chartist.isFalseyButZero = function (value) {
            return !value && value !== 0;
        };

        /**
         * Returns a number if the passed parameter is a valid number or the function will return undefined. On all other values than a valid number, this function will return undefined.
         *
         * @memberof Chartist.Core
         * @param value
         * @returns {*}
         */
        Chartist.getNumberOrUndefined = function (value) {
            return Chartist.isNumeric(value) ? +value : undefined;
        };

        /**
         * Checks if provided value object is multi value (contains x or y properties)
         *
         * @memberof Chartist.Core
         * @param value
         */
        Chartist.isMultiValue = function (value) {
            return typeof value === 'object' && ('x' in value || 'y' in value);
        };

        /**
         * Gets a value from a dimension `value.x` or `value.y` while returning value directly if it's a valid numeric value. If the value is not numeric and it's falsey this function will return `defaultValue`.
         *
         * @memberof Chartist.Core
         * @param value
         * @param dimension
         * @param defaultValue
         * @returns {*}
         */
        Chartist.getMultiValue = function (value, dimension) {
            if (Chartist.isMultiValue(value)) {
                return Chartist.getNumberOrUndefined(value[dimension || 'y']);
            } else {
                return Chartist.getNumberOrUndefined(value);
            }
        };

        /**
         * Pollard Rho Algorithm to find smallest factor of an integer value. There are more efficient algorithms for factorization, but this one is quite efficient and not so complex.
         *
         * @memberof Chartist.Core
         * @param {Number} num An integer number where the smallest factor should be searched for
         * @returns {Number} The smallest integer factor of the parameter num.
         */
        Chartist.rho = function (num) {
            if (num === 1) {
                return num;
            }

            function gcd(p, q) {
                if (p % q === 0) {
                    return q;
                } else {
                    return gcd(q, p % q);
                }
            }

            function f(x) {
                return x * x + 1;
            }

            var x1 = 2, x2 = 2, divisor;
            if (num % 2 === 0) {
                return 2;
            }

            do {
                x1 = f(x1) % num;
                x2 = f(f(x2)) % num;
                divisor = gcd(Math.abs(x1 - x2), num);
            } while (divisor === 1);

            return divisor;
        };

        /**
         * Calculate and retrieve all the bounds for the chart and return them in one array
         *
         * @memberof Chartist.Core
         * @param {Number} axisLength The length of the Axis used for
         * @param {Object} highLow An object containing a high and low property indicating the value range of the chart.
         * @param {Number} scaleMinSpace The minimum projected length a step should result in
         * @param {Boolean} onlyInteger
         * @return {Object} All the values to set the bounds of the chart
         */
        Chartist.getBounds = function (axisLength, highLow, scaleMinSpace, onlyInteger) {
            var i,
              optimizationCounter = 0,
              newMin,
              newMax,
              bounds = {
                  high: highLow.high,
                  low: highLow.low
              };

            bounds.valueRange = bounds.high - bounds.low;
            bounds.oom = Chartist.orderOfMagnitude(bounds.valueRange);
            bounds.step = Math.pow(10, bounds.oom);
            bounds.min = Math.floor(bounds.low / bounds.step) * bounds.step;
            bounds.max = Math.ceil(bounds.high / bounds.step) * bounds.step;
            bounds.range = bounds.max - bounds.min;
            bounds.numberOfSteps = Math.round(bounds.range / bounds.step);

            // Optimize scale step by checking if subdivision is possible based on horizontalGridMinSpace
            // If we are already below the scaleMinSpace value we will scale up
            var length = Chartist.projectLength(axisLength, bounds.step, bounds);
            var scaleUp = length < scaleMinSpace;
            var smallestFactor = onlyInteger ? Chartist.rho(bounds.range) : 0;

            // First check if we should only use integer steps and if step 1 is still larger than scaleMinSpace so we can use 1
            if (onlyInteger && Chartist.projectLength(axisLength, 1, bounds) >= scaleMinSpace) {
                bounds.step = 1;
            } else if (onlyInteger && smallestFactor < bounds.step && Chartist.projectLength(axisLength, smallestFactor, bounds) >= scaleMinSpace) {
                // If step 1 was too small, we can try the smallest factor of range
                // If the smallest factor is smaller than the current bounds.step and the projected length of smallest factor
                // is larger than the scaleMinSpace we should go for it.
                bounds.step = smallestFactor;
            } else {
                // Trying to divide or multiply by 2 and find the best step value
                while (true) {
                    if (scaleUp && Chartist.projectLength(axisLength, bounds.step, bounds) <= scaleMinSpace) {
                        bounds.step *= 2;
                    } else if (!scaleUp && Chartist.projectLength(axisLength, bounds.step / 2, bounds) >= scaleMinSpace) {
                        bounds.step /= 2;
                        if (onlyInteger && bounds.step % 1 !== 0) {
                            bounds.step *= 2;
                            break;
                        }
                    } else {
                        break;
                    }

                    if (optimizationCounter++ > 1000) {
                        throw new Error('Exceeded maximum number of iterations while optimizing scale step!');
                    }
                }
            }

            var EPSILON = 2.221E-16;
            bounds.step = Math.max(bounds.step, EPSILON);
            function safeIncrement(value, increment) {
                // If increment is too small use *= (1+EPSILON) as a simple nextafter
                if (value === (value += increment)) {
                    value *= (1 + (increment > 0 ? EPSILON : -EPSILON));
                }
                return value;
            }

            // Narrow min and max based on new step
            newMin = bounds.min;
            newMax = bounds.max;
            while (newMin + bounds.step <= bounds.low) {
                newMin = safeIncrement(newMin, bounds.step);
            }
            while (newMax - bounds.step >= bounds.high) {
                newMax = safeIncrement(newMax, -bounds.step);
            }
            bounds.min = newMin;
            bounds.max = newMax;
            bounds.range = bounds.max - bounds.min;

            var values = [];
            for (i = bounds.min; i <= bounds.max; i = safeIncrement(i, bounds.step)) {
                var value = Chartist.roundWithPrecision(i);
                if (value !== values[values.length - 1]) {
                    values.push(value);
                }
            }
            bounds.values = values;
            return bounds;
        };

        /**
         * Calculate cartesian coordinates of polar coordinates
         *
         * @memberof Chartist.Core
         * @param {Number} centerX X-axis coordinates of center point of circle segment
         * @param {Number} centerY X-axis coordinates of center point of circle segment
         * @param {Number} radius Radius of circle segment
         * @param {Number} angleInDegrees Angle of circle segment in degrees
         * @return {{x:Number, y:Number}} Coordinates of point on circumference
         */
        Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) {
            var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;

            return {
                x: centerX + (radius * Math.cos(angleInRadians)),
                y: centerY + (radius * Math.sin(angleInRadians))
            };
        };

        /**
         * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right
         *
         * @memberof Chartist.Core
         * @param {Object} svg The svg element for the chart
         * @param {Object} options The Object that contains all the optional values for the chart
         * @param {Number} [fallbackPadding] The fallback padding if partial padding objects are used
         * @return {Object} The chart rectangles coordinates inside the svg element plus the rectangles measurements
         */
        Chartist.createChartRect = function (svg, options, fallbackPadding) {
            var hasAxis = !!(options.axisX || options.axisY);
            var yAxisOffset = hasAxis ? options.axisY.offset : 0;
            var xAxisOffset = hasAxis ? options.axisX.offset : 0;
            // If width or height results in invalid value (including 0) we fallback to the unitless settings or even 0
            var width = svg.width() || Chartist.quantity(options.width).value || 0;
            var height = svg.height() || Chartist.quantity(options.height).value || 0;
            var normalizedPadding = Chartist.normalizePadding(options.chartPadding, fallbackPadding);

            // If settings were to small to cope with offset (legacy) and padding, we'll adjust
            width = Math.max(width, yAxisOffset + normalizedPadding.left + normalizedPadding.right);
            height = Math.max(height, xAxisOffset + normalizedPadding.top + normalizedPadding.bottom);

            var chartRect = {
                padding: normalizedPadding,
                width: function () {
                    return this.x2 - this.x1;
                },
                height: function () {
                    return this.y1 - this.y2;
                }
            };

            if (hasAxis) {
                if (options.axisX.position === 'start') {
                    chartRect.y2 = normalizedPadding.top + xAxisOffset;
                    chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);
                } else {
                    chartRect.y2 = normalizedPadding.top;
                    chartRect.y1 = Math.max(height - normalizedPadding.bottom - xAxisOffset, chartRect.y2 + 1);
                }

                if (options.axisY.position === 'start') {
                    chartRect.x1 = normalizedPadding.left + yAxisOffset;
                    chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);
                } else {
                    chartRect.x1 = normalizedPadding.left;
                    chartRect.x2 = Math.max(width - normalizedPadding.right - yAxisOffset, chartRect.x1 + 1);
                }
            } else {
                chartRect.x1 = normalizedPadding.left;
                chartRect.x2 = Math.max(width - normalizedPadding.right, chartRect.x1 + 1);
                chartRect.y2 = normalizedPadding.top;
                chartRect.y1 = Math.max(height - normalizedPadding.bottom, chartRect.y2 + 1);
            }

            return chartRect;
        };

        /**
         * Creates a grid line based on a projected value.
         *
         * @memberof Chartist.Core
         * @param position
         * @param index
         * @param axis
         * @param offset
         * @param length
         * @param group
         * @param classes
         * @param eventEmitter
         */
        Chartist.createGrid = function (position, index, axis, offset, length, group, classes, eventEmitter) {
            var positionalData = {};
            positionalData[axis.units.pos + '1'] = position;
            positionalData[axis.units.pos + '2'] = position;
            positionalData[axis.counterUnits.pos + '1'] = offset;
            positionalData[axis.counterUnits.pos + '2'] = offset + length;

            var gridElement = group.elem('line', positionalData, classes.join(' '));

            // Event for grid draw
            eventEmitter.emit('draw',
              Chartist.extend({
                  type: 'grid',
                  axis: axis,
                  index: index,
                  group: group,
                  element: gridElement
              }, positionalData)
            );
        };

        /**
         * Creates a grid background rect and emits the draw event.
         *
         * @memberof Chartist.Core
         * @param gridGroup
         * @param chartRect
         * @param className
         * @param eventEmitter
         */
        Chartist.createGridBackground = function (gridGroup, chartRect, className, eventEmitter) {
            var gridBackground = gridGroup.elem('rect', {
                x: chartRect.x1,
                y: chartRect.y2,
                width: chartRect.width(),
                height: chartRect.height(),
            }, className, true);

            // Event for grid background draw
            eventEmitter.emit('draw', {
                type: 'gridBackground',
                group: gridGroup,
                element: gridBackground
            });
        };

        /**
         * Creates a label based on a projected value and an axis.
         *
         * @memberof Chartist.Core
         * @param position
         * @param length
         * @param index
         * @param labels
         * @param axis
         * @param axisOffset
         * @param labelOffset
         * @param group
         * @param classes
         * @param useForeignObject
         * @param eventEmitter
         */
        Chartist.createLabel = function (position, length, index, labels, axis, axisOffset, labelOffset, group, classes, useForeignObject, eventEmitter) {
            var labelElement;
            var positionalData = {};

            positionalData[axis.units.pos] = position + labelOffset[axis.units.pos];
            positionalData[axis.counterUnits.pos] = labelOffset[axis.counterUnits.pos];
            positionalData[axis.units.len] = length;
            positionalData[axis.counterUnits.len] = Math.max(0, axisOffset - 10);

            if (useForeignObject) {
                // We need to set width and height explicitly to px as span will not expand with width and height being
                // 100% in all browsers
                var content = document.createElement('span');
                content.className = classes.join(' ');
                content.setAttribute('xmlns', Chartist.namespaces.xhtml);
                content.innerText = labels[index];
                content.style[axis.units.len] = Math.round(positionalData[axis.units.len]) + 'px';
                content.style[axis.counterUnits.len] = Math.round(positionalData[axis.counterUnits.len]) + 'px';

                labelElement = group.foreignObject(content, Chartist.extend({
                    style: 'overflow: visible;'
                }, positionalData));
            } else {
                labelElement = group.elem('text', positionalData, classes.join(' ')).text(labels[index]);
            }

            eventEmitter.emit('draw', Chartist.extend({
                type: 'label',
                axis: axis,
                index: index,
                group: group,
                element: labelElement,
                text: labels[index]
            }, positionalData));
        };

        /**
         * Helper to read series specific options from options object. It automatically falls back to the global option if
         * there is no option in the series options.
         *
         * @param {Object} series Series object
         * @param {Object} options Chartist options object
         * @param {string} key The options key that should be used to obtain the options
         * @returns {*}
         */
        Chartist.getSeriesOption = function (series, options, key) {
            if (series.name && options.series && options.series[series.name]) {
                var seriesOptions = options.series[series.name];
                return seriesOptions.hasOwnProperty(key) ? seriesOptions[key] : options[key];
            } else {
                return options[key];
            }
        };

        /**
         * Provides options handling functionality with callback for options changes triggered by responsive options and media query matches
         *
         * @memberof Chartist.Core
         * @param {Object} options Options set by user
         * @param {Array} responsiveOptions Optional functions to add responsive behavior to chart
         * @param {Object} eventEmitter The event emitter that will be used to emit the options changed events
         * @return {Object} The consolidated options object from the defaults, base and matching responsive options
         */
        Chartist.optionsProvider = function (options, responsiveOptions, eventEmitter) {
            var baseOptions = Chartist.extend({}, options),
              currentOptions,
              mediaQueryListeners = [],
              i;

            function updateCurrentOptions(mediaEvent) {
                var previousOptions = currentOptions;
                currentOptions = Chartist.extend({}, baseOptions);

                if (responsiveOptions) {
                    for (i = 0; i < responsiveOptions.length; i++) {
                        var mql = window.matchMedia(responsiveOptions[i][0]);
                        if (mql.matches) {
                            currentOptions = Chartist.extend(currentOptions, responsiveOptions[i][1]);
                        }
                    }
                }

                if (eventEmitter && mediaEvent) {
                    eventEmitter.emit('optionsChanged', {
                        previousOptions: previousOptions,
                        currentOptions: currentOptions
                    });
                }
            }

            function removeMediaQueryListeners() {
                mediaQueryListeners.forEach(function (mql) {
                    mql.removeListener(updateCurrentOptions);
                });
            }

            if (!window.matchMedia) {
                throw 'window.matchMedia not found! Make sure you\'re using a polyfill.';
            } else if (responsiveOptions) {

                for (i = 0; i < responsiveOptions.length; i++) {
                    var mql = window.matchMedia(responsiveOptions[i][0]);
                    mql.addListener(updateCurrentOptions);
                    mediaQueryListeners.push(mql);
                }
            }
            // Execute initially without an event argument so we get the correct options
            updateCurrentOptions();

            return {
                removeMediaQueryListeners: removeMediaQueryListeners,
                getCurrentOptions: function getCurrentOptions() {
                    return Chartist.extend({}, currentOptions);
                }
            };
        };


        /**
         * Splits a list of coordinates and associated values into segments. Each returned segment contains a pathCoordinates
         * valueData property describing the segment.
         *
         * With the default options, segments consist of contiguous sets of points that do not have an undefined value. Any
         * points with undefined values are discarded.
         *
         * **Options**
         * The following options are used to determine how segments are formed
         * ```javascript
         * var options = {
         *   // If fillHoles is true, undefined values are simply discarded without creating a new segment. Assuming other options are default, this returns single segment.
         *   fillHoles: false,
         *   // If increasingX is true, the coordinates in all segments have strictly increasing x-values.
         *   increasingX: false
         * };
         * ```
         *
         * @memberof Chartist.Core
         * @param {Array} pathCoordinates List of point coordinates to be split in the form [x1, y1, x2, y2 ... xn, yn]
         * @param {Array} values List of associated point values in the form [v1, v2 .. vn]
         * @param {Object} options Options set by user
         * @return {Array} List of segments, each containing a pathCoordinates and valueData property.
         */
        Chartist.splitIntoSegments = function (pathCoordinates, valueData, options) {
            var defaultOptions = {
                increasingX: false,
                fillHoles: false
            };

            options = Chartist.extend({}, defaultOptions, options);

            var segments = [];
            var hole = true;

            for (var i = 0; i < pathCoordinates.length; i += 2) {
                // If this value is a "hole" we set the hole flag
                if (Chartist.getMultiValue(valueData[i / 2].value) === undefined) {
                    // if(valueData[i / 2].value === undefined) {
                    if (!options.fillHoles) {
                        hole = true;
                    }
                } else {
                    if (options.increasingX && i >= 2 && pathCoordinates[i] <= pathCoordinates[i - 2]) {
                        // X is not increasing, so we need to make sure we start a new segment
                        hole = true;
                    }


                    // If it's a valid value we need to check if we're coming out of a hole and create a new empty segment
                    if (hole) {
                        segments.push({
                            pathCoordinates: [],
                            valueData: []
                        });
                        // As we have a valid value now, we are not in a "hole" anymore
                        hole = false;
                    }

                    // Add to the segment pathCoordinates and valueData
                    segments[segments.length - 1].pathCoordinates.push(pathCoordinates[i], pathCoordinates[i + 1]);
                    segments[segments.length - 1].valueData.push(valueData[i / 2]);
                }
            }

            return segments;
        };
    }(window, document, Chartist));
    ;/**
 * Chartist path interpolation functions.
 *
 * @module Chartist.Interpolation
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        Chartist.Interpolation = {};

        /**
         * This interpolation function does not smooth the path and the result is only containing lines and no curves.
         *
         * @example
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [[1, 2, 8, 1, 7]]
         * }, {
         *   lineSmooth: Chartist.Interpolation.none({
         *     fillHoles: false
         *   })
         * });
         *
         *
         * @memberof Chartist.Interpolation
         * @return {Function}
         */
        Chartist.Interpolation.none = function (options) {
            var defaultOptions = {
                fillHoles: false
            };
            options = Chartist.extend({}, defaultOptions, options);
            return function none(pathCoordinates, valueData) {
                var path = new Chartist.Svg.Path();
                var hole = true;

                for (var i = 0; i < pathCoordinates.length; i += 2) {
                    var currX = pathCoordinates[i];
                    var currY = pathCoordinates[i + 1];
                    var currData = valueData[i / 2];

                    if (Chartist.getMultiValue(currData.value) !== undefined) {

                        if (hole) {
                            path.move(currX, currY, false, currData);
                        } else {
                            path.line(currX, currY, false, currData);
                        }

                        hole = false;
                    } else if (!options.fillHoles) {
                        hole = true;
                    }
                }

                return path;
            };
        };

        /**
         * Simple smoothing creates horizontal handles that are positioned with a fraction of the length between two data points. You can use the divisor option to specify the amount of smoothing.
         *
         * Simple smoothing can be used instead of `Chartist.Smoothing.cardinal` if you'd like to get rid of the artifacts it produces sometimes. Simple smoothing produces less flowing lines but is accurate by hitting the points and it also doesn't swing below or above the given data point.
         *
         * All smoothing functions within Chartist are factory functions that accept an options parameter. The simple interpolation function accepts one configuration parameter `divisor`, between 1 and ∞, which controls the smoothing characteristics.
         *
         * @example
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [[1, 2, 8, 1, 7]]
         * }, {
         *   lineSmooth: Chartist.Interpolation.simple({
         *     divisor: 2,
         *     fillHoles: false
         *   })
         * });
         *
         *
         * @memberof Chartist.Interpolation
         * @param {Object} options The options of the simple interpolation factory function.
         * @return {Function}
         */
        Chartist.Interpolation.simple = function (options) {
            var defaultOptions = {
                divisor: 2,
                fillHoles: false
            };
            options = Chartist.extend({}, defaultOptions, options);

            var d = 1 / Math.max(1, options.divisor);

            return function simple(pathCoordinates, valueData) {
                var path = new Chartist.Svg.Path();
                var prevX, prevY, prevData;

                for (var i = 0; i < pathCoordinates.length; i += 2) {
                    var currX = pathCoordinates[i];
                    var currY = pathCoordinates[i + 1];
                    var length = (currX - prevX) * d;
                    var currData = valueData[i / 2];

                    if (currData.value !== undefined) {

                        if (prevData === undefined) {
                            path.move(currX, currY, false, currData);
                        } else {
                            path.curve(
                              prevX + length,
                              prevY,
                              currX - length,
                              currY,
                              currX,
                              currY,
                              false,
                              currData
                            );
                        }

                        prevX = currX;
                        prevY = currY;
                        prevData = currData;
                    } else if (!options.fillHoles) {
                        prevX = currX = prevData = undefined;
                    }
                }

                return path;
            };
        };

        /**
         * Cardinal / Catmull-Rome spline interpolation is the default smoothing function in Chartist. It produces nice results where the splines will always meet the points. It produces some artifacts though when data values are increased or decreased rapidly. The line may not follow a very accurate path and if the line should be accurate this smoothing function does not produce the best results.
         *
         * Cardinal splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.
         *
         * All smoothing functions within Chartist are factory functions that accept an options parameter. The cardinal interpolation function accepts one configuration parameter `tension`, between 0 and 1, which controls the smoothing intensity.
         *
         * @example
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [[1, 2, 8, 1, 7]]
         * }, {
         *   lineSmooth: Chartist.Interpolation.cardinal({
         *     tension: 1,
         *     fillHoles: false
         *   })
         * });
         *
         * @memberof Chartist.Interpolation
         * @param {Object} options The options of the cardinal factory function.
         * @return {Function}
         */
        Chartist.Interpolation.cardinal = function (options) {
            var defaultOptions = {
                tension: 1,
                fillHoles: false
            };

            options = Chartist.extend({}, defaultOptions, options);

            var t = Math.min(1, Math.max(0, options.tension)),
              c = 1 - t;

            return function cardinal(pathCoordinates, valueData) {
                // First we try to split the coordinates into segments
                // This is necessary to treat "holes" in line charts
                var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {
                    fillHoles: options.fillHoles
                });

                if (!segments.length) {
                    // If there were no segments return 'Chartist.Interpolation.none'
                    return Chartist.Interpolation.none()([]);
                } else if (segments.length > 1) {
                    // If the split resulted in more that one segment we need to interpolate each segment individually and join them
                    // afterwards together into a single path.
                    var paths = [];
                    // For each segment we will recurse the cardinal function
                    segments.forEach(function (segment) {
                        paths.push(cardinal(segment.pathCoordinates, segment.valueData));
                    });
                    // Join the segment path data into a single path and return
                    return Chartist.Svg.Path.join(paths);
                } else {
                    // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first
                    // segment
                    pathCoordinates = segments[0].pathCoordinates;
                    valueData = segments[0].valueData;

                    // If less than two points we need to fallback to no smoothing
                    if (pathCoordinates.length <= 4) {
                        return Chartist.Interpolation.none()(pathCoordinates, valueData);
                    }

                    var path = new Chartist.Svg.Path().move(pathCoordinates[0], pathCoordinates[1], false, valueData[0]),
                      z;

                    for (var i = 0, iLen = pathCoordinates.length; iLen - 2 * !z > i; i += 2) {
                        var p = [
                          { x: +pathCoordinates[i - 2], y: +pathCoordinates[i - 1] },
                          { x: +pathCoordinates[i], y: +pathCoordinates[i + 1] },
                          { x: +pathCoordinates[i + 2], y: +pathCoordinates[i + 3] },
                          { x: +pathCoordinates[i + 4], y: +pathCoordinates[i + 5] }
                        ];
                        if (z) {
                            if (!i) {
                                p[0] = { x: +pathCoordinates[iLen - 2], y: +pathCoordinates[iLen - 1] };
                            } else if (iLen - 4 === i) {
                                p[3] = { x: +pathCoordinates[0], y: +pathCoordinates[1] };
                            } else if (iLen - 2 === i) {
                                p[2] = { x: +pathCoordinates[0], y: +pathCoordinates[1] };
                                p[3] = { x: +pathCoordinates[2], y: +pathCoordinates[3] };
                            }
                        } else {
                            if (iLen - 4 === i) {
                                p[3] = p[2];
                            } else if (!i) {
                                p[0] = { x: +pathCoordinates[i], y: +pathCoordinates[i + 1] };
                            }
                        }

                        path.curve(
                          (t * (-p[0].x + 6 * p[1].x + p[2].x) / 6) + (c * p[2].x),
                          (t * (-p[0].y + 6 * p[1].y + p[2].y) / 6) + (c * p[2].y),
                          (t * (p[1].x + 6 * p[2].x - p[3].x) / 6) + (c * p[2].x),
                          (t * (p[1].y + 6 * p[2].y - p[3].y) / 6) + (c * p[2].y),
                          p[2].x,
                          p[2].y,
                          false,
                          valueData[(i + 2) / 2]
                        );
                    }

                    return path;
                }
            };
        };

        /**
         * Monotone Cubic spline interpolation produces a smooth curve which preserves monotonicity. Unlike cardinal splines, the curve will not extend beyond the range of y-values of the original data points.
         *
         * Monotone Cubic splines can only be created if there are more than two data points. If this is not the case this smoothing will fallback to `Chartist.Smoothing.none`.
         *
         * The x-values of subsequent points must be increasing to fit a Monotone Cubic spline. If this condition is not met for a pair of adjacent points, then there will be a break in the curve between those data points.
         *
         * All smoothing functions within Chartist are factory functions that accept an options parameter.
         *
         * @example
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [[1, 2, 8, 1, 7]]
         * }, {
         *   lineSmooth: Chartist.Interpolation.monotoneCubic({
         *     fillHoles: false
         *   })
         * });
         *
         * @memberof Chartist.Interpolation
         * @param {Object} options The options of the monotoneCubic factory function.
         * @return {Function}
         */
        Chartist.Interpolation.monotoneCubic = function (options) {
            var defaultOptions = {
                fillHoles: false
            };

            options = Chartist.extend({}, defaultOptions, options);

            return function monotoneCubic(pathCoordinates, valueData) {
                // First we try to split the coordinates into segments
                // This is necessary to treat "holes" in line charts
                var segments = Chartist.splitIntoSegments(pathCoordinates, valueData, {
                    fillHoles: options.fillHoles,
                    increasingX: true
                });

                if (!segments.length) {
                    // If there were no segments return 'Chartist.Interpolation.none'
                    return Chartist.Interpolation.none()([]);
                } else if (segments.length > 1) {
                    // If the split resulted in more that one segment we need to interpolate each segment individually and join them
                    // afterwards together into a single path.
                    var paths = [];
                    // For each segment we will recurse the monotoneCubic fn function
                    segments.forEach(function (segment) {
                        paths.push(monotoneCubic(segment.pathCoordinates, segment.valueData));
                    });
                    // Join the segment path data into a single path and return
                    return Chartist.Svg.Path.join(paths);
                } else {
                    // If there was only one segment we can proceed regularly by using pathCoordinates and valueData from the first
                    // segment
                    pathCoordinates = segments[0].pathCoordinates;
                    valueData = segments[0].valueData;

                    // If less than three points we need to fallback to no smoothing
                    if (pathCoordinates.length <= 4) {
                        return Chartist.Interpolation.none()(pathCoordinates, valueData);
                    }

                    var xs = [],
                      ys = [],
                      i,
                      n = pathCoordinates.length / 2,
                      ms = [],
                      ds = [], dys = [], dxs = [],
                      path;

                    // Populate x and y coordinates into separate arrays, for readability

                    for (i = 0; i < n; i++) {
                        xs[i] = pathCoordinates[i * 2];
                        ys[i] = pathCoordinates[i * 2 + 1];
                    }

                    // Calculate deltas and derivative

                    for (i = 0; i < n - 1; i++) {
                        dys[i] = ys[i + 1] - ys[i];
                        dxs[i] = xs[i + 1] - xs[i];
                        ds[i] = dys[i] / dxs[i];
                    }

                    // Determine desired slope (m) at each point using Fritsch-Carlson method
                    // See: http://math.stackexchange.com/questions/45218/implementation-of-monotone-cubic-interpolation

                    ms[0] = ds[0];
                    ms[n - 1] = ds[n - 2];

                    for (i = 1; i < n - 1; i++) {
                        if (ds[i] === 0 || ds[i - 1] === 0 || (ds[i - 1] > 0) !== (ds[i] > 0)) {
                            ms[i] = 0;
                        } else {
                            ms[i] = 3 * (dxs[i - 1] + dxs[i]) / (
                              (2 * dxs[i] + dxs[i - 1]) / ds[i - 1] +
                              (dxs[i] + 2 * dxs[i - 1]) / ds[i]);

                            if (!isFinite(ms[i])) {
                                ms[i] = 0;
                            }
                        }
                    }

                    // Now build a path from the slopes

                    path = new Chartist.Svg.Path().move(xs[0], ys[0], false, valueData[0]);

                    for (i = 0; i < n - 1; i++) {
                        path.curve(
                          // First control point
                          xs[i] + dxs[i] / 3,
                          ys[i] + ms[i] * dxs[i] / 3,
                          // Second control point
                          xs[i + 1] - dxs[i] / 3,
                          ys[i + 1] - ms[i + 1] * dxs[i] / 3,
                          // End point
                          xs[i + 1],
                          ys[i + 1],

                          false,
                          valueData[i + 1]
                        );
                    }

                    return path;
                }
            };
        };

        /**
         * Step interpolation will cause the line chart to move in steps rather than diagonal or smoothed lines. This interpolation will create additional points that will also be drawn when the `showPoint` option is enabled.
         *
         * All smoothing functions within Chartist are factory functions that accept an options parameter. The step interpolation function accepts one configuration parameter `postpone`, that can be `true` or `false`. The default value is `true` and will cause the step to occur where the value actually changes. If a different behaviour is needed where the step is shifted to the left and happens before the actual value, this option can be set to `false`.
         *
         * @example
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [[1, 2, 8, 1, 7]]
         * }, {
         *   lineSmooth: Chartist.Interpolation.step({
         *     postpone: true,
         *     fillHoles: false
         *   })
         * });
         *
         * @memberof Chartist.Interpolation
         * @param options
         * @returns {Function}
         */
        Chartist.Interpolation.step = function (options) {
            var defaultOptions = {
                postpone: true,
                fillHoles: false
            };

            options = Chartist.extend({}, defaultOptions, options);

            return function step(pathCoordinates, valueData) {
                var path = new Chartist.Svg.Path();

                var prevX, prevY, prevData;

                for (var i = 0; i < pathCoordinates.length; i += 2) {
                    var currX = pathCoordinates[i];
                    var currY = pathCoordinates[i + 1];
                    var currData = valueData[i / 2];

                    // If the current point is also not a hole we can draw the step lines
                    if (currData.value !== undefined) {
                        if (prevData === undefined) {
                            path.move(currX, currY, false, currData);
                        } else {
                            if (options.postpone) {
                                // If postponed we should draw the step line with the value of the previous value
                                path.line(currX, prevY, false, prevData);
                            } else {
                                // If not postponed we should draw the step line with the value of the current value
                                path.line(prevX, currY, false, currData);
                            }
                            // Line to the actual point (this should only be a Y-Axis movement
                            path.line(currX, currY, false, currData);
                        }

                        prevX = currX;
                        prevY = currY;
                        prevData = currData;
                    } else if (!options.fillHoles) {
                        prevX = prevY = prevData = undefined;
                    }
                }

                return path;
            };
        };

    }(window, document, Chartist));
    ;/**
 * A very basic event module that helps to generate and catch events.
 *
 * @module Chartist.Event
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        Chartist.EventEmitter = function () {
            var handlers = [];

            /**
             * Add an event handler for a specific event
             *
             * @memberof Chartist.Event
             * @param {String} event The event name
             * @param {Function} handler A event handler function
             */
            function addEventHandler(event, handler) {
                handlers[event] = handlers[event] || [];
                handlers[event].push(handler);
            }

            /**
             * Remove an event handler of a specific event name or remove all event handlers for a specific event.
             *
             * @memberof Chartist.Event
             * @param {String} event The event name where a specific or all handlers should be removed
             * @param {Function} [handler] An optional event handler function. If specified only this specific handler will be removed and otherwise all handlers are removed.
             */
            function removeEventHandler(event, handler) {
                // Only do something if there are event handlers with this name existing
                if (handlers[event]) {
                    // If handler is set we will look for a specific handler and only remove this
                    if (handler) {
                        handlers[event].splice(handlers[event].indexOf(handler), 1);
                        if (handlers[event].length === 0) {
                            delete handlers[event];
                        }
                    } else {
                        // If no handler is specified we remove all handlers for this event
                        delete handlers[event];
                    }
                }
            }

            /**
             * Use this function to emit an event. All handlers that are listening for this event will be triggered with the data parameter.
             *
             * @memberof Chartist.Event
             * @param {String} event The event name that should be triggered
             * @param {*} data Arbitrary data that will be passed to the event handler callback functions
             */
            function emit(event, data) {
                // Only do something if there are event handlers with this name existing
                if (handlers[event]) {
                    handlers[event].forEach(function (handler) {
                        handler(data);
                    });
                }

                // Emit event to star event handlers
                if (handlers['*']) {
                    handlers['*'].forEach(function (starHandler) {
                        starHandler(event, data);
                    });
                }
            }

            return {
                addEventHandler: addEventHandler,
                removeEventHandler: removeEventHandler,
                emit: emit
            };
        };

    }(window, document, Chartist));
    ;/**
 * This module provides some basic prototype inheritance utilities.
 *
 * @module Chartist.Class
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        function listToArray(list) {
            var arr = [];
            if (list.length) {
                for (var i = 0; i < list.length; i++) {
                    arr.push(list[i]);
                }
            }
            return arr;
        }

        /**
         * Method to extend from current prototype.
         *
         * @memberof Chartist.Class
         * @param {Object} properties The object that serves as definition for the prototype that gets created for the new class. This object should always contain a constructor property that is the desired constructor for the newly created class.
         * @param {Object} [superProtoOverride] By default extens will use the current class prototype or Chartist.class. With this parameter you can specify any super prototype that will be used.
         * @return {Function} Constructor function of the new class
         *
         * @example
         * var Fruit = Class.extend({
           * color: undefined,
           *   sugar: undefined,
           *
           *   constructor: function(color, sugar) {
           *     this.color = color;
           *     this.sugar = sugar;
           *   },
           *
           *   eat: function() {
           *     this.sugar = 0;
           *     return this;
           *   }
           * });
         *
         * var Banana = Fruit.extend({
           *   length: undefined,
           *
           *   constructor: function(length, sugar) {
           *     Banana.super.constructor.call(this, 'Yellow', sugar);
           *     this.length = length;
           *   }
           * });
         *
         * var banana = new Banana(20, 40);
         * console.log('banana instanceof Fruit', banana instanceof Fruit);
         * console.log('Fruit is prototype of banana', Fruit.prototype.isPrototypeOf(banana));
         * console.log('bananas prototype is Fruit', Object.getPrototypeOf(banana) === Fruit.prototype);
         * console.log(banana.sugar);
         * console.log(banana.eat().sugar);
         * console.log(banana.color);
         */
        function extend(properties, superProtoOverride) {
            var superProto = superProtoOverride || this.prototype || Chartist.Class;
            var proto = Object.create(superProto);

            Chartist.Class.cloneDefinitions(proto, properties);

            var constr = function () {
                var fn = proto.constructor || function () { },
                  instance;

                // If this is linked to the Chartist namespace the constructor was not called with new
                // To provide a fallback we will instantiate here and return the instance
                instance = this === Chartist ? Object.create(proto) : this;
                fn.apply(instance, Array.prototype.slice.call(arguments, 0));

                // If this constructor was not called with new we need to return the instance
                // This will not harm when the constructor has been called with new as the returned value is ignored
                return instance;
            };

            constr.prototype = proto;
            constr.super = superProto;
            constr.extend = this.extend;

            return constr;
        }

        // Variable argument list clones args > 0 into args[0] and retruns modified args[0]
        function cloneDefinitions() {
            var args = listToArray(arguments);
            var target = args[0];

            args.splice(1, args.length - 1).forEach(function (source) {
                Object.getOwnPropertyNames(source).forEach(function (propName) {
                    // If this property already exist in target we delete it first
                    delete target[propName];
                    // Define the property with the descriptor from source
                    Object.defineProperty(target, propName,
                      Object.getOwnPropertyDescriptor(source, propName));
                });
            });

            return target;
        }

        Chartist.Class = {
            extend: extend,
            cloneDefinitions: cloneDefinitions
        };

    }(window, document, Chartist));
    ;/**
 * Base for all chart types. The methods in Chartist.Base are inherited to all chart types.
 *
 * @module Chartist.Base
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        // TODO: Currently we need to re-draw the chart on window resize. This is usually very bad and will affect performance.
        // This is done because we can't work with relative coordinates when drawing the chart because SVG Path does not
        // work with relative positions yet. We need to check if we can do a viewBox hack to switch to percentage.
        // See http://mozilla.6506.n7.nabble.com/Specyfing-paths-with-percentages-unit-td247474.html
        // Update: can be done using the above method tested here: http://codepen.io/gionkunz/pen/KDvLj
        // The problem is with the label offsets that can't be converted into percentage and affecting the chart container
        /**
         * Updates the chart which currently does a full reconstruction of the SVG DOM
         *
         * @param {Object} [data] Optional data you'd like to set for the chart before it will update. If not specified the update method will use the data that is already configured with the chart.
         * @param {Object} [options] Optional options you'd like to add to the previous options for the chart before it will update. If not specified the update method will use the options that have been already configured with the chart.
         * @param {Boolean} [override] If set to true, the passed options will be used to extend the options that have been configured already. Otherwise the chart default options will be used as the base
         * @memberof Chartist.Base
         */
        function update(data, options, override) {
            if (data) {
                this.data = data || {};
                this.data.labels = this.data.labels || [];
                this.data.series = this.data.series || [];
                // Event for data transformation that allows to manipulate the data before it gets rendered in the charts
                this.eventEmitter.emit('data', {
                    type: 'update',
                    data: this.data
                });
            }

            if (options) {
                this.options = Chartist.extend({}, override ? this.options : this.defaultOptions, options);

                // If chartist was not initialized yet, we just set the options and leave the rest to the initialization
                // Otherwise we re-create the optionsProvider at this point
                if (!this.initializeTimeoutId) {
                    this.optionsProvider.removeMediaQueryListeners();
                    this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);
                }
            }

            // Only re-created the chart if it has been initialized yet
            if (!this.initializeTimeoutId) {
                this.createChart(this.optionsProvider.getCurrentOptions());
            }

            // Return a reference to the chart object to chain up calls
            return this;
        }

        /**
         * This method can be called on the API object of each chart and will un-register all event listeners that were added to other components. This currently includes a window.resize listener as well as media query listeners if any responsive options have been provided. Use this function if you need to destroy and recreate Chartist charts dynamically.
         *
         * @memberof Chartist.Base
         */
        function detach() {
            // Only detach if initialization already occurred on this chart. If this chart still hasn't initialized (therefore
            // the initializationTimeoutId is still a valid timeout reference, we will clear the timeout
            if (!this.initializeTimeoutId) {
                window.removeEventListener('resize', this.resizeListener);
                this.optionsProvider.removeMediaQueryListeners();
            } else {
                window.clearTimeout(this.initializeTimeoutId);
            }

            return this;
        }

        /**
         * Use this function to register event handlers. The handler callbacks are synchronous and will run in the main thread rather than the event loop.
         *
         * @memberof Chartist.Base
         * @param {String} event Name of the event. Check the examples for supported events.
         * @param {Function} handler The handler function that will be called when an event with the given name was emitted. This function will receive a data argument which contains event data. See the example for more details.
         */
        function on(event, handler) {
            this.eventEmitter.addEventHandler(event, handler);
            return this;
        }

        /**
         * Use this function to un-register event handlers. If the handler function parameter is omitted all handlers for the given event will be un-registered.
         *
         * @memberof Chartist.Base
         * @param {String} event Name of the event for which a handler should be removed
         * @param {Function} [handler] The handler function that that was previously used to register a new event handler. This handler will be removed from the event handler list. If this parameter is omitted then all event handlers for the given event are removed from the list.
         */
        function off(event, handler) {
            this.eventEmitter.removeEventHandler(event, handler);
            return this;
        }

        function initialize() {
            // Add window resize listener that re-creates the chart
            window.addEventListener('resize', this.resizeListener);

            // Obtain current options based on matching media queries (if responsive options are given)
            // This will also register a listener that is re-creating the chart based on media changes
            this.optionsProvider = Chartist.optionsProvider(this.options, this.responsiveOptions, this.eventEmitter);
            // Register options change listener that will trigger a chart update
            this.eventEmitter.addEventHandler('optionsChanged', function () {
                this.update();
            }.bind(this));

            // Before the first chart creation we need to register us with all plugins that are configured
            // Initialize all relevant plugins with our chart object and the plugin options specified in the config
            if (this.options.plugins) {
                this.options.plugins.forEach(function (plugin) {
                    if (plugin instanceof Array) {
                        plugin[0](this, plugin[1]);
                    } else {
                        plugin(this);
                    }
                }.bind(this));
            }

            // Event for data transformation that allows to manipulate the data before it gets rendered in the charts
            this.eventEmitter.emit('data', {
                type: 'initial',
                data: this.data
            });

            // Create the first chart
            this.createChart(this.optionsProvider.getCurrentOptions());

            // As chart is initialized from the event loop now we can reset our timeout reference
            // This is important if the chart gets initialized on the same element twice
            this.initializeTimeoutId = undefined;
        }

        /**
         * Constructor of chart base class.
         *
         * @param query
         * @param data
         * @param defaultOptions
         * @param options
         * @param responsiveOptions
         * @constructor
         */
        function Base(query, data, defaultOptions, options, responsiveOptions) {
            this.container = Chartist.querySelector(query);
            this.data = data || {};
            this.data.labels = this.data.labels || [];
            this.data.series = this.data.series || [];
            this.defaultOptions = defaultOptions;
            this.options = options;
            this.responsiveOptions = responsiveOptions;
            this.eventEmitter = Chartist.EventEmitter();
            this.supportsForeignObject = Chartist.Svg.isSupported('Extensibility');
            this.supportsAnimations = Chartist.Svg.isSupported('AnimationEventsAttribute');
            this.resizeListener = function resizeListener() {
                this.update();
            }.bind(this);

            if (this.container) {
                // If chartist was already initialized in this container we are detaching all event listeners first
                if (this.container.__chartist__) {
                    this.container.__chartist__.detach();
                }

                this.container.__chartist__ = this;
            }

            // Using event loop for first draw to make it possible to register event listeners in the same call stack where
            // the chart was created.
            this.initializeTimeoutId = setTimeout(initialize.bind(this), 0);
        }

        // Creating the chart base class
        Chartist.Base = Chartist.Class.extend({
            constructor: Base,
            optionsProvider: undefined,
            container: undefined,
            svg: undefined,
            eventEmitter: undefined,
            createChart: function () {
                throw new Error('Base chart type can\'t be instantiated!');
            },
            update: update,
            detach: detach,
            on: on,
            off: off,
            version: Chartist.version,
            supportsForeignObject: false
        });

    }(window, document, Chartist));
    ;/**
 * Chartist SVG module for simple SVG DOM abstraction
 *
 * @module Chartist.Svg
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        /**
         * Chartist.Svg creates a new SVG object wrapper with a starting element. You can use the wrapper to fluently create sub-elements and modify them.
         *
         * @memberof Chartist.Svg
         * @constructor
         * @param {String|Element} name The name of the SVG element to create or an SVG dom element which should be wrapped into Chartist.Svg
         * @param {Object} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.
         * @param {String} className This class or class list will be added to the SVG element
         * @param {Object} parent The parent SVG wrapper object where this newly created wrapper and it's element will be attached to as child
         * @param {Boolean} insertFirst If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element
         */
        function Svg(name, attributes, className, parent, insertFirst) {
            // If Svg is getting called with an SVG element we just return the wrapper
            if (name instanceof Element) {
                this._node = name;
            } else {
                this._node = document.createElementNS(Chartist.namespaces.svg, name);

                // If this is an SVG element created then custom namespace
                if (name === 'svg') {
                    this.attr({
                        'xmlns:ct': Chartist.namespaces.ct
                    });
                }
            }

            if (attributes) {
                this.attr(attributes);
            }

            if (className) {
                this.addClass(className);
            }

            if (parent) {
                if (insertFirst && parent._node.firstChild) {
                    parent._node.insertBefore(this._node, parent._node.firstChild);
                } else {
                    parent._node.appendChild(this._node);
                }
            }
        }

        /**
         * Set attributes on the current SVG element of the wrapper you're currently working on.
         *
         * @memberof Chartist.Svg
         * @param {Object|String} attributes An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added. If this parameter is a String then the function is used as a getter and will return the attribute value.
         * @param {String} [ns] If specified, the attribute will be obtained using getAttributeNs. In order to write namepsaced attributes you can use the namespace:attribute notation within the attributes object.
         * @return {Object|String} The current wrapper object will be returned so it can be used for chaining or the attribute value if used as getter function.
         */
        function attr(attributes, ns) {
            if (typeof attributes === 'string') {
                if (ns) {
                    return this._node.getAttributeNS(ns, attributes);
                } else {
                    return this._node.getAttribute(attributes);
                }
            }

            Object.keys(attributes).forEach(function (key) {
                // If the attribute value is undefined we can skip this one
                if (attributes[key] === undefined) {
                    return;
                }

                if (key.indexOf(':') !== -1) {
                    var namespacedAttribute = key.split(':');
                    this._node.setAttributeNS(Chartist.namespaces[namespacedAttribute[0]], key, attributes[key]);
                } else {
                    this._node.setAttribute(key, attributes[key]);
                }
            }.bind(this));

            return this;
        }

        /**
         * Create a new SVG element whose wrapper object will be selected for further operations. This way you can also create nested groups easily.
         *
         * @memberof Chartist.Svg
         * @param {String} name The name of the SVG element that should be created as child element of the currently selected element wrapper
         * @param {Object} [attributes] An object with properties that will be added as attributes to the SVG element that is created. Attributes with undefined values will not be added.
         * @param {String} [className] This class or class list will be added to the SVG element
         * @param {Boolean} [insertFirst] If this param is set to true in conjunction with a parent element the newly created element will be added as first child element in the parent element
         * @return {Chartist.Svg} Returns a Chartist.Svg wrapper object that can be used to modify the containing SVG data
         */
        function elem(name, attributes, className, insertFirst) {
            return new Chartist.Svg(name, attributes, className, this, insertFirst);
        }

        /**
         * Returns the parent Chartist.SVG wrapper object
         *
         * @memberof Chartist.Svg
         * @return {Chartist.Svg} Returns a Chartist.Svg wrapper around the parent node of the current node. If the parent node is not existing or it's not an SVG node then this function will return null.
         */
        function parent() {
            return this._node.parentNode instanceof SVGElement ? new Chartist.Svg(this._node.parentNode) : null;
        }

        /**
         * This method returns a Chartist.Svg wrapper around the root SVG element of the current tree.
         *
         * @memberof Chartist.Svg
         * @return {Chartist.Svg} The root SVG element wrapped in a Chartist.Svg element
         */
        function root() {
            var node = this._node;
            while (node.nodeName !== 'svg') {
                node = node.parentNode;
            }
            return new Chartist.Svg(node);
        }

        /**
         * Find the first child SVG element of the current element that matches a CSS selector. The returned object is a Chartist.Svg wrapper.
         *
         * @memberof Chartist.Svg
         * @param {String} selector A CSS selector that is used to query for child SVG elements
         * @return {Chartist.Svg} The SVG wrapper for the element found or null if no element was found
         */
        function querySelector(selector) {
            var foundNode = this._node.querySelector(selector);
            return foundNode ? new Chartist.Svg(foundNode) : null;
        }

        /**
         * Find the all child SVG elements of the current element that match a CSS selector. The returned object is a Chartist.Svg.List wrapper.
         *
         * @memberof Chartist.Svg
         * @param {String} selector A CSS selector that is used to query for child SVG elements
         * @return {Chartist.Svg.List} The SVG wrapper list for the element found or null if no element was found
         */
        function querySelectorAll(selector) {
            var foundNodes = this._node.querySelectorAll(selector);
            return foundNodes.length ? new Chartist.Svg.List(foundNodes) : null;
        }

        /**
         * Returns the underlying SVG node for the current element.
         *
         * @memberof Chartist.Svg
         * @returns {Node}
         */
        function getNode() {
            return this._node;
        }

        /**
         * This method creates a foreignObject (see https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) that allows to embed HTML content into a SVG graphic. With the help of foreignObjects you can enable the usage of regular HTML elements inside of SVG where they are subject for SVG positioning and transformation but the Browser will use the HTML rendering capabilities for the containing DOM.
         *
         * @memberof Chartist.Svg
         * @param {Node|String} content The DOM Node, or HTML string that will be converted to a DOM Node, that is then placed into and wrapped by the foreignObject
         * @param {String} [attributes] An object with properties that will be added as attributes to the foreignObject element that is created. Attributes with undefined values will not be added.
         * @param {String} [className] This class or class list will be added to the SVG element
         * @param {Boolean} [insertFirst] Specifies if the foreignObject should be inserted as first child
         * @return {Chartist.Svg} New wrapper object that wraps the foreignObject element
         */
        function foreignObject(content, attributes, className, insertFirst) {
            // If content is string then we convert it to DOM
            // TODO: Handle case where content is not a string nor a DOM Node
            if (typeof content === 'string') {
                var container = document.createElement('div');
                container.innerHTML = content;
                content = container.firstChild;
            }

            // Adding namespace to content element
            content.setAttribute('xmlns', Chartist.namespaces.xmlns);

            // Creating the foreignObject without required extension attribute (as described here
            // http://www.w3.org/TR/SVG/extend.html#ForeignObjectElement)
            var fnObj = this.elem('foreignObject', attributes, className, insertFirst);

            // Add content to foreignObjectElement
            fnObj._node.appendChild(content);

            return fnObj;
        }

        /**
         * This method adds a new text element to the current Chartist.Svg wrapper.
         *
         * @memberof Chartist.Svg
         * @param {String} t The text that should be added to the text element that is created
         * @return {Chartist.Svg} The same wrapper object that was used to add the newly created element
         */
        function text(t) {
            this._node.appendChild(document.createTextNode(t));
            return this;
        }

        /**
         * This method will clear all child nodes of the current wrapper object.
         *
         * @memberof Chartist.Svg
         * @return {Chartist.Svg} The same wrapper object that got emptied
         */
        function empty() {
            while (this._node.firstChild) {
                this._node.removeChild(this._node.firstChild);
            }

            return this;
        }

        /**
         * This method will cause the current wrapper to remove itself from its parent wrapper. Use this method if you'd like to get rid of an element in a given DOM structure.
         *
         * @memberof Chartist.Svg
         * @return {Chartist.Svg} The parent wrapper object of the element that got removed
         */
        function remove() {
            this._node.parentNode.removeChild(this._node);
            return this.parent();
        }

        /**
         * This method will replace the element with a new element that can be created outside of the current DOM.
         *
         * @memberof Chartist.Svg
         * @param {Chartist.Svg} newElement The new Chartist.Svg object that will be used to replace the current wrapper object
         * @return {Chartist.Svg} The wrapper of the new element
         */
        function replace(newElement) {
            this._node.parentNode.replaceChild(newElement._node, this._node);
            return newElement;
        }

        /**
         * This method will append an element to the current element as a child.
         *
         * @memberof Chartist.Svg
         * @param {Chartist.Svg} element The Chartist.Svg element that should be added as a child
         * @param {Boolean} [insertFirst] Specifies if the element should be inserted as first child
         * @return {Chartist.Svg} The wrapper of the appended object
         */
        function append(element, insertFirst) {
            if (insertFirst && this._node.firstChild) {
                this._node.insertBefore(element._node, this._node.firstChild);
            } else {
                this._node.appendChild(element._node);
            }

            return this;
        }

        /**
         * Returns an array of class names that are attached to the current wrapper element. This method can not be chained further.
         *
         * @memberof Chartist.Svg
         * @return {Array} A list of classes or an empty array if there are no classes on the current element
         */
        function classes() {
            return this._node.getAttribute('class') ? this._node.getAttribute('class').trim().split(/\s+/) : [];
        }

        /**
         * Adds one or a space separated list of classes to the current element and ensures the classes are only existing once.
         *
         * @memberof Chartist.Svg
         * @param {String} names A white space separated list of class names
         * @return {Chartist.Svg} The wrapper of the current element
         */
        function addClass(names) {
            this._node.setAttribute('class',
              this.classes(this._node)
                .concat(names.trim().split(/\s+/))
                .filter(function (elem, pos, self) {
                    return self.indexOf(elem) === pos;
                }).join(' ')
            );

            return this;
        }

        /**
         * Removes one or a space separated list of classes from the current element.
         *
         * @memberof Chartist.Svg
         * @param {String} names A white space separated list of class names
         * @return {Chartist.Svg} The wrapper of the current element
         */
        function removeClass(names) {
            var removedClasses = names.trim().split(/\s+/);

            this._node.setAttribute('class', this.classes(this._node).filter(function (name) {
                return removedClasses.indexOf(name) === -1;
            }).join(' '));

            return this;
        }

        /**
         * Removes all classes from the current element.
         *
         * @memberof Chartist.Svg
         * @return {Chartist.Svg} The wrapper of the current element
         */
        function removeAllClasses() {
            this._node.setAttribute('class', '');

            return this;
        }

        /**
         * Get element height using `getBoundingClientRect`
         *
         * @memberof Chartist.Svg
         * @return {Number} The elements height in pixels
         */
        function height() {
            return this._node.getBoundingClientRect().height;
        }

        /**
         * Get element width using `getBoundingClientRect`
         *
         * @memberof Chartist.Core
         * @return {Number} The elements width in pixels
         */
        function width() {
            return this._node.getBoundingClientRect().width;
        }

        /**
         * The animate function lets you animate the current element with SMIL animations. You can add animations for multiple attributes at the same time by using an animation definition object. This object should contain SMIL animation attributes. Please refer to http://www.w3.org/TR/SVG/animate.html for a detailed specification about the available animation attributes. Additionally an easing property can be passed in the animation definition object. This can be a string with a name of an easing function in `Chartist.Svg.Easing` or an array with four numbers specifying a cubic Bézier curve.
         * **An animations object could look like this:**
         * ```javascript
         * element.animate({
         *   opacity: {
         *     dur: 1000,
         *     from: 0,
         *     to: 1
         *   },
         *   x1: {
         *     dur: '1000ms',
         *     from: 100,
         *     to: 200,
         *     easing: 'easeOutQuart'
         *   },
         *   y1: {
         *     dur: '2s',
         *     from: 0,
         *     to: 100
         *   }
         * });
         * ```
         * **Automatic unit conversion**
         * For the `dur` and the `begin` animate attribute you can also omit a unit by passing a number. The number will automatically be converted to milli seconds.
         * **Guided mode**
         * The default behavior of SMIL animations with offset using the `begin` attribute is that the attribute will keep it's original value until the animation starts. Mostly this behavior is not desired as you'd like to have your element attributes already initialized with the animation `from` value even before the animation starts. Also if you don't specify `fill="freeze"` on an animate element or if you delete the animation after it's done (which is done in guided mode) the attribute will switch back to the initial value. This behavior is also not desired when performing simple one-time animations. For one-time animations you'd want to trigger animations immediately instead of relative to the document begin time. That's why in guided mode Chartist.Svg will also use the `begin` property to schedule a timeout and manually start the animation after the timeout. If you're using multiple SMIL definition objects for an attribute (in an array), guided mode will be disabled for this attribute, even if you explicitly enabled it.
         * If guided mode is enabled the following behavior is added:
         * - Before the animation starts (even when delayed with `begin`) the animated attribute will be set already to the `from` value of the animation
         * - `begin` is explicitly set to `indefinite` so it can be started manually without relying on document begin time (creation)
         * - The animate element will be forced to use `fill="freeze"`
         * - The animation will be triggered with `beginElement()` in a timeout where `begin` of the definition object is interpreted in milli seconds. If no `begin` was specified the timeout is triggered immediately.
         * - After the animation the element attribute value will be set to the `to` value of the animation
         * - The animate element is deleted from the DOM
         *
         * @memberof Chartist.Svg
         * @param {Object} animations An animations object where the property keys are the attributes you'd like to animate. The properties should be objects again that contain the SMIL animation attributes (usually begin, dur, from, and to). The property begin and dur is auto converted (see Automatic unit conversion). You can also schedule multiple animations for the same attribute by passing an Array of SMIL definition objects. Attributes that contain an array of SMIL definition objects will not be executed in guided mode.
         * @param {Boolean} guided Specify if guided mode should be activated for this animation (see Guided mode). If not otherwise specified, guided mode will be activated.
         * @param {Object} eventEmitter If specified, this event emitter will be notified when an animation starts or ends.
         * @return {Chartist.Svg} The current element where the animation was added
         */
        function animate(animations, guided, eventEmitter) {
            if (guided === undefined) {
                guided = true;
            }

            Object.keys(animations).forEach(function createAnimateForAttributes(attribute) {

                function createAnimate(animationDefinition, guided) {
                    var attributeProperties = {},
                      animate,
                      timeout,
                      easing;

                    // Check if an easing is specified in the definition object and delete it from the object as it will not
                    // be part of the animate element attributes.
                    if (animationDefinition.easing) {
                        // If already an easing Bézier curve array we take it or we lookup a easing array in the Easing object
                        easing = animationDefinition.easing instanceof Array ?
                          animationDefinition.easing :
                          Chartist.Svg.Easing[animationDefinition.easing];
                        delete animationDefinition.easing;
                    }

                    // If numeric dur or begin was provided we assume milli seconds
                    animationDefinition.begin = Chartist.ensureUnit(animationDefinition.begin, 'ms');
                    animationDefinition.dur = Chartist.ensureUnit(animationDefinition.dur, 'ms');

                    if (easing) {
                        animationDefinition.calcMode = 'spline';
                        animationDefinition.keySplines = easing.join(' ');
                        animationDefinition.keyTimes = '0;1';
                    }

                    // Adding "fill: freeze" if we are in guided mode and set initial attribute values
                    if (guided) {
                        animationDefinition.fill = 'freeze';
                        // Animated property on our element should already be set to the animation from value in guided mode
                        attributeProperties[attribute] = animationDefinition.from;
                        this.attr(attributeProperties);

                        // In guided mode we also set begin to indefinite so we can trigger the start manually and put the begin
                        // which needs to be in ms aside
                        timeout = Chartist.quantity(animationDefinition.begin || 0).value;
                        animationDefinition.begin = 'indefinite';
                    }

                    animate = this.elem('animate', Chartist.extend({
                        attributeName: attribute
                    }, animationDefinition));

                    if (guided) {
                        // If guided we take the value that was put aside in timeout and trigger the animation manually with a timeout
                        setTimeout(function () {
                            // If beginElement fails we set the animated attribute to the end position and remove the animate element
                            // This happens if the SMIL ElementTimeControl interface is not supported or any other problems occured in
                            // the browser. (Currently FF 34 does not support animate elements in foreignObjects)
                            try {
                                animate._node.beginElement();
                            } catch (err) {
                                // Set animated attribute to current animated value
                                attributeProperties[attribute] = animationDefinition.to;
                                this.attr(attributeProperties);
                                // Remove the animate element as it's no longer required
                                animate.remove();
                            }
                        }.bind(this), timeout);
                    }

                    if (eventEmitter) {
                        animate._node.addEventListener('beginEvent', function handleBeginEvent() {
                            eventEmitter.emit('animationBegin', {
                                element: this,
                                animate: animate._node,
                                params: animationDefinition
                            });
                        }.bind(this));
                    }

                    animate._node.addEventListener('endEvent', function handleEndEvent() {
                        if (eventEmitter) {
                            eventEmitter.emit('animationEnd', {
                                element: this,
                                animate: animate._node,
                                params: animationDefinition
                            });
                        }

                        if (guided) {
                            // Set animated attribute to current animated value
                            attributeProperties[attribute] = animationDefinition.to;
                            this.attr(attributeProperties);
                            // Remove the animate element as it's no longer required
                            animate.remove();
                        }
                    }.bind(this));
                }

                // If current attribute is an array of definition objects we create an animate for each and disable guided mode
                if (animations[attribute] instanceof Array) {
                    animations[attribute].forEach(function (animationDefinition) {
                        createAnimate.bind(this)(animationDefinition, false);
                    }.bind(this));
                } else {
                    createAnimate.bind(this)(animations[attribute], guided);
                }

            }.bind(this));

            return this;
        }

        Chartist.Svg = Chartist.Class.extend({
            constructor: Svg,
            attr: attr,
            elem: elem,
            parent: parent,
            root: root,
            querySelector: querySelector,
            querySelectorAll: querySelectorAll,
            getNode: getNode,
            foreignObject: foreignObject,
            text: text,
            empty: empty,
            remove: remove,
            replace: replace,
            append: append,
            classes: classes,
            addClass: addClass,
            removeClass: removeClass,
            removeAllClasses: removeAllClasses,
            height: height,
            width: width,
            animate: animate
        });

        /**
         * This method checks for support of a given SVG feature like Extensibility, SVG-animation or the like. Check http://www.w3.org/TR/SVG11/feature for a detailed list.
         *
         * @memberof Chartist.Svg
         * @param {String} feature The SVG 1.1 feature that should be checked for support.
         * @return {Boolean} True of false if the feature is supported or not
         */
        Chartist.Svg.isSupported = function (feature) {
            return document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#' + feature, '1.1');
        };

        /**
         * This Object contains some standard easing cubic bezier curves. Then can be used with their name in the `Chartist.Svg.animate`. You can also extend the list and use your own name in the `animate` function. Click the show code button to see the available bezier functions.
         *
         * @memberof Chartist.Svg
         */
        var easingCubicBeziers = {
            easeInSine: [0.47, 0, 0.745, 0.715],
            easeOutSine: [0.39, 0.575, 0.565, 1],
            easeInOutSine: [0.445, 0.05, 0.55, 0.95],
            easeInQuad: [0.55, 0.085, 0.68, 0.53],
            easeOutQuad: [0.25, 0.46, 0.45, 0.94],
            easeInOutQuad: [0.455, 0.03, 0.515, 0.955],
            easeInCubic: [0.55, 0.055, 0.675, 0.19],
            easeOutCubic: [0.215, 0.61, 0.355, 1],
            easeInOutCubic: [0.645, 0.045, 0.355, 1],
            easeInQuart: [0.895, 0.03, 0.685, 0.22],
            easeOutQuart: [0.165, 0.84, 0.44, 1],
            easeInOutQuart: [0.77, 0, 0.175, 1],
            easeInQuint: [0.755, 0.05, 0.855, 0.06],
            easeOutQuint: [0.23, 1, 0.32, 1],
            easeInOutQuint: [0.86, 0, 0.07, 1],
            easeInExpo: [0.95, 0.05, 0.795, 0.035],
            easeOutExpo: [0.19, 1, 0.22, 1],
            easeInOutExpo: [1, 0, 0, 1],
            easeInCirc: [0.6, 0.04, 0.98, 0.335],
            easeOutCirc: [0.075, 0.82, 0.165, 1],
            easeInOutCirc: [0.785, 0.135, 0.15, 0.86],
            easeInBack: [0.6, -0.28, 0.735, 0.045],
            easeOutBack: [0.175, 0.885, 0.32, 1.275],
            easeInOutBack: [0.68, -0.55, 0.265, 1.55]
        };

        Chartist.Svg.Easing = easingCubicBeziers;

        /**
         * This helper class is to wrap multiple `Chartist.Svg` elements into a list where you can call the `Chartist.Svg` functions on all elements in the list with one call. This is helpful when you'd like to perform calls with `Chartist.Svg` on multiple elements.
         * An instance of this class is also returned by `Chartist.Svg.querySelectorAll`.
         *
         * @memberof Chartist.Svg
         * @param {Array<Node>|NodeList} nodeList An Array of SVG DOM nodes or a SVG DOM NodeList (as returned by document.querySelectorAll)
         * @constructor
         */
        function SvgList(nodeList) {
            var list = this;

            this.svgElements = [];
            for (var i = 0; i < nodeList.length; i++) {
                this.svgElements.push(new Chartist.Svg(nodeList[i]));
            }

            // Add delegation methods for Chartist.Svg
            Object.keys(Chartist.Svg.prototype).filter(function (prototypeProperty) {
                return ['constructor',
                    'parent',
                    'querySelector',
                    'querySelectorAll',
                    'replace',
                    'append',
                    'classes',
                    'height',
                    'width'].indexOf(prototypeProperty) === -1;
            }).forEach(function (prototypeProperty) {
                list[prototypeProperty] = function () {
                    var args = Array.prototype.slice.call(arguments, 0);
                    list.svgElements.forEach(function (element) {
                        Chartist.Svg.prototype[prototypeProperty].apply(element, args);
                    });
                    return list;
                };
            });
        }

        Chartist.Svg.List = Chartist.Class.extend({
            constructor: SvgList
        });
    }(window, document, Chartist));
    ;/**
 * Chartist SVG path module for SVG path description creation and modification.
 *
 * @module Chartist.Svg.Path
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        /**
         * Contains the descriptors of supported element types in a SVG path. Currently only move, line and curve are supported.
         *
         * @memberof Chartist.Svg.Path
         * @type {Object}
         */
        var elementDescriptions = {
            m: ['x', 'y'],
            l: ['x', 'y'],
            c: ['x1', 'y1', 'x2', 'y2', 'x', 'y'],
            a: ['rx', 'ry', 'xAr', 'lAf', 'sf', 'x', 'y']
        };

        /**
         * Default options for newly created SVG path objects.
         *
         * @memberof Chartist.Svg.Path
         * @type {Object}
         */
        var defaultOptions = {
            // The accuracy in digit count after the decimal point. This will be used to round numbers in the SVG path. If this option is set to false then no rounding will be performed.
            accuracy: 3
        };

        function element(command, params, pathElements, pos, relative, data) {
            var pathElement = Chartist.extend({
                command: relative ? command.toLowerCase() : command.toUpperCase()
            }, params, data ? { data: data } : {});

            pathElements.splice(pos, 0, pathElement);
        }

        function forEachParam(pathElements, cb) {
            pathElements.forEach(function (pathElement, pathElementIndex) {
                elementDescriptions[pathElement.command.toLowerCase()].forEach(function (paramName, paramIndex) {
                    cb(pathElement, paramName, pathElementIndex, paramIndex, pathElements);
                });
            });
        }

        /**
         * Used to construct a new path object.
         *
         * @memberof Chartist.Svg.Path
         * @param {Boolean} close If set to true then this path will be closed when stringified (with a Z at the end)
         * @param {Object} options Options object that overrides the default objects. See default options for more details.
         * @constructor
         */
        function SvgPath(close, options) {
            this.pathElements = [];
            this.pos = 0;
            this.close = close;
            this.options = Chartist.extend({}, defaultOptions, options);
        }

        /**
         * Gets or sets the current position (cursor) inside of the path. You can move around the cursor freely but limited to 0 or the count of existing elements. All modifications with element functions will insert new elements at the position of this cursor.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} [pos] If a number is passed then the cursor is set to this position in the path element array.
         * @return {Chartist.Svg.Path|Number} If the position parameter was passed then the return value will be the path object for easy call chaining. If no position parameter was passed then the current position is returned.
         */
        function position(pos) {
            if (pos !== undefined) {
                this.pos = Math.max(0, Math.min(this.pathElements.length, pos));
                return this;
            } else {
                return this.pos;
            }
        }

        /**
         * Removes elements from the path starting at the current position.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} count Number of path elements that should be removed from the current position.
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function remove(count) {
            this.pathElements.splice(this.pos, count);
            return this;
        }

        /**
         * Use this function to add a new move SVG path element.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} x The x coordinate for the move element.
         * @param {Number} y The y coordinate for the move element.
         * @param {Boolean} [relative] If set to true the move element will be created with relative coordinates (lowercase letter)
         * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function move(x, y, relative, data) {
            element('M', {
                x: +x,
                y: +y
            }, this.pathElements, this.pos++, relative, data);
            return this;
        }

        /**
         * Use this function to add a new line SVG path element.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} x The x coordinate for the line element.
         * @param {Number} y The y coordinate for the line element.
         * @param {Boolean} [relative] If set to true the line element will be created with relative coordinates (lowercase letter)
         * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function line(x, y, relative, data) {
            element('L', {
                x: +x,
                y: +y
            }, this.pathElements, this.pos++, relative, data);
            return this;
        }

        /**
         * Use this function to add a new curve SVG path element.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} x1 The x coordinate for the first control point of the bezier curve.
         * @param {Number} y1 The y coordinate for the first control point of the bezier curve.
         * @param {Number} x2 The x coordinate for the second control point of the bezier curve.
         * @param {Number} y2 The y coordinate for the second control point of the bezier curve.
         * @param {Number} x The x coordinate for the target point of the curve element.
         * @param {Number} y The y coordinate for the target point of the curve element.
         * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)
         * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function curve(x1, y1, x2, y2, x, y, relative, data) {
            element('C', {
                x1: +x1,
                y1: +y1,
                x2: +x2,
                y2: +y2,
                x: +x,
                y: +y
            }, this.pathElements, this.pos++, relative, data);
            return this;
        }

        /**
         * Use this function to add a new non-bezier curve SVG path element.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} rx The radius to be used for the x-axis of the arc.
         * @param {Number} ry The radius to be used for the y-axis of the arc.
         * @param {Number} xAr Defines the orientation of the arc
         * @param {Number} lAf Large arc flag
         * @param {Number} sf Sweep flag
         * @param {Number} x The x coordinate for the target point of the curve element.
         * @param {Number} y The y coordinate for the target point of the curve element.
         * @param {Boolean} [relative] If set to true the curve element will be created with relative coordinates (lowercase letter)
         * @param {*} [data] Any data that should be stored with the element object that will be accessible in pathElement
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function arc(rx, ry, xAr, lAf, sf, x, y, relative, data) {
            element('A', {
                rx: +rx,
                ry: +ry,
                xAr: +xAr,
                lAf: +lAf,
                sf: +sf,
                x: +x,
                y: +y
            }, this.pathElements, this.pos++, relative, data);
            return this;
        }

        /**
         * Parses an SVG path seen in the d attribute of path elements, and inserts the parsed elements into the existing path object at the current cursor position. Any closing path indicators (Z at the end of the path) will be ignored by the parser as this is provided by the close option in the options of the path object.
         *
         * @memberof Chartist.Svg.Path
         * @param {String} path Any SVG path that contains move (m), line (l) or curve (c) components.
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function parse(path) {
            // Parsing the SVG path string into an array of arrays [['M', '10', '10'], ['L', '100', '100']]
            var chunks = path.replace(/([A-Za-z])([0-9])/g, '$1 $2')
              .replace(/([0-9])([A-Za-z])/g, '$1 $2')
              .split(/[\s,]+/)
              .reduce(function (result, element) {
                  if (element.match(/[A-Za-z]/)) {
                      result.push([]);
                  }

                  result[result.length - 1].push(element);
                  return result;
              }, []);

            // If this is a closed path we remove the Z at the end because this is determined by the close option
            if (chunks[chunks.length - 1][0].toUpperCase() === 'Z') {
                chunks.pop();
            }

            // Using svgPathElementDescriptions to map raw path arrays into objects that contain the command and the parameters
            // For example {command: 'M', x: '10', y: '10'}
            var elements = chunks.map(function (chunk) {
                var command = chunk.shift(),
                  description = elementDescriptions[command.toLowerCase()];

                return Chartist.extend({
                    command: command
                }, description.reduce(function (result, paramName, index) {
                    result[paramName] = +chunk[index];
                    return result;
                }, {}));
            });

            // Preparing a splice call with the elements array as var arg params and insert the parsed elements at the current position
            var spliceArgs = [this.pos, 0];
            Array.prototype.push.apply(spliceArgs, elements);
            Array.prototype.splice.apply(this.pathElements, spliceArgs);
            // Increase the internal position by the element count
            this.pos += elements.length;

            return this;
        }

        /**
         * This function renders to current SVG path object into a final SVG string that can be used in the d attribute of SVG path elements. It uses the accuracy option to round big decimals. If the close parameter was set in the constructor of this path object then a path closing Z will be appended to the output string.
         *
         * @memberof Chartist.Svg.Path
         * @return {String}
         */
        function stringify() {
            var accuracyMultiplier = Math.pow(10, this.options.accuracy);

            return this.pathElements.reduce(function (path, pathElement) {
                var params = elementDescriptions[pathElement.command.toLowerCase()].map(function (paramName) {
                    return this.options.accuracy ?
                      (Math.round(pathElement[paramName] * accuracyMultiplier) / accuracyMultiplier) :
                      pathElement[paramName];
                }.bind(this));

                return path + pathElement.command + params.join(',');
            }.bind(this), '') + (this.close ? 'Z' : '');
        }

        /**
         * Scales all elements in the current SVG path object. There is an individual parameter for each coordinate. Scaling will also be done for control points of curves, affecting the given coordinate.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} x The number which will be used to scale the x, x1 and x2 of all path elements.
         * @param {Number} y The number which will be used to scale the y, y1 and y2 of all path elements.
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function scale(x, y) {
            forEachParam(this.pathElements, function (pathElement, paramName) {
                pathElement[paramName] *= paramName[0] === 'x' ? x : y;
            });
            return this;
        }

        /**
         * Translates all elements in the current SVG path object. The translation is relative and there is an individual parameter for each coordinate. Translation will also be done for control points of curves, affecting the given coordinate.
         *
         * @memberof Chartist.Svg.Path
         * @param {Number} x The number which will be used to translate the x, x1 and x2 of all path elements.
         * @param {Number} y The number which will be used to translate the y, y1 and y2 of all path elements.
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function translate(x, y) {
            forEachParam(this.pathElements, function (pathElement, paramName) {
                pathElement[paramName] += paramName[0] === 'x' ? x : y;
            });
            return this;
        }

        /**
         * This function will run over all existing path elements and then loop over their attributes. The callback function will be called for every path element attribute that exists in the current path.
         * The method signature of the callback function looks like this:
         * ```javascript
         * function(pathElement, paramName, pathElementIndex, paramIndex, pathElements)
         * ```
         * If something else than undefined is returned by the callback function, this value will be used to replace the old value. This allows you to build custom transformations of path objects that can't be achieved using the basic transformation functions scale and translate.
         *
         * @memberof Chartist.Svg.Path
         * @param {Function} transformFnc The callback function for the transformation. Check the signature in the function description.
         * @return {Chartist.Svg.Path} The current path object for easy call chaining.
         */
        function transform(transformFnc) {
            forEachParam(this.pathElements, function (pathElement, paramName, pathElementIndex, paramIndex, pathElements) {
                var transformed = transformFnc(pathElement, paramName, pathElementIndex, paramIndex, pathElements);
                if (transformed || transformed === 0) {
                    pathElement[paramName] = transformed;
                }
            });
            return this;
        }

        /**
         * This function clones a whole path object with all its properties. This is a deep clone and path element objects will also be cloned.
         *
         * @memberof Chartist.Svg.Path
         * @param {Boolean} [close] Optional option to set the new cloned path to closed. If not specified or false, the original path close option will be used.
         * @return {Chartist.Svg.Path}
         */
        function clone(close) {
            var c = new Chartist.Svg.Path(close || this.close);
            c.pos = this.pos;
            c.pathElements = this.pathElements.slice().map(function cloneElements(pathElement) {
                return Chartist.extend({}, pathElement);
            });
            c.options = Chartist.extend({}, this.options);
            return c;
        }

        /**
         * Split a Svg.Path object by a specific command in the path chain. The path chain will be split and an array of newly created paths objects will be returned. This is useful if you'd like to split an SVG path by it's move commands, for example, in order to isolate chunks of drawings.
         *
         * @memberof Chartist.Svg.Path
         * @param {String} command The command you'd like to use to split the path
         * @return {Array<Chartist.Svg.Path>}
         */
        function splitByCommand(command) {
            var split = [
              new Chartist.Svg.Path()
            ];

            this.pathElements.forEach(function (pathElement) {
                if (pathElement.command === command.toUpperCase() && split[split.length - 1].pathElements.length !== 0) {
                    split.push(new Chartist.Svg.Path());
                }

                split[split.length - 1].pathElements.push(pathElement);
            });

            return split;
        }

        /**
         * This static function on `Chartist.Svg.Path` is joining multiple paths together into one paths.
         *
         * @memberof Chartist.Svg.Path
         * @param {Array<Chartist.Svg.Path>} paths A list of paths to be joined together. The order is important.
         * @param {boolean} close If the newly created path should be a closed path
         * @param {Object} options Path options for the newly created path.
         * @return {Chartist.Svg.Path}
         */

        function join(paths, close, options) {
            var joinedPath = new Chartist.Svg.Path(close, options);
            for (var i = 0; i < paths.length; i++) {
                var path = paths[i];
                for (var j = 0; j < path.pathElements.length; j++) {
                    joinedPath.pathElements.push(path.pathElements[j]);
                }
            }
            return joinedPath;
        }

        Chartist.Svg.Path = Chartist.Class.extend({
            constructor: SvgPath,
            position: position,
            remove: remove,
            move: move,
            line: line,
            curve: curve,
            arc: arc,
            scale: scale,
            translate: translate,
            transform: transform,
            parse: parse,
            stringify: stringify,
            clone: clone,
            splitByCommand: splitByCommand
        });

        Chartist.Svg.Path.elementDescriptions = elementDescriptions;
        Chartist.Svg.Path.join = join;
    }(window, document, Chartist));
    ;/* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        var axisUnits = {
            x: {
                pos: 'x',
                len: 'width',
                dir: 'horizontal',
                rectStart: 'x1',
                rectEnd: 'x2',
                rectOffset: 'y2'
            },
            y: {
                pos: 'y',
                len: 'height',
                dir: 'vertical',
                rectStart: 'y2',
                rectEnd: 'y1',
                rectOffset: 'x1'
            }
        };

        function Axis(units, chartRect, ticks, options) {
            this.units = units;
            this.counterUnits = units === axisUnits.x ? axisUnits.y : axisUnits.x;
            this.chartRect = chartRect;
            this.axisLength = chartRect[units.rectEnd] - chartRect[units.rectStart];
            this.gridOffset = chartRect[units.rectOffset];
            this.ticks = ticks;
            this.options = options;
        }

        function createGridAndLabels(gridGroup, labelGroup, useForeignObject, chartOptions, eventEmitter) {
            var axisOptions = chartOptions['axis' + this.units.pos.toUpperCase()];
            var projectedValues = this.ticks.map(this.projectValue.bind(this));
            var labelValues = this.ticks.map(axisOptions.labelInterpolationFnc);

            projectedValues.forEach(function (projectedValue, index) {
                var labelOffset = {
                    x: 0,
                    y: 0
                };

                // TODO: Find better solution for solving this problem
                // Calculate how much space we have available for the label
                var labelLength;
                if (projectedValues[index + 1]) {
                    // If we still have one label ahead, we can calculate the distance to the next tick / label
                    labelLength = projectedValues[index + 1] - projectedValue;
                } else {
                    // If we don't have a label ahead and we have only two labels in total, we just take the remaining distance to
                    // on the whole axis length. We limit that to a minimum of 30 pixel, so that labels close to the border will
                    // still be visible inside of the chart padding.
                    labelLength = Math.max(this.axisLength - projectedValue, 30);
                }

                // Skip grid lines and labels where interpolated label values are falsey (execpt for 0)
                if (Chartist.isFalseyButZero(labelValues[index]) && labelValues[index] !== '') {
                    return;
                }

                // Transform to global coordinates using the chartRect
                // We also need to set the label offset for the createLabel function
                if (this.units.pos === 'x') {
                    projectedValue = this.chartRect.x1 + projectedValue;
                    labelOffset.x = chartOptions.axisX.labelOffset.x;

                    // If the labels should be positioned in start position (top side for vertical axis) we need to set a
                    // different offset as for positioned with end (bottom)
                    if (chartOptions.axisX.position === 'start') {
                        labelOffset.y = this.chartRect.padding.top + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);
                    } else {
                        labelOffset.y = this.chartRect.y1 + chartOptions.axisX.labelOffset.y + (useForeignObject ? 5 : 20);
                    }
                } else {
                    projectedValue = this.chartRect.y1 - projectedValue;
                    labelOffset.y = chartOptions.axisY.labelOffset.y - (useForeignObject ? labelLength : 0);

                    // If the labels should be positioned in start position (left side for horizontal axis) we need to set a
                    // different offset as for positioned with end (right side)
                    if (chartOptions.axisY.position === 'start') {
                        labelOffset.x = useForeignObject ? this.chartRect.padding.left + chartOptions.axisY.labelOffset.x : this.chartRect.x1 - 10;
                    } else {
                        labelOffset.x = this.chartRect.x2 + chartOptions.axisY.labelOffset.x + 10;
                    }
                }

                if (axisOptions.showGrid) {
                    Chartist.createGrid(projectedValue, index, this, this.gridOffset, this.chartRect[this.counterUnits.len](), gridGroup, [
                      chartOptions.classNames.grid,
                      chartOptions.classNames[this.units.dir]
                    ], eventEmitter);
                }

                if (axisOptions.showLabel) {
                    Chartist.createLabel(projectedValue, labelLength, index, labelValues, this, axisOptions.offset, labelOffset, labelGroup, [
                      chartOptions.classNames.label,
                      chartOptions.classNames[this.units.dir],
                      (axisOptions.position === 'start' ? chartOptions.classNames[axisOptions.position] : chartOptions.classNames['end'])
                    ], useForeignObject, eventEmitter);
                }
            }.bind(this));
        }

        Chartist.Axis = Chartist.Class.extend({
            constructor: Axis,
            createGridAndLabels: createGridAndLabels,
            projectValue: function (value, index, data) {
                throw new Error('Base axis can\'t be instantiated!');
            }
        });

        Chartist.Axis.units = axisUnits;

    }(window, document, Chartist));
    ;/**
 * The auto scale axis uses standard linear scale projection of values along an axis. It uses order of magnitude to find a scale automatically and evaluates the available space in order to find the perfect amount of ticks for your chart.
 * **Options**
 * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.
 * ```javascript
 * var options = {
 *   // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored
 *   high: 100,
 *   // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored
 *   low: 0,
 *   // This option will be used when finding the right scale division settings. The amount of ticks on the scale will be determined so that as many ticks as possible will be displayed, while not violating this minimum required space (in pixel).
 *   scaleMinSpace: 20,
 *   // Can be set to true or false. If set to true, the scale will be generated with whole numbers only.
 *   onlyInteger: true,
 *   // The reference value can be used to make sure that this value will always be on the chart. This is especially useful on bipolar charts where the bipolar center always needs to be part of the chart.
 *   referenceValue: 5
 * };
 * ```
 *
 * @module Chartist.AutoScaleAxis
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        function AutoScaleAxis(axisUnit, data, chartRect, options) {
            // Usually we calculate highLow based on the data but this can be overriden by a highLow object in the options
            var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);
            this.bounds = Chartist.getBounds(chartRect[axisUnit.rectEnd] - chartRect[axisUnit.rectStart], highLow, options.scaleMinSpace || 20, options.onlyInteger);
            this.range = {
                min: this.bounds.min,
                max: this.bounds.max
            };

            Chartist.AutoScaleAxis.super.constructor.call(this,
              axisUnit,
              chartRect,
              this.bounds.values,
              options);
        }

        function projectValue(value) {
            return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.bounds.min) / this.bounds.range;
        }

        Chartist.AutoScaleAxis = Chartist.Axis.extend({
            constructor: AutoScaleAxis,
            projectValue: projectValue
        });

    }(window, document, Chartist));
    ;/**
 * The fixed scale axis uses standard linear projection of values along an axis. It makes use of a divisor option to divide the range provided from the minimum and maximum value or the options high and low that will override the computed minimum and maximum.
 * **Options**
 * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.
 * ```javascript
 * var options = {
 *   // If high is specified then the axis will display values explicitly up to this value and the computed maximum from the data is ignored
 *   high: 100,
 *   // If low is specified then the axis will display values explicitly down to this value and the computed minimum from the data is ignored
 *   low: 0,
 *   // If specified then the value range determined from minimum to maximum (or low and high) will be divided by this number and ticks will be generated at those division points. The default divisor is 1.
 *   divisor: 4,
 *   // If ticks is explicitly set, then the axis will not compute the ticks with the divisor, but directly use the data in ticks to determine at what points on the axis a tick need to be generated.
 *   ticks: [1, 10, 20, 30]
 * };
 * ```
 *
 * @module Chartist.FixedScaleAxis
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        function FixedScaleAxis(axisUnit, data, chartRect, options) {
            var highLow = options.highLow || Chartist.getHighLow(data, options, axisUnit.pos);
            this.divisor = options.divisor || 1;
            this.ticks = options.ticks || Chartist.times(this.divisor).map(function (value, index) {
                return highLow.low + (highLow.high - highLow.low) / this.divisor * index;
            }.bind(this));
            this.ticks.sort(function (a, b) {
                return a - b;
            });
            this.range = {
                min: highLow.low,
                max: highLow.high
            };

            Chartist.FixedScaleAxis.super.constructor.call(this,
              axisUnit,
              chartRect,
              this.ticks,
              options);

            this.stepLength = this.axisLength / this.divisor;
        }

        function projectValue(value) {
            return this.axisLength * (+Chartist.getMultiValue(value, this.units.pos) - this.range.min) / (this.range.max - this.range.min);
        }

        Chartist.FixedScaleAxis = Chartist.Axis.extend({
            constructor: FixedScaleAxis,
            projectValue: projectValue
        });

    }(window, document, Chartist));
    ;/**
 * The step axis for step based charts like bar chart or step based line charts. It uses a fixed amount of ticks that will be equally distributed across the whole axis length. The projection is done using the index of the data value rather than the value itself and therefore it's only useful for distribution purpose.
 * **Options**
 * The following options are used by this axis in addition to the default axis options outlined in the axis configuration of the chart default settings.
 * ```javascript
 * var options = {
 *   // Ticks to be used to distribute across the axis length. As this axis type relies on the index of the value rather than the value, arbitrary data that can be converted to a string can be used as ticks.
 *   ticks: ['One', 'Two', 'Three'],
 *   // If set to true the full width will be used to distribute the values where the last value will be at the maximum of the axis length. If false the spaces between the ticks will be evenly distributed instead.
 *   stretch: true
 * };
 * ```
 *
 * @module Chartist.StepAxis
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        function StepAxis(axisUnit, data, chartRect, options) {
            Chartist.StepAxis.super.constructor.call(this,
              axisUnit,
              chartRect,
              options.ticks,
              options);

            var calc = Math.max(1, options.ticks.length - (options.stretch ? 1 : 0));
            this.stepLength = this.axisLength / calc;
        }

        function projectValue(value, index) {
            return this.stepLength * index;
        }

        Chartist.StepAxis = Chartist.Axis.extend({
            constructor: StepAxis,
            projectValue: projectValue
        });

    }(window, document, Chartist));
    ;/**
 * The Chartist line chart can be used to draw Line or Scatter charts. If used in the browser you can access the global `Chartist` namespace where you find the `Line` function as a main entry point.
 *
 * For examples on how to use the line chart please check the examples of the `Chartist.Line` method.
 *
 * @module Chartist.Line
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        /**
         * Default options in line charts. Expand the code view to see a detailed list of options with comments.
         *
         * @memberof Chartist.Line
         */
        var defaultOptions = {
            // Options for X-Axis
            axisX: {
                // The offset of the labels to the chart area
                offset: 30,
                // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.
                position: 'end',
                // Allows you to correct label positioning on this axis by positive or negative x and y offset.
                labelOffset: {
                    x: 0,
                    y: 0
                },
                // If labels should be shown or not
                showLabel: true,
                // If the axis grid should be drawn or not
                showGrid: true,
                // Interpolation function that allows you to intercept the value from the axis label
                labelInterpolationFnc: Chartist.noop,
                // Set the axis type to be used to project values on this axis. If not defined, Chartist.StepAxis will be used for the X-Axis, where the ticks option will be set to the labels in the data and the stretch option will be set to the global fullWidth option. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.
                type: undefined
            },
            // Options for Y-Axis
            axisY: {
                // The offset of the labels to the chart area
                offset: 40,
                // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.
                position: 'start',
                // Allows you to correct label positioning on this axis by positive or negative x and y offset.
                labelOffset: {
                    x: 0,
                    y: 0
                },
                // If labels should be shown or not
                showLabel: true,
                // If the axis grid should be drawn or not
                showGrid: true,
                // Interpolation function that allows you to intercept the value from the axis label
                labelInterpolationFnc: Chartist.noop,
                // Set the axis type to be used to project values on this axis. If not defined, Chartist.AutoScaleAxis will be used for the Y-Axis, where the high and low options will be set to the global high and low options. This type can be changed to any axis constructor available (e.g. Chartist.FixedScaleAxis), where all axis options should be present here.
                type: undefined,
                // This value specifies the minimum height in pixel of the scale steps
                scaleMinSpace: 20,
                // Use only integer values (whole numbers) for the scale steps
                onlyInteger: false
            },
            // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')
            width: undefined,
            // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')
            height: undefined,
            // If the line should be drawn or not
            showLine: true,
            // If dots should be drawn or not
            showPoint: true,
            // If the line chart should draw an area
            showArea: false,
            // The base for the area chart that will be used to close the area shape (is normally 0)
            areaBase: 0,
            // Specify if the lines should be smoothed. This value can be true or false where true will result in smoothing using the default smoothing interpolation function Chartist.Interpolation.cardinal and false results in Chartist.Interpolation.none. You can also choose other smoothing / interpolation functions available in the Chartist.Interpolation module, or write your own interpolation function. Check the examples for a brief description.
            lineSmooth: true,
            // If the line chart should add a background fill to the .ct-grids group.
            showGridBackground: false,
            // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value
            low: undefined,
            // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value
            high: undefined,
            // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}
            chartPadding: {
                top: 15,
                right: 15,
                bottom: 5,
                left: 10
            },
            // When set to true, the last grid line on the x-axis is not drawn and the chart elements will expand to the full available width of the chart. For the last label to be drawn correctly you might need to add chart padding or offset the last label with a draw event handler.
            fullWidth: false,
            // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.
            reverseData: false,
            // Override the class names that get used to generate the SVG structure of the chart
            classNames: {
                chart: 'ct-chart-line',
                label: 'ct-label',
                labelGroup: 'ct-labels',
                series: 'ct-series',
                line: 'ct-line',
                point: 'ct-point',
                area: 'ct-area',
                grid: 'ct-grid',
                gridGroup: 'ct-grids',
                gridBackground: 'ct-grid-background',
                vertical: 'ct-vertical',
                horizontal: 'ct-horizontal',
                start: 'ct-start',
                end: 'ct-end'
            }
        };

        /**
         * Creates a new chart
         *
         */
        function createChart(options) {
            var data = Chartist.normalizeData(this.data, options.reverseData, true);

            // Create new svg object
            this.svg = Chartist.createSvg(this.container, options.width, options.height, options.classNames.chart);
            // Create groups for labels, grid and series
            var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);
            var seriesGroup = this.svg.elem('g');
            var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);

            var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);
            var axisX, axisY;

            if (options.axisX.type === undefined) {
                axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
                    ticks: data.normalized.labels,
                    stretch: options.fullWidth
                }));
            } else {
                axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);
            }

            if (options.axisY.type === undefined) {
                axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
                    high: Chartist.isNumeric(options.high) ? options.high : options.axisY.high,
                    low: Chartist.isNumeric(options.low) ? options.low : options.axisY.low
                }));
            } else {
                axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);
            }

            axisX.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
            axisY.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);

            if (options.showGridBackground) {
                Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);
            }

            // Draw the series
            data.raw.series.forEach(function (series, seriesIndex) {
                var seriesElement = seriesGroup.elem('g');

                // Write attributes to series group element. If series name or meta is undefined the attributes will not be written
                seriesElement.attr({
                    'ct:series-name': series.name,
                    'ct:meta': Chartist.serialize(series.meta)
                });

                // Use series class from series data or if not set generate one
                seriesElement.addClass([
                  options.classNames.series,
                  (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))
                ].join(' '));

                var pathCoordinates = [],
                  pathData = [];

                data.normalized.series[seriesIndex].forEach(function (value, valueIndex) {
                    var p = {
                        x: chartRect.x1 + axisX.projectValue(value, valueIndex, data.normalized.series[seriesIndex]),
                        y: chartRect.y1 - axisY.projectValue(value, valueIndex, data.normalized.series[seriesIndex])
                    };
                    pathCoordinates.push(p.x, p.y);
                    pathData.push({
                        value: value,
                        valueIndex: valueIndex,
                        meta: Chartist.getMetaData(series, valueIndex)
                    });
                }.bind(this));

                var seriesOptions = {
                    lineSmooth: Chartist.getSeriesOption(series, options, 'lineSmooth'),
                    showPoint: Chartist.getSeriesOption(series, options, 'showPoint'),
                    showLine: Chartist.getSeriesOption(series, options, 'showLine'),
                    showArea: Chartist.getSeriesOption(series, options, 'showArea'),
                    areaBase: Chartist.getSeriesOption(series, options, 'areaBase')
                };

                var smoothing = typeof seriesOptions.lineSmooth === 'function' ?
                  seriesOptions.lineSmooth : (seriesOptions.lineSmooth ? Chartist.Interpolation.monotoneCubic() : Chartist.Interpolation.none());
                // Interpolating path where pathData will be used to annotate each path element so we can trace back the original
                // index, value and meta data
                var path = smoothing(pathCoordinates, pathData);

                // If we should show points we need to create them now to avoid secondary loop
                // Points are drawn from the pathElements returned by the interpolation function
                // Small offset for Firefox to render squares correctly
                if (seriesOptions.showPoint) {

                    path.pathElements.forEach(function (pathElement) {
                        var point = seriesElement.elem('line', {
                            x1: pathElement.x,
                            y1: pathElement.y,
                            x2: pathElement.x + 0.01,
                            y2: pathElement.y
                        }, options.classNames.point).attr({
                            'ct:value': [pathElement.data.value.x, pathElement.data.value.y].filter(Chartist.isNumeric).join(','),
                            'ct:meta': Chartist.serialize(pathElement.data.meta)
                        });

                        this.eventEmitter.emit('draw', {
                            type: 'point',
                            value: pathElement.data.value,
                            index: pathElement.data.valueIndex,
                            meta: pathElement.data.meta,
                            series: series,
                            seriesIndex: seriesIndex,
                            axisX: axisX,
                            axisY: axisY,
                            group: seriesElement,
                            element: point,
                            x: pathElement.x,
                            y: pathElement.y
                        });
                    }.bind(this));
                }

                if (seriesOptions.showLine) {
                    var line = seriesElement.elem('path', {
                        d: path.stringify()
                    }, options.classNames.line, true);

                    this.eventEmitter.emit('draw', {
                        type: 'line',
                        values: data.normalized.series[seriesIndex],
                        path: path.clone(),
                        chartRect: chartRect,
                        index: seriesIndex,
                        series: series,
                        seriesIndex: seriesIndex,
                        seriesMeta: series.meta,
                        axisX: axisX,
                        axisY: axisY,
                        group: seriesElement,
                        element: line
                    });
                }

                // Area currently only works with axes that support a range!
                if (seriesOptions.showArea && axisY.range) {
                    // If areaBase is outside the chart area (< min or > max) we need to set it respectively so that
                    // the area is not drawn outside the chart area.
                    var areaBase = Math.max(Math.min(seriesOptions.areaBase, axisY.range.max), axisY.range.min);

                    // We project the areaBase value into screen coordinates
                    var areaBaseProjected = chartRect.y1 - axisY.projectValue(areaBase);

                    // In order to form the area we'll first split the path by move commands so we can chunk it up into segments
                    path.splitByCommand('M').filter(function onlySolidSegments(pathSegment) {
                        // We filter only "solid" segments that contain more than one point. Otherwise there's no need for an area
                        return pathSegment.pathElements.length > 1;
                    }).map(function convertToArea(solidPathSegments) {
                        // Receiving the filtered solid path segments we can now convert those segments into fill areas
                        var firstElement = solidPathSegments.pathElements[0];
                        var lastElement = solidPathSegments.pathElements[solidPathSegments.pathElements.length - 1];

                        // Cloning the solid path segment with closing option and removing the first move command from the clone
                        // We then insert a new move that should start at the area base and draw a straight line up or down
                        // at the end of the path we add an additional straight line to the projected area base value
                        // As the closing option is set our path will be automatically closed
                        return solidPathSegments.clone(true)
                          .position(0)
                          .remove(1)
                          .move(firstElement.x, areaBaseProjected)
                          .line(firstElement.x, firstElement.y)
                          .position(solidPathSegments.pathElements.length + 1)
                          .line(lastElement.x, areaBaseProjected);

                    }).forEach(function createArea(areaPath) {
                        // For each of our newly created area paths, we'll now create path elements by stringifying our path objects
                        // and adding the created DOM elements to the correct series group
                        var area = seriesElement.elem('path', {
                            d: areaPath.stringify()
                        }, options.classNames.area, true);

                        // Emit an event for each area that was drawn
                        this.eventEmitter.emit('draw', {
                            type: 'area',
                            values: data.normalized.series[seriesIndex],
                            path: areaPath.clone(),
                            series: series,
                            seriesIndex: seriesIndex,
                            axisX: axisX,
                            axisY: axisY,
                            chartRect: chartRect,
                            index: seriesIndex,
                            group: seriesElement,
                            element: area
                        });
                    }.bind(this));
                }
            }.bind(this));

            this.eventEmitter.emit('created', {
                bounds: axisY.bounds,
                chartRect: chartRect,
                axisX: axisX,
                axisY: axisY,
                svg: this.svg,
                options: options
            });
        }

        /**
         * This method creates a new line chart.
         *
         * @memberof Chartist.Line
         * @param {String|Node} query A selector query string or directly a DOM element
         * @param {Object} data The data object that needs to consist of a labels and a series array
         * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.
         * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]
         * @return {Object} An object which exposes the API for the created chart
         *
         * @example
         * // Create a simple line chart
         * var data = {
         *   // A labels array that can contain any sort of values
         *   labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
         *   // Our series array that contains series objects or in this case series data arrays
         *   series: [
         *     [5, 2, 4, 2, 0]
         *   ]
         * };
         *
         * // As options we currently only set a static size of 300x200 px
         * var options = {
         *   width: '300px',
         *   height: '200px'
         * };
         *
         * // In the global name space Chartist we call the Line function to initialize a line chart. As a first parameter we pass in a selector where we would like to get our chart created. Second parameter is the actual data object and as a third parameter we pass in our options
         * new Chartist.Line('.ct-chart', data, options);
         *
         * @example
         * // Use specific interpolation function with configuration from the Chartist.Interpolation module
         *
         * var chart = new Chartist.Line('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5],
         *   series: [
         *     [1, 1, 8, 1, 7]
         *   ]
         * }, {
         *   lineSmooth: Chartist.Interpolation.cardinal({
         *     tension: 0.2
         *   })
         * });
         *
         * @example
         * // Create a line chart with responsive options
         *
         * var data = {
         *   // A labels array that can contain any sort of values
         *   labels: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
         *   // Our series array that contains series objects or in this case series data arrays
         *   series: [
         *     [5, 2, 4, 2, 0]
         *   ]
         * };
         *
         * // In addition to the regular options we specify responsive option overrides that will override the default configutation based on the matching media queries.
         * var responsiveOptions = [
         *   ['screen and (min-width: 641px) and (max-width: 1024px)', {
         *     showPoint: false,
         *     axisX: {
         *       labelInterpolationFnc: function(value) {
         *         // Will return Mon, Tue, Wed etc. on medium screens
         *         return value.slice(0, 3);
         *       }
         *     }
         *   }],
         *   ['screen and (max-width: 640px)', {
         *     showLine: false,
         *     axisX: {
         *       labelInterpolationFnc: function(value) {
         *         // Will return M, T, W etc. on small screens
         *         return value[0];
         *       }
         *     }
         *   }]
         * ];
         *
         * new Chartist.Line('.ct-chart', data, null, responsiveOptions);
         *
         */
        function Line(query, data, options, responsiveOptions) {
            Chartist.Line.super.constructor.call(this,
              query,
              data,
              defaultOptions,
              Chartist.extend({}, defaultOptions, options),
              responsiveOptions);
        }

        // Creating line chart type in Chartist namespace
        Chartist.Line = Chartist.Base.extend({
            constructor: Line,
            createChart: createChart
        });

    }(window, document, Chartist));
    ;/**
 * The bar chart module of Chartist that can be used to draw unipolar or bipolar bar and grouped bar charts.
 *
 * @module Chartist.Bar
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        /**
         * Default options in bar charts. Expand the code view to see a detailed list of options with comments.
         *
         * @memberof Chartist.Bar
         */
        var defaultOptions = {
            // Options for X-Axis
            axisX: {
                // The offset of the chart drawing area to the border of the container
                offset: 30,
                // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.
                position: 'end',
                // Allows you to correct label positioning on this axis by positive or negative x and y offset.
                labelOffset: {
                    x: 0,
                    y: 0
                },
                // If labels should be shown or not
                showLabel: true,
                // If the axis grid should be drawn or not
                showGrid: true,
                // Interpolation function that allows you to intercept the value from the axis label
                labelInterpolationFnc: Chartist.noop,
                // This value specifies the minimum width in pixel of the scale steps
                scaleMinSpace: 30,
                // Use only integer values (whole numbers) for the scale steps
                onlyInteger: false
            },
            // Options for Y-Axis
            axisY: {
                // The offset of the chart drawing area to the border of the container
                offset: 40,
                // Position where labels are placed. Can be set to `start` or `end` where `start` is equivalent to left or top on vertical axis and `end` is equivalent to right or bottom on horizontal axis.
                position: 'start',
                // Allows you to correct label positioning on this axis by positive or negative x and y offset.
                labelOffset: {
                    x: 0,
                    y: 0
                },
                // If labels should be shown or not
                showLabel: true,
                // If the axis grid should be drawn or not
                showGrid: true,
                // Interpolation function that allows you to intercept the value from the axis label
                labelInterpolationFnc: Chartist.noop,
                // This value specifies the minimum height in pixel of the scale steps
                scaleMinSpace: 20,
                // Use only integer values (whole numbers) for the scale steps
                onlyInteger: false
            },
            // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')
            width: undefined,
            // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')
            height: undefined,
            // Overriding the natural high of the chart allows you to zoom in or limit the charts highest displayed value
            high: undefined,
            // Overriding the natural low of the chart allows you to zoom in or limit the charts lowest displayed value
            low: undefined,
            // Unless low/high are explicitly set, bar chart will be centered at zero by default. Set referenceValue to null to auto scale.
            referenceValue: 0,
            // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}
            chartPadding: {
                top: 15,
                right: 15,
                bottom: 5,
                left: 10
            },
            // Specify the distance in pixel of bars in a group
            seriesBarDistance: 15,
            // If set to true this property will cause the series bars to be stacked. Check the `stackMode` option for further stacking options.
            stackBars: false,
            // If set to 'overlap' this property will force the stacked bars to draw from the zero line.
            // If set to 'accumulate' this property will form a total for each series point. This will also influence the y-axis and the overall bounds of the chart. In stacked mode the seriesBarDistance property will have no effect.
            stackMode: 'accumulate',
            // Inverts the axes of the bar chart in order to draw a horizontal bar chart. Be aware that you also need to invert your axis settings as the Y Axis will now display the labels and the X Axis the values.
            horizontalBars: false,
            // If set to true then each bar will represent a series and the data array is expected to be a one dimensional array of data values rather than a series array of series. This is useful if the bar chart should represent a profile rather than some data over time.
            distributeSeries: false,
            // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.
            reverseData: false,
            // If the bar chart should add a background fill to the .ct-grids group.
            showGridBackground: false,
            // Override the class names that get used to generate the SVG structure of the chart
            classNames: {
                chart: 'ct-chart-bar',
                horizontalBars: 'ct-horizontal-bars',
                label: 'ct-label',
                labelGroup: 'ct-labels',
                series: 'ct-series',
                bar: 'ct-bar',
                grid: 'ct-grid',
                gridGroup: 'ct-grids',
                gridBackground: 'ct-grid-background',
                vertical: 'ct-vertical',
                horizontal: 'ct-horizontal',
                start: 'ct-start',
                end: 'ct-end'
            }
        };

        /**
         * Creates a new chart
         *
         */
        function createChart(options) {
            var data;
            var highLow;

            if (options.distributeSeries) {
                data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');
                data.normalized.series = data.normalized.series.map(function (value) {
                    return [value];
                });
            } else {
                data = Chartist.normalizeData(this.data, options.reverseData, options.horizontalBars ? 'x' : 'y');
            }

            // Create new svg element
            this.svg = Chartist.createSvg(
              this.container,
              options.width,
              options.height,
              options.classNames.chart + (options.horizontalBars ? ' ' + options.classNames.horizontalBars : '')
            );

            // Drawing groups in correct order
            var gridGroup = this.svg.elem('g').addClass(options.classNames.gridGroup);
            var seriesGroup = this.svg.elem('g');
            var labelGroup = this.svg.elem('g').addClass(options.classNames.labelGroup);

            if (options.stackBars && data.normalized.series.length !== 0) {

                // If stacked bars we need to calculate the high low from stacked values from each series
                var serialSums = Chartist.serialMap(data.normalized.series, function serialSums() {
                    return Array.prototype.slice.call(arguments).map(function (value) {
                        return value;
                    }).reduce(function (prev, curr) {
                        return {
                            x: prev.x + (curr && curr.x) || 0,
                            y: prev.y + (curr && curr.y) || 0
                        };
                    }, { x: 0, y: 0 });
                });

                highLow = Chartist.getHighLow([serialSums], options, options.horizontalBars ? 'x' : 'y');

            } else {

                highLow = Chartist.getHighLow(data.normalized.series, options, options.horizontalBars ? 'x' : 'y');
            }

            // Overrides of high / low from settings
            highLow.high = +options.high || (options.high === 0 ? 0 : highLow.high);
            highLow.low = +options.low || (options.low === 0 ? 0 : highLow.low);

            var chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);

            var valueAxis,
              labelAxisTicks,
              labelAxis,
              axisX,
              axisY;

            // We need to set step count based on some options combinations
            if (options.distributeSeries && options.stackBars) {
                // If distributed series are enabled and bars need to be stacked, we'll only have one bar and therefore should
                // use only the first label for the step axis
                labelAxisTicks = data.normalized.labels.slice(0, 1);
            } else {
                // If distributed series are enabled but stacked bars aren't, we should use the series labels
                // If we are drawing a regular bar chart with two dimensional series data, we just use the labels array
                // as the bars are normalized
                labelAxisTicks = data.normalized.labels;
            }

            // Set labelAxis and valueAxis based on the horizontalBars setting. This setting will flip the axes if necessary.
            if (options.horizontalBars) {
                if (options.axisX.type === undefined) {
                    valueAxis = axisX = new Chartist.AutoScaleAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
                        highLow: highLow,
                        referenceValue: 0
                    }));
                } else {
                    valueAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, Chartist.extend({}, options.axisX, {
                        highLow: highLow,
                        referenceValue: 0
                    }));
                }

                if (options.axisY.type === undefined) {
                    labelAxis = axisY = new Chartist.StepAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, {
                        ticks: labelAxisTicks
                    });
                } else {
                    labelAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, options.axisY);
                }
            } else {
                if (options.axisX.type === undefined) {
                    labelAxis = axisX = new Chartist.StepAxis(Chartist.Axis.units.x, data.normalized.series, chartRect, {
                        ticks: labelAxisTicks
                    });
                } else {
                    labelAxis = axisX = options.axisX.type.call(Chartist, Chartist.Axis.units.x, data.normalized.series, chartRect, options.axisX);
                }

                if (options.axisY.type === undefined) {
                    valueAxis = axisY = new Chartist.AutoScaleAxis(Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
                        highLow: highLow,
                        referenceValue: 0
                    }));
                } else {
                    valueAxis = axisY = options.axisY.type.call(Chartist, Chartist.Axis.units.y, data.normalized.series, chartRect, Chartist.extend({}, options.axisY, {
                        highLow: highLow,
                        referenceValue: 0
                    }));
                }
            }

            // Projected 0 point
            var zeroPoint = options.horizontalBars ? (chartRect.x1 + valueAxis.projectValue(0)) : (chartRect.y1 - valueAxis.projectValue(0));
            // Used to track the screen coordinates of stacked bars
            var stackedBarValues = [];

            labelAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);
            valueAxis.createGridAndLabels(gridGroup, labelGroup, this.supportsForeignObject, options, this.eventEmitter);

            if (options.showGridBackground) {
                Chartist.createGridBackground(gridGroup, chartRect, options.classNames.gridBackground, this.eventEmitter);
            }

            // Draw the series
            data.raw.series.forEach(function (series, seriesIndex) {
                // Calculating bi-polar value of index for seriesOffset. For i = 0..4 biPol will be -1.5, -0.5, 0.5, 1.5 etc.
                var biPol = seriesIndex - (data.raw.series.length - 1) / 2;
                // Half of the period width between vertical grid lines used to position bars
                var periodHalfLength;
                // Current series SVG element
                var seriesElement;

                // We need to set periodHalfLength based on some options combinations
                if (options.distributeSeries && !options.stackBars) {
                    // If distributed series are enabled but stacked bars aren't, we need to use the length of the normaizedData array
                    // which is the series count and divide by 2
                    periodHalfLength = labelAxis.axisLength / data.normalized.series.length / 2;
                } else if (options.distributeSeries && options.stackBars) {
                    // If distributed series and stacked bars are enabled we'll only get one bar so we should just divide the axis
                    // length by 2
                    periodHalfLength = labelAxis.axisLength / 2;
                } else {
                    // On regular bar charts we should just use the series length
                    periodHalfLength = labelAxis.axisLength / data.normalized.series[seriesIndex].length / 2;
                }

                // Adding the series group to the series element
                seriesElement = seriesGroup.elem('g');

                // Write attributes to series group element. If series name or meta is undefined the attributes will not be written
                seriesElement.attr({
                    'ct:series-name': series.name,
                    'ct:meta': Chartist.serialize(series.meta)
                });

                // Use series class from series data or if not set generate one
                seriesElement.addClass([
                  options.classNames.series,
                  (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(seriesIndex))
                ].join(' '));

                data.normalized.series[seriesIndex].forEach(function (value, valueIndex) {
                    var projected,
                      bar,
                      previousStack,
                      labelAxisValueIndex;

                    // We need to set labelAxisValueIndex based on some options combinations
                    if (options.distributeSeries && !options.stackBars) {
                        // If distributed series are enabled but stacked bars aren't, we can use the seriesIndex for later projection
                        // on the step axis for label positioning
                        labelAxisValueIndex = seriesIndex;
                    } else if (options.distributeSeries && options.stackBars) {
                        // If distributed series and stacked bars are enabled, we will only get one bar and therefore always use
                        // 0 for projection on the label step axis
                        labelAxisValueIndex = 0;
                    } else {
                        // On regular bar charts we just use the value index to project on the label step axis
                        labelAxisValueIndex = valueIndex;
                    }

                    // We need to transform coordinates differently based on the chart layout
                    if (options.horizontalBars) {
                        projected = {
                            x: chartRect.x1 + valueAxis.projectValue(value && value.x ? value.x : 0, valueIndex, data.normalized.series[seriesIndex]),
                            y: chartRect.y1 - labelAxis.projectValue(value && value.y ? value.y : 0, labelAxisValueIndex, data.normalized.series[seriesIndex])
                        };
                    } else {
                        projected = {
                            x: chartRect.x1 + labelAxis.projectValue(value && value.x ? value.x : 0, labelAxisValueIndex, data.normalized.series[seriesIndex]),
                            y: chartRect.y1 - valueAxis.projectValue(value && value.y ? value.y : 0, valueIndex, data.normalized.series[seriesIndex])
                        }
                    }

                    // If the label axis is a step based axis we will offset the bar into the middle of between two steps using
                    // the periodHalfLength value. Also we do arrange the different series so that they align up to each other using
                    // the seriesBarDistance. If we don't have a step axis, the bar positions can be chosen freely so we should not
                    // add any automated positioning.
                    if (labelAxis instanceof Chartist.StepAxis) {
                        // Offset to center bar between grid lines, but only if the step axis is not stretched
                        if (!labelAxis.options.stretch) {
                            projected[labelAxis.units.pos] += periodHalfLength * (options.horizontalBars ? -1 : 1);
                        }
                        // Using bi-polar offset for multiple series if no stacked bars or series distribution is used
                        projected[labelAxis.units.pos] += (options.stackBars || options.distributeSeries) ? 0 : biPol * options.seriesBarDistance * (options.horizontalBars ? -1 : 1);
                    }

                    // Enter value in stacked bar values used to remember previous screen value for stacking up bars
                    previousStack = stackedBarValues[valueIndex] || zeroPoint;
                    stackedBarValues[valueIndex] = previousStack - (zeroPoint - projected[labelAxis.counterUnits.pos]);

                    // Skip if value is undefined
                    if (value === undefined) {
                        return;
                    }

                    var positions = {};
                    positions[labelAxis.units.pos + '1'] = projected[labelAxis.units.pos];
                    positions[labelAxis.units.pos + '2'] = projected[labelAxis.units.pos];

                    if (options.stackBars && (options.stackMode === 'accumulate' || !options.stackMode)) {
                        // Stack mode: accumulate (default)
                        // If bars are stacked we use the stackedBarValues reference and otherwise base all bars off the zero line
                        // We want backwards compatibility, so the expected fallback without the 'stackMode' option
                        // to be the original behaviour (accumulate)
                        positions[labelAxis.counterUnits.pos + '1'] = previousStack;
                        positions[labelAxis.counterUnits.pos + '2'] = stackedBarValues[valueIndex];
                    } else {
                        // Draw from the zero line normally
                        // This is also the same code for Stack mode: overlap
                        positions[labelAxis.counterUnits.pos + '1'] = zeroPoint;
                        positions[labelAxis.counterUnits.pos + '2'] = projected[labelAxis.counterUnits.pos];
                    }

                    // Limit x and y so that they are within the chart rect
                    positions.x1 = Math.min(Math.max(positions.x1, chartRect.x1), chartRect.x2);
                    positions.x2 = Math.min(Math.max(positions.x2, chartRect.x1), chartRect.x2);
                    positions.y1 = Math.min(Math.max(positions.y1, chartRect.y2), chartRect.y1);
                    positions.y2 = Math.min(Math.max(positions.y2, chartRect.y2), chartRect.y1);

                    var metaData = Chartist.getMetaData(series, valueIndex);

                    // Create bar element
                    bar = seriesElement.elem('line', positions, options.classNames.bar).attr({
                        'ct:value': [value.x, value.y].filter(Chartist.isNumeric).join(','),
                        'ct:meta': Chartist.serialize(metaData)
                    });

                    this.eventEmitter.emit('draw', Chartist.extend({
                        type: 'bar',
                        value: value,
                        index: valueIndex,
                        meta: metaData,
                        series: series,
                        seriesIndex: seriesIndex,
                        axisX: axisX,
                        axisY: axisY,
                        chartRect: chartRect,
                        group: seriesElement,
                        element: bar
                    }, positions));
                }.bind(this));
            }.bind(this));

            this.eventEmitter.emit('created', {
                bounds: valueAxis.bounds,
                chartRect: chartRect,
                axisX: axisX,
                axisY: axisY,
                svg: this.svg,
                options: options
            });
        }

        /**
         * This method creates a new bar chart and returns API object that you can use for later changes.
         *
         * @memberof Chartist.Bar
         * @param {String|Node} query A selector query string or directly a DOM element
         * @param {Object} data The data object that needs to consist of a labels and a series array
         * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.
         * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]
         * @return {Object} An object which exposes the API for the created chart
         *
         * @example
         * // Create a simple bar chart
         * var data = {
         *   labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
         *   series: [
         *     [5, 2, 4, 2, 0]
         *   ]
         * };
         *
         * // In the global name space Chartist we call the Bar function to initialize a bar chart. As a first parameter we pass in a selector where we would like to get our chart created and as a second parameter we pass our data object.
         * new Chartist.Bar('.ct-chart', data);
         *
         * @example
         * // This example creates a bipolar grouped bar chart where the boundaries are limitted to -10 and 10
         * new Chartist.Bar('.ct-chart', {
         *   labels: [1, 2, 3, 4, 5, 6, 7],
         *   series: [
         *     [1, 3, 2, -5, -3, 1, -6],
         *     [-5, -2, -4, -1, 2, -3, 1]
         *   ]
         * }, {
         *   seriesBarDistance: 12,
         *   low: -10,
         *   high: 10
         * });
         *
         */
        function Bar(query, data, options, responsiveOptions) {
            Chartist.Bar.super.constructor.call(this,
              query,
              data,
              defaultOptions,
              Chartist.extend({}, defaultOptions, options),
              responsiveOptions);
        }

        // Creating bar chart type in Chartist namespace
        Chartist.Bar = Chartist.Base.extend({
            constructor: Bar,
            createChart: createChart
        });

    }(window, document, Chartist));
    ;/**
 * The pie chart module of Chartist that can be used to draw pie, donut or gauge charts
 *
 * @module Chartist.Pie
 */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        /**
         * Default options in line charts. Expand the code view to see a detailed list of options with comments.
         *
         * @memberof Chartist.Pie
         */
        var defaultOptions = {
            // Specify a fixed width for the chart as a string (i.e. '100px' or '50%')
            width: undefined,
            // Specify a fixed height for the chart as a string (i.e. '100px' or '50%')
            height: undefined,
            // Padding of the chart drawing area to the container element and labels as a number or padding object {top: 5, right: 5, bottom: 5, left: 5}
            chartPadding: 5,
            // Override the class names that are used to generate the SVG structure of the chart
            classNames: {
                chartPie: 'ct-chart-pie',
                chartDonut: 'ct-chart-donut',
                series: 'ct-series',
                slicePie: 'ct-slice-pie',
                sliceDonut: 'ct-slice-donut',
                sliceDonutSolid: 'ct-slice-donut-solid',
                label: 'ct-label'
            },
            // The start angle of the pie chart in degrees where 0 points north. A higher value offsets the start angle clockwise.
            startAngle: 0,
            // An optional total you can specify. By specifying a total value, the sum of the values in the series must be this total in order to draw a full pie. You can use this parameter to draw only parts of a pie or gauge charts.
            total: undefined,
            // If specified the donut CSS classes will be used and strokes will be drawn instead of pie slices.
            donut: false,
            // If specified the donut segments will be drawn as shapes instead of strokes.
            donutSolid: false,
            // Specify the donut stroke width, currently done in javascript for convenience. May move to CSS styles in the future.
            // This option can be set as number or string to specify a relative width (i.e. 100 or '30%').
            donutWidth: 60,
            // If a label should be shown or not
            showLabel: true,
            // Label position offset from the standard position which is half distance of the radius. This value can be either positive or negative. Positive values will position the label away from the center.
            labelOffset: 0,
            // This option can be set to 'inside', 'outside' or 'center'. Positioned with 'inside' the labels will be placed on half the distance of the radius to the border of the Pie by respecting the 'labelOffset'. The 'outside' option will place the labels at the border of the pie and 'center' will place the labels in the absolute center point of the chart. The 'center' option only makes sense in conjunction with the 'labelOffset' option.
            labelPosition: 'inside',
            // An interpolation function for the label value
            labelInterpolationFnc: Chartist.noop,
            // Label direction can be 'neutral', 'explode' or 'implode'. The labels anchor will be positioned based on those settings as well as the fact if the labels are on the right or left side of the center of the chart. Usually explode is useful when labels are positioned far away from the center.
            labelDirection: 'neutral',
            // If true the whole data is reversed including labels, the series order as well as the whole series data arrays.
            reverseData: false,
            // If true empty values will be ignored to avoid drawing unncessary slices and labels
            ignoreEmptyValues: false
        };

        /**
         * Determines SVG anchor position based on direction and center parameter
         *
         * @param center
         * @param label
         * @param direction
         * @return {string}
         */
        function determineAnchorPosition(center, label, direction) {
            var toTheRight = label.x > center.x;

            if (toTheRight && direction === 'explode' ||
              !toTheRight && direction === 'implode') {
                return 'start';
            } else if (toTheRight && direction === 'implode' ||
              !toTheRight && direction === 'explode') {
                return 'end';
            } else {
                return 'middle';
            }
        }

        /**
         * Creates the pie chart
         *
         * @param options
         */
        function createChart(options) {
            var data = Chartist.normalizeData(this.data);
            var seriesGroups = [],
              labelsGroup,
              chartRect,
              radius,
              labelRadius,
              totalDataSum,
              startAngle = options.startAngle;

            // Create SVG.js draw
            this.svg = Chartist.createSvg(this.container, options.width, options.height, options.donut ? options.classNames.chartDonut : options.classNames.chartPie);
            // Calculate charting rect
            chartRect = Chartist.createChartRect(this.svg, options, defaultOptions.padding);
            // Get biggest circle radius possible within chartRect
            radius = Math.min(chartRect.width() / 2, chartRect.height() / 2);
            // Calculate total of all series to get reference value or use total reference from optional options
            totalDataSum = options.total || data.normalized.series.reduce(function (previousValue, currentValue) {
                return previousValue + currentValue;
            }, 0);

            var donutWidth = Chartist.quantity(options.donutWidth);
            if (donutWidth.unit === '%') {
                donutWidth.value *= radius / 100;
            }

            // If this is a donut chart we need to adjust our radius to enable strokes to be drawn inside
            // Unfortunately this is not possible with the current SVG Spec
            // See this proposal for more details: http://lists.w3.org/Archives/Public/www-svg/2003Oct/0000.html
            radius -= options.donut && !options.donutSolid ? donutWidth.value / 2 : 0;

            // If labelPosition is set to `outside` or a donut chart is drawn then the label position is at the radius,
            // if regular pie chart it's half of the radius
            if (options.labelPosition === 'outside' || options.donut && !options.donutSolid) {
                labelRadius = radius;
            } else if (options.labelPosition === 'center') {
                // If labelPosition is center we start with 0 and will later wait for the labelOffset
                labelRadius = 0;
            } else if (options.donutSolid) {
                labelRadius = radius - donutWidth.value / 2;
            } else {
                // Default option is 'inside' where we use half the radius so the label will be placed in the center of the pie
                // slice
                labelRadius = radius / 2;
            }
            // Add the offset to the labelRadius where a negative offset means closed to the center of the chart
            labelRadius += options.labelOffset;

            // Calculate end angle based on total sum and current data value and offset with padding
            var center = {
                x: chartRect.x1 + chartRect.width() / 2,
                y: chartRect.y2 + chartRect.height() / 2
            };

            // Check if there is only one non-zero value in the series array.
            var hasSingleValInSeries = data.raw.series.filter(function (val) {
                return val.hasOwnProperty('value') ? val.value !== 0 : val !== 0;
            }).length === 1;

            // Creating the series groups
            data.raw.series.forEach(function (series, index) {
                seriesGroups[index] = this.svg.elem('g', null, null);
            }.bind(this));
            //if we need to show labels we create the label group now
            if (options.showLabel) {
                labelsGroup = this.svg.elem('g', null, null);
            }

            // Draw the series
            // initialize series groups
            data.raw.series.forEach(function (series, index) {
                // If current value is zero and we are ignoring empty values then skip to next value
                if (data.normalized.series[index] === 0 && options.ignoreEmptyValues) return;

                // If the series is an object and contains a name or meta data we add a custom attribute
                seriesGroups[index].attr({
                    'ct:series-name': series.name
                });

                // Use series class from series data or if not set generate one
                seriesGroups[index].addClass([
                  options.classNames.series,
                  (series.className || options.classNames.series + '-' + Chartist.alphaNumerate(index))
                ].join(' '));

                // If the whole dataset is 0 endAngle should be zero. Can't divide by 0.
                var endAngle = (totalDataSum > 0 ? startAngle + data.normalized.series[index] / totalDataSum * 360 : 0);

                // Use slight offset so there are no transparent hairline issues
                var overlappigStartAngle = Math.max(0, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));

                // If we need to draw the arc for all 360 degrees we need to add a hack where we close the circle
                // with Z and use 359.99 degrees
                if (endAngle - overlappigStartAngle >= 359.99) {
                    endAngle = overlappigStartAngle + 359.99;
                }

                var start = Chartist.polarToCartesian(center.x, center.y, radius, overlappigStartAngle),
                  end = Chartist.polarToCartesian(center.x, center.y, radius, endAngle);

                var innerStart,
                  innerEnd,
                  donutSolidRadius;

                // Create a new path element for the pie chart. If this isn't a donut chart we should close the path for a correct stroke
                var path = new Chartist.Svg.Path(!options.donut || options.donutSolid)
                  .move(end.x, end.y)
                  .arc(radius, radius, 0, endAngle - startAngle > 180, 0, start.x, start.y);

                // If regular pie chart (no donut) we add a line to the center of the circle for completing the pie
                if (!options.donut) {
                    path.line(center.x, center.y);
                } else if (options.donutSolid) {
                    donutSolidRadius = radius - donutWidth.value;
                    innerStart = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, startAngle - (index === 0 || hasSingleValInSeries ? 0 : 0.2));
                    innerEnd = Chartist.polarToCartesian(center.x, center.y, donutSolidRadius, endAngle);
                    path.line(innerStart.x, innerStart.y);
                    path.arc(donutSolidRadius, donutSolidRadius, 0, endAngle - startAngle > 180, 1, innerEnd.x, innerEnd.y);
                }

                // Create the SVG path
                // If this is a donut chart we add the donut class, otherwise just a regular slice
                var pathClassName = options.classNames.slicePie;
                if (options.donut) {
                    pathClassName = options.classNames.sliceDonut;
                    if (options.donutSolid) {
                        pathClassName = options.classNames.sliceDonutSolid;
                    }
                }
                var pathElement = seriesGroups[index].elem('path', {
                    d: path.stringify()
                }, pathClassName);

                // Adding the pie series value to the path
                pathElement.attr({
                    'ct:value': data.normalized.series[index],
                    'ct:meta': Chartist.serialize(series.meta)
                });

                // If this is a donut, we add the stroke-width as style attribute
                if (options.donut && !options.donutSolid) {
                    pathElement._node.style.strokeWidth = donutWidth.value + 'px';
                }

                // Fire off draw event
                this.eventEmitter.emit('draw', {
                    type: 'slice',
                    value: data.normalized.series[index],
                    totalDataSum: totalDataSum,
                    index: index,
                    meta: series.meta,
                    series: series,
                    group: seriesGroups[index],
                    element: pathElement,
                    path: path.clone(),
                    center: center,
                    radius: radius,
                    startAngle: startAngle,
                    endAngle: endAngle
                });

                // If we need to show labels we need to add the label for this slice now
                if (options.showLabel) {
                    var labelPosition;
                    if (data.raw.series.length === 1) {
                        // If we have only 1 series, we can position the label in the center of the pie
                        labelPosition = {
                            x: center.x,
                            y: center.y
                        };
                    } else {
                        // Position at the labelRadius distance from center and between start and end angle
                        labelPosition = Chartist.polarToCartesian(
                          center.x,
                          center.y,
                          labelRadius,
                          startAngle + (endAngle - startAngle) / 2
                        );
                    }

                    var rawValue;
                    if (data.normalized.labels && !Chartist.isFalseyButZero(data.normalized.labels[index])) {
                        rawValue = data.normalized.labels[index];
                    } else {
                        rawValue = data.normalized.series[index];
                    }

                    var interpolatedValue = options.labelInterpolationFnc(rawValue, index);

                    if (interpolatedValue || interpolatedValue === 0) {
                        var labelElement = labelsGroup.elem('text', {
                            dx: labelPosition.x,
                            dy: labelPosition.y,
                            'text-anchor': determineAnchorPosition(center, labelPosition, options.labelDirection)
                        }, options.classNames.label).text('' + interpolatedValue);

                        // Fire off draw event
                        this.eventEmitter.emit('draw', {
                            type: 'label',
                            index: index,
                            group: labelsGroup,
                            element: labelElement,
                            text: '' + interpolatedValue,
                            x: labelPosition.x,
                            y: labelPosition.y
                        });
                    }
                }

                // Set next startAngle to current endAngle.
                // (except for last slice)
                startAngle = endAngle;
            }.bind(this));

            this.eventEmitter.emit('created', {
                chartRect: chartRect,
                svg: this.svg,
                options: options
            });
        }

        /**
         * This method creates a new pie chart and returns an object that can be used to redraw the chart.
         *
         * @memberof Chartist.Pie
         * @param {String|Node} query A selector query string or directly a DOM element
         * @param {Object} data The data object in the pie chart needs to have a series property with a one dimensional data array. The values will be normalized against each other and don't necessarily need to be in percentage. The series property can also be an array of value objects that contain a value property and a className property to override the CSS class name for the series group.
         * @param {Object} [options] The options object with options that override the default options. Check the examples for a detailed list.
         * @param {Array} [responsiveOptions] Specify an array of responsive option arrays which are a media query and options object pair => [[mediaQueryString, optionsObject],[more...]]
         * @return {Object} An object with a version and an update method to manually redraw the chart
         *
         * @example
         * // Simple pie chart example with four series
         * new Chartist.Pie('.ct-chart', {
         *   series: [10, 2, 4, 3]
         * });
         *
         * @example
         * // Drawing a donut chart
         * new Chartist.Pie('.ct-chart', {
         *   series: [10, 2, 4, 3]
         * }, {
         *   donut: true
         * });
         *
         * @example
         * // Using donut, startAngle and total to draw a gauge chart
         * new Chartist.Pie('.ct-chart', {
         *   series: [20, 10, 30, 40]
         * }, {
         *   donut: true,
         *   donutWidth: 20,
         *   startAngle: 270,
         *   total: 200
         * });
         *
         * @example
         * // Drawing a pie chart with padding and labels that are outside the pie
         * new Chartist.Pie('.ct-chart', {
         *   series: [20, 10, 30, 40]
         * }, {
         *   chartPadding: 30,
         *   labelOffset: 50,
         *   labelDirection: 'explode'
         * });
         *
         * @example
         * // Overriding the class names for individual series as well as a name and meta data.
         * // The name will be written as ct:series-name attribute and the meta data will be serialized and written
         * // to a ct:meta attribute.
         * new Chartist.Pie('.ct-chart', {
         *   series: [{
         *     value: 20,
         *     name: 'Series 1',
         *     className: 'my-custom-class-one',
         *     meta: 'Meta One'
         *   }, {
         *     value: 10,
         *     name: 'Series 2',
         *     className: 'my-custom-class-two',
         *     meta: 'Meta Two'
         *   }, {
         *     value: 70,
         *     name: 'Series 3',
         *     className: 'my-custom-class-three',
         *     meta: 'Meta Three'
         *   }]
         * });
         */
        function Pie(query, data, options, responsiveOptions) {
            Chartist.Pie.super.constructor.call(this,
              query,
              data,
              defaultOptions,
              Chartist.extend({}, defaultOptions, options),
              responsiveOptions);
        }

        // Creating pie chart type in Chartist namespace
        Chartist.Pie = Chartist.Base.extend({
            constructor: Pie,
            createChart: createChart,
            determineAnchorPosition: determineAnchorPosition
        });

    }(window, document, Chartist));

    return Chartist;

}));

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(["chartist"], function (Chartist) {
            return (root.returnExportsGlobal = factory(Chartist));
        });
    } else if (typeof exports === 'object') {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like enviroments that support module.exports,
        // like Node.
        module.exports = factory(require("chartist"));
    } else {
        root['Chartist.plugins.tooltips'] = factory(Chartist);
    }
}(this, function (Chartist) {

    /**
     * Chartist.js plugin to display a data label on top of the points in a line chart.
     *
     */
    /* global Chartist */
    (function (window, document, Chartist) {
        'use strict';

        var defaultOptions = {
            currency: undefined,
            currencyFormatCallback: undefined,
            tooltipOffset: {
                x: 0,
                y: -20
            },
            anchorToPoint: false,
            appendToBody: false,
            class: undefined,
            pointClass: 'ct-point'
        };

        Chartist.plugins = Chartist.plugins || {};
        Chartist.plugins.tooltip = function (options) {
            options = Chartist.extend({}, defaultOptions, options);

            return function tooltip(chart) {
                var tooltipSelector = options.pointClass;
                if (chart instanceof Chartist.Bar) {
                    tooltipSelector = 'ct-bar';
                } else if (chart instanceof Chartist.Pie) {
                    // Added support for donut graph
                    if (chart.options.donut) {
                        tooltipSelector = 'ct-slice-donut';
                    } else {
                        tooltipSelector = 'ct-slice-pie';
                    }
                }

                var $chart = chart.container;
                var $toolTip = $chart.querySelector('.chartist-tooltip');
                if (!$toolTip) {
                    $toolTip = document.createElement('div');
                    $toolTip.className = (!options.class) ? 'chartist-tooltip' : 'chartist-tooltip ' + options.class;
                    if (!options.appendToBody) {
                        $chart.appendChild($toolTip);
                    } else {
                        document.body.appendChild($toolTip);
                    }
                }
                var height = $toolTip.offsetHeight;
                var width = $toolTip.offsetWidth;

                hide($toolTip);

                function on(event, selector, callback) {
                    $chart.addEventListener(event, function (e) {
                        if (!selector || hasClass(e.target, selector))
                            callback(e);
                    });
                }

                on('mouseover', tooltipSelector, function (event) {
                    var $point = event.target;
                    var tooltipText = '';

                    var isPieChart = (chart instanceof Chartist.Pie) ? $point : $point.parentNode;
                    var seriesName = (isPieChart) ? $point.parentNode.getAttribute('ct:meta') || $point.parentNode.getAttribute('ct:series-name') : '';
                    var meta = $point.getAttribute('ct:meta') || seriesName || '';
                    var hasMeta = !!meta;
                    var value = $point.getAttribute('ct:value');

                    if (options.transformTooltipTextFnc && typeof options.transformTooltipTextFnc === 'function') {
                        value = options.transformTooltipTextFnc(value);
                    }

                    if (options.tooltipFnc && typeof options.tooltipFnc === 'function') {
                        tooltipText = options.tooltipFnc(meta, value, event.target);
                    } else {
                        if (options.metaIsHTML) {
                            var txt = document.createElement('textarea');
                            txt.innerHTML = meta;
                            meta = txt.value;
                        }

                        meta = '<span class="chartist-tooltip-meta">' + meta + '</span>';

                        if (hasMeta) {
                            tooltipText += meta + '<br>';
                        } else {
                            // For Pie Charts also take the labels into account
                            // Could add support for more charts here as well!
                            if (chart instanceof Chartist.Pie) {
                                var label = next($point, 'ct-label');
                                if (label) {
                                    tooltipText += text(label) + '<br>';
                                }
                            }
                        }

                        if (value) {
                            if (options.currency) {
                                if (options.currencyFormatCallback != undefined) {
                                    value = options.currencyFormatCallback(value, options);
                                } else {
                                    value = options.currency + value.replace(/(\d)(?=(\d{3})+(?:\.\d+)?$)/g, '$1,');
                                }
                            }
                            value = '<span class="chartist-tooltip-value">' + value + '</span>';
                            tooltipText += value;
                        }
                    }

                    if (tooltipText) {
                        $toolTip.innerHTML = tooltipText;
                        setPosition(event);
                        show($toolTip);

                        // Remember height and width to avoid wrong position in IE
                        height = $toolTip.offsetHeight;
                        width = $toolTip.offsetWidth;
                    }
                });

                on('mouseout', tooltipSelector, function () {
                    hide($toolTip);
                });

                on('mousemove', null, function (event) {
                    if (false === options.anchorToPoint)
                        setPosition(event);
                });

                function setPosition(event) {
                    height = height || $toolTip.offsetHeight;
                    width = width || $toolTip.offsetWidth;
                    var offsetX = -width / 2 + options.tooltipOffset.x
                    var offsetY = -height + options.tooltipOffset.y;
                    var anchorX, anchorY;

                    if (!options.appendToBody) {
                        var box = $chart.getBoundingClientRect();
                        var left = event.pageX - box.left - window.pageXOffset;
                        var top = event.pageY - box.top - window.pageYOffset;

                        if (true === options.anchorToPoint && event.target.x2 && event.target.y2) {
                            anchorX = parseInt(event.target.x2.baseVal.value);
                            anchorY = parseInt(event.target.y2.baseVal.value);
                        }

                        $toolTip.style.top = (anchorY || top) + offsetY + 'px';
                        $toolTip.style.left = (anchorX || left) + offsetX + 'px';
                    } else {
                        $toolTip.style.top = event.pageY + offsetY + 'px';
                        $toolTip.style.left = event.pageX + offsetX + 'px';
                    }
                }
            }
        };

        function show(element) {
            if (!hasClass(element, 'tooltip-show')) {
                element.className = element.className + ' tooltip-show';
            }
        }

        function hide(element) {
            var regex = new RegExp('tooltip-show' + '\\s*', 'gi');
            element.className = element.className.replace(regex, '').trim();
        }

        function hasClass(element, className) {
            return (' ' + element.getAttribute('class') + ' ').indexOf(' ' + className + ' ') > -1;
        }

        function next(element, className) {
            do {
                element = element.nextSibling;
            } while (element && !hasClass(element, className));
            return element;
        }

        function text(element) {
            return element.innerText || element.textContent;
        }

    }(window, document, Chartist));

    return Chartist.plugins.tooltips;

}));
/*!
 * Cropper v2.3.4
 * https://github.com/fengyuanchen/cropper
 *
 * Copyright (c) 2014-2016 Fengyuan Chen and contributors
 * Released under the MIT license
 *
 * Date: 2016-09-03T05:50:45.412Z
 */

(function (factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node / CommonJS
    factory(require('jquery'));
  } else {
    // Browser globals.
    factory(jQuery);
  }
})(function ($) {

  'use strict';

  // Globals
  var $window = $(window);
  var $document = $(document);
  var location = window.location;
  var navigator = window.navigator;
  var ArrayBuffer = window.ArrayBuffer;
  var Uint8Array = window.Uint8Array;
  var DataView = window.DataView;
  var btoa = window.btoa;

  // Constants
  var NAMESPACE = 'cropper';

  // Classes
  var CLASS_MODAL = 'cropper-modal';
  var CLASS_HIDE = 'cropper-hide';
  var CLASS_HIDDEN = 'cropper-hidden';
  var CLASS_INVISIBLE = 'cropper-invisible';
  var CLASS_MOVE = 'cropper-move';
  var CLASS_CROP = 'cropper-crop';
  var CLASS_DISABLED = 'cropper-disabled';
  var CLASS_BG = 'cropper-bg';

  // Events
  var EVENT_MOUSE_DOWN = 'mousedown touchstart pointerdown MSPointerDown';
  var EVENT_MOUSE_MOVE = 'mousemove touchmove pointermove MSPointerMove';
  var EVENT_MOUSE_UP = 'mouseup touchend touchcancel pointerup pointercancel MSPointerUp MSPointerCancel';
  var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll';
  var EVENT_DBLCLICK = 'dblclick';
  var EVENT_LOAD = 'load.' + NAMESPACE;
  var EVENT_ERROR = 'error.' + NAMESPACE;
  var EVENT_RESIZE = 'resize.' + NAMESPACE; // Bind to window with namespace
  var EVENT_BUILD = 'build.' + NAMESPACE;
  var EVENT_BUILT = 'built.' + NAMESPACE;
  var EVENT_CROP_START = 'cropstart.' + NAMESPACE;
  var EVENT_CROP_MOVE = 'cropmove.' + NAMESPACE;
  var EVENT_CROP_END = 'cropend.' + NAMESPACE;
  var EVENT_CROP = 'crop.' + NAMESPACE;
  var EVENT_ZOOM = 'zoom.' + NAMESPACE;

  // RegExps
  var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/;
  var REGEXP_DATA_URL = /^data:/;
  var REGEXP_DATA_URL_HEAD = /^data:([^;]+);base64,/;
  var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg.*;base64,/;

  // Data keys
  var DATA_PREVIEW = 'preview';
  var DATA_ACTION = 'action';

  // Actions
  var ACTION_EAST = 'e';
  var ACTION_WEST = 'w';
  var ACTION_SOUTH = 's';
  var ACTION_NORTH = 'n';
  var ACTION_SOUTH_EAST = 'se';
  var ACTION_SOUTH_WEST = 'sw';
  var ACTION_NORTH_EAST = 'ne';
  var ACTION_NORTH_WEST = 'nw';
  var ACTION_ALL = 'all';
  var ACTION_CROP = 'crop';
  var ACTION_MOVE = 'move';
  var ACTION_ZOOM = 'zoom';
  var ACTION_NONE = 'none';

  // Supports
  var SUPPORT_CANVAS = $.isFunction($('<canvas>')[0].getContext);
  var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);

  // Maths
  var num = Number;
  var min = Math.min;
  var max = Math.max;
  var abs = Math.abs;
  var sin = Math.sin;
  var cos = Math.cos;
  var sqrt = Math.sqrt;
  var round = Math.round;
  var floor = Math.floor;

  // Utilities
  var fromCharCode = String.fromCharCode;

  function isNumber(n) {
    return typeof n === 'number' && !isNaN(n);
  }

  function isUndefined(n) {
    return typeof n === 'undefined';
  }

  function toArray(obj, offset) {
    var args = [];

    // This is necessary for IE8
    if (isNumber(offset)) {
      args.push(offset);
    }

    return args.slice.apply(obj, args);
  }

  // Custom proxy to avoid jQuery's guid
  function proxy(fn, context) {
    var args = toArray(arguments, 2);

    return function () {
      return fn.apply(context, args.concat(toArray(arguments)));
    };
  }

  function isCrossOriginURL(url) {
    var parts = url.match(/^(https?:)\/\/([^\:\/\?#]+):?(\d*)/i);

    return parts && (
      parts[1] !== location.protocol ||
      parts[2] !== location.hostname ||
      parts[3] !== location.port
    );
  }

  function addTimestamp(url) {
    var timestamp = 'timestamp=' + (new Date()).getTime();

    return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
  }

  function getCrossOrigin(crossOrigin) {
    return crossOrigin ? ' crossOrigin="' + crossOrigin + '"' : '';
  }

  function getImageSize(image, callback) {
    var newImage;

    // Modern browsers (ignore Safari, #120 & #509)
    if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) {
      return callback(image.naturalWidth, image.naturalHeight);
    }

    // IE8: Don't use `new Image()` here (#319)
    newImage = document.createElement('img');

    newImage.onload = function () {
      callback(this.width, this.height);
    };

    newImage.src = image.src;
  }

  function getTransform(options) {
    var transforms = [];
    var rotate = options.rotate;
    var scaleX = options.scaleX;
    var scaleY = options.scaleY;

    // Rotate should come first before scale to match orientation transform
    if (isNumber(rotate) && rotate !== 0) {
      transforms.push('rotate(' + rotate + 'deg)');
    }

    if (isNumber(scaleX) && scaleX !== 1) {
      transforms.push('scaleX(' + scaleX + ')');
    }

    if (isNumber(scaleY) && scaleY !== 1) {
      transforms.push('scaleY(' + scaleY + ')');
    }

    return transforms.length ? transforms.join(' ') : 'none';
  }

  function getRotatedSizes(data, isReversed) {
    var deg = abs(data.degree) % 180;
    var arc = (deg > 90 ? (180 - deg) : deg) * Math.PI / 180;
    var sinArc = sin(arc);
    var cosArc = cos(arc);
    var width = data.width;
    var height = data.height;
    var aspectRatio = data.aspectRatio;
    var newWidth;
    var newHeight;

    if (!isReversed) {
      newWidth = width * cosArc + height * sinArc;
      newHeight = width * sinArc + height * cosArc;
    } else {
      newWidth = width / (cosArc + sinArc / aspectRatio);
      newHeight = newWidth / aspectRatio;
    }

    return {
      width: newWidth,
      height: newHeight
    };
  }

  function getSourceCanvas(image, data) {
    var canvas = $('<canvas>')[0];
    var context = canvas.getContext('2d');
    var dstX = 0;
    var dstY = 0;
    var dstWidth = data.naturalWidth;
    var dstHeight = data.naturalHeight;
    var rotate = data.rotate;
    var scaleX = data.scaleX;
    var scaleY = data.scaleY;
    var scalable = isNumber(scaleX) && isNumber(scaleY) && (scaleX !== 1 || scaleY !== 1);
    var rotatable = isNumber(rotate) && rotate !== 0;
    var advanced = rotatable || scalable;
    var canvasWidth = dstWidth * abs(scaleX || 1);
    var canvasHeight = dstHeight * abs(scaleY || 1);
    var translateX;
    var translateY;
    var rotated;

    if (scalable) {
      translateX = canvasWidth / 2;
      translateY = canvasHeight / 2;
    }

    if (rotatable) {
      rotated = getRotatedSizes({
        width: canvasWidth,
        height: canvasHeight,
        degree: rotate
      });

      canvasWidth = rotated.width;
      canvasHeight = rotated.height;
      translateX = canvasWidth / 2;
      translateY = canvasHeight / 2;
    }

    canvas.width = canvasWidth;
    canvas.height = canvasHeight;

    if (advanced) {
      dstX = -dstWidth / 2;
      dstY = -dstHeight / 2;

      context.save();
      context.translate(translateX, translateY);
    }

    // Rotate should come first before scale as in the "getTransform" function
    if (rotatable) {
      context.rotate(rotate * Math.PI / 180);
    }

    if (scalable) {
      context.scale(scaleX, scaleY);
    }

    context.drawImage(image, floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));

    if (advanced) {
      context.restore();
    }

    return canvas;
  }

  function getTouchesCenter(touches) {
    var length = touches.length;
    var pageX = 0;
    var pageY = 0;

    if (length) {
      $.each(touches, function (i, touch) {
        pageX += touch.pageX;
        pageY += touch.pageY;
      });

      pageX /= length;
      pageY /= length;
    }

    return {
      pageX: pageX,
      pageY: pageY
    };
  }

  function getStringFromCharCode(dataView, start, length) {
    var str = '';
    var i;

    for (i = start, length += start; i < length; i++) {
      str += fromCharCode(dataView.getUint8(i));
    }

    return str;
  }

  function getOrientation(arrayBuffer) {
    var dataView = new DataView(arrayBuffer);
    var length = dataView.byteLength;
    var orientation;
    var exifIDCode;
    var tiffOffset;
    var firstIFDOffset;
    var littleEndian;
    var endianness;
    var app1Start;
    var ifdStart;
    var offset;
    var i;

    // Only handle JPEG image (start by 0xFFD8)
    if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
      offset = 2;

      while (offset < length) {
        if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
          app1Start = offset;
          break;
        }

        offset++;
      }
    }

    if (app1Start) {
      exifIDCode = app1Start + 4;
      tiffOffset = app1Start + 10;

      if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
        endianness = dataView.getUint16(tiffOffset);
        littleEndian = endianness === 0x4949;

        if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
          if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
            firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);

            if (firstIFDOffset >= 0x00000008) {
              ifdStart = tiffOffset + firstIFDOffset;
            }
          }
        }
      }
    }

    if (ifdStart) {
      length = dataView.getUint16(ifdStart, littleEndian);

      for (i = 0; i < length; i++) {
        offset = ifdStart + i * 12 + 2;

        if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {

          // 8 is the offset of the current tag's value
          offset += 8;

          // Get the original orientation value
          orientation = dataView.getUint16(offset, littleEndian);

          // Override the orientation with its default value for Safari (#120)
          if (IS_SAFARI_OR_UIWEBVIEW) {
            dataView.setUint16(offset, 1, littleEndian);
          }

          break;
        }
      }
    }

    return orientation;
  }

  function dataURLToArrayBuffer(dataURL) {
    var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, '');
    var binary = atob(base64);
    var length = binary.length;
    var arrayBuffer = new ArrayBuffer(length);
    var dataView = new Uint8Array(arrayBuffer);
    var i;

    for (i = 0; i < length; i++) {
      dataView[i] = binary.charCodeAt(i);
    }

    return arrayBuffer;
  }

  // Only available for JPEG image
  function arrayBufferToDataURL(arrayBuffer) {
    var dataView = new Uint8Array(arrayBuffer);
    var length = dataView.length;
    var base64 = '';
    var i;

    for (i = 0; i < length; i++) {
      base64 += fromCharCode(dataView[i]);
    }

    return 'data:image/jpeg;base64,' + btoa(base64);
  }

  function Cropper(element, options) {
    this.$element = $(element);
    this.options = $.extend({}, Cropper.DEFAULTS, $.isPlainObject(options) && options);
    this.isLoaded = false;
    this.isBuilt = false;
    this.isCompleted = false;
    this.isRotated = false;
    this.isCropped = false;
    this.isDisabled = false;
    this.isReplaced = false;
    this.isLimited = false;
    this.wheeling = false;
    this.isImg = false;
    this.originalUrl = '';
    this.canvas = null;
    this.cropBox = null;
    this.init();
  }

  Cropper.prototype = {
    constructor: Cropper,

    init: function () {
      var $this = this.$element;
      var url;

      if ($this.is('img')) {
        this.isImg = true;

        // Should use `$.fn.attr` here. e.g.: "img/picture.jpg"
        this.originalUrl = url = $this.attr('src');

        // Stop when it's a blank image
        if (!url) {
          return;
        }

        // Should use `$.fn.prop` here. e.g.: "http://example.com/img/picture.jpg"
        url = $this.prop('src');
      } else if ($this.is('canvas') && SUPPORT_CANVAS) {
        url = $this[0].toDataURL();
      }

      this.load(url);
    },

    // A shortcut for triggering custom events
    trigger: function (type, data) {
      var e = $.Event(type, data);

      this.$element.trigger(e);

      return e;
    },

    load: function (url) {
      var options = this.options;
      var $this = this.$element;
      var read;
      var xhr;

      if (!url) {
        return;
      }

      // Trigger build event first
      $this.one(EVENT_BUILD, options.build);

      if (this.trigger(EVENT_BUILD).isDefaultPrevented()) {
        return;
      }

      this.url = url;
      this.image = {};

      if (!options.checkOrientation || !ArrayBuffer) {
        return this.clone();
      }

      read = $.proxy(this.read, this);

      // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari
      if (REGEXP_DATA_URL.test(url)) {
        return REGEXP_DATA_URL_JPEG.test(url) ?
          read(dataURLToArrayBuffer(url)) :
          this.clone();
      }

      xhr = new XMLHttpRequest();

      xhr.onerror = xhr.onabort = $.proxy(function () {
        this.clone();
      }, this);

      xhr.onload = function () {
        read(this.response);
      };

      if (options.checkCrossOrigin && isCrossOriginURL(url) && $this.prop('crossOrigin')) {
        url = addTimestamp(url);
      }

      xhr.open('get', url);
      xhr.responseType = 'arraybuffer';
      xhr.send();
    },

    read: function (arrayBuffer) {
      var options = this.options;
      var orientation = getOrientation(arrayBuffer);
      var image = this.image;
      var rotate = 0;
      var scaleX = 1;
      var scaleY = 1;

      if (orientation > 1) {
        this.url = arrayBufferToDataURL(arrayBuffer);

        switch (orientation) {

          // flip horizontal
          case 2:
            scaleX = -1;
            break;

          // rotate left 180°
          case 3:
            rotate = -180;
            break;

          // flip vertical
          case 4:
            scaleY = -1;
            break;

          // flip vertical + rotate right 90°
          case 5:
            rotate = 90;
            scaleY = -1;
            break;

          // rotate right 90°
          case 6:
            rotate = 90;
            break;

          // flip horizontal + rotate right 90°
          case 7:
            rotate = 90;
            scaleX = -1;
            break;

          // rotate left 90°
          case 8:
            rotate = -90;
            break;
        }
      }

      if (options.rotatable) {
        image.rotate = rotate;
      }

      if (options.scalable) {
        image.scaleX = scaleX;
        image.scaleY = scaleY;
      }

      this.clone();
    },

    clone: function () {
      var options = this.options;
      var $this = this.$element;
      var url = this.url;
      var crossOrigin = '';
      var crossOriginUrl;
      var $clone;

      if (options.checkCrossOrigin && isCrossOriginURL(url)) {
        crossOrigin = $this.prop('crossOrigin');

        if (crossOrigin) {
          crossOriginUrl = url;
        } else {
          crossOrigin = 'anonymous';

          // Bust cache (#148) when there is not a "crossOrigin" property
          crossOriginUrl = addTimestamp(url);
        }
      }

      this.crossOrigin = crossOrigin;
      this.crossOriginUrl = crossOriginUrl;
      this.$clone = $clone = $('<img' + getCrossOrigin(crossOrigin) + ' src="' + (crossOriginUrl || url) + '">');

      if (this.isImg) {
        if ($this[0].complete) {
          this.start();
        } else {
          $this.one(EVENT_LOAD, $.proxy(this.start, this));
        }
      } else {
        $clone.
          one(EVENT_LOAD, $.proxy(this.start, this)).
          one(EVENT_ERROR, $.proxy(this.stop, this)).
          addClass(CLASS_HIDE).
          insertAfter($this);
      }
    },

    start: function () {
      var $image = this.$element;
      var $clone = this.$clone;

      if (!this.isImg) {
        $clone.off(EVENT_ERROR, this.stop);
        $image = $clone;
      }

      getImageSize($image[0], $.proxy(function (naturalWidth, naturalHeight) {
        $.extend(this.image, {
          naturalWidth: naturalWidth,
          naturalHeight: naturalHeight,
          aspectRatio: naturalWidth / naturalHeight
        });

        this.isLoaded = true;
        this.build();
      }, this));
    },

    stop: function () {
      this.$clone.remove();
      this.$clone = null;
    },

    build: function () {
      var options = this.options;
      var $this = this.$element;
      var $clone = this.$clone;
      var $cropper;
      var $cropBox;
      var $face;

      if (!this.isLoaded) {
        return;
      }

      // Unbuild first when replace
      if (this.isBuilt) {
        this.unbuild();
      }

      // Create cropper elements
      this.$container = $this.parent();
      this.$cropper = $cropper = $(Cropper.TEMPLATE);
      this.$canvas = $cropper.find('.cropper-canvas').append($clone);
      this.$dragBox = $cropper.find('.cropper-drag-box');
      this.$cropBox = $cropBox = $cropper.find('.cropper-crop-box');
      this.$viewBox = $cropper.find('.cropper-view-box');
      this.$face = $face = $cropBox.find('.cropper-face');

      // Hide the original image
      $this.addClass(CLASS_HIDDEN).after($cropper);

      // Show the clone image if is hidden
      if (!this.isImg) {
        $clone.removeClass(CLASS_HIDE);
      }

      this.initPreview();
      this.bind();

      options.aspectRatio = max(0, options.aspectRatio) || NaN;
      options.viewMode = max(0, min(3, round(options.viewMode))) || 0;

      if (options.autoCrop) {
        this.isCropped = true;

        if (options.modal) {
          this.$dragBox.addClass(CLASS_MODAL);
        }
      } else {
        $cropBox.addClass(CLASS_HIDDEN);
      }

      if (!options.guides) {
        $cropBox.find('.cropper-dashed').addClass(CLASS_HIDDEN);
      }

      if (!options.center) {
        $cropBox.find('.cropper-center').addClass(CLASS_HIDDEN);
      }

      if (options.cropBoxMovable) {
        $face.addClass(CLASS_MOVE).data(DATA_ACTION, ACTION_ALL);
      }

      if (!options.highlight) {
        $face.addClass(CLASS_INVISIBLE);
      }

      if (options.background) {
        $cropper.addClass(CLASS_BG);
      }

      if (!options.cropBoxResizable) {
        $cropBox.find('.cropper-line, .cropper-point').addClass(CLASS_HIDDEN);
      }

      this.setDragMode(options.dragMode);
      this.render();
      this.isBuilt = true;
      this.setData(options.data);
      $this.one(EVENT_BUILT, options.built);

      // Trigger the built event asynchronously to keep `data('cropper')` is defined
      this.completing = setTimeout($.proxy(function () {
        this.trigger(EVENT_BUILT);
        this.trigger(EVENT_CROP, this.getData());
        this.isCompleted = true;
      }, this), 0);
    },

    unbuild: function () {
      if (!this.isBuilt) {
        return;
      }

      if (!this.isCompleted) {
        clearTimeout(this.completing);
      }

      this.isBuilt = false;
      this.isCompleted = false;
      this.initialImage = null;

      // Clear `initialCanvas` is necessary when replace
      this.initialCanvas = null;
      this.initialCropBox = null;
      this.container = null;
      this.canvas = null;

      // Clear `cropBox` is necessary when replace
      this.cropBox = null;
      this.unbind();

      this.resetPreview();
      this.$preview = null;

      this.$viewBox = null;
      this.$cropBox = null;
      this.$dragBox = null;
      this.$canvas = null;
      this.$container = null;

      this.$cropper.remove();
      this.$cropper = null;
    },

    render: function () {
      this.initContainer();
      this.initCanvas();
      this.initCropBox();

      this.renderCanvas();

      if (this.isCropped) {
        this.renderCropBox();
      }
    },

    initContainer: function () {
      var options = this.options;
      var $this = this.$element;
      var $container = this.$container;
      var $cropper = this.$cropper;

      $cropper.addClass(CLASS_HIDDEN);
      $this.removeClass(CLASS_HIDDEN);

      $cropper.css((this.container = {
        width: max($container.width(), num(options.minContainerWidth) || 200),
        height: max($container.height(), num(options.minContainerHeight) || 100)
      }));

      $this.addClass(CLASS_HIDDEN);
      $cropper.removeClass(CLASS_HIDDEN);
    },

    // Canvas (image wrapper)
    initCanvas: function () {
      var viewMode = this.options.viewMode;
      var container = this.container;
      var containerWidth = container.width;
      var containerHeight = container.height;
      var image = this.image;
      var imageNaturalWidth = image.naturalWidth;
      var imageNaturalHeight = image.naturalHeight;
      var is90Degree = abs(image.rotate) === 90;
      var naturalWidth = is90Degree ? imageNaturalHeight : imageNaturalWidth;
      var naturalHeight = is90Degree ? imageNaturalWidth : imageNaturalHeight;
      var aspectRatio = naturalWidth / naturalHeight;
      var canvasWidth = containerWidth;
      var canvasHeight = containerHeight;
      var canvas;

      if (containerHeight * aspectRatio > containerWidth) {
        if (viewMode === 3) {
          canvasWidth = containerHeight * aspectRatio;
        } else {
          canvasHeight = containerWidth / aspectRatio;
        }
      } else {
        if (viewMode === 3) {
          canvasHeight = containerWidth / aspectRatio;
        } else {
          canvasWidth = containerHeight * aspectRatio;
        }
      }

      canvas = {
        naturalWidth: naturalWidth,
        naturalHeight: naturalHeight,
        aspectRatio: aspectRatio,
        width: canvasWidth,
        height: canvasHeight
      };

      canvas.oldLeft = canvas.left = (containerWidth - canvasWidth) / 2;
      canvas.oldTop = canvas.top = (containerHeight - canvasHeight) / 2;

      this.canvas = canvas;
      this.isLimited = (viewMode === 1 || viewMode === 2);
      this.limitCanvas(true, true);
      this.initialImage = $.extend({}, image);
      this.initialCanvas = $.extend({}, canvas);
    },

    limitCanvas: function (isSizeLimited, isPositionLimited) {
      var options = this.options;
      var viewMode = options.viewMode;
      var container = this.container;
      var containerWidth = container.width;
      var containerHeight = container.height;
      var canvas = this.canvas;
      var aspectRatio = canvas.aspectRatio;
      var cropBox = this.cropBox;
      var isCropped = this.isCropped && cropBox;
      var minCanvasWidth;
      var minCanvasHeight;
      var newCanvasLeft;
      var newCanvasTop;

      if (isSizeLimited) {
        minCanvasWidth = num(options.minCanvasWidth) || 0;
        minCanvasHeight = num(options.minCanvasHeight) || 0;

        if (viewMode) {
          if (viewMode > 1) {
            minCanvasWidth = max(minCanvasWidth, containerWidth);
            minCanvasHeight = max(minCanvasHeight, containerHeight);

            if (viewMode === 3) {
              if (minCanvasHeight * aspectRatio > minCanvasWidth) {
                minCanvasWidth = minCanvasHeight * aspectRatio;
              } else {
                minCanvasHeight = minCanvasWidth / aspectRatio;
              }
            }
          } else {
            if (minCanvasWidth) {
              minCanvasWidth = max(minCanvasWidth, isCropped ? cropBox.width : 0);
            } else if (minCanvasHeight) {
              minCanvasHeight = max(minCanvasHeight, isCropped ? cropBox.height : 0);
            } else if (isCropped) {
              minCanvasWidth = cropBox.width;
              minCanvasHeight = cropBox.height;

              if (minCanvasHeight * aspectRatio > minCanvasWidth) {
                minCanvasWidth = minCanvasHeight * aspectRatio;
              } else {
                minCanvasHeight = minCanvasWidth / aspectRatio;
              }
            }
          }
        }

        if (minCanvasWidth && minCanvasHeight) {
          if (minCanvasHeight * aspectRatio > minCanvasWidth) {
            minCanvasHeight = minCanvasWidth / aspectRatio;
          } else {
            minCanvasWidth = minCanvasHeight * aspectRatio;
          }
        } else if (minCanvasWidth) {
          minCanvasHeight = minCanvasWidth / aspectRatio;
        } else if (minCanvasHeight) {
          minCanvasWidth = minCanvasHeight * aspectRatio;
        }

        canvas.minWidth = minCanvasWidth;
        canvas.minHeight = minCanvasHeight;
        canvas.maxWidth = Infinity;
        canvas.maxHeight = Infinity;
      }

      if (isPositionLimited) {
        if (viewMode) {
          newCanvasLeft = containerWidth - canvas.width;
          newCanvasTop = containerHeight - canvas.height;

          canvas.minLeft = min(0, newCanvasLeft);
          canvas.minTop = min(0, newCanvasTop);
          canvas.maxLeft = max(0, newCanvasLeft);
          canvas.maxTop = max(0, newCanvasTop);

          if (isCropped && this.isLimited) {
            canvas.minLeft = min(
              cropBox.left,
              cropBox.left + cropBox.width - canvas.width
            );
            canvas.minTop = min(
              cropBox.top,
              cropBox.top + cropBox.height - canvas.height
            );
            canvas.maxLeft = cropBox.left;
            canvas.maxTop = cropBox.top;

            if (viewMode === 2) {
              if (canvas.width >= containerWidth) {
                canvas.minLeft = min(0, newCanvasLeft);
                canvas.maxLeft = max(0, newCanvasLeft);
              }

              if (canvas.height >= containerHeight) {
                canvas.minTop = min(0, newCanvasTop);
                canvas.maxTop = max(0, newCanvasTop);
              }
            }
          }
        } else {
          canvas.minLeft = -canvas.width;
          canvas.minTop = -canvas.height;
          canvas.maxLeft = containerWidth;
          canvas.maxTop = containerHeight;
        }
      }
    },

    renderCanvas: function (isChanged) {
      var canvas = this.canvas;
      var image = this.image;
      var rotate = image.rotate;
      var naturalWidth = image.naturalWidth;
      var naturalHeight = image.naturalHeight;
      var aspectRatio;
      var rotated;

      if (this.isRotated) {
        this.isRotated = false;

        // Computes rotated sizes with image sizes
        rotated = getRotatedSizes({
          width: image.width,
          height: image.height,
          degree: rotate
        });

        aspectRatio = rotated.width / rotated.height;

        if (aspectRatio !== canvas.aspectRatio) {
          canvas.left -= (rotated.width - canvas.width) / 2;
          canvas.top -= (rotated.height - canvas.height) / 2;
          canvas.width = rotated.width;
          canvas.height = rotated.height;
          canvas.aspectRatio = aspectRatio;
          canvas.naturalWidth = naturalWidth;
          canvas.naturalHeight = naturalHeight;

          // Computes rotated sizes with natural image sizes
          if (rotate % 180) {
            rotated = getRotatedSizes({
              width: naturalWidth,
              height: naturalHeight,
              degree: rotate
            });

            canvas.naturalWidth = rotated.width;
            canvas.naturalHeight = rotated.height;
          }

          this.limitCanvas(true, false);
        }
      }

      if (canvas.width > canvas.maxWidth || canvas.width < canvas.minWidth) {
        canvas.left = canvas.oldLeft;
      }

      if (canvas.height > canvas.maxHeight || canvas.height < canvas.minHeight) {
        canvas.top = canvas.oldTop;
      }

      canvas.width = min(max(canvas.width, canvas.minWidth), canvas.maxWidth);
      canvas.height = min(max(canvas.height, canvas.minHeight), canvas.maxHeight);

      this.limitCanvas(false, true);

      canvas.oldLeft = canvas.left = min(max(canvas.left, canvas.minLeft), canvas.maxLeft);
      canvas.oldTop = canvas.top = min(max(canvas.top, canvas.minTop), canvas.maxTop);

      this.$canvas.css({
        width: canvas.width,
        height: canvas.height,
        left: canvas.left,
        top: canvas.top
      });

      this.renderImage();

      if (this.isCropped && this.isLimited) {
        this.limitCropBox(true, true);
      }

      if (isChanged) {
        this.output();
      }
    },

    renderImage: function (isChanged) {
      var canvas = this.canvas;
      var image = this.image;
      var reversed;

      if (image.rotate) {
        reversed = getRotatedSizes({
          width: canvas.width,
          height: canvas.height,
          degree: image.rotate,
          aspectRatio: image.aspectRatio
        }, true);
      }

      $.extend(image, reversed ? {
        width: reversed.width,
        height: reversed.height,
        left: (canvas.width - reversed.width) / 2,
        top: (canvas.height - reversed.height) / 2
      } : {
        width: canvas.width,
        height: canvas.height,
        left: 0,
        top: 0
      });

      this.$clone.css({
        width: image.width,
        height: image.height,
        marginLeft: image.left,
        marginTop: image.top,
        transform: getTransform(image)
      });

      if (isChanged) {
        this.output();
      }
    },

    initCropBox: function () {
      var options = this.options;
      var canvas = this.canvas;
      var aspectRatio = options.aspectRatio;
      var autoCropArea = num(options.autoCropArea) || 0.8;
      var cropBox = {
            width: canvas.width,
            height: canvas.height
          };

      if (aspectRatio) {
        if (canvas.height * aspectRatio > canvas.width) {
          cropBox.height = cropBox.width / aspectRatio;
        } else {
          cropBox.width = cropBox.height * aspectRatio;
        }
      }

      this.cropBox = cropBox;
      this.limitCropBox(true, true);

      // Initialize auto crop area
      cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
      cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);

      // The width of auto crop area must large than "minWidth", and the height too. (#164)
      cropBox.width = max(cropBox.minWidth, cropBox.width * autoCropArea);
      cropBox.height = max(cropBox.minHeight, cropBox.height * autoCropArea);
      cropBox.oldLeft = cropBox.left = canvas.left + (canvas.width - cropBox.width) / 2;
      cropBox.oldTop = cropBox.top = canvas.top + (canvas.height - cropBox.height) / 2;

      this.initialCropBox = $.extend({}, cropBox);
    },

    limitCropBox: function (isSizeLimited, isPositionLimited) {
      var options = this.options;
      var aspectRatio = options.aspectRatio;
      var container = this.container;
      var containerWidth = container.width;
      var containerHeight = container.height;
      var canvas = this.canvas;
      var cropBox = this.cropBox;
      var isLimited = this.isLimited;
      var minCropBoxWidth;
      var minCropBoxHeight;
      var maxCropBoxWidth;
      var maxCropBoxHeight;

      if (isSizeLimited) {
        minCropBoxWidth = num(options.minCropBoxWidth) || 0;
        minCropBoxHeight = num(options.minCropBoxHeight) || 0;

        // The min/maxCropBoxWidth/Height must be less than containerWidth/Height
        minCropBoxWidth = min(minCropBoxWidth, containerWidth);
        minCropBoxHeight = min(minCropBoxHeight, containerHeight);
        maxCropBoxWidth = min(containerWidth, isLimited ? canvas.width : containerWidth);
        maxCropBoxHeight = min(containerHeight, isLimited ? canvas.height : containerHeight);

        if (aspectRatio) {
          if (minCropBoxWidth && minCropBoxHeight) {
            if (minCropBoxHeight * aspectRatio > minCropBoxWidth) {
              minCropBoxHeight = minCropBoxWidth / aspectRatio;
            } else {
              minCropBoxWidth = minCropBoxHeight * aspectRatio;
            }
          } else if (minCropBoxWidth) {
            minCropBoxHeight = minCropBoxWidth / aspectRatio;
          } else if (minCropBoxHeight) {
            minCropBoxWidth = minCropBoxHeight * aspectRatio;
          }

          if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) {
            maxCropBoxHeight = maxCropBoxWidth / aspectRatio;
          } else {
            maxCropBoxWidth = maxCropBoxHeight * aspectRatio;
          }
        }

        // The minWidth/Height must be less than maxWidth/Height
        cropBox.minWidth = min(minCropBoxWidth, maxCropBoxWidth);
        cropBox.minHeight = min(minCropBoxHeight, maxCropBoxHeight);
        cropBox.maxWidth = maxCropBoxWidth;
        cropBox.maxHeight = maxCropBoxHeight;
      }

      if (isPositionLimited) {
        if (isLimited) {
          cropBox.minLeft = max(0, canvas.left);
          cropBox.minTop = max(0, canvas.top);
          cropBox.maxLeft = min(containerWidth, canvas.left + canvas.width) - cropBox.width;
          cropBox.maxTop = min(containerHeight, canvas.top + canvas.height) - cropBox.height;
        } else {
          cropBox.minLeft = 0;
          cropBox.minTop = 0;
          cropBox.maxLeft = containerWidth - cropBox.width;
          cropBox.maxTop = containerHeight - cropBox.height;
        }
      }
    },

    renderCropBox: function () {
      var options = this.options;
      var container = this.container;
      var containerWidth = container.width;
      var containerHeight = container.height;
      var cropBox = this.cropBox;

      if (cropBox.width > cropBox.maxWidth || cropBox.width < cropBox.minWidth) {
        cropBox.left = cropBox.oldLeft;
      }

      if (cropBox.height > cropBox.maxHeight || cropBox.height < cropBox.minHeight) {
        cropBox.top = cropBox.oldTop;
      }

      cropBox.width = min(max(cropBox.width, cropBox.minWidth), cropBox.maxWidth);
      cropBox.height = min(max(cropBox.height, cropBox.minHeight), cropBox.maxHeight);

      this.limitCropBox(false, true);

      cropBox.oldLeft = cropBox.left = min(max(cropBox.left, cropBox.minLeft), cropBox.maxLeft);
      cropBox.oldTop = cropBox.top = min(max(cropBox.top, cropBox.minTop), cropBox.maxTop);

      if (options.movable && options.cropBoxMovable) {

        // Turn to move the canvas when the crop box is equal to the container
        this.$face.data(DATA_ACTION, (cropBox.width === containerWidth && cropBox.height === containerHeight) ? ACTION_MOVE : ACTION_ALL);
      }

      this.$cropBox.css({
        width: cropBox.width,
        height: cropBox.height,
        left: cropBox.left,
        top: cropBox.top
      });

      if (this.isCropped && this.isLimited) {
        this.limitCanvas(true, true);
      }

      if (!this.isDisabled) {
        this.output();
      }
    },

    output: function () {
      this.preview();

      if (this.isCompleted) {
        this.trigger(EVENT_CROP, this.getData());
      }
    },

    initPreview: function () {
      var crossOrigin = getCrossOrigin(this.crossOrigin);
      var url = crossOrigin ? this.crossOriginUrl : this.url;
      var $clone2;

      this.$preview = $(this.options.preview);
      this.$clone2 = $clone2 = $('<img' + crossOrigin + ' src="' + url + '">');
      this.$viewBox.html($clone2);
      this.$preview.each(function () {
        var $this = $(this);

        // Save the original size for recover
        $this.data(DATA_PREVIEW, {
          width: $this.width(),
          height: $this.height(),
          html: $this.html()
        });

        /**
         * Override img element styles
         * Add `display:block` to avoid margin top issue
         * (Occur only when margin-top <= -height)
         */
        $this.html(
          '<img' + crossOrigin + ' src="' + url + '" style="' +
          'display:block;width:100%;height:auto;' +
          'min-width:0!important;min-height:0!important;' +
          'max-width:none!important;max-height:none!important;' +
          'image-orientation:0deg!important;">'
        );
      });
    },

    resetPreview: function () {
      this.$preview.each(function () {
        var $this = $(this);
        var data = $this.data(DATA_PREVIEW);

        $this.css({
          width: data.width,
          height: data.height
        }).html(data.html).removeData(DATA_PREVIEW);
      });
    },

    preview: function () {
      var image = this.image;
      var canvas = this.canvas;
      var cropBox = this.cropBox;
      var cropBoxWidth = cropBox.width;
      var cropBoxHeight = cropBox.height;
      var width = image.width;
      var height = image.height;
      var left = cropBox.left - canvas.left - image.left;
      var top = cropBox.top - canvas.top - image.top;

      if (!this.isCropped || this.isDisabled) {
        return;
      }

      this.$clone2.css({
        width: width,
        height: height,
        marginLeft: -left,
        marginTop: -top,
        transform: getTransform(image)
      });

      this.$preview.each(function () {
        var $this = $(this);
        var data = $this.data(DATA_PREVIEW);
        var originalWidth = data.width;
        var originalHeight = data.height;
        var newWidth = originalWidth;
        var newHeight = originalHeight;
        var ratio = 1;

        if (cropBoxWidth) {
          ratio = originalWidth / cropBoxWidth;
          newHeight = cropBoxHeight * ratio;
        }

        if (cropBoxHeight && newHeight > originalHeight) {
          ratio = originalHeight / cropBoxHeight;
          newWidth = cropBoxWidth * ratio;
          newHeight = originalHeight;
        }

        $this.css({
          width: newWidth,
          height: newHeight
        }).find('img').css({
          width: width * ratio,
          height: height * ratio,
          marginLeft: -left * ratio,
          marginTop: -top * ratio,
          transform: getTransform(image)
        });
      });
    },

    bind: function () {
      var options = this.options;
      var $this = this.$element;
      var $cropper = this.$cropper;

      if ($.isFunction(options.cropstart)) {
        $this.on(EVENT_CROP_START, options.cropstart);
      }

      if ($.isFunction(options.cropmove)) {
        $this.on(EVENT_CROP_MOVE, options.cropmove);
      }

      if ($.isFunction(options.cropend)) {
        $this.on(EVENT_CROP_END, options.cropend);
      }

      if ($.isFunction(options.crop)) {
        $this.on(EVENT_CROP, options.crop);
      }

      if ($.isFunction(options.zoom)) {
        $this.on(EVENT_ZOOM, options.zoom);
      }

      $cropper.on(EVENT_MOUSE_DOWN, $.proxy(this.cropStart, this));

      if (options.zoomable && options.zoomOnWheel) {
        $cropper.on(EVENT_WHEEL, $.proxy(this.wheel, this));
      }

      if (options.toggleDragModeOnDblclick) {
        $cropper.on(EVENT_DBLCLICK, $.proxy(this.dblclick, this));
      }

      $document.
        on(EVENT_MOUSE_MOVE, (this._cropMove = proxy(this.cropMove, this))).
        on(EVENT_MOUSE_UP, (this._cropEnd = proxy(this.cropEnd, this)));

      if (options.responsive) {
        $window.on(EVENT_RESIZE, (this._resize = proxy(this.resize, this)));
      }
    },

    unbind: function () {
      var options = this.options;
      var $this = this.$element;
      var $cropper = this.$cropper;

      if ($.isFunction(options.cropstart)) {
        $this.off(EVENT_CROP_START, options.cropstart);
      }

      if ($.isFunction(options.cropmove)) {
        $this.off(EVENT_CROP_MOVE, options.cropmove);
      }

      if ($.isFunction(options.cropend)) {
        $this.off(EVENT_CROP_END, options.cropend);
      }

      if ($.isFunction(options.crop)) {
        $this.off(EVENT_CROP, options.crop);
      }

      if ($.isFunction(options.zoom)) {
        $this.off(EVENT_ZOOM, options.zoom);
      }

      $cropper.off(EVENT_MOUSE_DOWN, this.cropStart);

      if (options.zoomable && options.zoomOnWheel) {
        $cropper.off(EVENT_WHEEL, this.wheel);
      }

      if (options.toggleDragModeOnDblclick) {
        $cropper.off(EVENT_DBLCLICK, this.dblclick);
      }

      $document.
        off(EVENT_MOUSE_MOVE, this._cropMove).
        off(EVENT_MOUSE_UP, this._cropEnd);

      if (options.responsive) {
        $window.off(EVENT_RESIZE, this._resize);
      }
    },

    resize: function () {
      var restore = this.options.restore;
      var $container = this.$container;
      var container = this.container;
      var canvasData;
      var cropBoxData;
      var ratio;

      // Check `container` is necessary for IE8
      if (this.isDisabled || !container) {
        return;
      }

      ratio = $container.width() / container.width;

      // Resize when width changed or height changed
      if (ratio !== 1 || $container.height() !== container.height) {
        if (restore) {
          canvasData = this.getCanvasData();
          cropBoxData = this.getCropBoxData();
        }

        this.render();

        if (restore) {
          this.setCanvasData($.each(canvasData, function (i, n) {
            canvasData[i] = n * ratio;
          }));
          this.setCropBoxData($.each(cropBoxData, function (i, n) {
            cropBoxData[i] = n * ratio;
          }));
        }
      }
    },

    dblclick: function () {
      if (this.isDisabled) {
        return;
      }

      if (this.$dragBox.hasClass(CLASS_CROP)) {
        this.setDragMode(ACTION_MOVE);
      } else {
        this.setDragMode(ACTION_CROP);
      }
    },

    wheel: function (event) {
      var e = event.originalEvent || event;
      var ratio = num(this.options.wheelZoomRatio) || 0.1;
      var delta = 1;

      if (this.isDisabled) {
        return;
      }

      event.preventDefault();

      // Limit wheel speed to prevent zoom too fast
      if (this.wheeling) {
        return;
      }

      this.wheeling = true;

      setTimeout($.proxy(function () {
        this.wheeling = false;
      }, this), 50);

      if (e.deltaY) {
        delta = e.deltaY > 0 ? 1 : -1;
      } else if (e.wheelDelta) {
        delta = -e.wheelDelta / 120;
      } else if (e.detail) {
        delta = e.detail > 0 ? 1 : -1;
      }

      this.zoom(-delta * ratio, event);
    },

    cropStart: function (event) {
      var options = this.options;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var touchesLength;
      var action;

      if (this.isDisabled) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
            e = touches[1];
            this.startX2 = e.pageX;
            this.startY2 = e.pageY;
            action = ACTION_ZOOM;
          } else {
            return;
          }
        }

        e = touches[0];
      }

      action = action || $(e.target).data(DATA_ACTION);

      if (REGEXP_ACTIONS.test(action)) {
        if (this.trigger(EVENT_CROP_START, {
          originalEvent: originalEvent,
          action: action
        }).isDefaultPrevented()) {
          return;
        }

        event.preventDefault();

        this.action = action;
        this.cropping = false;

        // IE8  has `event.pageX/Y`, but not `event.originalEvent.pageX/Y`
        // IE10 has `event.originalEvent.pageX/Y`, but not `event.pageX/Y`
        this.startX = e.pageX || originalEvent && originalEvent.pageX;
        this.startY = e.pageY || originalEvent && originalEvent.pageY;

        if (action === ACTION_CROP) {
          this.cropping = true;
          this.$dragBox.addClass(CLASS_MODAL);
        }
      }
    },

    cropMove: function (event) {
      var options = this.options;
      var originalEvent = event.originalEvent;
      var touches = originalEvent && originalEvent.touches;
      var e = event;
      var action = this.action;
      var touchesLength;

      if (this.isDisabled) {
        return;
      }

      if (touches) {
        touchesLength = touches.length;

        if (touchesLength > 1) {
          if (options.zoomable && options.zoomOnTouch && touchesLength === 2) {
            e = touches[1];
            this.endX2 = e.pageX;
            this.endY2 = e.pageY;
          } else {
            return;
          }
        }

        e = touches[0];
      }

      if (action) {
        if (this.trigger(EVENT_CROP_MOVE, {
          originalEvent: originalEvent,
          action: action
        }).isDefaultPrevented()) {
          return;
        }

        event.preventDefault();

        this.endX = e.pageX || originalEvent && originalEvent.pageX;
        this.endY = e.pageY || originalEvent && originalEvent.pageY;

        this.change(e.shiftKey, action === ACTION_ZOOM ? event : null);
      }
    },

    cropEnd: function (event) {
      var originalEvent = event.originalEvent;
      var action = this.action;

      if (this.isDisabled) {
        return;
      }

      if (action) {
        event.preventDefault();

        if (this.cropping) {
          this.cropping = false;
          this.$dragBox.toggleClass(CLASS_MODAL, this.isCropped && this.options.modal);
        }

        this.action = '';

        this.trigger(EVENT_CROP_END, {
          originalEvent: originalEvent,
          action: action
        });
      }
    },

    change: function (shiftKey, event) {
      var options = this.options;
      var aspectRatio = options.aspectRatio;
      var action = this.action;
      var container = this.container;
      var canvas = this.canvas;
      var cropBox = this.cropBox;
      var width = cropBox.width;
      var height = cropBox.height;
      var left = cropBox.left;
      var top = cropBox.top;
      var right = left + width;
      var bottom = top + height;
      var minLeft = 0;
      var minTop = 0;
      var maxWidth = container.width;
      var maxHeight = container.height;
      var renderable = true;
      var offset;
      var range;

      // Locking aspect ratio in "free mode" by holding shift key (#259)
      if (!aspectRatio && shiftKey) {
        aspectRatio = width && height ? width / height : 1;
      }

      if (this.isLimited) {
        minLeft = cropBox.minLeft;
        minTop = cropBox.minTop;
        maxWidth = minLeft + min(container.width, canvas.width, canvas.left + canvas.width);
        maxHeight = minTop + min(container.height, canvas.height, canvas.top + canvas.height);
      }

      range = {
        x: this.endX - this.startX,
        y: this.endY - this.startY
      };

      if (aspectRatio) {
        range.X = range.y * aspectRatio;
        range.Y = range.x / aspectRatio;
      }

      switch (action) {
        // Move crop box
        case ACTION_ALL:
          left += range.x;
          top += range.y;
          break;

        // Resize crop box
        case ACTION_EAST:
          if (range.x >= 0 && (right >= maxWidth || aspectRatio &&
            (top <= minTop || bottom >= maxHeight))) {

            renderable = false;
            break;
          }

          width += range.x;

          if (aspectRatio) {
            height = width / aspectRatio;
            top -= range.Y / 2;
          }

          if (width < 0) {
            action = ACTION_WEST;
            width = 0;
          }

          break;

        case ACTION_NORTH:
          if (range.y <= 0 && (top <= minTop || aspectRatio &&
            (left <= minLeft || right >= maxWidth))) {

            renderable = false;
            break;
          }

          height -= range.y;
          top += range.y;

          if (aspectRatio) {
            width = height * aspectRatio;
            left += range.X / 2;
          }

          if (height < 0) {
            action = ACTION_SOUTH;
            height = 0;
          }

          break;

        case ACTION_WEST:
          if (range.x <= 0 && (left <= minLeft || aspectRatio &&
            (top <= minTop || bottom >= maxHeight))) {

            renderable = false;
            break;
          }

          width -= range.x;
          left += range.x;

          if (aspectRatio) {
            height = width / aspectRatio;
            top += range.Y / 2;
          }

          if (width < 0) {
            action = ACTION_EAST;
            width = 0;
          }

          break;

        case ACTION_SOUTH:
          if (range.y >= 0 && (bottom >= maxHeight || aspectRatio &&
            (left <= minLeft || right >= maxWidth))) {

            renderable = false;
            break;
          }

          height += range.y;

          if (aspectRatio) {
            width = height * aspectRatio;
            left -= range.X / 2;
          }

          if (height < 0) {
            action = ACTION_NORTH;
            height = 0;
          }

          break;

        case ACTION_NORTH_EAST:
          if (aspectRatio) {
            if (range.y <= 0 && (top <= minTop || right >= maxWidth)) {
              renderable = false;
              break;
            }

            height -= range.y;
            top += range.y;
            width = height * aspectRatio;
          } else {
            if (range.x >= 0) {
              if (right < maxWidth) {
                width += range.x;
              } else if (range.y <= 0 && top <= minTop) {
                renderable = false;
              }
            } else {
              width += range.x;
            }

            if (range.y <= 0) {
              if (top > minTop) {
                height -= range.y;
                top += range.y;
              }
            } else {
              height -= range.y;
              top += range.y;
            }
          }

          if (width < 0 && height < 0) {
            action = ACTION_SOUTH_WEST;
            height = 0;
            width = 0;
          } else if (width < 0) {
            action = ACTION_NORTH_WEST;
            width = 0;
          } else if (height < 0) {
            action = ACTION_SOUTH_EAST;
            height = 0;
          }

          break;

        case ACTION_NORTH_WEST:
          if (aspectRatio) {
            if (range.y <= 0 && (top <= minTop || left <= minLeft)) {
              renderable = false;
              break;
            }

            height -= range.y;
            top += range.y;
            width = height * aspectRatio;
            left += range.X;
          } else {
            if (range.x <= 0) {
              if (left > minLeft) {
                width -= range.x;
                left += range.x;
              } else if (range.y <= 0 && top <= minTop) {
                renderable = false;
              }
            } else {
              width -= range.x;
              left += range.x;
            }

            if (range.y <= 0) {
              if (top > minTop) {
                height -= range.y;
                top += range.y;
              }
            } else {
              height -= range.y;
              top += range.y;
            }
          }

          if (width < 0 && height < 0) {
            action = ACTION_SOUTH_EAST;
            height = 0;
            width = 0;
          } else if (width < 0) {
            action = ACTION_NORTH_EAST;
            width = 0;
          } else if (height < 0) {
            action = ACTION_SOUTH_WEST;
            height = 0;
          }

          break;

        case ACTION_SOUTH_WEST:
          if (aspectRatio) {
            if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) {
              renderable = false;
              break;
            }

            width -= range.x;
            left += range.x;
            height = width / aspectRatio;
          } else {
            if (range.x <= 0) {
              if (left > minLeft) {
                width -= range.x;
                left += range.x;
              } else if (range.y >= 0 && bottom >= maxHeight) {
                renderable = false;
              }
            } else {
              width -= range.x;
              left += range.x;
            }

            if (range.y >= 0) {
              if (bottom < maxHeight) {
                height += range.y;
              }
            } else {
              height += range.y;
            }
          }

          if (width < 0 && height < 0) {
            action = ACTION_NORTH_EAST;
            height = 0;
            width = 0;
          } else if (width < 0) {
            action = ACTION_SOUTH_EAST;
            width = 0;
          } else if (height < 0) {
            action = ACTION_NORTH_WEST;
            height = 0;
          }

          break;

        case ACTION_SOUTH_EAST:
          if (aspectRatio) {
            if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) {
              renderable = false;
              break;
            }

            width += range.x;
            height = width / aspectRatio;
          } else {
            if (range.x >= 0) {
              if (right < maxWidth) {
                width += range.x;
              } else if (range.y >= 0 && bottom >= maxHeight) {
                renderable = false;
              }
            } else {
              width += range.x;
            }

            if (range.y >= 0) {
              if (bottom < maxHeight) {
                height += range.y;
              }
            } else {
              height += range.y;
            }
          }

          if (width < 0 && height < 0) {
            action = ACTION_NORTH_WEST;
            height = 0;
            width = 0;
          } else if (width < 0) {
            action = ACTION_SOUTH_WEST;
            width = 0;
          } else if (height < 0) {
            action = ACTION_NORTH_EAST;
            height = 0;
          }

          break;

        // Move canvas
        case ACTION_MOVE:
          this.move(range.x, range.y);
          renderable = false;
          break;

        // Zoom canvas
        case ACTION_ZOOM:
          this.zoom((function (x1, y1, x2, y2) {
            var z1 = sqrt(x1 * x1 + y1 * y1);
            var z2 = sqrt(x2 * x2 + y2 * y2);

            return (z2 - z1) / z1;
          })(
            abs(this.startX - this.startX2),
            abs(this.startY - this.startY2),
            abs(this.endX - this.endX2),
            abs(this.endY - this.endY2)
          ), event);
          this.startX2 = this.endX2;
          this.startY2 = this.endY2;
          renderable = false;
          break;

        // Create crop box
        case ACTION_CROP:
          if (!range.x || !range.y) {
            renderable = false;
            break;
          }

          offset = this.$cropper.offset();
          left = this.startX - offset.left;
          top = this.startY - offset.top;
          width = cropBox.minWidth;
          height = cropBox.minHeight;

          if (range.x > 0) {
            action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST;
          } else if (range.x < 0) {
            left -= width;
            action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST;
          }

          if (range.y < 0) {
            top -= height;
          }

          // Show the crop box if is hidden
          if (!this.isCropped) {
            this.$cropBox.removeClass(CLASS_HIDDEN);
            this.isCropped = true;

            if (this.isLimited) {
              this.limitCropBox(true, true);
            }
          }

          break;

        // No default
      }

      if (renderable) {
        cropBox.width = width;
        cropBox.height = height;
        cropBox.left = left;
        cropBox.top = top;
        this.action = action;

        this.renderCropBox();
      }

      // Override
      this.startX = this.endX;
      this.startY = this.endY;
    },

    // Show the crop box manually
    crop: function () {
      if (!this.isBuilt || this.isDisabled) {
        return;
      }

      if (!this.isCropped) {
        this.isCropped = true;
        this.limitCropBox(true, true);

        if (this.options.modal) {
          this.$dragBox.addClass(CLASS_MODAL);
        }

        this.$cropBox.removeClass(CLASS_HIDDEN);
      }

      this.setCropBoxData(this.initialCropBox);
    },

    // Reset the image and crop box to their initial states
    reset: function () {
      if (!this.isBuilt || this.isDisabled) {
        return;
      }

      this.image = $.extend({}, this.initialImage);
      this.canvas = $.extend({}, this.initialCanvas);
      this.cropBox = $.extend({}, this.initialCropBox);

      this.renderCanvas();

      if (this.isCropped) {
        this.renderCropBox();
      }
    },

    // Clear the crop box
    clear: function () {
      if (!this.isCropped || this.isDisabled) {
        return;
      }

      $.extend(this.cropBox, {
        left: 0,
        top: 0,
        width: 0,
        height: 0
      });

      this.isCropped = false;
      this.renderCropBox();

      this.limitCanvas(true, true);

      // Render canvas after crop box rendered
      this.renderCanvas();

      this.$dragBox.removeClass(CLASS_MODAL);
      this.$cropBox.addClass(CLASS_HIDDEN);
    },

    /**
     * Replace the image's src and rebuild the cropper
     *
     * @param {String} url
     * @param {Boolean} onlyColorChanged (optional)
     */
    replace: function (url, onlyColorChanged) {
      if (!this.isDisabled && url) {
        if (this.isImg) {
          this.$element.attr('src', url);
        }

        if (onlyColorChanged) {
          this.url = url;
          this.$clone.attr('src', url);

          if (this.isBuilt) {
            this.$preview.find('img').add(this.$clone2).attr('src', url);
          }
        } else {
          if (this.isImg) {
            this.isReplaced = true;
          }

          // Clear previous data
          this.options.data = null;
          this.load(url);
        }
      }
    },

    // Enable (unfreeze) the cropper
    enable: function () {
      if (this.isBuilt) {
        this.isDisabled = false;
        this.$cropper.removeClass(CLASS_DISABLED);
      }
    },

    // Disable (freeze) the cropper
    disable: function () {
      if (this.isBuilt) {
        this.isDisabled = true;
        this.$cropper.addClass(CLASS_DISABLED);
      }
    },

    // Destroy the cropper and remove the instance from the image
    destroy: function () {
      var $this = this.$element;

      if (this.isLoaded) {
        if (this.isImg && this.isReplaced) {
          $this.attr('src', this.originalUrl);
        }

        this.unbuild();
        $this.removeClass(CLASS_HIDDEN);
      } else {
        if (this.isImg) {
          $this.off(EVENT_LOAD, this.start);
        } else if (this.$clone) {
          this.$clone.remove();
        }
      }

      $this.removeData(NAMESPACE);
    },

    /**
     * Move the canvas with relative offsets
     *
     * @param {Number} offsetX
     * @param {Number} offsetY (optional)
     */
    move: function (offsetX, offsetY) {
      var canvas = this.canvas;

      this.moveTo(
        isUndefined(offsetX) ? offsetX : canvas.left + num(offsetX),
        isUndefined(offsetY) ? offsetY : canvas.top + num(offsetY)
      );
    },

    /**
     * Move the canvas to an absolute point
     *
     * @param {Number} x
     * @param {Number} y (optional)
     */
    moveTo: function (x, y) {
      var canvas = this.canvas;
      var isChanged = false;

      // If "y" is not present, its default value is "x"
      if (isUndefined(y)) {
        y = x;
      }

      x = num(x);
      y = num(y);

      if (this.isBuilt && !this.isDisabled && this.options.movable) {
        if (isNumber(x)) {
          canvas.left = x;
          isChanged = true;
        }

        if (isNumber(y)) {
          canvas.top = y;
          isChanged = true;
        }

        if (isChanged) {
          this.renderCanvas(true);
        }
      }
    },

    /**
     * Zoom the canvas with a relative ratio
     *
     * @param {Number} ratio
     * @param {jQuery Event} _event (private)
     */
    zoom: function (ratio, _event) {
      var canvas = this.canvas;

      ratio = num(ratio);

      if (ratio < 0) {
        ratio =  1 / (1 - ratio);
      } else {
        ratio = 1 + ratio;
      }

      this.zoomTo(canvas.width * ratio / canvas.naturalWidth, _event);
    },

    /**
     * Zoom the canvas to an absolute ratio
     *
     * @param {Number} ratio
     * @param {jQuery Event} _event (private)
     */
    zoomTo: function (ratio, _event) {
      var options = this.options;
      var canvas = this.canvas;
      var width = canvas.width;
      var height = canvas.height;
      var naturalWidth = canvas.naturalWidth;
      var naturalHeight = canvas.naturalHeight;
      var originalEvent;
      var newWidth;
      var newHeight;
      var offset;
      var center;

      ratio = num(ratio);

      if (ratio >= 0 && this.isBuilt && !this.isDisabled && options.zoomable) {
        newWidth = naturalWidth * ratio;
        newHeight = naturalHeight * ratio;

        if (_event) {
          originalEvent = _event.originalEvent;
        }

        if (this.trigger(EVENT_ZOOM, {
          originalEvent: originalEvent,
          oldRatio: width / naturalWidth,
          ratio: newWidth / naturalWidth
        }).isDefaultPrevented()) {
          return;
        }

        if (originalEvent) {
          offset = this.$cropper.offset();
          center = originalEvent.touches ? getTouchesCenter(originalEvent.touches) : {
            pageX: _event.pageX || originalEvent.pageX || 0,
            pageY: _event.pageY || originalEvent.pageY || 0
          };

          // Zoom from the triggering point of the event
          canvas.left -= (newWidth - width) * (
            ((center.pageX - offset.left) - canvas.left) / width
          );
          canvas.top -= (newHeight - height) * (
            ((center.pageY - offset.top) - canvas.top) / height
          );
        } else {

          // Zoom from the center of the canvas
          canvas.left -= (newWidth - width) / 2;
          canvas.top -= (newHeight - height) / 2;
        }

        canvas.width = newWidth;
        canvas.height = newHeight;
        this.renderCanvas(true);
      }
    },

    /**
     * Rotate the canvas with a relative degree
     *
     * @param {Number} degree
     */
    rotate: function (degree) {
      this.rotateTo((this.image.rotate || 0) + num(degree));
    },

    /**
     * Rotate the canvas to an absolute degree
     * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#rotate()
     *
     * @param {Number} degree
     */
    rotateTo: function (degree) {
      degree = num(degree);

      if (isNumber(degree) && this.isBuilt && !this.isDisabled && this.options.rotatable) {
        this.image.rotate = degree % 360;
        this.isRotated = true;
        this.renderCanvas(true);
      }
    },

    /**
     * Scale the image
     * https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function#scale()
     *
     * @param {Number} scaleX
     * @param {Number} scaleY (optional)
     */
    scale: function (scaleX, scaleY) {
      var image = this.image;
      var isChanged = false;

      // If "scaleY" is not present, its default value is "scaleX"
      if (isUndefined(scaleY)) {
        scaleY = scaleX;
      }

      scaleX = num(scaleX);
      scaleY = num(scaleY);

      if (this.isBuilt && !this.isDisabled && this.options.scalable) {
        if (isNumber(scaleX)) {
          image.scaleX = scaleX;
          isChanged = true;
        }

        if (isNumber(scaleY)) {
          image.scaleY = scaleY;
          isChanged = true;
        }

        if (isChanged) {
          this.renderImage(true);
        }
      }
    },

    /**
     * Scale the abscissa of the image
     *
     * @param {Number} scaleX
     */
    scaleX: function (scaleX) {
      var scaleY = this.image.scaleY;

      this.scale(scaleX, isNumber(scaleY) ? scaleY : 1);
    },

    /**
     * Scale the ordinate of the image
     *
     * @param {Number} scaleY
     */
    scaleY: function (scaleY) {
      var scaleX = this.image.scaleX;

      this.scale(isNumber(scaleX) ? scaleX : 1, scaleY);
    },

    /**
     * Get the cropped area position and size data (base on the original image)
     *
     * @param {Boolean} isRounded (optional)
     * @return {Object} data
     */
    getData: function (isRounded) {
      var options = this.options;
      var image = this.image;
      var canvas = this.canvas;
      var cropBox = this.cropBox;
      var ratio;
      var data;

      if (this.isBuilt && this.isCropped) {
        data = {
          x: cropBox.left - canvas.left,
          y: cropBox.top - canvas.top,
          width: cropBox.width,
          height: cropBox.height
        };

        ratio = image.width / image.naturalWidth;

        $.each(data, function (i, n) {
          n = n / ratio;
          data[i] = isRounded ? round(n) : n;
        });

      } else {
        data = {
          x: 0,
          y: 0,
          width: 0,
          height: 0
        };
      }

      if (options.rotatable) {
        data.rotate = image.rotate || 0;
      }

      if (options.scalable) {
        data.scaleX = image.scaleX || 1;
        data.scaleY = image.scaleY || 1;
      }

      return data;
    },

    /**
     * Set the cropped area position and size with new data
     *
     * @param {Object} data
     */
    setData: function (data) {
      var options = this.options;
      var image = this.image;
      var canvas = this.canvas;
      var cropBoxData = {};
      var isRotated;
      var isScaled;
      var ratio;

      if ($.isFunction(data)) {
        data = data.call(this.element);
      }

      if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
        if (options.rotatable) {
          if (isNumber(data.rotate) && data.rotate !== image.rotate) {
            image.rotate = data.rotate;
            this.isRotated = isRotated = true;
          }
        }

        if (options.scalable) {
          if (isNumber(data.scaleX) && data.scaleX !== image.scaleX) {
            image.scaleX = data.scaleX;
            isScaled = true;
          }

          if (isNumber(data.scaleY) && data.scaleY !== image.scaleY) {
            image.scaleY = data.scaleY;
            isScaled = true;
          }
        }

        if (isRotated) {
          this.renderCanvas();
        } else if (isScaled) {
          this.renderImage();
        }

        ratio = image.width / image.naturalWidth;

        if (isNumber(data.x)) {
          cropBoxData.left = data.x * ratio + canvas.left;
        }

        if (isNumber(data.y)) {
          cropBoxData.top = data.y * ratio + canvas.top;
        }

        if (isNumber(data.width)) {
          cropBoxData.width = data.width * ratio;
        }

        if (isNumber(data.height)) {
          cropBoxData.height = data.height * ratio;
        }

        this.setCropBoxData(cropBoxData);
      }
    },

    /**
     * Get the container size data
     *
     * @return {Object} data
     */
    getContainerData: function () {
      return this.isBuilt ? this.container : {};
    },

    /**
     * Get the image position and size data
     *
     * @return {Object} data
     */
    getImageData: function () {
      return this.isLoaded ? this.image : {};
    },

    /**
     * Get the canvas position and size data
     *
     * @return {Object} data
     */
    getCanvasData: function () {
      var canvas = this.canvas;
      var data = {};

      if (this.isBuilt) {
        $.each([
          'left',
          'top',
          'width',
          'height',
          'naturalWidth',
          'naturalHeight'
        ], function (i, n) {
          data[n] = canvas[n];
        });
      }

      return data;
    },

    /**
     * Set the canvas position and size with new data
     *
     * @param {Object} data
     */
    setCanvasData: function (data) {
      var canvas = this.canvas;
      var aspectRatio = canvas.aspectRatio;

      if ($.isFunction(data)) {
        data = data.call(this.$element);
      }

      if (this.isBuilt && !this.isDisabled && $.isPlainObject(data)) {
        if (isNumber(data.left)) {
          canvas.left = data.left;
        }

        if (isNumber(data.top)) {
          canvas.top = data.top;
        }

        if (isNumber(data.width)) {
          canvas.width = data.width;
          canvas.height = data.width / aspectRatio;
        } else if (isNumber(data.height)) {
          canvas.height = data.height;
          canvas.width = data.height * aspectRatio;
        }

        this.renderCanvas(true);
      }
    },

    /**
     * Get the crop box position and size data
     *
     * @return {Object} data
     */
    getCropBoxData: function () {
      var cropBox = this.cropBox;
      var data;

      if (this.isBuilt && this.isCropped) {
        data = {
          left: cropBox.left,
          top: cropBox.top,
          width: cropBox.width,
          height: cropBox.height
        };
      }

      return data || {};
    },

    /**
     * Set the crop box position and size with new data
     *
     * @param {Object} data
     */
    setCropBoxData: function (data) {
      var cropBox = this.cropBox;
      var aspectRatio = this.options.aspectRatio;
      var isWidthChanged;
      var isHeightChanged;

      if ($.isFunction(data)) {
        data = data.call(this.$element);
      }

      if (this.isBuilt && this.isCropped && !this.isDisabled && $.isPlainObject(data)) {

        if (isNumber(data.left)) {
          cropBox.left = data.left;
        }

        if (isNumber(data.top)) {
          cropBox.top = data.top;
        }

        if (isNumber(data.width)) {
          isWidthChanged = true;
          cropBox.width = data.width;
        }

        if (isNumber(data.height)) {
          isHeightChanged = true;
          cropBox.height = data.height;
        }

        if (aspectRatio) {
          if (isWidthChanged) {
            cropBox.height = cropBox.width / aspectRatio;
          } else if (isHeightChanged) {
            cropBox.width = cropBox.height * aspectRatio;
          }
        }

        this.renderCropBox();
      }
    },

    /**
     * Get a canvas drawn the cropped image
     *
     * @param {Object} options (optional)
     * @return {HTMLCanvasElement} canvas
     */
    getCroppedCanvas: function (options) {
      var originalWidth;
      var originalHeight;
      var canvasWidth;
      var canvasHeight;
      var scaledWidth;
      var scaledHeight;
      var scaledRatio;
      var aspectRatio;
      var canvas;
      var context;
      var data;

      if (!this.isBuilt || !SUPPORT_CANVAS) {
        return;
      }

      if (!this.isCropped) {
        return getSourceCanvas(this.$clone[0], this.image);
      }

      if (!$.isPlainObject(options)) {
        options = {};
      }

      data = this.getData();
      originalWidth = data.width;
      originalHeight = data.height;
      aspectRatio = originalWidth / originalHeight;

      if ($.isPlainObject(options)) {
        scaledWidth = options.width;
        scaledHeight = options.height;

        if (scaledWidth) {
          scaledHeight = scaledWidth / aspectRatio;
          scaledRatio = scaledWidth / originalWidth;
        } else if (scaledHeight) {
          scaledWidth = scaledHeight * aspectRatio;
          scaledRatio = scaledHeight / originalHeight;
        }
      }

      // The canvas element will use `Math.floor` on a float number, so floor first
      canvasWidth = floor(scaledWidth || originalWidth);
      canvasHeight = floor(scaledHeight || originalHeight);

      canvas = $('<canvas>')[0];
      canvas.width = canvasWidth;
      canvas.height = canvasHeight;
      context = canvas.getContext('2d');

      if (options.fillColor) {
        context.fillStyle = options.fillColor;
        context.fillRect(0, 0, canvasWidth, canvasHeight);
      }

      // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage
      context.drawImage.apply(context, (function () {
        var source = getSourceCanvas(this.$clone[0], this.image);
        var sourceWidth = source.width;
        var sourceHeight = source.height;
        var canvas = this.canvas;
        var params = [source];

        // Source canvas
        var srcX = data.x + canvas.naturalWidth * (abs(data.scaleX || 1) - 1) / 2;
        var srcY = data.y + canvas.naturalHeight * (abs(data.scaleY || 1) - 1) / 2;
        var srcWidth;
        var srcHeight;

        // Destination canvas
        var dstX;
        var dstY;
        var dstWidth;
        var dstHeight;

        if (srcX <= -originalWidth || srcX > sourceWidth) {
          srcX = srcWidth = dstX = dstWidth = 0;
        } else if (srcX <= 0) {
          dstX = -srcX;
          srcX = 0;
          srcWidth = dstWidth = min(sourceWidth, originalWidth + srcX);
        } else if (srcX <= sourceWidth) {
          dstX = 0;
          srcWidth = dstWidth = min(originalWidth, sourceWidth - srcX);
        }

        if (srcWidth <= 0 || srcY <= -originalHeight || srcY > sourceHeight) {
          srcY = srcHeight = dstY = dstHeight = 0;
        } else if (srcY <= 0) {
          dstY = -srcY;
          srcY = 0;
          srcHeight = dstHeight = min(sourceHeight, originalHeight + srcY);
        } else if (srcY <= sourceHeight) {
          dstY = 0;
          srcHeight = dstHeight = min(originalHeight, sourceHeight - srcY);
        }

        // All the numerical parameters should be integer for `drawImage` (#476)
        params.push(floor(srcX), floor(srcY), floor(srcWidth), floor(srcHeight));

        // Scale destination sizes
        if (scaledRatio) {
          dstX *= scaledRatio;
          dstY *= scaledRatio;
          dstWidth *= scaledRatio;
          dstHeight *= scaledRatio;
        }

        // Avoid "IndexSizeError" in IE and Firefox
        if (dstWidth > 0 && dstHeight > 0) {
          params.push(floor(dstX), floor(dstY), floor(dstWidth), floor(dstHeight));
        }

        return params;
      }).call(this));

      return canvas;
    },

    /**
     * Change the aspect ratio of the crop box
     *
     * @param {Number} aspectRatio
     */
    setAspectRatio: function (aspectRatio) {
      var options = this.options;

      if (!this.isDisabled && !isUndefined(aspectRatio)) {

        // 0 -> NaN
        options.aspectRatio = max(0, aspectRatio) || NaN;

        if (this.isBuilt) {
          this.initCropBox();

          if (this.isCropped) {
            this.renderCropBox();
          }
        }
      }
    },

    /**
     * Change the drag mode
     *
     * @param {String} mode (optional)
     */
    setDragMode: function (mode) {
      var options = this.options;
      var croppable;
      var movable;

      if (this.isLoaded && !this.isDisabled) {
        croppable = mode === ACTION_CROP;
        movable = options.movable && mode === ACTION_MOVE;
        mode = (croppable || movable) ? mode : ACTION_NONE;

        this.$dragBox.
          data(DATA_ACTION, mode).
          toggleClass(CLASS_CROP, croppable).
          toggleClass(CLASS_MOVE, movable);

        if (!options.cropBoxMovable) {

          // Sync drag mode to crop box when it is not movable(#300)
          this.$face.
            data(DATA_ACTION, mode).
            toggleClass(CLASS_CROP, croppable).
            toggleClass(CLASS_MOVE, movable);
        }
      }
    }
  };

  Cropper.DEFAULTS = {

    // Define the view mode of the cropper
    viewMode: 0, // 0, 1, 2, 3

    // Define the dragging mode of the cropper
    dragMode: 'crop', // 'crop', 'move' or 'none'

    // Define the aspect ratio of the crop box
    aspectRatio: NaN,

    // An object with the previous cropping result data
    data: null,

    // A jQuery selector for adding extra containers to preview
    preview: '',

    // Re-render the cropper when resize the window
    responsive: true,

    // Restore the cropped area after resize the window
    restore: true,

    // Check if the current image is a cross-origin image
    checkCrossOrigin: true,

    // Check the current image's Exif Orientation information
    checkOrientation: true,

    // Show the black modal
    modal: true,

    // Show the dashed lines for guiding
    guides: true,

    // Show the center indicator for guiding
    center: true,

    // Show the white modal to highlight the crop box
    highlight: true,

    // Show the grid background
    background: true,

    // Enable to crop the image automatically when initialize
    autoCrop: true,

    // Define the percentage of automatic cropping area when initializes
    autoCropArea: 0.8,

    // Enable to move the image
    movable: true,

    // Enable to rotate the image
    rotatable: true,

    // Enable to scale the image
    scalable: true,

    // Enable to zoom the image
    zoomable: true,

    // Enable to zoom the image by dragging touch
    zoomOnTouch: true,

    // Enable to zoom the image by wheeling mouse
    zoomOnWheel: true,

    // Define zoom ratio when zoom the image by wheeling mouse
    wheelZoomRatio: 0.1,

    // Enable to move the crop box
    cropBoxMovable: true,

    // Enable to resize the crop box
    cropBoxResizable: true,

    // Toggle drag mode between "crop" and "move" when click twice on the cropper
    toggleDragModeOnDblclick: true,

    // Size limitation
    minCanvasWidth: 0,
    minCanvasHeight: 0,
    minCropBoxWidth: 0,
    minCropBoxHeight: 0,
    minContainerWidth: 200,
    minContainerHeight: 100,

    // Shortcuts of events
    build: null,
    built: null,
    cropstart: null,
    cropmove: null,
    cropend: null,
    crop: null,
    zoom: null
  };

  Cropper.setDefaults = function (options) {
    $.extend(Cropper.DEFAULTS, options);
  };

  Cropper.TEMPLATE = (
    '<div class="cropper-container">' +
      '<div class="cropper-wrap-box">' +
        '<div class="cropper-canvas"></div>' +
      '</div>' +
      '<div class="cropper-drag-box"></div>' +
      '<div class="cropper-crop-box">' +
        '<span class="cropper-view-box"></span>' +
        '<span class="cropper-dashed dashed-h"></span>' +
        '<span class="cropper-dashed dashed-v"></span>' +
        '<span class="cropper-center"></span>' +
        '<span class="cropper-face"></span>' +
        '<span class="cropper-line line-e" data-action="e"></span>' +
        '<span class="cropper-line line-n" data-action="n"></span>' +
        '<span class="cropper-line line-w" data-action="w"></span>' +
        '<span class="cropper-line line-s" data-action="s"></span>' +
        '<span class="cropper-point point-e" data-action="e"></span>' +
        '<span class="cropper-point point-n" data-action="n"></span>' +
        '<span class="cropper-point point-w" data-action="w"></span>' +
        '<span class="cropper-point point-s" data-action="s"></span>' +
        '<span class="cropper-point point-ne" data-action="ne"></span>' +
        '<span class="cropper-point point-nw" data-action="nw"></span>' +
        '<span class="cropper-point point-sw" data-action="sw"></span>' +
        '<span class="cropper-point point-se" data-action="se"></span>' +
      '</div>' +
    '</div>'
  );

  // Save the other cropper
  Cropper.other = $.fn.cropper;

  // Register as jQuery plugin
  $.fn.cropper = function (option) {
    var args = toArray(arguments, 1);
    var result;

    this.each(function () {
      var $this = $(this);
      var data = $this.data(NAMESPACE);
      var options;
      var fn;

      if (!data) {
        if (/destroy/.test(option)) {
          return;
        }

        options = $.extend({}, $this.data(), $.isPlainObject(option) && option);
        $this.data(NAMESPACE, (data = new Cropper(this, options)));
      }

      if (typeof option === 'string' && $.isFunction(fn = data[option])) {
        result = fn.apply(data, args);
      }
    });

    return isUndefined(result) ? this : result;
  };

  $.fn.cropper.Constructor = Cropper;
  $.fn.cropper.setDefaults = Cropper.setDefaults;

  // No conflict
  $.fn.cropper.noConflict = function () {
    $.fn.cropper = Cropper.other;
    return this;
  };

});
//Title: Custom DropDown plugin by PC
//Documentation: http://designwithpc.com/Plugins/ddslick
//Author: PC 
//Website: http://designwithpc.com
//Twitter: http://twitter.com/chaudharyp

(function ($) {

    $.fn.ddslick = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exists.');
        }
    };

    var methods = {},

    //Set defauls for the control
    defaults = {
        data: [],
        keepJSONItemsOnTop: false,
        width: 260,
        dropwidth: 260,
        height: null,
        background: "#eee",
        selectText: "",
        defaultSelectedIndex: null,
        truncateDescription: true,
        imagePosition: "left",
        showSelectedHTML: true,
        clickOffToClose: true,
        onSelected: function () { },
        miniMode: false,
		className: null
    },

    ddSelectHtml = '<div class="dd-select"><input class="dd-selected-value" type="hidden" /><a class="dd-selected"></a><span class="dd-pointer dd-pointer-down"></span></div>',
    ddOptionsHtml = '<ul class="dd-options"></ul>',

    //CSS for ddSlick
    ddslickCSS = '<style id="css-ddslick" type="text/css">' +
                '.dd-select{ border-radius:2px; border:solid 1px #ccc; position:relative; cursor:pointer;}' +
                '.dd-desc { color:#aaa; display:block; overflow: hidden; font-weight:normal; line-height: 1.4em; }' +
                '.dd-selected{ overflow:hidden; display:block; padding:10px; font-weight:bold;}' +
                '.dd-pointer{ width:0; height:0; position:absolute; right:10px; top:50%; margin-top:-3px;}' +
                '.dd-pointer-down{ border:solid 5px transparent; border-top:solid 5px #000; }' +
                '.dd-pointer-up{border:solid 5px transparent !important; border-bottom:solid 5px #000 !important; margin-top:-8px;}' +
                '.dd-options{ border:solid 1px #ccc; border-top:none; list-style:none; box-shadow:0px 1px 5px #ddd; display:none; position:absolute; z-index:30001; margin:0; padding:0;background:#fff; overflow:auto;}' +
                '.dd-option{ padding:10px; display:block; border-bottom:solid 1px #ddd; overflow:hidden; text-decoration:none; color:#333; cursor:pointer;-webkit-transition: all 0.25s ease-in-out; -moz-transition: all 0.25s ease-in-out;-o-transition: all 0.25s ease-in-out;-ms-transition: all 0.25s ease-in-out; }' +
                '.dd-options > li:last-child > .dd-option{ border-bottom:none;}' +
                '.dd-option:hover{ background:#f3f3f3; color:#000;}' +
                '.dd-selected-description-truncated { text-overflow: ellipsis; white-space:nowrap; }' +
                '.dd-option-selected { background:#f6f6f6; }' +
                '.dd-option-image, .dd-selected-image { vertical-align:middle; float:left; margin-right:5px; max-width:64px;}' +
                '.dd-image-right { float:right; margin-right:15px; margin-left:5px;}' +
                '.dd-container{ position:relative;}​ .dd-selected-text { font-weight:bold}​</style>';

    //CSS styles are only added once.
    if ($('#css-ddslick').length <= 0) {
        $(ddslickCSS).appendTo('head');
    }

    //Public methods 
    methods.init = function (options) {
        //Preserve the original defaults by passing an empty object as the target
        var options = $.extend({}, defaults, options);

        //Apply on all selected elements
        return this.each(function () {
            var obj = $(this),
                data = obj.data('ddslick');
            //If the plugin has not been initialized yet
            if (!data) {

                var ddSelect = [], ddJson = options.data;

                //Get data from HTML select options
                obj.find('option').each(function () {
                    var $this = $(this), thisData = $this.data();
                    ddSelect.push({
                        text: $.trim($this.text()),
                        value: $this.val(),
                        selected: $this.is(':selected'),
                        description: thisData.description,
                        imageSrc: thisData.imagesrc //keep it lowercase for HTML5 data-attributes
                    });
                });

                //Update Plugin data merging both HTML select data and JSON data for the dropdown
                if (options.keepJSONItemsOnTop)
                    $.merge(options.data, ddSelect);
                else options.data = $.merge(ddSelect, options.data);

                //Replace HTML select with empty placeholder, keep the original
                var original = obj, placeholder = $('<div id="' + obj.attr('id') + '"></div>');
                obj.replaceWith(placeholder);
                obj = placeholder;
				
				if(options.className)
					obj.addClass(options.className);

                //Add classes and append ddSelectHtml & ddOptionsHtml to the container
                obj.addClass('dd-container').append(ddSelectHtml).append(ddOptionsHtml);

                //Get newly created ddOptions and ddSelect to manipulate
                var ddSelect = obj.find('.dd-select'),
                    ddOptions = obj.find('.dd-options'),
                    ddSelected = obj.find('.dd-selected');

                //Set widths
                ddOptions.css({ width: options.dropwidth });
                ddSelect.css({ width: options.width, background: options.background });
                obj.css({ width: options.width });

                //Set height
                if (options.height != null)
                    ddOptions.css({ height: options.height, overflow: 'auto' });

                //Add ddOptions to the container. Replace with template engine later.
                $.each(options.data, function (index, item) {
                    if (item.selected) options.defaultSelectedIndex = index;
                    ddOptions.append('<li>' +
                        '<a class="dd-option" miniMode="' + options.miniMode + '">' +
                            (item.value ? ' <input class="dd-option-value" type="hidden" value="' + item.value + '" />' : '') +
                            (item.imageSrc ? ' <img class="dd-option-image' + (options.imagePosition == "right" ? ' dd-image-right' : '') + '" src="' + item.imageSrc + '" />' : '') +
                            (item.text ? ' <label class="dd-option-text">' + item.text + '</label>' : '') +
                            (item.description ? ' <small class="dd-option-description dd-desc">' + item.description + '</small>' : '') +
                        '</a>' +
                    '</li>');
                });

                //Mini mode
                if (options.miniMode) {
                    ddSelect.css({ padding: "0px", margin: "5px" });
                    ddSelected.css({ color: "Black", "font-weight": "Normal", padding: "0px", display: "inline", "font-size": "18px" });
                    obj.css("display", "inline-block");
                }

                //Save plugin data.
                var pluginData = {
                    settings: options,
                    original: original,
                    selectedIndex: -1,
                    selectedItem: null,
                    selectedData: null
                }
                obj.data('ddslick', pluginData);

                //Check if needs to show the select text, otherwise show selected or default selection
                if (options.selectText.length > 0 && options.defaultSelectedIndex == null) {
                    obj.find('.dd-selected').html(options.selectText);
                }
                else {
                    var index = (options.defaultSelectedIndex != null && options.defaultSelectedIndex >= 0 && options.defaultSelectedIndex < options.data.length)
                                ? options.defaultSelectedIndex
                                : 0;
                    selectIndex(obj, index);
                }

                //EVENTS
                //Displaying options
                obj.find('.dd-select').on('click.ddslick', function () {
                    open(obj);
                });

                //Selecting an option
                obj.find('.dd-option').on('click.ddslick', function () {
                    selectIndex(obj, $(this).closest('li').index());
                });

                //Click anywhere to close
                if (options.clickOffToClose) {
                    ddOptions.addClass('dd-click-off-close');
                    obj.on('click.ddslick', function (e) { e.stopPropagation(); });
                    $('body').on('click', function () {
                        $('.dd-click-off-close').slideUp(50).siblings('.dd-select').find('.dd-pointer').removeClass('dd-pointer-up');
                    });
                }
            }
        });
    };

    //Public method to select an option by its index
    methods.select = function (options) {
        return this.each(function () {
            if (options.index)
                selectIndex($(this), options.index);
        });
    }

    //Public method to open drop down
    methods.open = function () {
        return this.each(function () {
            var $this = $(this),
                pluginData = $this.data('ddslick');

            //Check if plugin is initialized
            if (pluginData)
                open($this);
        });
    };

    //Public method to close drop down
    methods.close = function () {
        return this.each(function () {
            var $this = $(this),
                pluginData = $this.data('ddslick');

            //Check if plugin is initialized
            if (pluginData)
                close($this);
        });
    };

    //Public method to destroy. Unbind all events and restore the original Html select/options
    methods.destroy = function () {
        return this.each(function () {
            var $this = $(this),
                pluginData = $this.data('ddslick');

            //Check if already destroyed
            if (pluginData) {
                var originalElement = pluginData.original;
                $this.removeData('ddslick').unbind('.ddslick').replaceWith(originalElement);
            }
        });
    }

    //Private: Select index
    function selectIndex(obj, index) {

        //Get plugin data
        var pluginData = obj.data('ddslick');

        //Get required elements
        var ddSelected = obj.find('.dd-selected'),
            ddSelectedValue = ddSelected.siblings('.dd-selected-value'),
            ddOptions = obj.find('.dd-options'),
            ddPointer = ddSelected.siblings('.dd-pointer'),
            selectedOption = obj.find('.dd-option').eq(index),
            selectedLiItem = selectedOption.closest('li'),
            settings = pluginData.settings,
            selectedData = pluginData.settings.data[index];

        //Highlight selected option
        obj.find('.dd-option').removeClass('dd-option-selected');
        selectedOption.addClass('dd-option-selected');

        //Update or Set plugin data with new selection
        pluginData.selectedIndex = index;
        pluginData.selectedItem = selectedLiItem;
        pluginData.selectedData = selectedData;

        //If set to display to full html, add html
        if (settings.showSelectedHTML) {
            ddSelected.html(
                    (selectedData.imageSrc ? '<img class="dd-selected-image' + (settings.imagePosition == "right" ? ' dd-image-right' : '') + '" src="' + selectedData.imageSrc + '" />' : '') +
                    (selectedData.text ? '<label class="dd-selected-text">' + selectedData.text + '</label>' : '') +
                    (selectedData.description ? '<small class="dd-selected-description dd-desc' + (settings.truncateDescription ? ' dd-selected-description-truncated' : '') + '" >' + selectedData.description + '</small>' : '')
                );

        }
        //Else only display text as selection
        else ddSelected.html(selectedData.text);

        //Updating selected option value
        ddSelectedValue.val(selectedData.value);

        //BONUS! Update the original element attribute with the new selection
        pluginData.original.val(selectedData.value);
        obj.data('ddslick', pluginData);

        //Close options on selection
        close(obj);

        //Adjust appearence for selected option
        adjustSelectedHeight(obj);

        //Callback function on selection
        if (typeof settings.onSelected == 'function') {
            settings.onSelected.call(this, pluginData);
        }
    }

    //Private: Close the drop down options
    function open(obj) {

        var $this = obj.find('.dd-select'),
            ddOptions = $this.siblings('.dd-options'),
            ddPointer = $this.find('.dd-pointer'),
            wasOpen = ddOptions.is(':visible');

        //Close all open options (multiple plugins) on the page
        $('.dd-click-off-close').not(ddOptions).slideUp(50);
        $('.dd-pointer').removeClass('dd-pointer-up');

        if (wasOpen) {
            ddOptions.slideUp('fast');
            ddPointer.removeClass('dd-pointer-up');
        }
        else {
            ddOptions.slideDown('fast');
            ddPointer.addClass('dd-pointer-up');
        }

        //Fix text height (i.e. display title in center), if there is no description
        adjustOptionsHeight(obj);
    }

    //Private: Close the drop down options
    function close(obj) {
        //Close drop down and adjust pointer direction
        obj.find('.dd-options').slideUp(50);
        obj.find('.dd-pointer').removeClass('dd-pointer-up').removeClass('dd-pointer-up');
    }

    //Private: Adjust appearence for selected option (move title to middle), when no desripction
    function adjustSelectedHeight(obj) {

        //Get height of dd-selected
        var lSHeight = obj.find('.dd-select').css('height');

        //Check if there is selected description
        var descriptionSelected = obj.find('.dd-selected-description');
        var imgSelected = obj.find('.dd-selected-image');
        if (descriptionSelected.length <= 0 && imgSelected.length > 0) {
            obj.find('.dd-selected-text').css('lineHeight', lSHeight);
        }
    }

    //Private: Adjust appearence for drop down options (move title to middle), when no desripction
    function adjustOptionsHeight(obj) {
		return;
        obj.find('.dd-option').each(function () {
            var $this = $(this);
            var lOHeight = $this.css('height');
            var descriptionOption = $this.find('.dd-option-description');
            var imgOption = obj.find('.dd-option-image');
            if (descriptionOption.length <= 0 && imgOption.length > 0 && $this.attr("miniMode") != "true") {
                $this.find('.dd-option-text').css('lineHeight', lOHeight);
            } else {
                $this.find('.dd-option-text').css('lineHeight', '');
            }
        });
    }

})(jQuery);
/*!jQuery Knob*/
/**
* Downward compatible, touchable dial
*
* Version: 1.2.0 (15/07/2012)
* Requires: jQuery v1.7+
*
* Copyright (c) 2012 Anthony Terrien
* Under MIT and GPL licenses:
*  http://www.opensource.org/licenses/mit-license.php
*  http://www.gnu.org/licenses/gpl.html
*
* Thanks to vor, eskimoblood, spiffistan, FabrizioC
*/
(function ($) {

    /**
    * Kontrol library
    */
    "use strict";

    /**
    * Definition of globals and core
    */
    var k = {}, // kontrol
        max = Math.max,
        min = Math.min;

    k.c = {};
    k.c.d = $(document);
    k.c.t = function (e) {
        return e.originalEvent.touches.length - 1;
    };

    /**
    * Kontrol Object
    *
    * Definition of an abstract UI control
    *
    * Each concrete component must call this one.
    * <code>
    * k.o.call(this);
    * </code>
    */
    k.o = function () {
        var s = this;

        this.o = null; // array of options
        this.$ = null; // jQuery wrapped element
        this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
        this.g = null; // 2D graphics context for 'pre-rendering'
        this.v = null; // value ; mixed array or integer
        this.cv = null; // change value ; not commited value
        this.x = 0; // canvas x position
        this.y = 0; // canvas y position
        this.$c = null; // jQuery canvas element
        this.c = null; // rendered canvas context
        this.t = 0; // touches index
        this.isInit = false;
        this.fgColor = null; // main color
        this.pColor = null; // previous color
        this.dH = null; // draw hook
        this.cH = null; // change hook
        this.eH = null; // cancel hook
        this.rH = null; // release hook

        this.run = function () {
            var cf = function (e, conf) {
                var k;
                for (k in conf) {
                    s.o[k] = conf[k];
                }
                s.init();
                s._configure()
                 ._draw();
            };

            if (this.$.data('kontroled')) return;
            this.$.data('kontroled', true);

            this.extend();
            this.o = $.extend(
                {
                    // Config
                    min: this.$.data('min') || 0,
                    max: this.$.data('max') || 100,
                    stopper: true,
                    readOnly: this.$.data('readonly'),

                    // UI
                    cursor: (this.$.data('cursor') === true && 30)
                                || this.$.data('cursor')
                                || 0,
                    thickness: this.$.data('thickness') || 0.35,
                    lineCap: this.$.data('linecap') || 'butt',
                    width: this.$.data('width') || 200,
                    height: this.$.data('height') || 200,
                    displayInput: this.$.data('displayinput') == null || this.$.data('displayinput'),
                    displayPrevious: this.$.data('displayprevious'),
                    fgColor: this.$.data('fgcolor') || '#333',
                    inputColor: this.$.data('inputcolor') || this.$.data('fgcolor') || '#333',
                    inline: false,
                    step: this.$.data('step') || 1,

                    // Hooks
                    draw: null, // function () {}
                    change: null, // function (value) {}
                    cancel: null, // function () {}
                    release: null // function (value) {}
                }, this.o
            );

            // routing value
            if (this.$.is('fieldset')) {

                // fieldset = array of integer
                this.v = {};
                this.i = this.$.find('input')
                this.i.each(function (k) {
                    var $this = $(this);
                    s.i[k] = $this;
                    s.v[k] = $this.val();

                    $this.bind(
                        'change'
                        , function () {
                            var val = {};
                            val[k] = $this.val();
                            s.val(val);
                        }
                    );
                });
                this.$.find('legend').remove();

            } else {
                // input = integer
                this.i = this.$;
                this.v = this.$.val();
                (this.v == '') && (this.v = this.o.min);

                this.$.bind(
                    'change'
                    , function () {
                        s.val(s._validate(s.$.val()));
                    }
                );
            }

            (!this.o.displayInput) && this.$.hide();

            this.$c = $('<canvas width="' +
                            this.o.width + 'px" height="' +
                            this.o.height + 'px" style="opacity: .8"></canvas>');
            this.c = this.$c[0].getContext("2d");

            this.$
                .wrap($('<div style="' + (this.o.inline ? 'display:inline;' : '') +
                        'width:' + this.o.width + 'px;height:' +
                        this.o.height + 'px;"></div>'))
                .before(this.$c);

            if (this.v instanceof Object) {
                this.cv = {};
                this.copy(this.v, this.cv);
            } else {
                this.cv = this.v;
            }

            this.$
                .bind("configure", cf)
                .parent()
                .bind("configure", cf);

            this._listen()
                ._configure()
                ._xy()
                .init();

            this.isInit = true;

            this._draw();

            return this;
        };

        this._draw = function () {

            // canvas pre-rendering
            var d = true,
                c = document.createElement('canvas');

            c.width = s.o.width;
            c.height = s.o.height;
            s.g = c.getContext('2d');

            s.clear();

            s.dH
            && (d = s.dH());

            (d !== false) && s.draw();

            s.c.drawImage(c, 0, 0);
            c = null;
        };

        this._touch = function (e) {

            var touchMove = function (e) {

                var v = s.xy2val(
                            e.originalEvent.touches[s.t].pageX,
                            e.originalEvent.touches[s.t].pageY
                            );

                if (v == s.cv) return;

                if (
                    s.cH
                    && (s.cH(v) === false)
                ) return;


                s.change(s._validate(v));
                s._draw();
            };

            // get touches index
            this.t = k.c.t(e);

            // First touch
            touchMove(e);

            // Touch events listeners
            k.c.d
                .bind("touchmove.k", touchMove)
                .bind(
                    "touchend.k"
                    , function () {
                        k.c.d.unbind('touchmove.k touchend.k');

                        if (
                            s.rH
                            && (s.rH(s.cv) === false)
                        ) return;

                        s.val(s.cv);
                    }
                );

            return this;
        };

        this._mouse = function (e) {

            var mouseMove = function (e) {
                var v = s.xy2val(e.pageX, e.pageY);
                if (v == s.cv) return;

                if (
                    s.cH
                    && (s.cH(v) === false)
                ) return;

                s.change(s._validate(v));
                s._draw();
            };

            // First click
            mouseMove(e);

            // Mouse events listeners
            k.c.d
                .bind("mousemove.k", mouseMove)
                .bind(
            // Escape key cancel current change
                    "keyup.k"
                    , function (e) {
                        if (e.keyCode === 27) {
                            k.c.d.unbind("mouseup.k mousemove.k keyup.k");

                            if (
                                s.eH
                                && (s.eH() === false)
                            ) return;

                            s.cancel();
                        }
                    }
                )
                .bind(
                    "mouseup.k"
                    , function (e) {
                        k.c.d.unbind('mousemove.k mouseup.k keyup.k');

                        if (
                            s.rH
                            && (s.rH(s.cv) === false)
                        ) return;

                        s.val(s.cv);
                    }
                );

            return this;
        };

        this._xy = function () {
            var o = this.$c.offset();
            this.x = o.left;
            this.y = o.top;
            return this;
        };

        this._listen = function () {

            if (!this.o.readOnly) {
                this.$c
                    .bind(
                        "mousedown"
                        , function (e) {
                            e.preventDefault();
                            s._xy()._mouse(e);
                        }
                    )
                    .bind(
                        "touchstart"
                        , function (e) {
                            e.preventDefault();
                            s._xy()._touch(e);
                        }
                    );
                this.listen();
            } else {
                this.$.attr('readonly', 'readonly');
            }

            return this;
        };

        this._configure = function () {

            // Hooks
            if (this.o.draw) this.dH = this.o.draw;
            if (this.o.change) this.cH = this.o.change;
            if (this.o.cancel) this.eH = this.o.cancel;
            if (this.o.release) this.rH = this.o.release;

            if (this.o.displayPrevious) {
                this.pColor = this.h2rgba(this.o.fgColor, "0.4");
                this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
            } else {
                this.fgColor = this.o.fgColor;
            }

            return this;
        };

        this._clear = function () {
            this.$c[0].width = this.$c[0].width;
        };

        this._validate = function (v) {
            return (~ ~(((v < 0) ? -0.5 : 0.5) + (v / this.o.step))) * this.o.step;
        };

        // Abstract methods
        this.listen = function () { }; // on start, one time
        this.extend = function () { }; // each time configure triggered
        this.init = function () { }; // each time configure triggered
        this.change = function (v) { }; // on change
        this.val = function (v) { }; // on release
        this.xy2val = function (x, y) { }; //
        this.draw = function () { }; // on change / on release
        this.clear = function () { this._clear(); };

        // Utils
        this.h2rgba = function (h, a) {
            var rgb;
            h = h.substring(1, 7)
            rgb = [parseInt(h.substring(0, 2), 16)
                   , parseInt(h.substring(2, 4), 16)
                   , parseInt(h.substring(4, 6), 16)];
            return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
        };

        this.copy = function (f, t) {
            for (var i in f) { t[i] = f[i]; }
        };
    };


    /**
    * k.Dial
    */
    k.Dial = function () {
        k.o.call(this);

        this.startAngle = null;
        this.xy = null;
        this.radius = null;
        this.lineWidth = null;
        this.cursorExt = null;
        this.w2 = null;
        this.PI2 = 2 * Math.PI;

        this.extend = function () {
            this.o = $.extend(
                {
                    bgColor: this.$.data('bgcolor') || '#EEEEEE',
                    angleOffset: this.$.data('angleoffset') || 0,
                    angleArc: this.$.data('anglearc') || 360,
                    inline: true
                }, this.o
            );
        };

        this.val = function (v) {
            if (null != v) {
                this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
                this.v = this.cv;
                this.$.val(this.v);
                this._draw();
            } else {
                return this.v;
            }
        };

        this.xy2val = function (x, y) {
            var a, ret;

            a = Math.atan2(
                        x - (this.x + this.w2)
                        , -(y - this.y - this.w2)
                    ) - this.angleOffset;

            if (this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
                // if isset angleArc option, set to min if .5 under min
                a = 0;
            } else if (a < 0) {
                a += this.PI2;
            }

            ret = ~ ~(0.5 + (a * (this.o.max - this.o.min) / this.angleArc))
                    + this.o.min;

            this.o.stopper
            && (ret = max(min(ret, this.o.max), this.o.min));

            return ret;
        };

        this.listen = function () {
            // bind MouseWheel
            var s = this,
                mw = function (e) {
                    e.preventDefault();
                    var ori = e.originalEvent
                                , deltaX = ori.detail || ori.wheelDeltaX
                                , deltaY = ori.detail || ori.wheelDeltaY
                                , v = parseInt(s.$.val()) + (deltaX > 0 || deltaY > 0 ? s.o.step : deltaX < 0 || deltaY < 0 ? -s.o.step : 0);

                    if (
                                s.cH
                                && (s.cH(v) === false)
                            ) return;

                    s.val(v);
                }
                , kval, to, m = 1, kv = { 37: -s.o.step, 38: s.o.step, 39: s.o.step, 40: -s.o.step };

            this.$
                .bind(
                    "keydown"
                    , function (e) {
                        var kc = e.keyCode;

                        // numpad support
                        if (kc >= 96 && kc <= 105) {
                            kc = e.keyCode = kc - 48;
                        }

                        kval = parseInt(String.fromCharCode(kc));

                        if (isNaN(kval)) {

                            (kc !== 13)         // enter
                            && (kc !== 8)       // bs
                            && (kc !== 9)       // tab
                            && (kc !== 189)     // -
                            && e.preventDefault();

                            // arrows
                            if ($.inArray(kc, [37, 38, 39, 40]) > -1) {
                                e.preventDefault();

                                var v = parseInt(s.$.val()) + kv[kc] * m;

                                s.o.stopper
                                && (v = max(min(v, s.o.max), s.o.min));

                                s.change(v);
                                s._draw();

                                // long time keydown speed-up
                                to = window.setTimeout(
                                    function () { m *= 2; }
                                    , 30
                                );
                            }
                        }
                    }
                )
                .bind(
                    "keyup"
                    , function (e) {
                        if (isNaN(kval)) {
                            if (to) {
                                window.clearTimeout(to);
                                to = null;
                                m = 1;
                                s.val(s.$.val());
                            }
                        } else {
                            // kval postcond
                            (s.$.val() > s.o.max && s.$.val(s.o.max))
                            || (s.$.val() < s.o.min && s.$.val(s.o.min));
                        }

                    }
                );

            this.$c.bind("mousewheel DOMMouseScroll", mw);
            this.$.bind("mousewheel DOMMouseScroll", mw)
        };

        this.init = function () {

            if (
                this.v < this.o.min
                || this.v > this.o.max
            ) this.v = this.o.min;

            this.$.val(this.v);
            this.w2 = this.o.width / 2;
            this.cursorExt = this.o.cursor / 100;
            this.xy = this.w2;
            this.lineWidth = this.xy * this.o.thickness;
            this.lineCap = this.o.lineCap;
            this.radius = this.xy - this.lineWidth / 2;

            this.o.angleOffset
            && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);

            this.o.angleArc
            && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);

            // deg to rad
            this.angleOffset = this.o.angleOffset * Math.PI / 180;
            this.angleArc = this.o.angleArc * Math.PI / 180;

            // compute start and end angles
            this.startAngle = 1.5 * Math.PI + this.angleOffset;
            this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;

            var s = max(
                            String(Math.abs(this.o.max)).length
                            , String(Math.abs(this.o.min)).length
                            , 2
                            ) + 2;

            this.o.displayInput
                && this.i.css({
                    'width': ((this.o.width / 2 + 4) >> 0) + 'px'
                        , 'height': ((this.o.width / 3) >> 0) + 'px'
                        , 'position': 'absolute'
                        , 'vertical-align': 'middle'
                        , 'margin-top': ((this.o.width / 3) >> 0) + 'px'
                        , 'margin-left': '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px'
                        , 'border': 0
                        , 'background': 'none'
                        , 'font': 'bold ' + ((this.o.width / s) >> 0) + 'px Arial'
                        , 'text-align': 'center'
                        , 'color': this.o.inputColor || this.o.fgColor
                        , 'padding': '0px'
                        , '-webkit-appearance': 'none'
                })
                || this.i.css({
                    'width': '0px'
                        , 'visibility': 'hidden'
                });

        };

        this.change = function (v) {
            this.cv = v;
            this.$.val(v);
        };

        this.angle = function (v) {
            return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
        };

        this.draw = function () {

            var c = this.g,                 // context
                a = this.angle(this.cv)    // Angle
                , sat = this.startAngle     // Start angle
                , eat = sat + a             // End angle
                , sa, ea                    // Previous angles
                , r = 1;

            c.lineWidth = this.lineWidth;

            c.lineCap = this.lineCap;

            this.o.cursor
                && (sat = eat - this.cursorExt)
                && (eat = eat + this.cursorExt);

            c.beginPath();
            c.strokeStyle = this.o.bgColor;
            c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
            c.stroke();

            if (this.o.displayPrevious) {
                ea = this.startAngle + this.angle(this.v);
                sa = this.startAngle;
                this.o.cursor
                    && (sa = ea - this.cursorExt)
                    && (ea = ea + this.cursorExt);

                c.beginPath();
                c.strokeStyle = this.pColor;
                c.arc(this.xy, this.xy, this.radius, sa, ea, false);
                c.stroke();
                r = (this.cv == this.v);
            }

            c.beginPath();
            c.strokeStyle = r ? this.o.fgColor : this.fgColor;
            c.arc(this.xy, this.xy, this.radius, sat, eat, false);
            c.stroke();
        };

        this.cancel = function () {
            this.val(this.v);
        };
    };

    $.fn.dial = $.fn.knob = function (o) {
        return this.each(
            function () {
                var d = new k.Dial();
                d.o = o;
                d.$ = $(this);
                d.run();
            }
        ).parent();
    };

})(jQuery);
(function () {
    var Kudoable,
    __bind = function (fn, me) { return function () { return fn.apply(me, arguments); }; };

    Kudoable = (function () {
        function Kudoable(element) {
            this.element = element;
            this.unkudo = __bind(this.unkudo, this);
            this.complete = __bind(this.complete, this);
            this.end = __bind(this.end, this);
            this.start = __bind(this.start, this);
			this.click = __bind(this.click, this);
            this.bindEvents();
            this.counter = $('.count .num', this.element);
            this.element.data('kudoable', this);
        }

        Kudoable.prototype.bindEvents = function () {
            //this.element.mouseenter(this.start);
            //this.element.mouseleave(this.end);
            //this.element.click(this.unkudo);			
			this.element.click(this.click);			
            $(this.element).on('touchstart', this.element, this.start);
            return $(this.element).on('touchend', this.element, this.end);
        };

        Kudoable.prototype.isKudoable = function () {
            return this.element.hasClass('kudoable');
        };

        Kudoable.prototype.isKudod = function () {
            return this.element.hasClass('complete');
        };
		
		Kudoable.prototype.click = function (event) {
			if (this.isKudoable() && !this.isKudod()) {
				this.start();
			}else{
				this.unkudo(event);
			}
		};

        Kudoable.prototype.start = function () {
            if (this.isKudoable() && !this.isKudod()) {
                this.element.trigger('kudo:active');
                this.element.addClass('active');
                return this.timer = setTimeout(this.complete, 700);
            }
        };

        Kudoable.prototype.end = function () {
            if (this.isKudoable() && !this.isKudod()) {
                this.element.trigger('kudo:inactive');
                this.element.removeClass('active');
                if (this.timer != null) {
                    return clearTimeout(this.timer);
                }
            }
        };

        Kudoable.prototype.complete = function () {
            this.end();
            this.incrementCount();
            this.element.addClass('complete');
            return this.element.trigger('kudo:added');
        };

        Kudoable.prototype.unkudo = function (event) {
            event.preventDefault();
            if (this.isKudod()) {
                this.decrementCount();
                this.element.removeClass('complete');
                return this.element.trigger('kudo:removed');
            }
        };

        Kudoable.prototype.setCount = function (count) {
            return this.counter.html(count);
        };

        Kudoable.prototype.currentCount = function () {
            return parseInt(this.counter.html());
        };

        Kudoable.prototype.incrementCount = function () {
            return this.setCount(this.currentCount() + 1);
        };

        Kudoable.prototype.decrementCount = function () {
            return this.setCount(this.currentCount() - 1);
        };

        return Kudoable;

    })();

    jQuery(function ($) {
        return $.fn.kudoable = function () {
            return this.each(function () {
                return new Kudoable($(this));
            });
        };
    });

}).call(this);

(function($, window, document, undefined) {

    'use strict';

    var defaults = {

        mode: 'lg-slide',

        // Ex : 'ease'
        cssEasing: 'ease',

        //'for jquery animation'
        easing: 'linear',
        speed: 600,
        height: '100%',
        width: '100%',
        addClass: '',
        startClass: 'lg-start-zoom',
        backdropDuration: 150,
        hideBarsDelay: 6000,

        useLeft: false,

        closable: true,
        loop: true,
        escKey: true,
        keyPress: true,
        controls: true,
        slideEndAnimatoin: true,
        hideControlOnEnd: false,
        mousewheel: true,

        // .lg-item || '.lg-sub-html'
        appendSubHtmlTo: '.lg-sub-html',

        /**
         * @desc number of preload slides
         * will exicute only after the current slide is fully loaded.
         *
         * @ex you clicked on 4th image and if preload = 1 then 3rd slide and 5th
         * slide will be loaded in the background after the 4th slide is fully loaded..
         * if preload is 2 then 2nd 3rd 5th 6th slides will be preloaded.. ... ...
         *
         */
        preload: 1,
        showAfterLoad: true,
        selector: '',
        selectWithin: '',
        nextHtml: '',
        prevHtml: '',

        // 0, 1
        index: false,

        iframeMaxWidth: '100%',

        download: true,
        counter: true,
        appendCounterTo: '.lg-toolbar',

        swipeThreshold: 50,
        enableSwipe: true,
        enableDrag: true,

        dynamic: false,
        dynamicEl: [],
        galleryId: 1
    };

    function Plugin(element, options) {

        // Current lightGallery element
        this.el = element;

        // Current jquery element
        this.$el = $(element);

        // lightGallery settings
        this.s = $.extend({}, defaults, options);

        // When using dynamic mode, ensure dynamicEl is an array
        if (this.s.dynamic && this.s.dynamicEl !== 'undefined' && this.s.dynamicEl.constructor === Array && !this.s.dynamicEl.length) {
            throw ('When using dynamic mode, you must also define dynamicEl as an Array.');
        }

        // lightGallery modules
        this.modules = {};

        // false when lightgallery complete first slide;
        this.lGalleryOn = false;

        this.lgBusy = false;

        // Timeout function for hiding controls;
        this.hideBartimeout = false;

        // To determine browser supports for touch events;
        this.isTouch = ('ontouchstart' in document.documentElement);

        // Disable hideControlOnEnd if sildeEndAnimation is true
        if (this.s.slideEndAnimatoin) {
            this.s.hideControlOnEnd = false;
        }

        // Gallery items
        if (this.s.dynamic) {
            this.$items = this.s.dynamicEl;
        } else {
            if (this.s.selector === 'this') {
                this.$items = this.$el;
            } else if (this.s.selector !== '') {
                if (this.s.selectWithin) {
                    this.$items = $(this.s.selectWithin).find(this.s.selector);
                } else {
                    this.$items = this.$el.find($(this.s.selector));
                }
            } else {
                this.$items = this.$el.children();
            }
        }

        // .lg-item
        this.$slide = '';

        // .lg-outer
        this.$outer = '';

        this.init();

        return this;
    }

    Plugin.prototype.init = function() {

        var _this = this;

        // s.preload should not be more than $item.length
        if (_this.s.preload > _this.$items.length) {
            _this.s.preload = _this.$items.length;
        }

        // if dynamic option is enabled execute immediately
        var _hash = window.location.hash;
        if (_hash.indexOf('lg=' + this.s.galleryId) > 0) {

            _this.index = parseInt(_hash.split('&slide=')[1], 10);

            $('body').addClass('lg-from-hash');
            if (!$('body').hasClass('lg-on')) {
                setTimeout(function() {
                    _this.build(_this.index);
                    $('body').addClass('lg-on');
                });
            }
        }

        if (_this.s.dynamic) {

            _this.$el.trigger('onBeforeOpen.lg');

            _this.index = _this.s.index || 0;

            // prevent accidental double execution
            if (!$('body').hasClass('lg-on')) {
                setTimeout(function() {
                    _this.build(_this.index);
                    $('body').addClass('lg-on');
                });
            }
        } else {

            // Using different namespace for click because click event should not unbind if selector is same object('this')
            _this.$items.on('click.lgcustom', function(event) {

                // For IE8
                try {
                    event.preventDefault();
                    event.preventDefault();
                } catch (er) {
                    event.returnValue = false;
                }

                _this.$el.trigger('onBeforeOpen.lg');

                _this.index = _this.s.index || _this.$items.index(this);

                // prevent accidental double execution
                if (!$('body').hasClass('lg-on')) {
                    _this.build(_this.index);
                    $('body').addClass('lg-on');
                }
            });
        }

    };

    Plugin.prototype.build = function(index) {

        var _this = this;

        _this.structure();

        // module constructor
        $.each($.fn.lightGallery.modules, function(key) {
            _this.modules[key] = new $.fn.lightGallery.modules[key](_this.el);
        });

        // initiate slide function
        _this.slide(index, false, false);

        if (_this.s.keyPress) {
            _this.keyPress();
        }

        if (_this.$items.length > 1) {

            _this.arrow();

            setTimeout(function() {
                _this.enableDrag();
                _this.enableSwipe();
            }, 50);

            if (_this.s.mousewheel) {
                _this.mousewheel();
            }
        }

        _this.counter();

        _this.closeGallery();

        _this.$el.trigger('onAfterOpen.lg');

        // Hide controllers if mouse doesn't move for some period
        _this.$outer.on('mousemove.lg click.lg touchstart.lg', function() {

            _this.$outer.removeClass('lg-hide-items');

            clearTimeout(_this.hideBartimeout);

            // Timeout will be cleared on each slide movement also
            _this.hideBartimeout = setTimeout(function() {
                _this.$outer.addClass('lg-hide-items');
            }, _this.s.hideBarsDelay);

        });

    };

    Plugin.prototype.structure = function() {
        var list = '';
        var controls = '';
        var i = 0;
        var subHtmlCont = '';
        var template;
        var _this = this;

        $('body').append('<div class="lg-backdrop"></div>');
        $('.lg-backdrop').css('transition-duration', this.s.backdropDuration + 'ms');

        // Create gallery items
        for (i = 0; i < this.$items.length; i++) {
            list += '<div class="lg-item"></div>';
        }

        // Create controlls
        if (this.s.controls && this.$items.length > 1) {
            controls = '<div class="lg-actions">' +
                '<div class="lg-prev lg-icon">' + this.s.prevHtml + '</div>' +
                '<div class="lg-next lg-icon">' + this.s.nextHtml + '</div>' +
                '</div>';
        }

        if (this.s.appendSubHtmlTo === '.lg-sub-html') {
            subHtmlCont = '<div class="lg-sub-html"></div>';
        }

        template = '<div class="lg-outer ' + this.s.addClass + ' ' + this.s.startClass + '">' +
            '<div class="lg" style="width:' + this.s.width + '; height:' + this.s.height + '">' +
            '<div class="lg-inner">' + list + '</div>' +
            '<div class="lg-toolbar group">' +
            '<span class="lg-close lg-icon"></span>' +
            '</div>' +
            controls +
            subHtmlCont +
            '</div>' +
            '</div>';

        $('body').append(template);
        this.$outer = $('.lg-outer');
        this.$slide = this.$outer.find('.lg-item');

        if (this.s.useLeft) {
            this.$outer.addClass('lg-use-left');

            // Set mode lg-slide if use left is true;
            this.s.mode = 'lg-slide';
        } else {
            this.$outer.addClass('lg-use-css3');
        }

        // For fixed height gallery
        _this.setTop();
        $(window).on('resize.lg orientationchange.lg', function() {
            setTimeout(function() {
                _this.setTop();
            }, 100);
        });

        // add class lg-current to remove initial transition
        this.$slide.eq(this.index).addClass('lg-current');

        // add Class for css support and transition mode
        if (this.doCss()) {
            this.$outer.addClass('lg-css3');
        } else {
            this.$outer.addClass('lg-css');

            // Set speed 0 because no animation will happen if browser doesn't support css3
            this.s.speed = 0;
        }

        this.$outer.addClass(this.s.mode);

        if (this.s.enableDrag && this.$items.length > 1) {
            this.$outer.addClass('lg-grab');
        }

        if (this.s.showAfterLoad) {
            this.$outer.addClass('lg-show-after-load');
        }

        if (this.doCss()) {
            var $inner = this.$outer.find('.lg-inner');
            $inner.css('transition-timing-function', this.s.cssEasing);
            $inner.css('transition-duration', this.s.speed + 'ms');
        }

        $('.lg-backdrop').addClass('in');

        setTimeout(function() {
            _this.$outer.addClass('lg-visible');
        }, this.s.backdropDuration);

        if (this.s.download) {
            this.$outer.find('.lg-toolbar').append('<a id="lg-download" target="_blank" download class="lg-download lg-icon"></a>');
        }

        // Store the current scroll top value to scroll back after closing the gallery..
        this.prevScrollTop = $(window).scrollTop();

    };

    // For fixed height gallery
    Plugin.prototype.setTop = function() {
        if (this.s.height !== '100%') {
            var wH = $(window).height();
            var top = (wH - parseInt(this.s.height, 10)) / 2;
            var $lGallery = this.$outer.find('.lg');
            if (wH >= parseInt(this.s.height, 10)) {
                $lGallery.css('top', top + 'px');
            } else {
                $lGallery.css('top', '0px');
            }
        }
    };

    // Find css3 support
    Plugin.prototype.doCss = function() {
        // check for css animation support
        var support = function() {
            var transition = ['transition', 'MozTransition', 'WebkitTransition', 'OTransition', 'msTransition', 'KhtmlTransition'];
            var root = document.documentElement;
            var i = 0;
            for (i = 0; i < transition.length; i++) {
                if (transition[i] in root.style) {
                    return true;
                }
            }
        };

        if (support()) {
            return true;
        }

        return false;
    };

    /**
     *  @desc Check the given src is video
     *  @param {String} src
     *  @return {Object} video type
     *  Ex:{ youtube  :  ["//www.youtube.com/watch?v=c0asJgSyxcY", "c0asJgSyxcY"] }
     */
    Plugin.prototype.isVideo = function(src, index) {

        var html;
        if (this.s.dynamic) {
            html = this.s.dynamicEl[index].html;
        } else {
            html = this.$items.eq(index).attr('data-html');
        }

        if (!src && html) {
            return {
                html5: true
            };
        }

        var youtube = src.match(/\/\/(?:www\.)?youtu(?:\.be|be\.com)\/(?:watch\?v=|embed\/)?([a-z0-9\-\_\%]+)/i);
        var vimeo = src.match(/\/\/(?:www\.)?vimeo.com\/([0-9a-z\-_]+)/i);
        var dailymotion = src.match(/\/\/(?:www\.)?dai.ly\/([0-9a-z\-_]+)/i);
        var vk = src.match(/\/\/(?:www\.)?(?:vk\.com|vkontakte\.ru)\/(?:video_ext\.php\?)(.*)/i);

        if (youtube) {
            return {
                youtube: youtube
            };
        } else if (vimeo) {
            return {
                vimeo: vimeo
            };
        } else if (dailymotion) {
            return {
                dailymotion: dailymotion
            };
        } else if (vk) {
            return {
                vk: vk
            };
        }
    };

    /**
     *  @desc Create image counter
     *  Ex: 1/10
     */
    Plugin.prototype.counter = function() {
        if (this.s.counter) {
            $(this.s.appendCounterTo).append('<div id="lg-counter"><span id="lg-counter-current">' + (parseInt(this.index, 10) + 1) + '</span> / <span id="lg-counter-all">' + this.$items.length + '</span></div>');
        }
    };

    /**
     *  @desc add sub-html into the slide
     *  @param {Number} index - index of the slide
     */
    Plugin.prototype.addHtml = function(index) {
        var subHtml = null;
        var subHtmlUrl;
        if (this.s.dynamic) {
            if (this.s.dynamicEl[index].subHtmlUrl) {
                subHtmlUrl = this.s.dynamicEl[index].subHtmlUrl;
            } else {
                subHtml = this.s.dynamicEl[index].subHtml;
            }
        } else {
            if (this.$items.eq(index).attr('data-sub-html-url')) {
                subHtmlUrl = this.$items.eq(index).attr('data-sub-html-url');
            } else {
                subHtml = this.$items.eq(index).attr('data-sub-html');
            }
        }

        if (!subHtmlUrl) {
            if (typeof subHtml !== 'undefined' && subHtml !== null) {

                // get first letter of subhtml
                // if first letter starts with . or # get the html form the jQuery object
                var fL = subHtml.substring(0, 1);
                if (fL === '.' || fL === '#') {
                    subHtml = $(subHtml).html();
                } else {
                    subHtml = subHtml;
                }
            } else {
                subHtml = '';
            }
        }

        if (this.s.appendSubHtmlTo === '.lg-sub-html') {

            if (subHtmlUrl) {
                this.$outer.find(this.s.appendSubHtmlTo).load(subHtmlUrl);
            } else {
                this.$outer.find(this.s.appendSubHtmlTo).html(subHtml);
            }

        } else {

            if (subHtmlUrl) {
                this.$slide.eq(index).load(subHtmlUrl);
            } else {
                this.$slide.eq(index).append(subHtml);
            }
        }

        // Add lg-empty-html class if title doesn't exist
        if (typeof subHtml !== 'undefined' && subHtml !== null) {
            if (subHtml === '') {
                this.$outer.find(this.s.appendSubHtmlTo).addClass('lg-empty-html');
            } else {
                this.$outer.find(this.s.appendSubHtmlTo).removeClass('lg-empty-html');
            }
        }

        this.$el.trigger('onAfterAppendSubHtml.lg', [index]);
    };

    /**
     *  @desc Preload slides
     *  @param {Number} index - index of the slide
     */
    Plugin.prototype.preload = function(index) {
        var i = 1;
        var j = 1;
        for (i = 1; i <= this.s.preload; i++) {
            if (i >= this.$items.length - index) {
                break;
            }

            this.loadContent(index + i, false, 0);
        }

        for (j = 1; j <= this.s.preload; j++) {
            if (index - j < 0) {
                break;
            }

            this.loadContent(index - j, false, 0);
        }
    };

    /**
     *  @desc Load slide content into slide.
     *  @param {Number} index - index of the slide.
     *  @param {Boolean} rec - if true call loadcontent() function again.
     *  @param {Boolean} delay - delay for adding complete class. it is 0 except first time.
     */
    Plugin.prototype.loadContent = function(index, rec, delay) {

        var _this = this;
        var _hasPoster = false;
        var _$img;
        var _src;
        var _poster;
        var _srcset;
        var _sizes;
        var _html;
        var getResponsiveSrc = function(srcItms) {
            var rsWidth = [];
            var rsSrc = [];
            for (var i = 0; i < srcItms.length; i++) {
                var __src = srcItms[i].split(' ');

                // Manage empty space
                if (__src[0] === '') {
                    __src.splice(0, 1);
                }

                rsSrc.push(__src[0]);
                rsWidth.push(__src[1]);
            }

            var wWidth = $(window).width();
            for (var j = 0; j < rsWidth.length; j++) {
                if (parseInt(rsWidth[j], 10) > wWidth) {
                    _src = rsSrc[j];
                    break;
                }
            }
        };

        if (_this.s.dynamic) {

            if (_this.s.dynamicEl[index].poster) {
                _hasPoster = true;
                _poster = _this.s.dynamicEl[index].poster;
            }

            _html = _this.s.dynamicEl[index].html;
            _src = _this.s.dynamicEl[index].src;

            if (_this.s.dynamicEl[index].responsive) {
                var srcDyItms = _this.s.dynamicEl[index].responsive.split(',');
                getResponsiveSrc(srcDyItms);
            }

            _srcset = _this.s.dynamicEl[index].srcset;
            _sizes = _this.s.dynamicEl[index].sizes;

        } else {

            if (_this.$items.eq(index).attr('data-poster')) {
                _hasPoster = true;
                _poster = _this.$items.eq(index).attr('data-poster');
            }

            _html = _this.$items.eq(index).attr('data-html');
            _src = _this.$items.eq(index).attr('href') || _this.$items.eq(index).attr('data-src');

            if (_this.$items.eq(index).attr('data-responsive')) {
                var srcItms = _this.$items.eq(index).attr('data-responsive').split(',');
                getResponsiveSrc(srcItms);
            }

            _srcset = _this.$items.eq(index).attr('data-srcset');
            _sizes = _this.$items.eq(index).attr('data-sizes');

        }

        //if (_src || _srcset || _sizes || _poster) {

        var iframe = false;
        if (_this.s.dynamic) {
            if (_this.s.dynamicEl[index].iframe) {
                iframe = true;
            }
        } else {
            if (_this.$items.eq(index).attr('data-iframe') === 'true') {
                iframe = true;
            }
        }

        var _isVideo = _this.isVideo(_src, index);
        if (!_this.$slide.eq(index).hasClass('lg-loaded')) {
            if (iframe) {
                _this.$slide.eq(index).prepend('<div class="lg-video-cont" style="max-width:' + _this.s.iframeMaxWidth + '"><div class="lg-video"><iframe class="lg-object" frameborder="0" src="' + _src + '"  allowfullscreen="true"></iframe></div></div>');
            } else if (_hasPoster) {
                var videoClass = '';
                if (_isVideo && _isVideo.youtube) {
                    videoClass = 'lg-has-youtube';
                } else if (_isVideo && _isVideo.vimeo) {
                    videoClass = 'lg-has-vimeo';
                } else {
                    videoClass = 'lg-has-html5';
                }

                _this.$slide.eq(index).prepend('<div class="lg-video-cont ' + videoClass + ' "><div class="lg-video"><span class="lg-video-play"></span><img class="lg-object lg-has-poster" src="' + _poster + '" /></div></div>');

            } else if (_isVideo) {
                _this.$slide.eq(index).prepend('<div class="lg-video-cont "><div class="lg-video"></div></div>');
                _this.$el.trigger('hasVideo.lg', [index, _src, _html]);
            } else {
                _this.$slide.eq(index).prepend('<div class="lg-img-wrap"><img class="lg-object lg-image" src="' + _src + '" /></div>');
            }

            _this.$el.trigger('onAferAppendSlide.lg', [index]);

            _$img = _this.$slide.eq(index).find('.lg-object');
            if (_sizes) {
                _$img.attr('sizes', _sizes);
            }

            if (_srcset) {
                _$img.attr('srcset', _srcset);
                try {
                    picturefill({
                        elements: [_$img[0]]
                    });
                } catch (e) {
                    console.error('Make sure you have included Picturefill version 2');
                }
            }

            if (this.s.appendSubHtmlTo !== '.lg-sub-html') {
                _this.addHtml(index);
            }

            _this.$slide.eq(index).addClass('lg-loaded');
        }

        _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {

            // For first time add some delay for displaying the start animation.
            var _speed = 0;

            // Do not change the delay value because it is required for zoom plugin.
            // If gallery opened from direct url (hash) speed value should be 0
            if (delay && !$('body').hasClass('lg-from-hash')) {
                _speed = delay;
            }

            setTimeout(function() {
                _this.$slide.eq(index).addClass('lg-complete');
                _this.$el.trigger('onSlideItemLoad.lg', [index, delay || 0]);
            }, _speed);

        });

        // @todo check load state for html5 videos
        if (_isVideo && _isVideo.html5 && !_hasPoster) {
            _this.$slide.eq(index).addClass('lg-complete');
        }

        if (rec === true) {
            if (!_this.$slide.eq(index).hasClass('lg-complete')) {
                _this.$slide.eq(index).find('.lg-object').on('load.lg error.lg', function() {
                    _this.preload(index);
                });
            } else {
                _this.preload(index);
            }
        }

        //}
    };

    /**
    *   @desc slide function for lightgallery
        ** Slide() gets call on start
        ** ** Set lg.on true once slide() function gets called.
        ** Call loadContent() on slide() function inside setTimeout
        ** ** On first slide we do not want any animation like slide of fade
        ** ** So on first slide( if lg.on if false that is first slide) loadContent() should start loading immediately
        ** ** Else loadContent() should wait for the transition to complete.
        ** ** So set timeout s.speed + 50
    <=> ** loadContent() will load slide content in to the particular slide
        ** ** It has recursion (rec) parameter. if rec === true loadContent() will call preload() function.
        ** ** preload will execute only when the previous slide is fully loaded (images iframe)
        ** ** avoid simultaneous image load
    <=> ** Preload() will check for s.preload value and call loadContent() again accoring to preload value
        ** loadContent()  <====> Preload();

    *   @param {Number} index - index of the slide
    *   @param {Boolean} fromTouch - true if slide function called via touch event or mouse drag
    *   @param {Boolean} fromThumb - true if slide function called via thumbnail click
    */
    Plugin.prototype.slide = function(index, fromTouch, fromThumb) {

        var _prevIndex = this.$outer.find('.lg-current').index();
        var _this = this;

        // Prevent if multiple call
        // Required for hsh plugin
        if (_this.lGalleryOn && (_prevIndex === index)) {
            return;
        }

        var _length = this.$slide.length;
        var _time = _this.lGalleryOn ? this.s.speed : 0;
        var _next = false;
        var _prev = false;

        if (!_this.lgBusy) {

            if (this.s.download) {
                var _src;
                if (_this.s.dynamic) {
                    _src = _this.s.dynamicEl[index].downloadUrl !== false && (_this.s.dynamicEl[index].downloadUrl || _this.s.dynamicEl[index].src);
                } else {
                    _src = _this.$items.eq(index).attr('data-download-url') !== 'false' && (_this.$items.eq(index).attr('data-download-url') || _this.$items.eq(index).attr('href') || _this.$items.eq(index).attr('data-src'));

                }

                if (_src) {
                    $('#lg-download').attr('href', _src);
                    _this.$outer.removeClass('lg-hide-download');
                } else {
                    _this.$outer.addClass('lg-hide-download');
                }
            }

            this.$el.trigger('onBeforeSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);

            _this.lgBusy = true;

            clearTimeout(_this.hideBartimeout);

            // Add title if this.s.appendSubHtmlTo === lg-sub-html
            if (this.s.appendSubHtmlTo === '.lg-sub-html') {

                // wait for slide animation to complete
                setTimeout(function() {
                    _this.addHtml(index);
                }, _time);
            }

            this.arrowDisable(index);

            if (!fromTouch) {

                // remove all transitions
                _this.$outer.addClass('lg-no-trans');

                this.$slide.removeClass('lg-prev-slide lg-next-slide');

                if (index < _prevIndex) {
                    _prev = true;
                    if ((index === 0) && (_prevIndex === _length - 1) && !fromThumb) {
                        _prev = false;
                        _next = true;
                    }
                } else if (index > _prevIndex) {
                    _next = true;
                    if ((index === _length - 1) && (_prevIndex === 0) && !fromThumb) {
                        _prev = true;
                        _next = false;
                    }
                }

                if (_prev) {

                    //prevslide
                    this.$slide.eq(index).addClass('lg-prev-slide');
                    this.$slide.eq(_prevIndex).addClass('lg-next-slide');
                } else if (_next) {

                    // next slide
                    this.$slide.eq(index).addClass('lg-next-slide');
                    this.$slide.eq(_prevIndex).addClass('lg-prev-slide');
                }

                // give 50 ms for browser to add/remove class
                setTimeout(function() {
                    _this.$slide.removeClass('lg-current');

                    //_this.$slide.eq(_prevIndex).removeClass('lg-current');
                    _this.$slide.eq(index).addClass('lg-current');

                    // reset all transitions
                    _this.$outer.removeClass('lg-no-trans');
                }, 50);
            } else {

                var touchPrev = index - 1;
                var touchNext = index + 1;

                if ((index === 0) && (_prevIndex === _length - 1)) {

                    // next slide
                    touchNext = 0;
                    touchPrev = _length - 1;
                } else if ((index === _length - 1) && (_prevIndex === 0)) {

                    // prev slide
                    touchNext = 0;
                    touchPrev = _length - 1;
                }

                this.$slide.removeClass('lg-prev-slide lg-current lg-next-slide');
                _this.$slide.eq(touchPrev).addClass('lg-prev-slide');
                _this.$slide.eq(touchNext).addClass('lg-next-slide');
                _this.$slide.eq(index).addClass('lg-current');
            }

            if (_this.lGalleryOn) {
                setTimeout(function() {
                    _this.loadContent(index, true, 0);
                }, this.s.speed + 50);

                setTimeout(function() {
                    _this.lgBusy = false;
                    _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
                }, this.s.speed);

            } else {
                _this.loadContent(index, true, _this.s.backdropDuration);

                _this.lgBusy = false;
                _this.$el.trigger('onAfterSlide.lg', [_prevIndex, index, fromTouch, fromThumb]);
            }

            _this.lGalleryOn = true;

            if (this.s.counter) {
                $('#lg-counter-current').text(index + 1);
            }

        }

    };

    /**
     *  @desc Go to next slide
     *  @param {Boolean} fromTouch - true if slide function called via touch event
     */
    Plugin.prototype.goToNextSlide = function(fromTouch) {
        var _this = this;
        if (!_this.lgBusy) {
            if ((_this.index + 1) < _this.$slide.length) {
                _this.index++;
                _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
                _this.slide(_this.index, fromTouch, false);
            } else {
                if (_this.s.loop) {
                    _this.index = 0;
                    _this.$el.trigger('onBeforeNextSlide.lg', [_this.index]);
                    _this.slide(_this.index, fromTouch, false);
                } else if (_this.s.slideEndAnimatoin) {
                    _this.$outer.addClass('lg-right-end');
                    setTimeout(function() {
                        _this.$outer.removeClass('lg-right-end');
                    }, 400);
                }
            }
        }
    };

    /**
     *  @desc Go to previous slide
     *  @param {Boolean} fromTouch - true if slide function called via touch event
     */
    Plugin.prototype.goToPrevSlide = function(fromTouch) {
        var _this = this;
        if (!_this.lgBusy) {
            if (_this.index > 0) {
                _this.index--;
                _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
                _this.slide(_this.index, fromTouch, false);
            } else {
                if (_this.s.loop) {
                    _this.index = _this.$items.length - 1;
                    _this.$el.trigger('onBeforePrevSlide.lg', [_this.index, fromTouch]);
                    _this.slide(_this.index, fromTouch, false);
                } else if (_this.s.slideEndAnimatoin) {
                    _this.$outer.addClass('lg-left-end');
                    setTimeout(function() {
                        _this.$outer.removeClass('lg-left-end');
                    }, 400);
                }
            }
        }
    };

    Plugin.prototype.keyPress = function() {
        var _this = this;
        if (this.$items.length > 1) {
            $(window).on('keyup.lg', function(e) {
                if (_this.$items.length > 1) {
                    if (e.keyCode === 37) {
                        e.preventDefault();
                        _this.goToPrevSlide();
                    }

                    if (e.keyCode === 39) {
                        e.preventDefault();
                        _this.goToNextSlide();
                    }
                }
            });
        }

        $(window).on('keydown.lg', function(e) {
            if (_this.s.escKey === true && e.keyCode === 27) {
                e.preventDefault();
                if (!_this.$outer.hasClass('lg-thumb-open')) {
                    _this.destroy();
                } else {
                    _this.$outer.removeClass('lg-thumb-open');
                }
            }
        });
    };

    Plugin.prototype.arrow = function() {
        var _this = this;
        this.$outer.find('.lg-prev').on('click.lg', function() {
            _this.goToPrevSlide();
        });

        this.$outer.find('.lg-next').on('click.lg', function() {
            _this.goToNextSlide();
        });
    };

    Plugin.prototype.arrowDisable = function(index) {

        // Disable arrows if s.hideControlOnEnd is true
        if (!this.s.loop && this.s.hideControlOnEnd) {
            if ((index + 1) < this.$slide.length) {
                this.$outer.find('.lg-next').removeAttr('disabled').removeClass('disabled');
            } else {
                this.$outer.find('.lg-next').attr('disabled', 'disabled').addClass('disabled');
            }

            if (index > 0) {
                this.$outer.find('.lg-prev').removeAttr('disabled').removeClass('disabled');
            } else {
                this.$outer.find('.lg-prev').attr('disabled', 'disabled').addClass('disabled');
            }
        }
    };

    Plugin.prototype.setTranslate = function($el, xValue, yValue) {
        // jQuery supports Automatic CSS prefixing since jQuery 1.8.0
        if (this.s.useLeft) {
            $el.css('left', xValue);
        } else {
            $el.css({
                transform: 'translate3d(' + (xValue) + 'px, ' + yValue + 'px, 0px)'
            });
        }
    };

    Plugin.prototype.touchMove = function(startCoords, endCoords) {

        var distance = endCoords - startCoords;

        if (Math.abs(distance) > 15) {
            // reset opacity and transition duration
            this.$outer.addClass('lg-dragging');

            // move current slide
            this.setTranslate(this.$slide.eq(this.index), distance, 0);

            // move next and prev slide with current slide
            this.setTranslate($('.lg-prev-slide'), -this.$slide.eq(this.index).width() + distance, 0);
            this.setTranslate($('.lg-next-slide'), this.$slide.eq(this.index).width() + distance, 0);
        }
    };

    Plugin.prototype.touchEnd = function(distance) {
        var _this = this;

        // keep slide animation for any mode while dragg/swipe
        if (_this.s.mode !== 'lg-slide') {
            _this.$outer.addClass('lg-slide');
        }

        this.$slide.not('.lg-current, .lg-prev-slide, .lg-next-slide').css('opacity', '0');

        // set transition duration
        setTimeout(function() {
            _this.$outer.removeClass('lg-dragging');
            if ((distance < 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
                _this.goToNextSlide(true);
            } else if ((distance > 0) && (Math.abs(distance) > _this.s.swipeThreshold)) {
                _this.goToPrevSlide(true);
            } else if (Math.abs(distance) < 5) {

                // Trigger click if distance is less than 5 pix
                _this.$el.trigger('onSlideClick.lg');
            }

            _this.$slide.removeAttr('style');
        });

        // remove slide class once drag/swipe is completed if mode is not slide
        setTimeout(function() {
            if (!_this.$outer.hasClass('lg-dragging') && _this.s.mode !== 'lg-slide') {
                _this.$outer.removeClass('lg-slide');
            }
        }, _this.s.speed + 100);

    };

    Plugin.prototype.enableSwipe = function() {
        var _this = this;
        var startCoords = 0;
        var endCoords = 0;
        var isMoved = false;

        if (_this.s.enableSwipe && _this.isTouch && _this.doCss()) {

            _this.$slide.on('touchstart.lg', function(e) {
                if (!_this.$outer.hasClass('lg-zoomed') && !_this.lgBusy) {
                    e.preventDefault();
                    _this.manageSwipeClass();
                    startCoords = e.originalEvent.targetTouches[0].pageX;
                }
            });

            _this.$slide.on('touchmove.lg', function(e) {
                if (!_this.$outer.hasClass('lg-zoomed')) {
                    e.preventDefault();
                    endCoords = e.originalEvent.targetTouches[0].pageX;
                    _this.touchMove(startCoords, endCoords);
                    isMoved = true;
                }
            });

            _this.$slide.on('touchend.lg', function() {
                if (!_this.$outer.hasClass('lg-zoomed')) {
                    if (isMoved) {
                        isMoved = false;
                        _this.touchEnd(endCoords - startCoords);
                    } else {
                        _this.$el.trigger('onSlideClick.lg');
                    }
                }
            });
        }

    };

    Plugin.prototype.enableDrag = function() {
        var _this = this;
        var startCoords = 0;
        var endCoords = 0;
        var isDraging = false;
        var isMoved = false;
        if (_this.s.enableDrag && !_this.isTouch && _this.doCss()) {
            _this.$slide.on('mousedown.lg', function(e) {
                // execute only on .lg-object
                if (!_this.$outer.hasClass('lg-zoomed')) {
                    if ($(e.target).hasClass('lg-object') || $(e.target).hasClass('lg-video-play')) {
                        e.preventDefault();

                        if (!_this.lgBusy) {
                            _this.manageSwipeClass();
                            startCoords = e.pageX;
                            isDraging = true;

                            // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
                            _this.$outer.scrollLeft += 1;
                            _this.$outer.scrollLeft -= 1;

                            // *

                            _this.$outer.removeClass('lg-grab').addClass('lg-grabbing');

                            _this.$el.trigger('onDragstart.lg');
                        }

                    }
                }
            });

            $(window).on('mousemove.lg', function(e) {
                if (isDraging) {
                    isMoved = true;
                    endCoords = e.pageX;
                    _this.touchMove(startCoords, endCoords);
                    _this.$el.trigger('onDragmove.lg');
                }
            });

            $(window).on('mouseup.lg', function(e) {
                if (isMoved) {
                    isMoved = false;
                    _this.touchEnd(endCoords - startCoords);
                    _this.$el.trigger('onDragend.lg');
                } else if ($(e.target).hasClass('lg-object') || $(e.target).hasClass('lg-video-play')) {
                    _this.$el.trigger('onSlideClick.lg');
                }

                // Prevent execution on click
                if (isDraging) {
                    isDraging = false;
                    _this.$outer.removeClass('lg-grabbing').addClass('lg-grab');
                }
            });

        }
    };

    Plugin.prototype.manageSwipeClass = function() {
        var touchNext = this.index + 1;
        var touchPrev = this.index - 1;
        var length = this.$slide.length;
        if (this.s.loop) {
            if (this.index === 0) {
                touchPrev = length - 1;
            } else if (this.index === length - 1) {
                touchNext = 0;
            }
        }

        this.$slide.removeClass('lg-next-slide lg-prev-slide');
        if (touchPrev > -1) {
            this.$slide.eq(touchPrev).addClass('lg-prev-slide');
        }

        this.$slide.eq(touchNext).addClass('lg-next-slide');
    };

    Plugin.prototype.mousewheel = function() {
        var _this = this;
        _this.$outer.on('mousewheel.lg', function(e) {

            if (!e.deltaY) {
                return;
            }

            if (e.deltaY > 0) {
                _this.goToPrevSlide();
            } else {
                _this.goToNextSlide();
            }

            e.preventDefault();
        });

    };

    Plugin.prototype.closeGallery = function() {

        var _this = this;
        var mousedown = false;
        this.$outer.find('.lg-close').on('click.lg', function() {
            _this.destroy();
        });

        if (_this.s.closable) {

            // If you drag the slide and release outside gallery gets close on chrome
            // for preventing this check mousedown and mouseup happened on .lg-item or lg-outer
            _this.$outer.on('mousedown.lg', function(e) {

                if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap')) {
                    mousedown = true;
                } else {
                    mousedown = false;
                }

            });

            _this.$outer.on('mouseup.lg', function(e) {

                if ($(e.target).is('.lg-outer') || $(e.target).is('.lg-item ') || $(e.target).is('.lg-img-wrap') && mousedown) {
                    if (!_this.$outer.hasClass('lg-dragging')) {
                        _this.destroy();
                    }
                }

            });

        }

    };

    Plugin.prototype.destroy = function(d) {

        var _this = this;

        if (!d) {
            _this.$el.trigger('onBeforeClose.lg');
        }

        $(window).scrollTop(_this.prevScrollTop);

        /**
         * if d is false or undefined destroy will only close the gallery
         * plugins instance remains with the element
         *
         * if d is true destroy will completely remove the plugin
         */

        if (d) {
            if (!_this.s.dynamic) {
                // only when not using dynamic mode is $items a jquery collection
                this.$items.off('click.lg click.lgcustom');
            }

            $.removeData(_this.el, 'lightGallery');
        }

        // Unbind all events added by lightGallery
        this.$el.off('.lg.tm');

        // Distroy all lightGallery modules
        $.each($.fn.lightGallery.modules, function(key) {
            if (_this.modules[key]) {
                _this.modules[key].destroy();
            }
        });

        this.lGalleryOn = false;

        clearTimeout(_this.hideBartimeout);
        this.hideBartimeout = false;
        $(window).off('.lg');
        $('body').removeClass('lg-on lg-from-hash');

        if (_this.$outer) {
            _this.$outer.removeClass('lg-visible');
        }

        $('.lg-backdrop').removeClass('in');

        setTimeout(function() {
            if (_this.$outer) {
                _this.$outer.remove();
            }

            $('.lg-backdrop').remove();

            if (!d) {
                _this.$el.trigger('onCloseAfter.lg');
            }

        }, _this.s.backdropDuration + 50);
    };

    $.fn.lightGallery = function(options) {
        return this.each(function() {
            if (!$.data(this, 'lightGallery')) {
                $.data(this, 'lightGallery', new Plugin(this, options));
            } else {
                try {
                    $(this).data('lightGallery').init();
                } catch (err) {
                    console.error('lightGallery has not initiated properly');
                }
            }
        });
    };

    $.fn.lightGallery.modules = {};

})(jQuery, window, document);

(function($, window, document, undefined) {

    'use strict';

    var defaults = {
        scale: 1,
        zoom: true,
        enableZoomAfter: 300
    };

    var Zoom = function(element) {

        this.core = $(element).data('lightGallery');

        this.core.s = $.extend({}, defaults, this.core.s);

        if (this.core.s.zoom && this.core.doCss()) {
            this.init();

            // Store the zoomable timeout value just to clear it while closing
            this.zoomabletimeout = false;

            // Set the initial value center
            this.pageX = $(window).width() / 2;
            this.pageY = ($(window).height() / 2) + $(window).scrollTop();
        }

        return this;
    };

    Zoom.prototype.init = function() {

        var _this = this;
        var zoomIcons = '<span id="lg-zoom-in" class="lg-icon"></span><span id="lg-zoom-out" class="lg-icon"></span>';

        this.core.$outer.find('.lg-toolbar').append(zoomIcons);

        // Add zoomable class
        _this.core.$el.on('onSlideItemLoad.lg.tm.zoom', function(event, index, delay) {

            // delay will be 0 except first time
            var _speed = _this.core.s.enableZoomAfter + delay;

            // set _speed value 0 if gallery opened from direct url and if it is first slide
            if ($('body').hasClass('lg-from-hash') && delay) {

                // will execute only once
                _speed = 0;
            } else {

                // Remove lg-from-hash to enable starting animation.
                $('body').removeClass('lg-from-hash');
            }

            _this.zoomabletimeout = setTimeout(function() {
                _this.core.$slide.eq(index).addClass('lg-zoomable');
            }, _speed + 30);
        });

        var scale = 1;
        /**
         * @desc Image zoom
         * Translate the wrap and scale the image to get better user experience
         *
         * @param {String} scaleVal - Zoom decrement/increment value
         */
        var zoom = function(scaleVal) {

            var $image = _this.core.$outer.find('.lg-current .lg-image');
            var _x;
            var _y;

            // Find offset manually to avoid issue after zoom
            var offsetX = ($(window).width() - $image.width()) / 2;
            var offsetY = (($(window).height() - $image.height()) / 2) + $(window).scrollTop();

            _x = _this.pageX - offsetX;
            _y = _this.pageY - offsetY;

            var x = (scaleVal - 1) * (_x);
            var y = (scaleVal - 1) * (_y);

            $image.css('transform', 'scale3d(' + scaleVal + ', ' + scaleVal + ', 1)').attr('data-scale', scaleVal);

            $image.parent().css('transform', 'translate3d(-' + x + 'px, -' + y + 'px, 0)').attr('data-x', x).attr('data-y', y);
        };

        var callScale = function() {
            if (scale > 1) {
                _this.core.$outer.addClass('lg-zoomed');
            } else {
                _this.resetZoom();
            }

            if (scale < 1) {
                scale = 1;
            }

            zoom(scale);
        };

        var actualSize = function(event, $image, index) {
            var w = $image.width();
            var nw;
            if (_this.core.s.dynamic) {
                nw = _this.core.s.dynamicEl[index].width || $image[0].naturalWidth || w;
            } else {
                nw = _this.core.$items.eq(index).attr('data-width') || $image[0].naturalWidth || w;
            }

            var _scale;

            if (_this.core.$outer.hasClass('lg-zoomed')) {
                scale = 1;
            } else {
                if (nw > w) {
                    _scale = nw / w;
                    scale = _scale || 2;
                }
            }

            _this.pageX = event.pageX || event.originalEvent.targetTouches[0].pageX;
            _this.pageY = event.pageY || event.originalEvent.targetTouches[0].pageY;
            callScale();
            setTimeout(function() {
                _this.core.$outer.removeClass('lg-grabbing').addClass('lg-grab');
            }, 10);
        };

        var tapped = false;

        // event triggered after appending slide content
        _this.core.$el.on('onAferAppendSlide.lg.tm.zoom', function(event, index) {

            // Get the current element
            var $image = _this.core.$slide.eq(index).find('.lg-image');

            $image.on('dblclick', function(event) {
                actualSize(event, $image, index);
            });

            $image.on('touchstart', function(event) {
                if (!tapped) {
                    tapped = setTimeout(function() {
                        tapped = null;
                    }, 300);
                } else {
                    clearTimeout(tapped);
                    tapped = null;
                    actualSize(event, $image, index);
                }

                event.preventDefault();
            });

        });

        // Update zoom on resize and orientationchange
        $(window).on('resize.lg.zoom scroll.lg.zoom orientationchange.lg.zoom', function() {
            _this.pageX = $(window).width() / 2;
            _this.pageY = ($(window).height() / 2) + $(window).scrollTop();
            zoom(scale);
        });

        $('#lg-zoom-out').on('click.lg', function() {
            if (_this.core.$outer.find('.lg-current .lg-image').length) {
                scale -= _this.core.s.scale;
                callScale();
            }
        });

        $('#lg-zoom-in').on('click.lg', function() {
            if (_this.core.$outer.find('.lg-current .lg-image').length) {
                scale += _this.core.s.scale;
                callScale();
            }
        });

        // Reset zoom on slide change
        _this.core.$el.on('onBeforeSlide.lg.tm', function() {
            scale = 1;
            _this.resetZoom();
        });

        // Drag option after zoom
        if (!_this.core.isTouch) {
            _this.zoomDrag();
        }

        if (_this.core.isTouch) {
            _this.zoomSwipe();
        }

    };

    // Reset zoom effect
    Zoom.prototype.resetZoom = function() {
        this.core.$outer.removeClass('lg-zoomed');
        this.core.$slide.find('.lg-img-wrap').removeAttr('style data-x data-y');
        this.core.$slide.find('.lg-image').removeAttr('style data-scale');

        // Reset pagx pagy values to center
        this.pageX = $(window).width() / 2;
        this.pageY = ($(window).height() / 2) + $(window).scrollTop();
    };

    Zoom.prototype.zoomSwipe = function() {
        var _this = this;
        var startCoords = {};
        var endCoords = {};
        var isMoved = false;

        // Allow x direction drag
        var allowX = false;

        // Allow Y direction drag
        var allowY = false;

        _this.core.$slide.on('touchstart.lg', function(e) {

            if (_this.core.$outer.hasClass('lg-zoomed')) {
                var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object');

                allowY = $image.outerHeight() * $image.attr('data-scale') > _this.core.$outer.find('.lg').height();
                allowX = $image.outerWidth() * $image.attr('data-scale') > _this.core.$outer.find('.lg').width();
                if ((allowX || allowY)) {
                    e.preventDefault();
                    startCoords = {
                        x: e.originalEvent.targetTouches[0].pageX,
                        y: e.originalEvent.targetTouches[0].pageY
                    };
                }
            }

        });

        _this.core.$slide.on('touchmove.lg', function(e) {

            if (_this.core.$outer.hasClass('lg-zoomed')) {

                var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap');
                var distanceX;
                var distanceY;

                e.preventDefault();
                isMoved = true;

                endCoords = {
                    x: e.originalEvent.targetTouches[0].pageX,
                    y: e.originalEvent.targetTouches[0].pageY
                };

                // reset opacity and transition duration
                _this.core.$outer.addClass('lg-zoom-dragging');

                if (allowY) {
                    distanceY = (-Math.abs(_$el.attr('data-y'))) + (endCoords.y - startCoords.y);
                } else {
                    distanceY = -Math.abs(_$el.attr('data-y'));
                }

                if (allowX) {
                    distanceX = (-Math.abs(_$el.attr('data-x'))) + (endCoords.x - startCoords.x);
                } else {
                    distanceX = -Math.abs(_$el.attr('data-x'));
                }

                if ((Math.abs(endCoords.x - startCoords.x) > 15) || (Math.abs(endCoords.y - startCoords.y) > 15)) {
                    _$el.css('transform', 'translate3d(' + distanceX + 'px, ' + distanceY + 'px, 0)');
                }

            }

        });

        _this.core.$slide.on('touchend.lg', function() {
            if (_this.core.$outer.hasClass('lg-zoomed')) {
                if (isMoved) {
                    isMoved = false;
                    _this.core.$outer.removeClass('lg-zoom-dragging');
                    _this.touchendZoom(startCoords, endCoords, allowX, allowY);

                }
            }
        });

    };

    Zoom.prototype.zoomDrag = function() {

        var _this = this;
        var startCoords = {};
        var endCoords = {};
        var isDraging = false;
        var isMoved = false;

        // Allow x direction drag
        var allowX = false;

        // Allow Y direction drag
        var allowY = false;

        _this.core.$slide.on('mousedown.lg.zoom', function(e) {

            // execute only on .lg-object
            var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object');

            allowY = $image.outerHeight() * $image.attr('data-scale') > _this.core.$outer.find('.lg').height();
            allowX = $image.outerWidth() * $image.attr('data-scale') > _this.core.$outer.find('.lg').width();

            if (_this.core.$outer.hasClass('lg-zoomed')) {
                if ($(e.target).hasClass('lg-object') && (allowX || allowY)) {
                    e.preventDefault();
                    startCoords = {
                        x: e.pageX,
                        y: e.pageY
                    };

                    isDraging = true;

                    // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
                    _this.core.$outer.scrollLeft += 1;
                    _this.core.$outer.scrollLeft -= 1;

                    _this.core.$outer.removeClass('lg-grab').addClass('lg-grabbing');
                }
            }
        });

        $(window).on('mousemove.lg.zoom', function(e) {
            if (isDraging) {
                var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap');
                var distanceX;
                var distanceY;

                isMoved = true;
                endCoords = {
                    x: e.pageX,
                    y: e.pageY
                };

                // reset opacity and transition duration
                _this.core.$outer.addClass('lg-zoom-dragging');

                if (allowY) {
                    distanceY = (-Math.abs(_$el.attr('data-y'))) + (endCoords.y - startCoords.y);
                } else {
                    distanceY = -Math.abs(_$el.attr('data-y'));
                }

                if (allowX) {
                    distanceX = (-Math.abs(_$el.attr('data-x'))) + (endCoords.x - startCoords.x);
                } else {
                    distanceX = -Math.abs(_$el.attr('data-x'));
                }

                _$el.css('transform', 'translate3d(' + distanceX + 'px, ' + distanceY + 'px, 0)');
            }
        });

        $(window).on('mouseup.lg.zoom', function(e) {

            if (isDraging) {
                isDraging = false;
                _this.core.$outer.removeClass('lg-zoom-dragging');

                // Fix for chrome mouse move on click
                if (isMoved && ((startCoords.x !== endCoords.x) || (startCoords.y !== endCoords.y))) {
                    endCoords = {
                        x: e.pageX,
                        y: e.pageY
                    };
                    _this.touchendZoom(startCoords, endCoords, allowX, allowY);

                }

                isMoved = false;
            }

            _this.core.$outer.removeClass('lg-grabbing').addClass('lg-grab');

        });
    };

    Zoom.prototype.touchendZoom = function(startCoords, endCoords, allowX, allowY) {

        var _this = this;
        var _$el = _this.core.$slide.eq(_this.core.index).find('.lg-img-wrap');
        var $image = _this.core.$slide.eq(_this.core.index).find('.lg-object');
        var distanceX = (-Math.abs(_$el.attr('data-x'))) + (endCoords.x - startCoords.x);
        var distanceY = (-Math.abs(_$el.attr('data-y'))) + (endCoords.y - startCoords.y);
        var minY = (_this.core.$outer.find('.lg').height() - $image.outerHeight()) / 2;
        var maxY = Math.abs(($image.outerHeight() * Math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').height() + minY);
        var minX = (_this.core.$outer.find('.lg').width() - $image.outerWidth()) / 2;
        var maxX = Math.abs(($image.outerWidth() * Math.abs($image.attr('data-scale'))) - _this.core.$outer.find('.lg').width() + minX);

        if ((Math.abs(endCoords.x - startCoords.x) > 15) || (Math.abs(endCoords.y - startCoords.y) > 15)) {
            if (allowY) {
                if (distanceY <= -maxY) {
                    distanceY = -maxY;
                } else if (distanceY >= -minY) {
                    distanceY = -minY;
                }
            }

            if (allowX) {
                if (distanceX <= -maxX) {
                    distanceX = -maxX;
                } else if (distanceX >= -minX) {
                    distanceX = -minX;
                }
            }

            if (allowY) {
                _$el.attr('data-y', Math.abs(distanceY));
            } else {
                distanceY = -Math.abs(_$el.attr('data-y'));
            }

            if (allowX) {
                _$el.attr('data-x', Math.abs(distanceX));
            } else {
                distanceX = -Math.abs(_$el.attr('data-x'));
            }

            _$el.css('transform', 'translate3d(' + distanceX + 'px, ' + distanceY + 'px, 0)');
        }
    };

    Zoom.prototype.destroy = function() {

        var _this = this;

        // Unbind all events added by lightGallery zoom plugin
        _this.core.$el.off('.lg.zoom');
        $(window).off('.lg.zoom');
        _this.core.$slide.off('.lg.zoom');
        _this.core.$el.off('.lg.tm.zoom');
        _this.resetZoom();
        clearTimeout(_this.zoomabletimeout);
        _this.zoomabletimeout = false;
    };

    $.fn.lightGallery.modules.zoom = Zoom;

})(jQuery, window, document);

(function($, window, document, undefined) {

    'use strict';

    var defaults = {
        thumbnail: true,

        animateThumb: true,
        currentPagerPosition: 'middle',

        thumbWidth: 100,
        thumbContHeight: 100,
        thumbMargin: 5,

        exThumbImage: false,
        showThumbByDefault: true,
        toogleThumb: true,
        pullCaptionUp: true,

        enableThumbDrag: true,
        enableThumbSwipe: true,
        swipeThreshold: 50,

        loadYoutubeThumbnail: true,
        youtubeThumbSize: 1,

        loadVimeoThumbnail: true,
        vimeoThumbSize: 'thumbnail_small',

        loadDailymotionThumbnail: true
    };

    var Thumbnail = function(element) {

        // get lightGallery core plugin data
        this.core = $(element).data('lightGallery');

        // extend module default settings with lightGallery core settings
        this.core.s = $.extend({}, defaults, this.core.s);

        this.$el = $(element);
        this.$thumbOuter = null;
        this.thumbOuterWidth = 0;
        this.thumbTotalWidth = (this.core.$items.length * (this.core.s.thumbWidth + this.core.s.thumbMargin));
        this.thumbIndex = this.core.index;

        // Thumbnail animation value
        this.left = 0;

        this.init();

        return this;
    };

    Thumbnail.prototype.init = function() {
        var _this = this;
        if (this.core.s.thumbnail && this.core.$items.length > 1) {
            if (this.core.s.showThumbByDefault) {
                setTimeout(function(){
                    _this.core.$outer.addClass('lg-thumb-open');
                }, 700);
            }

            if (this.core.s.pullCaptionUp) {
                this.core.$outer.addClass('lg-pull-caption-up');
            }

            this.build();
            if (this.core.s.animateThumb) {
                if (this.core.s.enableThumbDrag && !this.core.isTouch && this.core.doCss()) {
                    this.enableThumbDrag();
                }

                if (this.core.s.enableThumbSwipe && this.core.isTouch && this.core.doCss()) {
                    this.enableThumbSwipe();
                }

                this.thumbClickable = false;
            } else {
                this.thumbClickable = true;
            }

            this.toogle();
            this.thumbkeyPress();
        }
    };

    Thumbnail.prototype.build = function() {
        var _this = this;
        var thumbList = '';
        var vimeoErrorThumbSize = '';
        var $thumb;
        var html = '<div class="lg-thumb-outer">' +
            '<div class="lg-thumb group">' +
            '</div>' +
            '</div>';

        switch (this.core.s.vimeoThumbSize) {
            case 'thumbnail_large':
                vimeoErrorThumbSize = '640';
                break;
            case 'thumbnail_medium':
                vimeoErrorThumbSize = '200x150';
                break;
            case 'thumbnail_small':
                vimeoErrorThumbSize = '100x75';
        }

        _this.core.$outer.addClass('lg-has-thumb');

        _this.core.$outer.find('.lg').append(html);

        _this.$thumbOuter = _this.core.$outer.find('.lg-thumb-outer');
        _this.thumbOuterWidth = _this.$thumbOuter.width();

        if (_this.core.s.animateThumb) {
            _this.core.$outer.find('.lg-thumb').css({
                width: _this.thumbTotalWidth + 'px',
                position: 'relative'
            });
        }

        if (this.core.s.animateThumb) {
            _this.$thumbOuter.css('height', _this.core.s.thumbContHeight + 'px');
        }

        function getThumb(src, thumb, index) {
            var isVideo = _this.core.isVideo(src, index) || {};
            var thumbImg;
            var vimeoId = '';

            if (isVideo.youtube || isVideo.vimeo || isVideo.dailymotion) {
                if (isVideo.youtube) {
                    if (_this.core.s.loadYoutubeThumbnail) {
                        thumbImg = '//img.youtube.com/vi/' + isVideo.youtube[1] + '/' + _this.core.s.youtubeThumbSize + '.jpg';
                    } else {
                        thumbImg = thumb;
                    }
                } else if (isVideo.vimeo) {
                    if (_this.core.s.loadVimeoThumbnail) {
                        thumbImg = '//i.vimeocdn.com/video/error_' + vimeoErrorThumbSize + '.jpg';
                        vimeoId = isVideo.vimeo[1];
                    } else {
                        thumbImg = thumb;
                    }
                } else if (isVideo.dailymotion) {
                    if (_this.core.s.loadDailymotionThumbnail) {
                        thumbImg = '//www.dailymotion.com/thumbnail/video/' + isVideo.dailymotion[1];
                    } else {
                        thumbImg = thumb;
                    }
                }
            } else {
                thumbImg = thumb;
            }

            thumbList += '<div data-vimeo-id="' + vimeoId + '" class="lg-thumb-item" style="width:' + _this.core.s.thumbWidth + 'px; margin-right: ' + _this.core.s.thumbMargin + 'px"><img src="' + thumbImg + '" /></div>';
            vimeoId = '';
        }

        if (_this.core.s.dynamic) {
            for (var i = 0; i < _this.core.s.dynamicEl.length; i++) {
                getThumb(_this.core.s.dynamicEl[i].src, _this.core.s.dynamicEl[i].thumb, i);
            }
        } else {
            _this.core.$items.each(function(i) {

                if (!_this.core.s.exThumbImage) {
                    getThumb($(this).attr('href') || $(this).attr('data-src'), $(this).find('img').attr('src'), i);
                } else {
                    getThumb($(this).attr('href') || $(this).attr('data-src'), $(this).attr(_this.core.s.exThumbImage), i);
                }

            });
        }

        _this.core.$outer.find('.lg-thumb').html(thumbList);

        $thumb = _this.core.$outer.find('.lg-thumb-item');

        // Load vimeo thumbnails
        $thumb.each(function() {
            var $this = $(this);
            var vimeoVideoId = $this.attr('data-vimeo-id');

            if (vimeoVideoId) {
                $.getJSON('//www.vimeo.com/api/v2/video/' + vimeoVideoId + '.json?callback=?', {
                    format: 'json'
                }, function(data) {
                    $this.find('img').attr('src', data[0][_this.core.s.vimeoThumbSize]);
                });
            }
        });

        // manage active class for thumbnail
        $thumb.eq(_this.core.index).addClass('active');
        _this.core.$el.on('onBeforeSlide.lg.tm', function() {
            $thumb.removeClass('active');
            $thumb.eq(_this.core.index).addClass('active');
        });

        $thumb.on('click.lg touchend.lg', function() {
            var _$this = $(this);
            setTimeout(function() {

                // In IE9 and bellow touch does not support
                // Go to slide if browser does not support css transitions
                if ((_this.thumbClickable && !_this.core.lgBusy) || !_this.core.doCss()) {
                    _this.core.index = _$this.index();
                    _this.core.slide(_this.core.index, false, true);
                }
            }, 50);
        });

        _this.core.$el.on('onBeforeSlide.lg.tm', function() {
            _this.animateThumb(_this.core.index);
        });

        $(window).on('resize.lg.thumb orientationchange.lg.thumb', function() {
            setTimeout(function() {
                _this.animateThumb(_this.core.index);
                _this.thumbOuterWidth = _this.$thumbOuter.width();
            }, 200);
        });

    };

    Thumbnail.prototype.setTranslate = function(value) {
        // jQuery supports Automatic CSS prefixing since jQuery 1.8.0
        this.core.$outer.find('.lg-thumb').css({
            transform: 'translate3d(-' + (value) + 'px, 0px, 0px)'
        });
    };

    Thumbnail.prototype.animateThumb = function(index) {
        var $thumb = this.core.$outer.find('.lg-thumb');
        if (this.core.s.animateThumb) {
            var position;
            switch (this.core.s.currentPagerPosition) {
                case 'left':
                    position = 0;
                    break;
                case 'middle':
                    position = (this.thumbOuterWidth / 2) - (this.core.s.thumbWidth / 2);
                    break;
                case 'right':
                    position = this.thumbOuterWidth - this.core.s.thumbWidth;
            }
            this.left = ((this.core.s.thumbWidth + this.core.s.thumbMargin) * index - 1) - position;
            if (this.left > (this.thumbTotalWidth - this.thumbOuterWidth)) {
                this.left = this.thumbTotalWidth - this.thumbOuterWidth;
            }

            if (this.left < 0) {
                this.left = 0;
            }

            if (this.core.lGalleryOn) {
                if (!$thumb.hasClass('on')) {
                    this.core.$outer.find('.lg-thumb').css('transition-duration', this.core.s.speed + 'ms');
                }

                if (!this.core.doCss()) {
                    $thumb.animate({
                        left: -this.left + 'px'
                    }, this.core.s.speed);
                }
            } else {
                if (!this.core.doCss()) {
                    $thumb.css('left', -this.left + 'px');
                }
            }

            this.setTranslate(this.left);

        }
    };

    // Enable thumbnail dragging and swiping
    Thumbnail.prototype.enableThumbDrag = function() {

        var _this = this;
        var startCoords = 0;
        var endCoords = 0;
        var isDraging = false;
        var isMoved = false;
        var tempLeft = 0;

        _this.$thumbOuter.addClass('lg-grab');

        _this.core.$outer.find('.lg-thumb').on('mousedown.lg.thumb', function(e) {
            if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
                // execute only on .lg-object
                e.preventDefault();
                startCoords = e.pageX;
                isDraging = true;

                // ** Fix for webkit cursor issue https://code.google.com/p/chromium/issues/detail?id=26723
                _this.core.$outer.scrollLeft += 1;
                _this.core.$outer.scrollLeft -= 1;

                // *
                _this.thumbClickable = false;
                _this.$thumbOuter.removeClass('lg-grab').addClass('lg-grabbing');
            }
        });

        $(window).on('mousemove.lg.thumb', function(e) {
            if (isDraging) {
                tempLeft = _this.left;
                isMoved = true;
                endCoords = e.pageX;

                _this.$thumbOuter.addClass('lg-dragging');

                tempLeft = tempLeft - (endCoords - startCoords);

                if (tempLeft > (_this.thumbTotalWidth - _this.thumbOuterWidth)) {
                    tempLeft = _this.thumbTotalWidth - _this.thumbOuterWidth;
                }

                if (tempLeft < 0) {
                    tempLeft = 0;
                }

                // move current slide
                _this.setTranslate(tempLeft);

            }
        });

        $(window).on('mouseup.lg.thumb', function() {
            if (isMoved) {
                isMoved = false;
                _this.$thumbOuter.removeClass('lg-dragging');

                _this.left = tempLeft;

                if (Math.abs(endCoords - startCoords) < _this.core.s.swipeThreshold) {
                    _this.thumbClickable = true;
                }

            } else {
                _this.thumbClickable = true;
            }

            if (isDraging) {
                isDraging = false;
                _this.$thumbOuter.removeClass('lg-grabbing').addClass('lg-grab');
            }
        });

    };

    Thumbnail.prototype.enableThumbSwipe = function() {
        var _this = this;
        var startCoords = 0;
        var endCoords = 0;
        var isMoved = false;
        var tempLeft = 0;

        _this.core.$outer.find('.lg-thumb').on('touchstart.lg', function(e) {
            if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
                e.preventDefault();
                startCoords = e.originalEvent.targetTouches[0].pageX;
                _this.thumbClickable = false;
            }
        });

        _this.core.$outer.find('.lg-thumb').on('touchmove.lg', function(e) {
            if (_this.thumbTotalWidth > _this.thumbOuterWidth) {
                e.preventDefault();
                endCoords = e.originalEvent.targetTouches[0].pageX;
                isMoved = true;

                _this.$thumbOuter.addClass('lg-dragging');

                tempLeft = _this.left;

                tempLeft = tempLeft - (endCoords - startCoords);

                if (tempLeft > (_this.thumbTotalWidth - _this.thumbOuterWidth)) {
                    tempLeft = _this.thumbTotalWidth - _this.thumbOuterWidth;
                }

                if (tempLeft < 0) {
                    tempLeft = 0;
                }

                // move current slide
                _this.setTranslate(tempLeft);

            }
        });

        _this.core.$outer.find('.lg-thumb').on('touchend.lg', function() {
            if (_this.thumbTotalWidth > _this.thumbOuterWidth) {

                if (isMoved) {
                    isMoved = false;
                    _this.$thumbOuter.removeClass('lg-dragging');
                    if (Math.abs(endCoords - startCoords) < _this.core.s.swipeThreshold) {
                        _this.thumbClickable = true;
                    }

                    _this.left = tempLeft;
                } else {
                    _this.thumbClickable = true;
                }
            } else {
                _this.thumbClickable = true;
            }
        });

    };

    Thumbnail.prototype.toogle = function() {
        var _this = this;
        if (_this.core.s.toogleThumb) {
            _this.core.$outer.addClass('lg-can-toggle');
            _this.$thumbOuter.append('<span class="lg-toogle-thumb lg-icon"></span>');
            _this.core.$outer.find('.lg-toogle-thumb').on('click.lg', function() {
                _this.core.$outer.toggleClass('lg-thumb-open');
            });
        }
    };

    Thumbnail.prototype.thumbkeyPress = function() {
        var _this = this;
        $(window).on('keydown.lg.thumb', function(e) {
            if (e.keyCode === 38) {
                e.preventDefault();
                _this.core.$outer.addClass('lg-thumb-open');
            } else if (e.keyCode === 40) {
                e.preventDefault();
                _this.core.$outer.removeClass('lg-thumb-open');
            }
        });
    };

    Thumbnail.prototype.destroy = function() {
        if (this.core.s.thumbnail && this.core.$items.length > 1) {
            $(window).off('resize.lg.thumb orientationchange.lg.thumb keydown.lg.thumb');
            this.$thumbOuter.remove();
            this.core.$outer.removeClass('lg-has-thumb');
        }
    };

    $.fn.lightGallery.modules.Thumbnail = Thumbnail;

})(jQuery, window, document);
/*
 * ************************************************************* *
 * Name       : Power Tour                                       *
 * Date       : June 2012                                        *
 * Owner      : CreativeMilk                                     *
 * Url        : www.creativemilk.net                             *
 * Version    : 2.5.1                                            *
 * Updated    : 2015-07-19 16:43:40 UTC+02:00                    *
 * Developer  : Mark                                             *
 * Dependency :                                                  *
 * Lib        : jQuery 1.7+                                      *
 * Licence    : NOT free                                         *
 * http://codecanyon.net/item/power-tour-powerfull-creative-jquery-tour-plugin/3246071
 * ************************************************************* *
 */

;(function(root, factory){
	
	if(typeof define === 'function' && define.amd){
		define(['jquery'], factory);
	}else{
		factory(root.jQuery);
	}
	
}(this, function($){		  
	
	//"use strict"; // jshint ;_;
	
	var pluginName = 'powerTour';
	
	function Plugin(element, options){
		
		/**
		* Variables.
		**/	
		this.obj = $(element);		
		this.o   = $.extend({}, $.fn[pluginName].defaults, options);

		this.init();
	};

	Plugin.prototype = {
								
		/**	
		* INIT.
		**/	
		init: function(){
			
			var self   = this;
			
			/**
			* Global variables.
			**/	
			bd         = $('body');
			clickEvent = 'click';
			screenPos  = new Array('sc','stl','stm','str','srm','sbr','sbm','sbl','slm');
			cdInterval = '';
			d_pwac     = 'data-powertour-action';
			d_pwcs     = 'data-powertour-currentstep';
			d_pwfx     = 'data-powertour-fx';
			d_pwfo     = 'data-powertour-fxout';
			d_pwid     = 'data-powertour-tour'; 
			d_pwpa     = 'data-powertour-pause';
			d_pwph     = 'data-powertour-placeholder';
			d_pwps     = 'data-powertour-previousstep';
			d_pwrn     = 'data-powertour-run';
			d_pwst     = 'data-powertour-step'; 
			d_pwsw     = 'data-powertour-startwith'; 
			d_pwtg     = 'data-powertour-trigger';
			d_pwtm     = 'data-powertour-timer';
			c_pwsw     = 'powertour-show';
			c_pwhd     = 'powertour-hide';
			c_pwhl     = 'powertour-highlight';
			c_pwhk     = 'powertour-hook';
			c_pwdc     = 'powertour-disable-cancel';
			c_pwst     = 'powertour-step';
			c_pwmk     = 'powertour-mask';
			c_pwkv     = 'powertour-keepvisible';
			
			/**
			* Check for CSS3 animation browser support.
			* http://stackoverflow.com/questions/7264899/detect-css-transitions-using-javascript-and-without-modernizr/13081497#13081497
			**/
			var supportsTransitions = (function() {
				var s = document.createElement('p').style,
					v = ['ms','O','Moz','Webkit'];
				if(s['transition'] == '') return true;
				while(v.length)
					if(v.pop() + 'Transition' in s)
						return true;
				return false;
			})();
			if(!supportsTransitions){
				bd.attr(d_pwfx, false);
			}
			
			/**	
			* Append the mask to the body. 
			**/
			if($('#'+c_pwmk).length < 1){
				bd.append('<div id="'+c_pwmk+'"></div>');
			}
			
			/**	
			* All methods that need to run at init. 
			**/
			self._build();
			self._clickEvents();
			self._keyboardEvents();
			self._runOnStart();

		},		

		/**
		* BUILD TOUR.
		*
		* All logic to build(wrap the steps and such) a tour.
		**/
		_build: function(){ 
		
			var self = this;
			
			/**
			* Create all steps with a loop.
			**/	
			$.each(self.o.tours, function(i, t){
				
				var def = t.stepDefaults[0];
				var sw  = $(t.trigger).attr(d_pwsw);
				var i   = parseInt(i + 1);
				
				/**
				* Use option or pre set value.
				**/	
				if(isNaN(sw)){
					var startWith = (t.startWith !== undefined && $.trim(t.startWith) != '' && t.startWith != '0') ? t.startWith : 1;	
				}else{
					var startWith = sw;	
				}
				
				/**
				* Set tour trigger meta.
				**/				
				$(t.trigger).attr({
					'data-powertour-startwith' : startWith,
					'data-powertour-trigger'   : i
				})
				.addClass(c_pwdc);				
				
				/**
				* Build every single step.
				**/	
				$.each(t.steps, function(ii, s){

	       			var ii = parseInt(ii + 1);
					
					/**
					* Setting the position.
					**/	
					self._setPosition(s, i, ii, t, true);

				});	
			});		
		},

		/**
		* SET POSITION.
		*
		* Step the position of each step.
		*
		* @param: s  | string  | The step.
		* @param: i  | integer | Tour index.
		* @param: ii | integer | Step index.
		* @param: t  | object  | Tour object.
		* @param: b  | boolean | Prevent second build if called.
		**/
		_setPosition: function(s, i, ii, t, b){
			
			var self   = this;
			var stepId = '['+d_pwid+'="'+i+'"]['+d_pwst+'="'+ii+'"]';
			var def    = t.stepDefaults[0];

			/**
			* If value is option is not present use defautl value(s).
			**/	
		    var width    = (s.width    !== undefined && $.trim(s.width)    != '') ? s.width    : def.width;
			var position = (s.position !== undefined && $.trim(s.position) != '') ? s.position : def.position;
			var Y        = (s.offsetY  !== undefined && $.trim(s.offsetY)  != '') ? s.offsetY  : def.offsetY;
			var X        = (s.offsetX  !== undefined && $.trim(s.offsetX)  != '') ? s.offsetX  : def.offsetX;
			
			/**
			* Check for screen postions, they should 
			* not use an hook, so append it to the body instead.
			**/					
			if($.inArray(position, screenPos) == -1){
					
				var hook = $(s.hookTo);
					
				/**
				* Add a relitive class for the highlight function.
				**/	
				hook.addClass(c_pwhk);
					
			}else{

				/**
				* Attach to body(dummy).
				**/
				var hook = bd;								
			}

			if(b === true){	
			
				/**
				* Build the powerTour template.
				**/
				var tourTemp = '<div class="'+c_pwst+' '+c_pwdc+'" '+d_pwid+'="'+i+'" '+d_pwst+'="'+ii+'" id="pw-'+i+'-'+ii+'" tabindex="-1" role="dialog" aria-hidden="true"></div>';
				
				/**
				* Create the single step of the tour.
				**/	
				hook
				.append(tourTemp)
				.children(stepId)
				.width(width)
				.html($(s.content))
				.children()
				.show();	
		    }
			
			/**
			* Set the main variable.
			**/	
			var step = $(stepId);
			
			/**
			* Getting width and height from the hook and step.
			**/	
			var hookWidth  = hook.outerWidth();
			var hookHeight = hook.outerHeight();	
			var stepWidth  = step.outerWidth();
			var stepHeight = step.outerHeight();

			/**
			* Check and set
			**/			
			switch(position){
				// top left
				case 'tl':
					step.css({left: X , top: -stepHeight - Y});					
				break;
				// top middle
				case 'tm':
					step.css({left: '50%', marginLeft: -(stepWidth/2) - X, top: -stepHeight - Y});					
				break;
				// top right
				case 'tr':
					step.css({right: X , top: -stepHeight - Y});					
				break;
	
				// right top
				case 'rt':
					step.css({left: hookWidth + X, top: Y});
				break;
				// right middle
				case 'rm':
					step.css({left: hookWidth + X, top: '50%', marginTop: -(stepHeight/2) - Y});						
				break;						
				// right bottom
				case 'rb':
					step.css({left: hookWidth + X, bottom: Y});						
				break;
				
				// bottom left
				case 'bl':
					step.css({left: X , bottom: -stepHeight - Y});					
				break;
				// bottom middle
				case 'bm':
					step.css({left: '50%', marginLeft: -(stepWidth/2) - X, bottom: -stepHeight - Y});					
				break;
				// bottom right
				case 'br':
					step.css({right: X , bottom: -stepHeight - Y});					
				break;
	
				// left top
				case 'lt':
					step.css({right: hookWidth + X, top: Y});
				break;
				// left middle
				case 'lm':
					step.css({right: hookWidth + X, top: '50%', marginTop: -(stepHeight/2) - Y});						
				break;						
				// left bottom
				case 'lb':
					step.css({right: hookWidth + X, bottom: Y});						
				break;
	
				// screen center
				case 'sc':
					step.css({left: '50%', top: '50%', marginLeft: -(width/2) - X, marginTop: -(stepHeight/2) - Y, position: 'absolute'});						
				break;						
					
				// screen top left
				case 'stl':
					step.css({left: 20 - X, top: 20 - Y, position: 'absolute'});						
				break;
				// screen top middle
				case 'stm':
					step.css({left: '50%', marginLeft: -(width/2) - X, top: 20 - Y, position: 'absolute'});						
				break;							
				// screen top right
				case 'str':
					step.css({right: 20 - X, top: 20 - Y, position: 'absolute'});						
				break;
				// screen right mid
				case 'srm':
					step.css({right: 20 - X, top: '50%', marginTop: -(stepHeight/2) - Y, position: 'absolute'});						
				break;							
				// screen bottom right
				case 'sbr':
					step.css({right: 20 - X, bottom: 20 - Y, position: 'absolute'});						
				break;
				// screen top middle
				case 'sbm':
					step.css({left: '50%', bottom: 20 - Y, marginLeft: -(width/2) - X, position: 'absolute'});						
				break;
				// screen bottom left
				case 'sbl':
					step.css({left: 20 - X, bottom: 20 - Y, position: 'absolute'});						
				break;									 							
				// screen left mid
				case 'slm':
					step.css({left: 20 - X, top: '50%', marginTop: -(stepHeight/2) - Y, position: 'absolute'});						
				break;								
				
				// no position
				case false:
					// do nothing
				break;
				// right top
				default:
					step.css({right: hookWidth + X, top: Y});
				break;																																				
			};
		},
		
		/**
		* TOUR DATA VARIABLES.
		*
		* Get all main tour and step data here and make them available als global vars.
		**/
		_tourDataVars: function(){
			
			var self  = this;
			id        = bd.attr(d_pwid);
			
			if(!isNaN(id)){

				cs                = bd.attr(d_pwcs);
				ps                = bd.attr(d_pwps);
				
				oid               = (id == 1) ? 1 : id;
				id                = (id == 0) ? 0 : id - 1;
								
				ocs               = (cs == 1) ? 1 : cs;
				cs                = (cs == 0) ? 1 : cs - 1;

				if(ps !== undefined){					
					ops           = (ps == 1) ? 1 : ps;
					ps            = (ps == 0) ? 1 : ps - 1;
				}else{
					ops = ps;
				}		
			    					
				tour              = self.o.tours[id];
				step              = tour.steps[cs];
				def               = tour.stepDefaults[0];
				hook              = tour.steps[cs].hookTo;
				scrollHorizontal  = tour.scrollHorizontal;
				loopTour          = tour.loopTour;
				highlightStartSpeed = tour.highlightStartSpeed;
				highlightEndSpeed = tour.highlightEndSpeed;
				countSteps        = tour.steps.length; 
			
				csObj             = $('['+d_pwst+'='+ocs+']['+d_pwid+'='+oid+']');	
				psObj             = $('['+d_pwst+'='+ops+']['+d_pwid+'='+oid+']');		
				
				position          = (step.position        !== undefined && $.trim(step.position)        != '') ? step.position        : def.position;
				center            = (step.center          !== undefined && $.trim(step.center)          != '') ? step.center          : def.center;
				scrollSpeed       = (step.scrollSpeed     !== undefined && $.trim(step.scrollSpeed)     != '') ? step.scrollSpeed     : def.scrollSpeed;
				scrollEasing      = (step.scrollEasing    !== undefined && $.trim(step.scrollEasing)    != '') ? step.scrollEasing    : def.scrollEasing;
				scrollDelay       = (step.scrollDelay     !== undefined && $.trim(step.scrollDelay)     != '') ? step.scrollDelay     : def.scrollDelay;
				highlight         = (step.highlight       !== undefined && $.trim(step.highlight)       != '') ? step.highlight       : def.highlight;
				fxIn              = (step.fxIn            !== undefined && $.trim(step.fxIn)            != '') ? step.fxIn            : def.fxIn;
				fxOut             = (step.fxOut           !== undefined && $.trim(step.fxOut)           != '') ? step.fxOut           : def.fxOut;
				showStepDelay     = (step.showStepDelay   !== undefined && $.trim(step.showStepDelay)   != '') ? step.showStepDelay   : def.showStepDelay;
				delay             = (step.delay           !== undefined && $.trim(step.delay)           != '') ? step.delay           : def.delay;
				timer             = (step.timer           !== undefined && $.trim(step.timer)           != '') ? step.timer           : def.timer;
				keepVisible       = (step.keepVisible     !== undefined && $.trim(step.keepVisible)     != '') ? step.keepVisible     : def.keepVisible;
			
				/**
				* Preious step data.
				**/	
				if(ps !== undefined){
					prevStep        = tour.steps[ps];
					prevFxOut       = (prevStep.fxOut           !== undefined && $.trim(prevStep.fxOut)           != '') ? prevStep.fxOut           : def.fxOut;
					keepHighlighted = (prevStep.keepHighlighted !== undefined && $.trim(prevStep.keepHighlighted) != '') ? prevStep.keepHighlighted : def.keepHighlighted;
				}else{
					keepHighlighted = false;
				}
			}
		},

		/**
		* FXIN.
		*
		* Run the CSS3 transitions(if present). 
		*
		* @param: csObj | object | Previous step object(index).
		* @param: fxIn  | string | Type of fx to use(class).
		**/
		_fxIn: function(csObj, fxIn){ 	

			if(bd.attr(d_pwid) !== undefined){
				
				var fxIn = $.trim(fxIn);
					
				if(bd.attr(d_pwfx) == 'false'){
					var show = c_pwsw;
				}else if(fxIn == '' || fxIn == 'none'){
					var show = c_pwsw;
				}else{
					var show = fxIn+' animated';
				}	

				if(keepVisible == true){
					var keep = c_pwkv;
				}else{
					var keep = '';
				}
				
				csObj.not('.'+c_pwkv).attr('class', c_pwst+' '+c_pwdc+' '+show+' '+keep);	
								
			}
		},
		
		/**
		* FXOUT.
		*
		* Run the CSS3 transitions(if present). 
		*
		* @param: psObj | object | Previous step object(index).
		* @param: fxOut | string | Type of fx to use(class).
		**/
		_fxOut: function(psObj, fxOut){ 

			if(bd.attr(d_pwid) !== undefined){
	
				var fxIn = $.trim(fxOut);
				
				if(bd.attr(d_pwfx) == 'false' || fxOut == '' || fxOut == 'none'){
					var hide = '';
				}else{
					var hide = fxOut+' animated';
				}	
		
				psObj.not('.'+c_pwkv).attr('class', c_pwst+' '+c_pwhd+' '+hide);
				
				psObj.filter('.'+c_pwkv).attr(d_pwfo, hide);	
	
			}
		
		},
		
		/**
		* GO TO.
		*
		* Go to the step or hook.
		*
		* @param: hook             | object  | Current hook.
		* @param: step             | object  | Current step.
		* @param: position         | string  | Position of the step.
		* @param: center           | string  | Choose the center(step or hook).
		* @param: scrollSpeed      | integer | Teh speed of the scroll.
		* @param: highlight        | boolean | Highlight hook and step.
		* @param: keepHighlight    | boolean | Keep the highlight active.
		* @param: scrollHorizontal | boolean | Scroll direction horizontal.
		**/
		_goTo: function(hook, step, center, position, scrollSpeed, scrollEasing, highlight, keepHighlighted, scrollHorizontal){
		
			var self = this;
						
			/**
			* Reset/hide and show the mask(highlight).
			**/	
			function resetHighlight(){
				var resetHl = $('.'+c_pwhl).removeClass(c_pwhl);
				
				if(highlight === true && keepHighlighted === true){
					resetHl; 
				}else{
					$('#'+c_pwmk).fadeOut((isNaN(highlightEndSpeed)) ? 200 : highlightEndSpeed ,function(){
						resetHl; 
					});
				}
			}
			resetHighlight();
			
			/**
			* Reset current step, CSS3 animation class must be removed due wrong offset values.
			**/	
			step.not('.'+c_pwkv).attr('class', c_pwst);

			/**
			* Reset previouse exclude class.
			**/	
			$('.'+c_pwhk+'.'+c_pwdc).removeClass(c_pwdc);
			
			/**
			* Choose direction.
			**/	
			if($.inArray(position, screenPos) == -1){
					
				var winHeight = $(window).height();
				var winWidth  = $(window).width();	
					
				if(scrollHorizontal === true){
					if(center == 'step' || $(hook).outerWidth() >= winWidth){ 
						var centerTo = step.show().offset().left - (winWidth/2) + (step.outerWidth()/2);//.show() = important!
					}else{
						var centerTo = $(hook).offset().left - (winWidth/2) + ($(hook).outerWidth()/2); 	
					}

					var scrollDir = { scrollLeft: centerTo }
				}else{
					if(center == 'step' || $(hook).outerHeight() >= winHeight){ 
						var centerTo = step.show().offset().top - (winHeight/2) + (step.outerHeight()/2);//.show() = important!
					}else{
						var centerTo = $(hook).offset().top - (winHeight/2) + ($(hook).outerHeight()/2); 	
					}

					var scrollDir = { scrollTop: centerTo }
				}

				/**
				* Animation callback gets triggerd twice due the compatibilty of the browsers(html,body).
				* This value prevents a double run.
				**/	
				var oro = false; 
			
				/**
				* Animate and highlight.
				**/	
				$('html, body').stop(true, true).animate(scrollDir, scrollSpeed, scrollEasing, function(){
					if(oro){
						if(highlight === true && bd.attr(d_pwid) !== undefined){
							$(hook).addClass(c_pwhl+' '+c_pwdc);
							$('#'+c_pwmk).fadeIn((isNaN(highlightStartSpeed)) ? 200 : highlightStartSpeed);
						}
					}else{
						oro = true; 
						resetHighlight();//savety reset
					}
				});	
	
			}else{
				if(highlight === true && bd.attr(d_pwid) !== undefined){
					$(hook).addClass(c_pwhl+' '+c_pwdc);
					$('#'+c_pwmk).fadeIn((isNaN(highlightStartSpeed)) ? 200 : highlightStartSpeed);					
				}
			}
		},
		
		/**
		* RUN TOUR.
		*
		* All code to run the tour.
		**/
		_runTour: function(){ 
		
			var self = this;
			
			/**
			* Clear placeholder.
			**/	
			$('['+d_pwph+'="timer"]').html('');	
			
			/**
			* Clear timer intervals.
			**/	
			clearInterval(window.cdInterval);	

			/**
			* Reset time in the timer dataset.
			**/	
			bd.attr(d_pwtm, false);

			/**
			* Remove pause indicator.
			**/	
			bd.removeAttr(d_pwpa);	
								
			/**
			* Get all tour variables.
			**/	
			self._tourDataVars();	

			/**
			* Run this callback function just once.
			**/	
			if(bd.attr(d_pwrn) == undefined){
				if(typeof tour.onStartTour == 'function'){
					tour.onStartTour.call(this, {
						currentStep : csObj
					});
				}
				
				bd.attr(d_pwrn, 'true');
			}
			
			/**
			* Previouse step.
			**/				
			if(ps !== undefined){
				
				/**
				* Run previous step fx.
				**/	
				self._fxOut(psObj, prevFxOut);
				
				/**
				* Run callback function.
				**/
				if(prevStep.onHideStep !== undefined && typeof prevStep.onHideStep == 'function'){
					prevStep.onHideStep.call(this, {
						currentStep  : csObj,
						previousStep : psObj
					});
				}else if(typeof def.onHideStep == 'function'){
					def.onHideStep.call(this, {
						currentStep  : csObj,
						previousStep : psObj
					});
				}
			}
			
			setTimeout(function(){	
			
				/**
				* Scroll to target.
				**/	
				self._goTo(hook, csObj, center, position, scrollSpeed, scrollEasing, highlight, keepHighlighted, scrollHorizontal);
				
				/**
				* Current(next) step.
				**/	
				if(cs !== undefined){
					setTimeout(function(){				

						/**
						* Run current step fx.
						**/	
						self._fxIn(csObj, fxIn);

						/**
						* Timer.
						**/	
						self._timer(timer);

						/**
						* Run callback function.
						**/
						if(step.onShowStep !== undefined && typeof step.onShowStep == 'function'){
							step.onShowStep.call(this, {
								currentStep  : csObj,
								previousStep : psObj
							});
						}else if(typeof def.onShowStep == 'function'){
							def.onShowStep.call(this, {
								currentStep  : csObj,
								previousStep : psObj
							});
						}	
						
						/**
						* Run callback function.
						**/
						if(typeof self.o.tours[id].onProgress == 'function'){
							self.o.tours[id].onProgress.call(this, {
								stepIndex  : parseInt(cs + 1),
								totalSteps : parseInt(countSteps),
								tourIndex  : parseInt(id + 1)
							});
						}
					},showStepDelay);
				}
				
			},scrollDelay);
		},

		/**
		* END TOUR.
		*
		* All code to end a tour.
		*
		* @param: type | string  | Type of end.
		**/
		_endTour: function(type){ 

			var self = this;
			
			/**
			* Stop countdown timer.
			**/	
			clearInterval(window.cdInterval);
			
			/**
			* Get all tour variables.
			**/	
			self._tourDataVars();			

			/**
			* Run fxOut.
			**/	
			self._fxOut(csObj, fxOut);
						
			/**
			* Run callback function.
			**/
			if(step.onHideStep !== undefined && typeof step.onHideStep == 'function'){
				step.onHideStep.call(this, {
					currentStep  : csObj,
					previousStep : psObj
				});
			}else if(typeof def.onHideStep == 'function'){
				def.onHideStep.call(this, {
					currentStep  : csObj,
					previousStep : psObj
				});
			}
			
			/**
			* Run callback function.
			**/
			if(typeof tour.onEndTour == 'function'){
				tour.onEndTour.call(this, {
					currentStep  : csObj,
					previousStep : psObj,
					endType      : type
				});
			}

			/**
			* Make sure keepvisible steps still use the exit fx.
			**/
			if($('.'+c_pwkv).length > 0){
				$('.'+c_pwkv).each(function(){
					var fx =$(this).attr(d_pwfo);
					$(this).addClass(fx);
				});
			}
					
			/**	
			* Remove datasets from body tag and find all open steps and hide these.
			**/	
			bd.removeAttr(d_pwid+' '+d_pwcs+' '+d_pwps+' '+d_pwtm+' '+d_pwrn+' '+d_pwpa+' '+d_pwfo);
			
			/**
			* Reset mask.
			**/	
			$('#'+c_pwmk).animate({opacity: 0}, (isNaN(highlightEndSpeed)) ? 200 : highlightEndSpeed, function(){
				$(this).removeAttr('style');
			});
			
			/**
			* Reset highlight class.
			**/	
			$('.'+c_pwhl).removeClass(c_pwhl);
			
			/**
			* Reset the zindex issue.
			**/
			setTimeout(function(){	
				if(!bd.attr(d_pwrn)){			
					$('.'+c_pwst).attr('class' , c_pwst+' '+c_pwdc);
				}
			},1200);
		},
		
		/**
		* ACTION BUTTONS.
		**/
		_actionButtons: function(action, goto){ 
		
			var self = this;
			
			/**
			* Get all tour variables.
			**/	
			self._tourDataVars();	
			
			if(id !== undefined){

				total     = parseInt(countSteps -1);
				cs        = parseInt(cs);
				var allAc = bd.attr('data-powertour-disable-all');
				
				/**
				* Choose type of action.
				**/	
				switch(action){
					case 'first':
						if(allAc === undefined && bd.attr('data-powertour-disable-first') === undefined){
							var newStep = 0;
						}else{
							return false;
						}
					break;
					case 'last':
						if(allAc === undefined && bd.attr('data-powertour-disable-last') === undefined){
							var newStep = total;
						}else{
							return false;
						}		
					break;
					case 'prev':
						if(allAc === undefined && bd.attr('data-powertour-disable-prev') === undefined){
							if(cs <= 0){
								if(loopTour === true){
									var newStep = total;	
								}else{
									var newStep = 0;	
								}		
							}else{
								var newStep = cs - 1;	
							}
						}else{
							return false;
						}
					break;
					case 'next':
					case 'timer':
						if(allAc === undefined && bd.attr('data-powertour-timer') != 'false' || bd.attr('data-powertour-disable-next') === undefined){
							if(cs >= total){
								if(loopTour === true){
									var newStep = 0;	
								}else{
									if(bd.attr('data-powertour-timer') == 'false'){
										var newStep = total;
									}else if(action != 'next'){
							
										/**
										* End tour.
										**/	
										self._endTour('stop');
									}
								}									
							}else{
								var newStep = cs + 1;	
							}
						}else{
							return false;
						}
					break;
					case 'pause':
					case 'play':
					case 'toggleplay':
						if(bd.attr(d_pwtm) != 'false'){
							
							/**
							* Stop countdown timer.
							**/	
							clearInterval(window.cdInterval);	
								
							if(action == 'play'){
								
								/**
								* Timer.
								**/	
								self._timer(bd.attr(d_pwtm));
								
								/**
								* Remove pause indicator.
								**/	
								bd.removeAttr(d_pwpa);
										
							}
							if(action == 'pause'){
																
								/**
								* Set pause indicator.
								**/	
								bd.attr(d_pwpa, true);	
								
							}
							if(action == 'toggleplay'){
								if(action == 'toggleplay' && bd.attr(d_pwpa) == 'true'){

									/**
									* Timer.
									**/	
									self._timer(bd.attr(d_pwtm));
									
									/**
									* Remove pause indicator.
									**/	
									bd.removeAttr(d_pwpa);	

								}else{
									
									/**
									* Set pause indicator.
									**/	
									bd.attr(d_pwpa, true);	
	
								}
							}							
						}
					break;
					case 'stop':
						if(allAc === undefined && bd.attr('data-powertour-disable-stop') === undefined){
							
							/**
							* End tour.
							**/	
							self._endTour('stop');
						
							var newStep = 'stop';
						}else{
							return false;
						}			
					break;
					case 'goto':
						if(allAc === undefined && bd.attr('data-powertour-disable-goto') === undefined){
							var newStep = goto - 1;	
						}else{
							return false;
						}		
					break;
				}
				
				/**
				* Set new current and previous step values and run the tour.
				**/	
				if(!isNaN(newStep) && newStep != cs){
					bd.attr({
						'data-powertour-currentstep'  : newStep + 1,
						'data-powertour-previousstep' : cs + 1
					});
				
					/**
					* Run the tour.
					**/	
					self._runTour();
				}
			}
		},

		/**
		* TIMER.
		*
		* Timer logic.
		*
		* @param: timer | string | Time.
		**/
		_timer: function(timer){ 
		
			var self = this;
			
			/**
			* Placeholder var
			**/	
			var tplace = $('['+d_pwph+'="timer"]');
				
			/**
			* Timer check and all it's logic.
			**/	
			if(timer !== false && timer != '00:00' && timer.match("^(60:00|[0-5][0-9]:[0-5][0-9])$")){

				var sTime   = timer.split(":").reverse();
				var	endTime = parseInt(((sTime[0]) * 1000 ) + (sTime[1] * 60000));

				/**
				* Place time in the timer placeholder.
				**/	
				tplace.html(timer);
				
				/**
				* Place time in the timer dataset.
				**/	
				bd.attr(d_pwtm, timer);

				/**
				* Countdown timer placeholder.
				**/	
				function countdown(){

					/**
					* Always display 2 numbers.
					**/	
					function calc(secs, num1, num2) {
						var s = ((Math.floor(secs/num1))%num2).toString();
						if (s.length < 2){
							var s = "0" + s;
						}
						return s;
					}	
					mins = calc(endTime,60000,60);
					secs = calc(endTime,1000,60);
											
					/**
					* Show the timer.
					**/
					tplace.html(mins+':'+secs);
					
					/**
					* Update the dataset value.
					**/
					bd.attr(d_pwtm, mins+':'+secs);
					
				}
				window.cdInterval = setInterval(function(){
					if(endTime != 0){
						endTime -= 1000;
						countdown();
					}else{
						self._actionButtons('timer', false);	
					}
				},1000);		
			}
		},
		
		/**
		* CLICK EVENTS.
		*
		* All click event like 'start', 'cancel' and 'actions'.
		**/
		_clickEvents: function(){ 
		
			var self = this;

			/**	
			* Start the tour with the trigger.
			**/	
			bd.on(clickEvent, '['+d_pwtg+']', function(e){

				/**	
				* End any running tours(savety).
				**/		
				if(bd.attr(d_pwid)){	
					self._endTour('end');
				}

				var id        = $(this).attr(d_pwtg);
				var startWith = $(this).attr(d_pwsw);
				
				if(id !== undefined){
					
					/**
					* Add dataset values to the body.
					**/	
					bd.attr({
						'data-powertour-tour'        : id,
						'data-powertour-currentstep' : startWith,
						'data-powertour-timer'       : false 
					});
	
					/**
					* Run the tour.
					**/	
					self._runTour();
				}

				/**
				* Disable only the anchors.
				**/	
				if($(this).is('a') || $(this).parents().is('a')){
					e.preventDefault();
				}
			});

			/**	
			* All action buttons.
			**/	
			bd.on(clickEvent, '['+d_pwac+']:not(.powertour-disable-action)', function(e){				
				self._actionButtons($(this).attr(d_pwac), $(this).attr('data-powertour-goto'));
				e.preventDefault();
			});
			
			/**	
			* Easy cancel allows a user(if this option is set to true and
			* a tour is running) to cancel the tour just by clicking somewhere 
			* on the page(excluding the steps them self and any kind of tour buttons).
			**/	
			$('body').on(clickEvent, this, function(e){
			
				var id = bd.attr(d_pwid);
				
				if(id !== undefined 
					&&
					self.o.tours[id == 0 ? 0 : id -1].easyCancel 
					&&
					!$(e.target).is($('.'+c_pwdc))
					&&
					!$(e.target).is($('.'+c_pwdc+' *'))
					&&
					!$(e.target).is($('['+d_pwac+']'))
					&&
					!$(e.target).is($('['+d_pwac+'] *'))){

						/**
						* End the tour.
						**/	
						self._endTour('cancel');  
						 
				}
			});
		},
		
		/**
		* KEYBOARD EVENTS.
		*
		* Manage the tour with the keyboard.
		**/
		_keyboardEvents: function(){ 
		
			var self  = this;

			/**	
			* ESC key needs to be keyup. 
			**/
			$('body').on('keyup', function(e){
				
				var id = bd.attr(d_pwid);
						
				if(id !== undefined && self.o.tours[id == 0 ? 0 : id -1].escKeyCancel === true && e.keyCode == 27){	
					
					/**
					* End the tour.
					**/	
					self._endTour('cancel');  
				}
			});

			/**	
			* Space key needs to be keydown. 
			**/
			$('body').on('keydown', function(e){
				
				var id = bd.attr(d_pwid);
				
				if(id !== undefined && self.o.tours[id == 0 ? 0 : id -1].keyboardNavigation === true){
					
					/**	
					* Space key.
					**/	
					if(e.keyCode == 32){ 
						e.preventDefault();
						self._actionButtons('toggleplay', false);
					}

					/**	
					* Arrow left key.
					**/								
					if(e.keyCode == 37){
						self._actionButtons('prev', false);
					}
					
					/**	
					* Arrow right key.
					**/
					if(e.keyCode == 39){
						self._actionButtons('next', false);
					}
					
				}
			});
		},
		
		/**
		* RUN ON START.
		*
		* Run on load with the 'powertour' param or the 'rnOnLoad' option.
		**/
		_runOnStart: function(){ 

			var self = this;
			
			/**
			* Get the param values.
			**/	
			function getParam(variable){
				var query = window.location.search.substring(1);
				var vars = query.split("&");
				for(var i=0;i<vars.length;i++) {
					var pair = vars[i].split("=");
					if(pair[0] == variable){return pair[1];}
				}
				return(false);
			}

			var startTour = getParam("powertour");
			var startWith = getParam("startwith");	
				
			/**
			* Check and set the values.
			**/	
			if(!isNaN(startTour) && startTour !== false && startTour !== undefined){

				if(startTour != 0){
					var id = startTour;
				}else{
					var id = 1;
				}
			
				if(!isNaN(startWith) && startWith !== false && startWith !== undefined){
					var cs = startWith;
				}else{
					var cs = 1;
				}

				/**
				* Add dataset values to the body.
				**/	
				bd.attr({
					'data-powertour-tour'        : id,
					'data-powertour-currentstep' : cs,
					'data-powertour-timer'       : false 
				});
		
				/**
				* Run the tour.
				**/	
				self._runTour();	
			}
		},
		
		/**
		* UPDATE
		*
		* Update the steps postion if this has not been step or has been changed.
		*
		* @param: hook | string/array | The hook thats being re-positioned.
		**/
		update: function(hook){ 
		
			var self = this; 
			
			/**
			* If not array make array.
			**/	
			if(!$.isArray(hook)){
				var hook = [hook];
			}			
	
			/**
			* Update every given step.
			**/	
			$.each(hook, function(i, h){

				var ti  = $(h).parent().attr(d_pwid);
				var si  = $(h).parent().attr(d_pwst);			
			
				var oti = (ti == 0) ? 0 : ti -1;
				var osi = (si == 0) ? 0 : si -1;
				
				var h   = self.o.tours[oti];				
				var s   = h.steps[osi];	

				/**
				* Setting the position.
				**/	
				self._setPosition(s, ti, si, h, false);	
			});
		
		},

		/**
		* NAVIGATION
		*
		* Programmatically access the navigation.
		*
		* @param: nav | string/array | Type of naviagtion is called.
		**/
		navigation: function(nav){ 
		
			var self = this;
			
			if($.isArray(nav)){			
				self._actionButtons(nav[0], nav[1]);
			}else{
				self._actionButtons(nav, false);
			}
		},
		
        /**
		* RUN
		*
		* Run the tour.
		*
		* @param: tour | integer/array | The tour that is called.
		**/
		run: function(tour){ 
		
			var self = this; 

			/**
			* Check if its an array of string.
			**/	
			if($.isArray(tour)){
								
				if(!isNaN(tour[0]) && !isNaN(tour[1])){
	 
					var tourVar   = tour[0];
					var startWith = tour[1];
	
				}else{
					
					var tourVar   = 1;
					var startWith = 1;
					
				}
				
				var startWith = (startWith == 0) ? 1 : startWith;
				
			}else{

				if(!isNaN(tour)){
	 
					var tourVar = tour;
	
				}else{
					
					var tourVar = 1;
					
				}
		
				var st        = self.o.tours[(tourVar == 0) ? 0 : tourVar -1].startWith;				
				var startWith = (st == '' || st == ' ' || st == undefined)? 1 : st;
				
			}
			
			/**
			* Add dataset values to the body.
			**/	
			bd.attr({
				'data-powertour-tour'        : (tourVar == 0) ? 1 : tourVar,
				'data-powertour-currentstep' : startWith,
				'data-powertour-timer'       : false 
			});

			/**
			* Run the tour.
			**/	
			self._runTour();
					
		},
		
		/**
		* END TOUR(S)
		*
		* Stops all tours.
		**/
		end: function(){ 
		
			var self = this; 
			
			/**
			* End tour.
			**/	
			self._endTour('stop');
			
		},
		
		/**
		* DESTROY TOUR(S)
		*
		* Destroy all tours.
		**/
		destroy: function(){ 
		
			var self = this; 

			if(!isNaN(bd.attr(d_pwid))){

				/**
				* End the tour.
				**/	
				self._endTour('end');  
			}

			/**
			* Unwrap every step.
			**/	
			$('.'+c_pwst).children().hide().unwrap();

			/**
			* Remove the mask element.
			**/	
			$('#'+c_pwmk).remove();

			/**
			* Remove all custom dataset attributes from the trigger(s).
			**/	
			$('['+d_pwtg+']').removeAttr(d_pwtg+' '+d_pwsw).removeClass(c_pwdc);
	
			/**
			* Remove custom classes.
			**/						
		    $('.'+c_pwhk).removeClass(c_pwhk);
			
			/**
			* Reset/remove all events.
			**/				
			$('body').off('click', self._clickEvents()).off('keydown keyup', self._keyboardEvents()).removeData(pluginName);
		}
		
	};

	$.fn[pluginName] = function(option, param) {
  		return this.each(function() {
			var $this   = $(this);
            var data    = $this.data(pluginName);
            var options = typeof option == 'object' && option;
			if(!data){ 
			  $this.data(pluginName, (data = new Plugin(this, options)))
			}
			if(typeof option == 'string'){
				 data[option](param);
			}
		});
	};

	/**
	* Default settings(dont change).
	* You can globally override these options
	* by using $.fn.pluginName.key = 'value';
	**/
	$.fn[pluginName].defaults = {
		tours:[
				{									
				trigger: '',
				startWith: '',
				easyCancel: '',
				escKeyCancel: '',
				scrollHorizontal: '',                                
				keyboardNavigation: '',
				loopTour: '',
				highlightStartSpeed:'',
				highlightEndSpeed:'',
				onStartTour: function(ui){}, 		
				onEndTour: function(ui){},	
				onProgress: function(ui){},		
				steps:[
				    {
					hookTo: '',
					content: '',
					width: '',
					position: '',
					offsetY: '',
					offsetX: '',
					fxIn: '',
					fxOut: '',
					showStepDelay:'',
					center: '',
					scrollSpeed: '',
					scrollEasing: '',
					scrollDelay:'',
					highlight: '',
					keepHighlighted: '',
					timer:'',
					keepVisible: '',										
					onShowStep: function(ui){},
					onHideStep: function(ui){}
					}		
				],
				stepDefaults:[
					{
					width: '',
					position: '',
					offsetY: '',
					offsetX: '',
					showStepDelay:'',
					fxIn: '',
					fxOut: '',
					center: '',
					scrollSpeed: '',
					scrollEasing: '',
					scrollDelay:'',
					highlight: '',
					keepHighlighted: '',
					timer:'',
					keepVisible: '',
					onShowStep: function(ui){},
					onHideStep: function(ui){}
				    }
				]
			}		
		]
	};
	
	// Call directly from jQuery on 'body'
	$[pluginName] = function() {
		var $body = $(document.body);
		$body[pluginName].apply($body, arguments);
	}
			
}));
/*!
* qTip2 - Pretty powerful tooltips - v2.0.1-11-
* http://qtip2.com
*
* Copyright (c) 2013 Craig Michael Thompson
* Released under the MIT, GPL licenses
* http://jquery.org/license
*
* Date: Sat Feb 9 2013 08:05 GMT+0000
* Plugins: svg ajax tips modal viewport imagemap ie6
* Styles: basic css3
*/

/*jslint browser: true, onevar: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: true */
/*global window: false, jQuery: false, console: false, define: false */

/* Cache window, document, undefined */
(function (window, document, undefined) {

    // Uses AMD or browser globals to create a jQuery plugin.
    (function (factory) {
        "use strict";
        if (typeof define === 'function' && define.amd) {
            define(['jquery'], factory);
        }
        else if (jQuery && !jQuery.fn.qtip) {
            factory(jQuery);
        }
    }
(function ($) {
    /* This currently causes issues with Safari 6, so for it's disabled */
    //"use strict"; // (Dis)able ECMAScript "strict" operation for this function. See more: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/

    // Munge the primitives - Paul Irish tip
    var TRUE = true,
		FALSE = false,
		NULL = null,

    // Side names and other stuff
		X = 'x', Y = 'y',
		WIDTH = 'width',
		HEIGHT = 'height',
		TOP = 'top',
		LEFT = 'left',
		BOTTOM = 'bottom',
		RIGHT = 'right',
		CENTER = 'center',
		FLIP = 'flip',
		FLIPINVERT = 'flipinvert',
		SHIFT = 'shift',

    // Shortcut vars
		QTIP, PLUGINS, MOUSE,
		NAMESPACE = 'qtip',
		usedIDs = {},
		widget = ['ui-widget', 'ui-tooltip'],
		selector = 'div.qtip.' + NAMESPACE,
		defaultClass = NAMESPACE + '-default',
		focusClass = NAMESPACE + '-focus',
		hoverClass = NAMESPACE + '-hover',
		replaceSuffix = '_replacedByqTip',
		oldtitle = 'oldtitle',
		trackingBound;

    // Store mouse coordinates
    function storeMouse(event) {
        MOUSE = {
            pageX: event.pageX,
            pageY: event.pageY,
            type: 'mousemove',
            scrollX: window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft,
            scrollY: window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop
        };
    }
    // Option object sanitizer
    function sanitizeOptions(opts) {
        var invalid = function (a) { return a === NULL || 'object' !== typeof a; },
		invalidContent = function (c) { return !$.isFunction(c) && ((!c && !c.attr) || c.length < 1 || ('object' === typeof c && !c.jquery && !c.then)); };

        if (!opts || 'object' !== typeof opts) { return FALSE; }

        if (invalid(opts.metadata)) {
            opts.metadata = { type: opts.metadata };
        }

        if ('content' in opts) {
            if (invalid(opts.content) || opts.content.jquery) {
                opts.content = { text: opts.content };
            }

            if (invalidContent(opts.content.text || FALSE)) {
                opts.content.text = FALSE;
            }

            if ('title' in opts.content) {
                if (invalid(opts.content.title)) {
                    opts.content.title = { text: opts.content.title };
                }

                if (invalidContent(opts.content.title.text || FALSE)) {
                    opts.content.title.text = FALSE;
                }
            }
        }

        if ('position' in opts && invalid(opts.position)) {
            opts.position = { my: opts.position, at: opts.position };
        }

        if ('show' in opts && invalid(opts.show)) {
            opts.show = opts.show.jquery ? { target: opts.show} : { event: opts.show };
        }

        if ('hide' in opts && invalid(opts.hide)) {
            opts.hide = opts.hide.jquery ? { target: opts.hide} : { event: opts.hide };
        }

        if ('style' in opts && invalid(opts.style)) {
            opts.style = { classes: opts.style };
        }

        // Sanitize plugin options
        $.each(PLUGINS, function () {
            if (this.sanitize) { this.sanitize(opts); }
        });

        return opts;
    }

    /*
    * Core plugin implementation
    */
    function QTip(target, options, id, attr) {
        // Declare this reference
        var self = this,
		docBody = document.body,
		tooltipID = NAMESPACE + '-' + id,
		isPositioning = 0,
		isDrawing = 0,
		tooltip = $(),
		namespace = '.qtip-' + id,
		disabledClass = 'qtip-disabled',
		elements, cache;

        // Setup class attributes
        self.id = id;
        self.rendered = FALSE;
        self.destroyed = FALSE;
        self.elements = elements = { target: target };
        self.timers = { img: {} };
        self.options = options;
        self.checks = {};
        self.plugins = {};
        self.cache = cache = {
            event: {},
            target: $(),
            disabled: FALSE,
            attr: attr,
            onTarget: FALSE,
            lastClass: ''
        };

        function convertNotation(notation) {
            var i = 0, obj, option = options,

            // Split notation into array
		levels = notation.split('.');

            // Loop through
            while (option = option[levels[i++]]) {
                if (i < levels.length) { obj = option; }
            }

            return [obj || options, levels.pop()];
        }

        function createWidgetClass(cls) {
            return widget.concat('').join(cls ? '-' + cls + ' ' : ' ');
        }

        function setWidget() {
            var on = options.style.widget,
			disabled = tooltip.hasClass(disabledClass);

            tooltip.removeClass(disabledClass);
            disabledClass = on ? 'ui-state-disabled' : 'qtip-disabled';
            tooltip.toggleClass(disabledClass, disabled);

            tooltip.toggleClass('ui-helper-reset ' + createWidgetClass(), on).toggleClass(defaultClass, options.style.def && !on);

            if (elements.content) {
                elements.content.toggleClass(createWidgetClass('content'), on);
            }
            if (elements.titlebar) {
                elements.titlebar.toggleClass(createWidgetClass('header'), on);
            }
            if (elements.button) {
                elements.button.toggleClass(NAMESPACE + '-icon', !on);
            }
        }

        function removeTitle(reposition) {
            if (elements.title) {
                elements.titlebar.remove();
                elements.titlebar = elements.title = elements.button = NULL;

                // Reposition if enabled
                if (reposition !== FALSE) { self.reposition(); }
            }
        }

        function createButton() {
            var button = options.content.title.button,
			isString = typeof button === 'string',
			close = isString ? button : 'Close tooltip';

            if (elements.button) { elements.button.remove(); }

            // Use custom button if one was supplied by user, else use default
            if (button.jquery) {
                elements.button = button;
            }
            else {
                elements.button = $('<a />', {
                    'class': 'qtip-close ' + (options.style.widget ? '' : NAMESPACE + '-icon'),
                    'title': close,
                    'aria-label': close
                })
			.prepend(
				$('<span />', {
				    'class': 'ui-icon ui-icon-close',
				    'html': '&times;'
				})
			);
            }

            // Create button and setup attributes
            elements.button.appendTo(elements.titlebar || tooltip)
			.attr('role', 'button')
			.click(function (event) {
			    if (!tooltip.hasClass(disabledClass)) { self.hide(event); }
			    return FALSE;
			});
        }

        function createTitle() {
            var id = tooltipID + '-title';

            // Destroy previous title element, if present
            if (elements.titlebar) { removeTitle(); }

            // Create title bar and title elements
            elements.titlebar = $('<div />', {
                'class': NAMESPACE + '-titlebar ' + (options.style.widget ? createWidgetClass('header') : '')
            })
		.append(
			elements.title = $('<div />', {
			    'id': id,
			    'class': NAMESPACE + '-title',
			    'aria-atomic': TRUE
			})
		)
		.insertBefore(elements.content)

            // Button-specific events
		.delegate('.qtip-close', 'mousedown keydown mouseup keyup mouseout', function (event) {
		    $(this).toggleClass('ui-state-active ui-state-focus', event.type.substr(-4) === 'down');
		})
		.delegate('.qtip-close', 'mouseover mouseout', function (event) {
		    $(this).toggleClass('ui-state-hover', event.type === 'mouseover');
		});

            // Create button if enabled
            if (options.content.title.button) { createButton(); }
        }

        function updateButton(button) {
            var elem = elements.button;

            // Make sure tooltip is rendered and if not, return
            if (!self.rendered) { return FALSE; }

            if (!button) {
                elem.remove();
            }
            else {
                createButton();
            }
        }

        function updateTitle(content, reposition) {
            var elem = elements.title;

            // Make sure tooltip is rendered and if not, return
            if (!self.rendered || !content) { return FALSE; }

            // Use function to parse content
            if ($.isFunction(content)) {
                content = content.call(target, cache.event, self);
            }

            // Remove title if callback returns false or null/undefined (but not '')
            if (content === FALSE || (!content && content !== '')) { return removeTitle(FALSE); }

            // Append new content if its a DOM array and show it if hidden
            else if (content.jquery && content.length > 0) {
                elem.empty().append(content.css({ display: 'block' }));
            }

            // Content is a regular string, insert the new content
            else { elem.html(content); }

            // Reposition if rnedered
            if (reposition !== FALSE && self.rendered && tooltip[0].offsetWidth > 0) {
                self.reposition(cache.event);
            }
        }

        function deferredContent(deferred) {
            if (deferred && $.isFunction(deferred.done)) {
                deferred.done(function (c) {
                    updateContent(c, null, FALSE);
                });
            }
        }

        function updateContent(content, reposition, checkDeferred) {
            var elem = elements.content;

            // Make sure tooltip is rendered and content is defined. If not return
            if (!self.rendered || !content) { return FALSE; }

            // Use function to parse content
            if ($.isFunction(content)) {
                content = content.call(target, cache.event, self) || '';
            }

            // Handle deferred content
            if (checkDeferred !== FALSE) {
                deferredContent(options.content.deferred);
            }

            // Append new content if its a DOM array and show it if hidden
            if (content.jquery && content.length > 0) {
                elem.empty().append(content.css({ display: 'block' }));
            }

            // Content is a regular string, insert the new content
            else { elem.html(content); }

            // Image detection
            function detectImages(next) {
                var images, srcs = {};

                function imageLoad(image) {
                    // Clear src from object and any timers and events associated with the image
                    if (image) {
                        delete srcs[image.src];
                        clearTimeout(self.timers.img[image.src]);
                        $(image).unbind(namespace);
                    }

                    // If queue is empty after image removal, update tooltip and continue the queue
                    if ($.isEmptyObject(srcs)) {
                        if (reposition !== FALSE) {
                            self.reposition(cache.event);
                        }

                        next();
                    }
                }

                // Find all content images without dimensions, and if no images were found, continue
                if ((images = elem.find('img[src]:not([height]):not([width])')).length === 0) { return imageLoad(); }

                // Apply timer to each image to poll for dimensions
                images.each(function (i, elem) {
                    // Skip if the src is already present
                    if (srcs[elem.src] !== undefined) { return; }

                    // Keep track of how many times we poll for image dimensions.
                    // If it doesn't return in a reasonable amount of time, it's better
                    // to display the tooltip, rather than hold up the queue.
                    var iterations = 0, maxIterations = 3;

                    (function timer() {
                        // When the dimensions are found, remove the image from the queue
                        if (elem.height || elem.width || (iterations > maxIterations)) { return imageLoad(elem); }

                        // Increase iterations and restart timer
                        iterations += 1;
                        self.timers.img[elem.src] = setTimeout(timer, 700);
                    } ());

                    // Also apply regular load/error event handlers
                    $(elem).bind('error' + namespace + ' load' + namespace, function () { imageLoad(this); });

                    // Store the src and element in our object
                    srcs[elem.src] = elem;
                });
            }

            /*
            * If we're still rendering... insert into 'fx' queue our image dimension
            * checker which will halt the showing of the tooltip until image dimensions
            * can be detected properly.
            */
            if (self.rendered < 0) { tooltip.queue('fx', detectImages); }

            // We're fully rendered, so reset isDrawing flag and proceed without queue delay
            else { isDrawing = 0; detectImages($.noop); }

            return self;
        }

        function assignEvents() {
            var posOptions = options.position,
			targets = {
			    show: options.show.target,
			    hide: options.hide.target,
			    viewport: $(posOptions.viewport),
			    document: $(document),
			    body: $(document.body),
			    window: $(window)
			},
			events = {
			    show: $.trim('' + options.show.event).split(' '),
			    hide: $.trim('' + options.hide.event).split(' ')
			},
			IE6 = PLUGINS.ie === 6;

            // Define show event method
            function showMethod(event) {
                if (tooltip.hasClass(disabledClass)) { return FALSE; }

                // Clear hide timers
                clearTimeout(self.timers.show);
                clearTimeout(self.timers.hide);

                // Start show timer
                var callback = function () { self.toggle(TRUE, event); };
                if (options.show.delay > 0) {
                    self.timers.show = setTimeout(callback, options.show.delay);
                }
                else { callback(); }
            }

            // Define hide method
            function hideMethod(event) {
                if (tooltip.hasClass(disabledClass) || isPositioning || isDrawing) { return FALSE; }

                // Check if new target was actually the tooltip element
                var relatedTarget = $(event.relatedTarget || event.target),
				ontoTooltip = relatedTarget.closest(selector)[0] === tooltip[0],
				ontoTarget = relatedTarget[0] === targets.show[0];

                // Clear timers and stop animation queue
                clearTimeout(self.timers.show);
                clearTimeout(self.timers.hide);

                // Prevent hiding if tooltip is fixed and event target is the tooltip. Or if mouse positioning is enabled and cursor momentarily overlaps
                if ((posOptions.target === 'mouse' && ontoTooltip) || (options.hide.fixed && ((/mouse(out|leave|move)/).test(event.type) && (ontoTooltip || ontoTarget)))) {
                    try { event.preventDefault(); event.stopImmediatePropagation(); } catch (e) { } return;
                }

                // If tooltip has displayed, start hide timer
                if (options.hide.delay > 0) {
                    self.timers.hide = setTimeout(function () { self.hide(event); }, options.hide.delay);
                }
                else { self.hide(event); }
            }

            // Define inactive method
            function inactiveMethod(event) {
                if (tooltip.hasClass(disabledClass)) { return FALSE; }

                // Clear timer
                clearTimeout(self.timers.inactive);
                self.timers.inactive = setTimeout(function () { self.hide(event); }, options.hide.inactive);
            }

            function repositionMethod(event) {
                if (self.rendered && tooltip[0].offsetWidth > 0) { self.reposition(event); }
            }

            // On mouseenter/mouseleave...
            tooltip.bind('mouseenter' + namespace + ' mouseleave' + namespace, function (event) {
                var state = event.type === 'mouseenter';

                // Focus the tooltip on mouseenter (z-index stacking)
                if (state) { self.focus(event); }

                // Add hover class
                tooltip.toggleClass(hoverClass, state);
            });

            // If using mouseout/mouseleave as a hide event...
            if (/mouse(out|leave)/i.test(options.hide.event)) {
                // Hide tooltips when leaving current window/frame (but not select/option elements)
                if (options.hide.leave === 'window') {
                    targets.window.bind('mouseout' + namespace + ' blur' + namespace, function (event) {
                        if (!/select|option/.test(event.target.nodeName) && !event.relatedTarget) { self.hide(event); }
                    });
                }
            }

            // Enable hide.fixed
            if (options.hide.fixed) {
                // Add tooltip as a hide target
                targets.hide = targets.hide.add(tooltip);

                // Clear hide timer on tooltip hover to prevent it from closing
                tooltip.bind('mouseover' + namespace, function () {
                    if (!tooltip.hasClass(disabledClass)) { clearTimeout(self.timers.hide); }
                });
            }

            /*
            * Make sure hoverIntent functions properly by using mouseleave to clear show timer if
            * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
            */
            else if (/mouse(over|enter)/i.test(options.show.event)) {
                targets.hide.bind('mouseleave' + namespace, function (event) {
                    clearTimeout(self.timers.show);
                });
            }

            // Hide tooltip on document mousedown if unfocus events are enabled
            if (('' + options.hide.event).indexOf('unfocus') > -1) {
                posOptions.container.closest('html').bind('mousedown' + namespace + ' touchstart' + namespace, function (event) {
                    var elem = $(event.target),
					enabled = self.rendered && !tooltip.hasClass(disabledClass) && tooltip[0].offsetWidth > 0,
					isAncestor = elem.parents(selector).filter(tooltip[0]).length > 0;

                    if (elem[0] !== target[0] && elem[0] !== tooltip[0] && !isAncestor &&
					!target.has(elem[0]).length && enabled
				) {
                        self.hide(event);
                    }
                });
            }

            // Check if the tooltip hides when inactive
            if ('number' === typeof options.hide.inactive) {
                // Bind inactive method to target as a custom event
                targets.show.bind('qtip-' + id + '-inactive', inactiveMethod);

                // Define events which reset the 'inactive' event handler
                $.each(QTIP.inactiveEvents, function (index, type) {
                    targets.hide.add(elements.tooltip).bind(type + namespace + '-inactive', inactiveMethod);
                });
            }

            // Apply hide events
            $.each(events.hide, function (index, type) {
                var showIndex = $.inArray(type, events.show),
					targetHide = $(targets.hide);

                // Both events and targets are identical, apply events using a toggle
                if ((showIndex > -1 && targetHide.add(targets.show).length === targetHide.length) || type === 'unfocus') {
                    targets.show.bind(type + namespace, function (event) {
                        if (tooltip[0].offsetWidth > 0) { hideMethod(event); }
                        else { showMethod(event); }
                    });

                    // Don't bind the event again
                    delete events.show[showIndex];
                }

                // Events are not identical, bind normally
                else { targets.hide.bind(type + namespace, hideMethod); }
            });

            // Apply show events
            $.each(events.show, function (index, type) {
                targets.show.bind(type + namespace, showMethod);
            });

            // Check if the tooltip hides when mouse is moved a certain distance
            if ('number' === typeof options.hide.distance) {
                // Bind mousemove to target to detect distance difference
                targets.show.add(tooltip).bind('mousemove' + namespace, function (event) {
                    var origin = cache.origin || {},
					limit = options.hide.distance,
					abs = Math.abs;

                    // Check if the movement has gone beyond the limit, and hide it if so
                    if (abs(event.pageX - origin.pageX) >= limit || abs(event.pageY - origin.pageY) >= limit) {
                        self.hide(event);
                    }
                });
            }

            // Mouse positioning events
            if (posOptions.target === 'mouse') {
                // Cache mousemove coords on show targets
                targets.show.bind('mousemove' + namespace, storeMouse);

                // If mouse adjustment is on...
                if (posOptions.adjust.mouse) {
                    // Apply a mouseleave event so we don't get problems with overlapping
                    if (options.hide.event) {
                        // Hide when we leave the tooltip and not onto the show target
                        tooltip.bind('mouseleave' + namespace, function (event) {
                            if ((event.relatedTarget || event.target) !== targets.show[0]) { self.hide(event); }
                        });

                        // Track if we're on the target or not
                        elements.target.bind('mouseenter' + namespace + ' mouseleave' + namespace, function (event) {
                            cache.onTarget = event.type === 'mouseenter';
                        });
                    }

                    // Update tooltip position on mousemove
                    targets.document.bind('mousemove' + namespace, function (event) {
                        // Update the tooltip position only if the tooltip is visible and adjustment is enabled
                        if (self.rendered && cache.onTarget && !tooltip.hasClass(disabledClass) && tooltip[0].offsetWidth > 0) {
                            self.reposition(event || MOUSE);
                        }
                    });
                }
            }

            // Adjust positions of the tooltip on window resize if enabled
            if (posOptions.adjust.resize || targets.viewport.length) {
                ($.event.special.resize ? targets.viewport : targets.window).bind('resize' + namespace, repositionMethod);
            }

            // Adjust tooltip position on scroll of the window or viewport element if present
            targets.window.add(posOptions.container).bind('scroll' + namespace, repositionMethod);
        }

        function unassignEvents() {
            var targets = [
				options.show.target[0],
				options.hide.target[0],
				self.rendered && elements.tooltip[0],
				options.position.container[0],
				options.position.viewport[0],
				options.position.container.closest('html')[0], // unfocus
				window,
				document
			];

            // Check if tooltip is rendered
            if (self.rendered) {
                $([]).pushStack($.grep(targets, function (i) { return typeof i === 'object'; })).unbind(namespace);
            }

            // Tooltip isn't yet rendered, remove render event
            else { options.show.target.unbind(namespace + '-create'); }
        }

        // Setup builtin .set() option checks
        self.checks.builtin = {
            // Core checks
            '^id$': function (obj, o, v) {
                var id = v === TRUE ? QTIP.nextid : v,
				tooltipID = NAMESPACE + '-' + id;

                if (id !== FALSE && id.length > 0 && !$('#' + tooltipID).length) {
                    tooltip[0].id = tooltipID;
                    elements.content[0].id = tooltipID + '-content';
                    elements.title[0].id = tooltipID + '-title';
                }
            },

            // Content checks
            '^content.text$': function (obj, o, v) { updateContent(options.content.text); },
            '^content.deferred$': function (obj, o, v) { deferredContent(options.content.deferred); },
            '^content.title.text$': function (obj, o, v) {
                // Remove title if content is null
                if (!v) { return removeTitle(); }

                // If title isn't already created, create it now and update
                if (!elements.title && v) { createTitle(); }
                updateTitle(v);
            },
            '^content.title.button$': function (obj, o, v) { updateButton(v); },

            // Position checks
            '^position.(my|at)$': function (obj, o, v) {
                // Parse new corner value into Corner objecct
                if ('string' === typeof v) {
                    obj[o] = new PLUGINS.Corner(v);
                }
            },
            '^position.container$': function (obj, o, v) {
                if (self.rendered) { tooltip.appendTo(v); }
            },

            // Show checks
            '^show.ready$': function () {
                if (!self.rendered) { self.render(1); }
                else { self.toggle(TRUE); }
            },

            // Style checks
            '^style.classes$': function (obj, o, v) {
                tooltip.attr('class', NAMESPACE + ' qtip ' + v);
            },
            '^style.width|height': function (obj, o, v) {
                tooltip.css(o, v);
            },
            '^style.widget|content.title': setWidget,

            // Events check
            '^events.(render|show|move|hide|focus|blur)$': function (obj, o, v) {
                tooltip[($.isFunction(v) ? '' : 'un') + 'bind']('tooltip' + o, v);
            },

            // Properties which require event reassignment
            '^(show|hide|position).(event|target|fixed|inactive|leave|distance|viewport|adjust)': function () {
                var posOptions = options.position;

                // Set tracking flag
                tooltip.attr('tracking', posOptions.target === 'mouse' && posOptions.adjust.mouse);

                // Reassign events
                unassignEvents(); assignEvents();
            }
        };

        $.extend(self, {
            /*
            * Psuedo-private API methods
            */
            _triggerEvent: function (type, args, event) {
                var callback = $.Event('tooltip' + type);
                callback.originalEvent = (event ? $.extend({}, event) : NULL) || cache.event || NULL;
                tooltip.trigger(callback, [self].concat(args || []));

                return !callback.isDefaultPrevented();
            },

            /*
            * Public API methods
            */
            render: function (show) {
                if (self.rendered) { return self; } // If tooltip has already been rendered, exit

                var text = options.content.text,
				title = options.content.title,
				posOptions = options.position;

                // Add ARIA attributes to target
                $.attr(target[0], 'aria-describedby', tooltipID);

                // Create tooltip element
                tooltip = elements.tooltip = $('<div/>', {
                    'id': tooltipID,
                    'class': [NAMESPACE, defaultClass, options.style.classes, NAMESPACE + '-pos-' + options.position.my.abbrev()].join(' '),
                    'width': options.style.width || '',
                    'height': options.style.height || '',
                    'tracking': posOptions.target === 'mouse' && posOptions.adjust.mouse,

                    /* ARIA specific attributes */
                    'role': 'alert',
                    'aria-live': 'polite',
                    'aria-atomic': FALSE,
                    'aria-describedby': tooltipID + '-content',
                    'aria-hidden': TRUE
                })
				.toggleClass(disabledClass, cache.disabled)
				.data('qtip', self)
				.appendTo(options.position.container)
				.append(
                // Create content element
					elements.content = $('<div />', {
					    'class': NAMESPACE + '-content',
					    'id': tooltipID + '-content',
					    'aria-atomic': TRUE
					})
				);

                // Set rendered flag and prevent redundant reposition calls for now
                self.rendered = -1;
                isPositioning = 1;

                // Create title...
                if (title.text) {
                    createTitle();

                    // Update title only if its not a callback (called in toggle if so)
                    if (!$.isFunction(title.text)) { updateTitle(title.text, FALSE); }
                }

                // Create button
                else if (title.button) { createButton(); }

                // Set proper rendered flag and update content if not a callback function (called in toggle)
                if (!$.isFunction(text) || text.then) { updateContent(text, FALSE); }
                self.rendered = TRUE;

                // Setup widget classes
                setWidget();

                // Assign passed event callbacks (before plugins!)
                $.each(options.events, function (name, callback) {
                    if ($.isFunction(callback)) {
                        tooltip.bind(name === 'toggle' ? 'tooltipshow tooltiphide' : 'tooltip' + name, callback);
                    }
                });

                // Initialize 'render' plugins
                $.each(PLUGINS, function () {
                    if (this.initialize === 'render') { this(self); }
                });

                // Assign events
                assignEvents();

                /* Queue this part of the render process in our fx queue so we can
                * load images before the tooltip renders fully.
                *
                * See: updateContent method
                */
                tooltip.queue('fx', function (next) {
                    // tooltiprender event
                    self._triggerEvent('render');

                    // Reset flags
                    isPositioning = 0;

                    // Show tooltip if needed
                    if (options.show.ready || show) {
                        self.toggle(TRUE, cache.event, FALSE);
                    }

                    next(); // Move on to next method in queue
                });

                return self;
            },

            get: function (notation) {
                var result, o;

                switch (notation.toLowerCase()) {
                    case 'dimensions':
                        result = {
                            height: tooltip.outerHeight(FALSE),
                            width: tooltip.outerWidth(FALSE)
                        };
                        break;

                    case 'offset':
                        result = PLUGINS.offset(tooltip, options.position.container);
                        break;

                    default:
                        o = convertNotation(notation.toLowerCase());
                        result = o[0][o[1]];
                        result = result.precedance ? result.string() : result;
                        break;
                }

                return result;
            },

            set: function (option, value) {
                var rmove = /^position\.(my|at|adjust|target|container)|style|content|show\.ready/i,
				rdraw = /^content\.(title|attr)|style/i,
				reposition = FALSE,
				checks = self.checks,
				name;

                function callback(notation, args) {
                    var category, rule, match;

                    for (category in checks) {
                        for (rule in checks[category]) {
                            if (match = (new RegExp(rule, 'i')).exec(notation)) {
                                args.push(match);
                                checks[category][rule].apply(self, args);
                            }
                        }
                    }
                }

                // Convert singular option/value pair into object form
                if ('string' === typeof option) {
                    name = option; option = {}; option[name] = value;
                }
                else { option = $.extend(TRUE, {}, option); }

                // Set all of the defined options to their new values
                $.each(option, function (notation, value) {
                    var obj = convertNotation(notation.toLowerCase()), previous;

                    // Set new obj value
                    previous = obj[0][obj[1]];
                    obj[0][obj[1]] = 'object' === typeof value && value.nodeType ? $(value) : value;

                    // Set the new params for the callback
                    option[notation] = [obj[0], obj[1], value, previous];

                    // Also check if we need to reposition
                    reposition = rmove.test(notation) || reposition;
                });

                // Re-sanitize options
                sanitizeOptions(options);

                /*
                * Execute any valid callbacks for the set options
                * Also set isPositioning/isDrawing so we don't get loads of redundant repositioning calls.
                */
                isPositioning = 1; $.each(option, callback); isPositioning = 0;

                // Update position if needed
                if (self.rendered && tooltip[0].offsetWidth > 0 && reposition) {
                    self.reposition(options.position.target === 'mouse' ? NULL : cache.event);
                }

                return self;
            },

            toggle: function (state, event) {
                // Try to prevent flickering when tooltip overlaps show element
                if (event) {
                    if ((/over|enter/).test(event.type) && (/out|leave/).test(cache.event.type) &&
					options.show.target.add(event.target).length === options.show.target.length &&
					tooltip.has(event.relatedTarget).length) {
                        return self;
                    }

                    // Cache event
                    cache.event = $.extend({}, event);
                }

                // Render the tooltip if showing and it isn't already
                if (!self.rendered) { return state ? self.render(1) : self; }

                var type = state ? 'show' : 'hide',
				opts = options[type],
				otherOpts = options[!state ? 'show' : 'hide'],
				posOptions = options.position,
				contentOptions = options.content,
				visible = tooltip[0].offsetWidth > 0,
				animate = state || opts.target.length === 1,
				sameTarget = !event || opts.target.length < 2 || cache.target[0] === event.target,
				showEvent, delay;

                // Detect state if valid one isn't provided
                if ((typeof state).search('boolean|number')) { state = !visible; }

                // Return if element is already in correct state
                if (!tooltip.is(':animated') && visible === state && sameTarget) { return self; }

                // tooltipshow/tooltiphide events
                if (!self._triggerEvent(type, [90])) { return self; }

                // Set ARIA hidden status attribute
                $.attr(tooltip[0], 'aria-hidden', !!!state);

                // Execute state specific properties
                if (state) {
                    // Store show origin coordinates
                    cache.origin = $.extend({}, MOUSE);

                    // Focus the tooltip
                    self.focus(event);

                    // Update tooltip content & title if it's a dynamic function
                    if ($.isFunction(contentOptions.text)) { updateContent(contentOptions.text, FALSE); }
                    if ($.isFunction(contentOptions.title.text)) { updateTitle(contentOptions.title.text, FALSE); }

                    // Cache mousemove events for positioning purposes (if not already tracking)
                    if (!trackingBound && posOptions.target === 'mouse' && posOptions.adjust.mouse) {
                        $(document).bind('mousemove.qtip', storeMouse);
                        trackingBound = TRUE;
                    }

                    // Update the tooltip position
                    self.reposition(event, arguments[2]);

                    // Hide other tooltips if tooltip is solo
                    if (!!opts.solo) {
                        (typeof opts.solo === 'string' ? $(opts.solo) : $(selector, opts.solo))
						.not(tooltip).not(opts.target).qtip('hide', $.Event('tooltipsolo'));
                    }
                }
                else {
                    // Clear show timer if we're hiding
                    clearTimeout(self.timers.show);

                    // Remove cached origin on hide
                    delete cache.origin;

                    // Remove mouse tracking event if not needed (all tracking qTips are hidden)
                    if (trackingBound && !$(selector + '[tracking="true"]:visible', opts.solo).not(tooltip).length) {
                        $(document).unbind('mousemove.qtip');
                        trackingBound = FALSE;
                    }

                    // Blur the tooltip
                    self.blur(event);
                }

                // Define post-animation, state specific properties
                function after() {
                    if (state) {
                        // Prevent antialias from disappearing in IE by removing filter
                        if (PLUGINS.ie) { tooltip[0].style.removeAttribute('filter'); }

                        // Remove overflow setting to prevent tip bugs
                        tooltip.css('overflow', '');

                        // Autofocus elements if enabled
                        if ('string' === typeof opts.autofocus) {
                            $(opts.autofocus, tooltip).focus();
                        }

                        // If set, hide tooltip when inactive for delay period
                        opts.target.trigger('qtip-' + id + '-inactive');
                    }
                    else {
                        // Reset CSS states
                        tooltip.css({
                            display: '',
                            visibility: '',
                            opacity: '',
                            left: '',
                            top: ''
                        });
                    }

                    // tooltipvisible/tooltiphidden events
                    self._triggerEvent(state ? 'visible' : 'hidden');
                }

                // If no effect type is supplied, use a simple toggle
                if (opts.effect === FALSE || animate === FALSE) {
                    tooltip[type]();
                    after.call(tooltip);
                }

                // Use custom function if provided
                else if ($.isFunction(opts.effect)) {
                    tooltip.stop(1, 1);
                    opts.effect.call(tooltip, self);
                    tooltip.queue('fx', function (n) { after(); n(); });
                }

                // Use basic fade function by default
                else { tooltip.fadeTo(90, state ? 1 : 0, after); }

                // If inactive hide method is set, active it
                if (state) { opts.target.trigger('qtip-' + id + '-inactive'); }

                return self;
            },

            show: function (event) { return self.toggle(TRUE, event); },

            hide: function (event) { return self.toggle(FALSE, event); },

            focus: function (event) {
                if (!self.rendered) { return self; }

                var qtips = $(selector),
				curIndex = parseInt(tooltip[0].style.zIndex, 10),
				newIndex = QTIP.zindex + qtips.length,
				cachedEvent = $.extend({}, event),
				focusedElem;

                // Only update the z-index if it has changed and tooltip is not already focused
                if (!tooltip.hasClass(focusClass)) {
                    // tooltipfocus event
                    if (self._triggerEvent('focus', [newIndex], cachedEvent)) {
                        // Only update z-index's if they've changed
                        if (curIndex !== newIndex) {
                            // Reduce our z-index's and keep them properly ordered
                            qtips.each(function () {
                                if (this.style.zIndex > curIndex) {
                                    this.style.zIndex = this.style.zIndex - 1;
                                }
                            });

                            // Fire blur event for focused tooltip
                            qtips.filter('.' + focusClass).qtip('blur', cachedEvent);
                        }

                        // Set the new z-index
                        tooltip.addClass(focusClass)[0].style.zIndex = newIndex;
                    }
                }

                return self;
            },

            blur: function (event) {
                // Set focused status to FALSE
                tooltip.removeClass(focusClass);

                // tooltipblur event
                self._triggerEvent('blur', [tooltip.css('zIndex')], event);

                return self;
            },

            reposition: function (event, effect) {
                if (!self.rendered || isPositioning) { return self; }

                // Set positioning flag
                isPositioning = 1;

                var target = options.position.target,
				posOptions = options.position,
				my = posOptions.my,
				at = posOptions.at,
				adjust = posOptions.adjust,
				method = adjust.method.split(' '),
				elemWidth = tooltip.outerWidth(FALSE),
				elemHeight = tooltip.outerHeight(FALSE),
				targetWidth = 0,
				targetHeight = 0,
				type = tooltip.css('position'),
				viewport = posOptions.viewport,
				position = { left: 0, top: 0 },
				container = posOptions.container,
				visible = tooltip[0].offsetWidth > 0,
				isScroll = event && event.type === 'scroll',
				win = $(window),
				adjusted, offset;

                // Check if absolute position was passed
                if ($.isArray(target) && target.length === 2) {
                    // Force left top and set position
                    at = { x: LEFT, y: TOP };
                    position = { left: target[0], top: target[1] };
                }

                // Check if mouse was the target
                else if (target === 'mouse' && ((event && event.pageX) || cache.event.pageX)) {
                    // Force left top to allow flipping
                    at = { x: LEFT, y: TOP };

                    // Use cached event if one isn't available for positioning
                    event = MOUSE && MOUSE.pageX && (adjust.mouse || !event || !event.pageX) ? { pageX: MOUSE.pageX, pageY: MOUSE.pageY} :
					(event && (event.type === 'resize' || event.type === 'scroll') ? cache.event :
					event && event.pageX && event.type === 'mousemove' ? event :
					(!adjust.mouse || options.show.distance) && cache.origin && cache.origin.pageX ? cache.origin :
					event) || event || cache.event || MOUSE || {};

                    // Use event coordinates for position
                    if (type !== 'static') { position = container.offset(); }
                    position = { left: event.pageX - position.left, top: event.pageY - position.top };

                    // Scroll events are a pain, some browsers
                    if (adjust.mouse && isScroll) {
                        position.left -= MOUSE.scrollX - win.scrollLeft();
                        position.top -= MOUSE.scrollY - win.scrollTop();
                    }
                }

                // Target wasn't mouse or absolute...
                else {
                    // Check if event targetting is being used
                    if (target === 'event' && event && event.target && event.type !== 'scroll' && event.type !== 'resize') {
                        cache.target = $(event.target);
                    }
                    else if (target !== 'event') {
                        cache.target = $(target.jquery ? target : elements.target);
                    }
                    target = cache.target;

                    // Parse the target into a jQuery object and make sure there's an element present
                    target = $(target).eq(0);
                    if (target.length === 0) { return self; }

                    // Check if window or document is the target
                    else if (target[0] === document || target[0] === window) {
                        targetWidth = PLUGINS.iOS ? window.innerWidth : target.width();
                        targetHeight = PLUGINS.iOS ? window.innerHeight : target.height();

                        if (target[0] === window) {
                            position = {
                                top: (viewport || target).scrollTop(),
                                left: (viewport || target).scrollLeft()
                            };
                        }
                    }

                    // Use Imagemap/SVG plugins if needed
                    else if (PLUGINS.imagemap && target.is('area')) {
                        adjusted = PLUGINS.imagemap(self, target, at, PLUGINS.viewport ? method : FALSE);
                    }
                    else if (PLUGINS.svg && target[0].ownerSVGElement) {
                        adjusted = PLUGINS.svg(self, target, at, PLUGINS.viewport ? method : FALSE);
                    }

                    else {
                        targetWidth = target.outerWidth(FALSE);
                        targetHeight = target.outerHeight(FALSE);

                        position = PLUGINS.offset(target, container);
                    }

                    // Parse returned plugin values into proper variables
                    if (adjusted) {
                        targetWidth = adjusted.width;
                        targetHeight = adjusted.height;
                        offset = adjusted.offset;
                        position = adjusted.position;
                    }

                    // Adjust for position.fixed tooltips (and also iOS scroll bug in v3.2-4.0 & v4.3-4.3.2)
                    if ((PLUGINS.iOS > 3.1 && PLUGINS.iOS < 4.1) ||
					(PLUGINS.iOS >= 4.3 && PLUGINS.iOS < 4.33) ||
					(!PLUGINS.iOS && type === 'fixed')
				) {
                        position.left -= win.scrollLeft();
                        position.top -= win.scrollTop();
                    }

                    // Adjust position relative to target
                    position.left += at.x === RIGHT ? targetWidth : at.x === CENTER ? targetWidth / 2 : 0;
                    position.top += at.y === BOTTOM ? targetHeight : at.y === CENTER ? targetHeight / 2 : 0;
                }

                // Adjust position relative to tooltip
                position.left += adjust.x + (my.x === RIGHT ? -elemWidth : my.x === CENTER ? -elemWidth / 2 : 0);
                position.top += adjust.y + (my.y === BOTTOM ? -elemHeight : my.y === CENTER ? -elemHeight / 2 : 0);

                // Use viewport adjustment plugin if enabled
                if (PLUGINS.viewport) {
                    position.adjusted = PLUGINS.viewport(
					self, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight
				);

                    // Apply offsets supplied by positioning plugin (if used)
                    if (offset && position.adjusted.left) { position.left += offset.left; }
                    if (offset && position.adjusted.top) { position.top += offset.top; }
                }

                // Viewport adjustment is disabled, set values to zero
                else { position.adjusted = { left: 0, top: 0 }; }

                // tooltipmove event
                if (!self._triggerEvent('move', [position, viewport.elem || viewport], event)) { return self; }
                delete position.adjusted;

                // If effect is disabled, target it mouse, no animation is defined or positioning gives NaN out, set CSS directly
                if (effect === FALSE || !visible || isNaN(position.left) || isNaN(position.top) || target === 'mouse' || !$.isFunction(posOptions.effect)) {
                    tooltip.css(position);
                }

                // Use custom function if provided
                else if ($.isFunction(posOptions.effect)) {
                    posOptions.effect.call(tooltip, self, $.extend({}, position));
                    tooltip.queue(function (next) {
                        // Reset attributes to avoid cross-browser rendering bugs
                        $(this).css({ opacity: '', height: '' });
                        if (PLUGINS.ie) { this.style.removeAttribute('filter'); }

                        next();
                    });
                }

                // Set positioning flagwtf
                isPositioning = 0;

                return self;
            },

            disable: function (state) {
                if ('boolean' !== typeof state) {
                    state = !(tooltip.hasClass(disabledClass) || cache.disabled);
                }

                if (self.rendered) {
                    tooltip.toggleClass(disabledClass, state);
                    $.attr(tooltip[0], 'aria-disabled', state);
                }
                else {
                    cache.disabled = !!state;
                }

                return self;
            },

            enable: function () { return self.disable(FALSE); },

            destroy: function () {
                var t = target[0],
				title = $.attr(t, oldtitle),
				elemAPI = target.data('qtip');

                // Set flag the signify destroy is taking place to plugins
                self.destroyed = TRUE;

                // Destroy tooltip and  any associated plugins if rendered
                if (self.rendered) {
                    tooltip.stop(1, 0).remove();

                    $.each(self.plugins, function () {
                        if (this.destroy) { this.destroy(); }
                    });
                }

                // Clear timers and remove bound events
                clearTimeout(self.timers.show);
                clearTimeout(self.timers.hide);
                unassignEvents();

                // If the API if actually this qTip API...
                if (!elemAPI || self === elemAPI) {
                    // Remove api object
                    $.removeData(t, 'qtip');

                    // Reset old title attribute if removed
                    if (options.suppress && title) {
                        $.attr(t, 'title', title);
                        target.removeAttr(oldtitle);
                    }

                    // Remove ARIA attributes
                    target.removeAttr('aria-describedby');
                }

                // Remove qTip events associated with this API
                target.unbind('.qtip-' + id);

                // Remove ID from sued id object
                delete usedIDs[self.id];

                return target;
            }
        });
    }

    // Initialization method
    function init(id, opts) {
        var obj, posOptions, attr, config, title,

        // Setup element references
	elem = $(this),
	docBody = $(document.body),

        // Use document body instead of document element if needed
	newTarget = this === document ? docBody : elem,

        // Grab metadata from element if plugin is present
	metadata = (elem.metadata) ? elem.metadata(opts.metadata) : NULL,

        // If metadata type if HTML5, grab 'name' from the object instead, or use the regular data object otherwise
	metadata5 = opts.metadata.type === 'html5' && metadata ? metadata[opts.metadata.name] : NULL,

        // Grab data from metadata.name (or data-qtipopts as fallback) using .data() method,
	html5 = elem.data(opts.metadata.name || 'qtipopts');

        // If we don't get an object returned attempt to parse it manualyl without parseJSON
        try { html5 = typeof html5 === 'string' ? $.parseJSON(html5) : html5; } catch (e) { }

        // Merge in and sanitize metadata
        config = $.extend(TRUE, {}, QTIP.defaults, opts,
		typeof html5 === 'object' ? sanitizeOptions(html5) : NULL,
		sanitizeOptions(metadata5 || metadata));

        // Re-grab our positioning options now we've merged our metadata and set id to passed value
        posOptions = config.position;
        config.id = id;

        // Setup missing content if none is detected
        if ('boolean' === typeof config.content.text) {
            attr = elem.attr(config.content.attr);

            // Grab from supplied attribute if available
            if (config.content.attr !== FALSE && attr) { config.content.text = attr; }

            // No valid content was found, abort render
            else { return FALSE; }
        }

        // Setup target options
        if (!posOptions.container.length) { posOptions.container = docBody; }
        if (posOptions.target === FALSE) { posOptions.target = newTarget; }
        if (config.show.target === FALSE) { config.show.target = newTarget; }
        if (config.show.solo === TRUE) { config.show.solo = posOptions.container.closest('body'); }
        if (config.hide.target === FALSE) { config.hide.target = newTarget; }
        if (config.position.viewport === TRUE) { config.position.viewport = posOptions.container; }

        // Ensure we only use a single container
        posOptions.container = posOptions.container.eq(0);

        // Convert position corner values into x and y strings
        posOptions.at = new PLUGINS.Corner(posOptions.at);
        posOptions.my = new PLUGINS.Corner(posOptions.my);

        // Destroy previous tooltip if overwrite is enabled, or skip element if not
        if ($.data(this, 'qtip')) {
            if (config.overwrite) {
                elem.qtip('destroy');
            }
            else if (config.overwrite === FALSE) {
                return FALSE;
            }
        }

        // Remove title attribute and store it if present
        if (config.suppress && (title = $.attr(this, 'title'))) {
            // Final attr call fixes event delegatiom and IE default tooltip showing problem
            $(this).removeAttr('title').attr(oldtitle, title).attr('title', '');
        }

        // Initialize the tooltip and add API reference
        obj = new QTip(elem, config, id, !!attr);
        $.data(this, 'qtip', obj);

        // Catch remove/removeqtip events on target element to destroy redundant tooltip
        elem.one('remove.qtip-' + id + ' removeqtip.qtip-' + id, function () { obj.destroy(); });

        return obj;
    }

    // jQuery $.fn extension method
    QTIP = $.fn.qtip = function (options, notation, newValue) {
        var command = ('' + options).toLowerCase(), // Parse command
		returned = NULL,
		args = $.makeArray(arguments).slice(1),
		event = args[args.length - 1],
		opts = this[0] ? $.data(this[0], 'qtip') : NULL;

        // Check for API request
        if ((!arguments.length && opts) || command === 'api') {
            return opts;
        }

        // Execute API command if present
        else if ('string' === typeof options) {
            this.each(function () {
                var api = $.data(this, 'qtip');
                if (!api) { return TRUE; }

                // Cache the event if possible
                if (event && event.timeStamp) { api.cache.event = event; }

                // Check for specific API commands
                if ((command === 'option' || command === 'options') && notation) {
                    if ($.isPlainObject(notation) || newValue !== undefined) {
                        api.set(notation, newValue);
                    }
                    else {
                        returned = api.get(notation);
                        return FALSE;
                    }
                }

                // Execute API command
                else if (api[command]) {
                    api[command].apply(api[command], args);
                }
            });

            return returned !== NULL ? returned : this;
        }

        // No API commands. validate provided options and setup qTips
        else if ('object' === typeof options || !arguments.length) {
            opts = sanitizeOptions($.extend(TRUE, {}, options));

            // Bind the qTips
            return QTIP.bind.call(this, opts, event);
        }
    };

    // $.fn.qtip Bind method
    QTIP.bind = function (opts, event) {
        return this.each(function (i) {
            var options, targets, events, namespace, api, id;

            // Find next available ID, or use custom ID if provided
            id = $.isArray(opts.id) ? opts.id[i] : opts.id;
            id = !id || id === FALSE || id.length < 1 || usedIDs[id] ? QTIP.nextid++ : (usedIDs[id] = id);

            // Setup events namespace
            namespace = '.qtip-' + id + '-create';

            // Initialize the qTip and re-grab newly sanitized options
            api = init.call(this, id, opts);
            if (api === FALSE) { return TRUE; }
            options = api.options;

            // Initialize plugins
            $.each(PLUGINS, function () {
                if (this.initialize === 'initialize') { this(api); }
            });

            // Determine hide and show targets
            targets = { show: options.show.target, hide: options.hide.target };
            events = {
                show: $.trim('' + options.show.event).replace(/ /g, namespace + ' ') + namespace,
                hide: $.trim('' + options.hide.event).replace(/ /g, namespace + ' ') + namespace
            };

            /*
            * Make sure hoverIntent functions properly by using mouseleave as a hide event if
            * mouseenter/mouseout is used for show.event, even if it isn't in the users options.
            */
            if (/mouse(over|enter)/i.test(events.show) && !/mouse(out|leave)/i.test(events.hide)) {
                events.hide += ' mouseleave' + namespace;
            }

            /*
            * Also make sure initial mouse targetting works correctly by caching mousemove coords
            * on show targets before the tooltip has rendered.
            *
            * Also set onTarget when triggered to keep mouse tracking working
            */
            targets.show.bind('mousemove' + namespace, function (event) {
                storeMouse(event);
                api.cache.onTarget = TRUE;
            });

            // Define hoverIntent function
            function hoverIntent(event) {
                function render() {
                    // Cache mouse coords,render and render the tooltip
                    api.render(typeof event === 'object' || options.show.ready);

                    // Unbind show and hide events
                    targets.show.add(targets.hide).unbind(namespace);
                }

                // Only continue if tooltip isn't disabled
                if (api.cache.disabled) { return FALSE; }

                // Cache the event data
                api.cache.event = $.extend({}, event);
                api.cache.target = event ? $(event.target) : [undefined];

                // Start the event sequence
                if (options.show.delay > 0) {
                    clearTimeout(api.timers.show);
                    api.timers.show = setTimeout(render, options.show.delay);
                    if (events.show !== events.hide) {
                        targets.hide.bind(events.hide, function () { clearTimeout(api.timers.show); });
                    }
                }
                else { render(); }
            }

            // Bind show events to target
            targets.show.bind(events.show, hoverIntent);

            // Prerendering is enabled, create tooltip now
            if (options.show.ready || options.prerender) { hoverIntent(event); }
        })
	.attr('data-hasqtip', TRUE);
    };

    // Setup base plugins
    PLUGINS = QTIP.plugins = {
        // Corner object parser
        Corner: function (corner) {
            corner = ('' + corner).replace(/([A-Z])/, ' $1').replace(/middle/gi, CENTER).toLowerCase();
            this.x = (corner.match(/left|right/i) || corner.match(/center/) || ['inherit'])[0].toLowerCase();
            this.y = (corner.match(/top|bottom|center/i) || ['inherit'])[0].toLowerCase();

            var f = corner.charAt(0); this.precedance = (f === 't' || f === 'b' ? Y : X);

            this.string = function () { return this.precedance === Y ? this.y + this.x : this.x + this.y; };
            this.abbrev = function () {
                var x = this.x.substr(0, 1), y = this.y.substr(0, 1);
                return x === y ? x : this.precedance === Y ? y + x : x + y;
            };

            this.invertx = function (center) { this.x = this.x === LEFT ? RIGHT : this.x === RIGHT ? LEFT : center || this.x; };
            this.inverty = function (center) { this.y = this.y === TOP ? BOTTOM : this.y === BOTTOM ? TOP : center || this.y; };

            this.clone = function () {
                return {
                    x: this.x, y: this.y, precedance: this.precedance,
                    string: this.string, abbrev: this.abbrev, clone: this.clone,
                    invertx: this.invertx, inverty: this.inverty
                };
            };
        },

        // Custom (more correct for qTip!) offset calculator
        offset: function (elem, container) {
            var pos = elem.offset(),
			docBody = elem.closest('body'),
			quirks = PLUGINS.ie && document.compatMode !== 'CSS1Compat',
			parent = container, scrolled,
			coffset, overflow;

            function scroll(e, i) {
                pos.left += i * e.scrollLeft();
                pos.top += i * e.scrollTop();
            }

            if (parent) {
                // Compensate for non-static containers offset
                do {
                    if (parent.css('position') !== 'static') {
                        coffset = parent.position();

                        // Account for element positioning, borders and margins
                        pos.left -= coffset.left + (parseInt(parent.css('borderLeftWidth'), 10) || 0) + (parseInt(parent.css('marginLeft'), 10) || 0);
                        pos.top -= coffset.top + (parseInt(parent.css('borderTopWidth'), 10) || 0) + (parseInt(parent.css('marginTop'), 10) || 0);

                        // If this is the first parent element with an overflow of "scroll" or "auto", store it
                        if (!scrolled && (overflow = parent.css('overflow')) !== 'hidden' && overflow !== 'visible') { scrolled = parent; }
                    }
                }
                while ((parent = $(parent[0].offsetParent)).length);

                // Compensate for containers scroll if it also has an offsetParent (or in IE quirks mode)
                if (scrolled && scrolled[0] !== docBody[0] || quirks) {
                    scroll(scrolled || docBody, 1);
                }
            }

            return pos;
        },

        /*
        * IE version detection
        *
        * Adapted from: http://ajaxian.com/archives/attack-of-the-ie-conditional-comment
        * Credit to James Padolsey for the original implemntation!
        */
        ie: (function () {
            var v = 3, div = document.createElement('div');
            while ((div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->')) {
                if (!div.getElementsByTagName('i')[0]) { break; }
            }
            return v > 4 ? v : FALSE;
        } ()),

        /*
        * iOS version detection
        */
        iOS: parseFloat(
		('' + (/CPU.*OS ([0-9_]{1,5})|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1])
		.replace('undefined', '3_2').replace('_', '.').replace('_', '')
	) || FALSE,

        /*
        * jQuery-specific $.fn overrides
        */
        fn: {
            /* Allow other plugins to successfully retrieve the title of an element with a qTip applied */
            attr: function (attr, val) {
                if (this.length) {
                    var self = this[0],
					title = 'title',
					api = $.data(self, 'qtip');

                    if (attr === title && api && 'object' === typeof api && api.options.suppress) {
                        if (arguments.length < 2) {
                            return $.attr(self, oldtitle);
                        }

                        // If qTip is rendered and title was originally used as content, update it
                        if (api && api.options.content.attr === title && api.cache.attr) {
                            api.set('content.text', val);
                        }

                        // Use the regular attr method to set, then cache the result
                        return this.attr(oldtitle, val);
                    }
                }

                return $.fn['attr' + replaceSuffix].apply(this, arguments);
            },

            /* Allow clone to correctly retrieve cached title attributes */
            clone: function (keepData) {
                var titles = $([]), title = 'title',

                // Clone our element using the real clone method
			elems = $.fn['clone' + replaceSuffix].apply(this, arguments);

                // Grab all elements with an oldtitle set, and change it to regular title attribute, if keepData is false
                if (!keepData) {
                    elems.filter('[' + oldtitle + ']').attr('title', function () {
                        return $.attr(this, oldtitle);
                    })
				.removeAttr(oldtitle);
                }

                return elems;
            }
        }
    };

    // Apply the fn overrides above
    $.each(PLUGINS.fn, function (name, func) {
        if (!func || $.fn[name + replaceSuffix]) { return TRUE; }

        var old = $.fn[name + replaceSuffix] = $.fn[name];
        $.fn[name] = function () {
            return func.apply(this, arguments) || old.apply(this, arguments);
        };
    });

    /* Fire off 'removeqtip' handler in $.cleanData if jQuery UI not present (it already does similar).
    * This snippet is taken directly from jQuery UI source code found here:
    *     http://code.jquery.com/ui/jquery-ui-git.js
    */
    if (!$.ui) {
        $['cleanData' + replaceSuffix] = $.cleanData;
        $.cleanData = function (elems) {
            for (var i = 0, elem; (elem = elems[i]) !== undefined; i++) {
                try { $(elem).triggerHandler('removeqtip'); }
                catch (e) { }
            }
            $['cleanData' + replaceSuffix](elems);
        };
    }

    // Set global qTip properties
    QTIP.version = '2.0.1-11-';
    QTIP.nextid = 0;
    QTIP.inactiveEvents = 'click dblclick mousedown mouseup mousemove mouseleave mouseenter'.split(' ');
    QTIP.zindex = 15000;

    // Define configuration defaults
    QTIP.defaults = {
        prerender: FALSE,
        id: FALSE,
        overwrite: TRUE,
        suppress: TRUE,
        content: {
            text: TRUE,
            attr: 'title',
            deferred: FALSE,
            title: {
                text: FALSE,
                button: FALSE
            }
        },
        position: {
            my: 'top left',
            at: 'bottom right',
            target: FALSE,
            container: FALSE,
            viewport: FALSE,
            adjust: {
                x: 0, y: 0,
                mouse: TRUE,
                resize: TRUE,
                method: 'flipinvert flipinvert'
            },
            effect: function (api, pos, viewport) {
                $(this).animate(pos, {
                    duration: 200,
                    queue: FALSE
                });
            }
        },
        show: {
            target: FALSE,
            event: 'mouseenter',
            effect: TRUE,
            delay: 90,
            solo: FALSE,
            ready: FALSE,
            autofocus: FALSE
        },
        hide: {
            target: FALSE,
            event: 'mouseleave',
            effect: TRUE,
            delay: 0,
            fixed: FALSE,
            inactive: FALSE,
            leave: 'window',
            distance: FALSE
        },
        style: {
            classes: '',
            widget: FALSE,
            width: FALSE,
            height: FALSE,
            def: TRUE
        },
        events: {
            render: NULL,
            move: NULL,
            show: NULL,
            hide: NULL,
            toggle: NULL,
            visible: NULL,
            hidden: NULL,
            focus: NULL,
            blur: NULL
        }
    };


    PLUGINS.svg = function (api, svg, corner, adjustMethod) {
        var doc = $(document),
		elem = svg[0],
		result = {
		    width: 0, height: 0,
		    position: { top: 1e10, left: 1e10 }
		},
		box, mtx, root, point, tPoint;

        // Ascend the parentNode chain until we find an element with getBBox()
        while (!elem.getBBox) { elem = elem.parentNode; }

        // Check for a valid bounding box method
        if (elem.getBBox && elem.parentNode) {
            box = elem.getBBox();
            mtx = elem.getScreenCTM();
            root = elem.farthestViewportElement || elem;

            // Return if no method is found
            if (!root.createSVGPoint) { return result; }

            // Create our point var
            point = root.createSVGPoint();

            // Adjust top and left
            point.x = box.x;
            point.y = box.y;
            tPoint = point.matrixTransform(mtx);
            result.position.left = tPoint.x;
            result.position.top = tPoint.y;

            // Adjust width and height
            point.x += box.width;
            point.y += box.height;
            tPoint = point.matrixTransform(mtx);
            result.width = tPoint.x - result.position.left;
            result.height = tPoint.y - result.position.top;

            // Adjust by scroll offset
            result.position.left += doc.scrollLeft();
            result.position.top += doc.scrollTop();
        }

        return result;
    };


    function Ajax(api) {
        var self = this,
		tooltip = api.elements.tooltip,
		opts = api.options.content.ajax,
		defaults = QTIP.defaults.content.ajax,
		namespace = '.qtip-ajax',
		rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
		first = TRUE,
		stop = FALSE,
		xhr;

        api.checks.ajax = {
            '^content.ajax': function (obj, name, v) {
                // If content.ajax object was reset, set our local var
                if (name === 'ajax') { opts = v; }

                if (name === 'once') {
                    self.init();
                }
                else if (opts && opts.url) {
                    self.load();
                }
                else {
                    tooltip.unbind(namespace);
                }
            }
        };

        $.extend(self, {
            init: function () {
                // Make sure ajax options are enabled and bind event
                if (opts && opts.url) {
                    tooltip.unbind(namespace)[opts.once ? 'one' : 'bind']('tooltipshow' + namespace, self.load);
                }

                return self;
            },

            load: function (event) {
                if (stop) { stop = FALSE; return; }

                var hasSelector = opts.url.lastIndexOf(' '),
				url = opts.url,
				selector,
				hideFirst = !opts.loading && first;

                // If loading option is disabled, prevent the tooltip showing until we've completed the request
                if (hideFirst) { try { event.preventDefault(); } catch (e) { } }

                // Make sure default event hasn't been prevented
                else if (event && event.isDefaultPrevented()) { return self; }

                // Cancel old request
                if (xhr && xhr.abort) { xhr.abort(); }

                // Check if user delcared a content selector like in .load()
                if (hasSelector > -1) {
                    selector = url.substr(hasSelector);
                    url = url.substr(0, hasSelector);
                }

                // Define common after callback for both success/error handlers
                function after() {
                    var complete;

                    // Don't proceed if tooltip is destroyed
                    if (api.destroyed) { return; }

                    // Set first flag to false
                    first = FALSE;

                    // Re-display tip if loading and first time, and reset first flag
                    if (hideFirst) { stop = TRUE; api.show(event.originalEvent); }

                    // Call users complete method if it was defined
                    if ((complete = defaults.complete || opts.complete) && $.isFunction(complete)) {
                        complete.apply(opts.context || api, arguments);
                    }
                }

                // Define success handler
                function successHandler(content, status, jqXHR) {
                    var success;

                    // Don't proceed if tooltip is destroyed
                    if (api.destroyed) { return; }

                    // If URL contains a selector
                    if (selector && 'string' === typeof content) {
                        // Create a dummy div to hold the results and grab the selector element
                        content = $('<div/>')
                        // inject the contents of the document in, removing the scripts
                        // to avoid any 'Permission Denied' errors in IE
						.append(content.replace(rscript, ""))

                        // Locate the specified elements
						.find(selector);
                    }

                    // Call the success function if one is defined
                    if ((success = defaults.success || opts.success) && $.isFunction(success)) {
                        success.call(opts.context || api, content, status, jqXHR);
                    }

                    // Otherwise set the content
                    else { api.set('content.text', content); }
                }

                // Error handler
                function errorHandler(xhr, status, error) {
                    if (api.destroyed || xhr.status === 0) { return; }
                    api.set('content.text', status + ': ' + error);
                }

                // Setup $.ajax option object and process the request
                xhr = $.ajax(
				$.extend({
				    error: defaults.error || errorHandler,
				    context: api
				},
				opts, { url: url, success: successHandler, complete: after })
			);
            },

            destroy: function () {
                // Cancel ajax request if possible
                if (xhr && xhr.abort) { xhr.abort(); }

                // Set api.destroyed flag
                api.destroyed = TRUE;
            }
        });

        self.init();
    }


    PLUGINS.ajax = function (api) {
        var self = api.plugins.ajax;

        return 'object' === typeof self ? self : (api.plugins.ajax = new Ajax(api));
    };

    PLUGINS.ajax.initialize = 'render';

    // Setup plugin sanitization
    PLUGINS.ajax.sanitize = function (options) {
        var content = options.content, opts;
        if (content && 'ajax' in content) {
            opts = content.ajax;
            if (typeof opts !== 'object') { opts = options.content.ajax = { url: opts }; }
            if ('boolean' !== typeof opts.once && opts.once) { opts.once = !!opts.once; }
        }
    };

    // Extend original api defaults
    $.extend(TRUE, QTIP.defaults, {
        content: {
            ajax: {
                loading: TRUE,
                once: TRUE
            }
        }
    });


    // Tip coordinates calculator
    function calculateTip(corner, width, height) {
        var width2 = Math.ceil(width / 2), height2 = Math.ceil(height / 2),

        // Define tip coordinates in terms of height and width values
	tips = {
	    bottomright: [[0, 0], [width, height], [width, 0]],
	    bottomleft: [[0, 0], [width, 0], [0, height]],
	    topright: [[0, height], [width, 0], [width, height]],
	    topleft: [[0, 0], [0, height], [width, height]],
	    topcenter: [[0, height], [width2, 0], [width, height]],
	    bottomcenter: [[0, 0], [width, 0], [width2, height]],
	    rightcenter: [[0, 0], [width, height2], [0, height]],
	    leftcenter: [[width, 0], [width, height], [0, height2]]
	};

        // Set common side shapes
        tips.lefttop = tips.bottomright; tips.righttop = tips.bottomleft;
        tips.leftbottom = tips.topright; tips.rightbottom = tips.topleft;

        return tips[corner.string()];
    }


    function Tip(qTip, command) {
        var self = this,
		opts = qTip.options.style.tip,
		elems = qTip.elements,
		tooltip = elems.tooltip,
		cache = { top: 0, left: 0 },
		size = {
		    width: opts.width,
		    height: opts.height
		},
		color = {},
		border = opts.border || 0,
		namespace = '.qtip-tip',
		hasCanvas = !!($('<canvas />')[0] || {}).getContext,
		tiphtml;

        self.corner = NULL;
        self.mimic = NULL;
        self.border = border;
        self.offset = opts.offset;
        self.size = size;

        // Add new option checks for the plugin
        qTip.checks.tip = {
            '^position.my|style.tip.(corner|mimic|border)$': function () {
                // Make sure a tip can be drawn
                if (!self.init()) {
                    self.destroy();
                }

                // Reposition the tooltip
                qTip.reposition();
            },
            '^style.tip.(height|width)$': function () {
                // Re-set dimensions and redraw the tip
                size = {
                    width: opts.width,
                    height: opts.height
                };
                self.create();
                self.update();

                // Reposition the tooltip
                qTip.reposition();
            },
            '^content.title.text|style.(classes|widget)$': function () {
                if (elems.tip && elems.tip.length) {
                    self.update();
                }
            }
        };

        function whileVisible(callback) {
            var visible = tooltip.is(':visible');
            tooltip.show(); callback(); tooltip.toggle(visible);
        }

        function swapDimensions() {
            size.width = opts.height;
            size.height = opts.width;
        }

        function resetDimensions() {
            size.width = opts.width;
            size.height = opts.height;
        }

        function reposition(event, api, pos, viewport) {
            if (!elems.tip) { return; }

            var newCorner = self.corner.clone(),
			adjust = pos.adjusted,
			method = qTip.options.position.adjust.method.split(' '),
			horizontal = method[0],
			vertical = method[1] || method[0],
			shift = { left: FALSE, top: FALSE, x: 0, y: 0 },
			offset, css = {}, props;

            // If our tip position isn't fixed e.g. doesn't adjust with viewport...
            if (self.corner.fixed !== TRUE) {
                // Horizontal - Shift or flip method
                if (horizontal === SHIFT && newCorner.precedance === X && adjust.left && newCorner.y !== CENTER) {
                    newCorner.precedance = newCorner.precedance === X ? Y : X;
                }
                else if (horizontal !== SHIFT && adjust.left) {
                    newCorner.x = newCorner.x === CENTER ? (adjust.left > 0 ? LEFT : RIGHT) : (newCorner.x === LEFT ? RIGHT : LEFT);
                }

                // Vertical - Shift or flip method
                if (vertical === SHIFT && newCorner.precedance === Y && adjust.top && newCorner.x !== CENTER) {
                    newCorner.precedance = newCorner.precedance === Y ? X : Y;
                }
                else if (vertical !== SHIFT && adjust.top) {
                    newCorner.y = newCorner.y === CENTER ? (adjust.top > 0 ? TOP : BOTTOM) : (newCorner.y === TOP ? BOTTOM : TOP);
                }

                // Update and redraw the tip if needed (check cached details of last drawn tip)
                if (newCorner.string() !== cache.corner.string() && (cache.top !== adjust.top || cache.left !== adjust.left)) {
                    self.update(newCorner, FALSE);
                }
            }

            // Setup tip offset properties
            offset = self.position(newCorner, adjust);
            offset[newCorner.x] += parseWidth(newCorner, newCorner.x);
            offset[newCorner.y] += parseWidth(newCorner, newCorner.y);

            // Readjust offset object to make it left/top
            if (offset.right !== undefined) { offset.left = -offset.right; }
            if (offset.bottom !== undefined) { offset.top = -offset.bottom; }
            offset.user = Math.max(0, opts.offset);

            // Viewport "shift" specific adjustments
            if (shift.left = (horizontal === SHIFT && !!adjust.left)) {
                if (newCorner.x === CENTER) {
                    css['margin-left'] = shift.x = offset['margin-left'];
                }
                else {
                    props = offset.right !== undefined ?
					[adjust.left, -offset.left] : [-adjust.left, offset.left];

                    if ((shift.x = Math.max(props[0], props[1])) > props[0]) {
                        pos.left -= adjust.left;
                        shift.left = FALSE;
                    }

                    css[offset.right !== undefined ? RIGHT : LEFT] = shift.x;
                }
            }
            if (shift.top = (vertical === SHIFT && !!adjust.top)) {
                if (newCorner.y === CENTER) {
                    css['margin-top'] = shift.y = offset['margin-top'];
                }
                else {
                    props = offset.bottom !== undefined ?
					[adjust.top, -offset.top] : [-adjust.top, offset.top];

                    if ((shift.y = Math.max(props[0], props[1])) > props[0]) {
                        pos.top -= adjust.top;
                        shift.top = FALSE;
                    }

                    css[offset.bottom !== undefined ? BOTTOM : TOP] = shift.y;
                }
            }

            /*
            * If the tip is adjusted in both dimensions, or in a
            * direction that would cause it to be anywhere but the
            * outer border, hide it!
            */
            elems.tip.css(css).toggle(
			!((shift.x && shift.y) || (newCorner.x === CENTER && shift.y) || (newCorner.y === CENTER && shift.x))
		);

            // Adjust position to accomodate tip dimensions
            pos.left -= offset.left.charAt ? offset.user : horizontal !== SHIFT || shift.top || !shift.left && !shift.top ? offset.left : 0;
            pos.top -= offset.top.charAt ? offset.user : vertical !== SHIFT || shift.left || !shift.left && !shift.top ? offset.top : 0;

            // Cache details
            cache.left = adjust.left; cache.top = adjust.top;
            cache.corner = newCorner.clone();
        }

        function parseCorner() {
            var corner = opts.corner,
			posOptions = qTip.options.position,
			at = posOptions.at,
			my = posOptions.my.string ? posOptions.my.string() : posOptions.my;

            // Detect corner and mimic properties
            if (corner === FALSE || (my === FALSE && at === FALSE)) {
                return FALSE;
            }
            else {
                if (corner === TRUE) {
                    self.corner = new PLUGINS.Corner(my);
                }
                else if (!corner.string) {
                    self.corner = new PLUGINS.Corner(corner);
                    self.corner.fixed = TRUE;
                }
            }

            // Cache it
            cache.corner = new PLUGINS.Corner(self.corner.string());

            return self.corner.string() !== 'centercenter';
        }

        /* border width calculator */
        function parseWidth(corner, side, use) {
            side = !side ? corner[corner.precedance] : side;

            var isTitleTop = elems.titlebar && corner.y === TOP,
			elem = isTitleTop ? elems.titlebar : tooltip,
			borderSide = 'border-' + side + '-width',
			css = function (elem) { return parseInt(elem.css(borderSide), 10); },
			val;

            // Grab the border-width value (make tooltip visible first)
            whileVisible(function () {
                val = (use ? css(use) : (css(elems.content) || css(elem) || css(tooltip))) || 0;
            });
            return val;
        }

        function parseRadius(corner) {
            var isTitleTop = elems.titlebar && corner.y === TOP,
			elem = isTitleTop ? elems.titlebar : elems.content,
			mozPrefix = '-moz-', webkitPrefix = '-webkit-',
			nonStandard = 'border-radius-' + corner.y + corner.x,
			standard = 'border-' + corner.y + '-' + corner.x + '-radius',
			css = function (c) { return parseInt(elem.css(c), 10) || parseInt(tooltip.css(c), 10); },
			val;

            whileVisible(function () {
                val = css(standard) || css(nonStandard) ||
				css(mozPrefix + standard) || css(mozPrefix + nonStandard) ||
				css(webkitPrefix + standard) || css(webkitPrefix + nonStandard) || 0;
            });
            return val;
        }

        function parseColours(actual) {
            var i, fill, border,
			tip = elems.tip.css('cssText', ''),
			corner = actual || self.corner,
			invalid = /rgba?\(0, 0, 0(, 0)?\)|transparent|#123456/i,
			borderSide = 'border-' + corner[corner.precedance] + '-color',
			bgColor = 'background-color',
			transparent = 'transparent',
			important = ' !important',

			titlebar = elems.titlebar,
			useTitle = titlebar && (corner.y === TOP || (corner.y === CENTER && tip.position().top + (size.height / 2) + opts.offset < titlebar.outerHeight(TRUE))),
			colorElem = useTitle ? titlebar : elems.content;

            function css(elem, prop, compare) {
                var val = elem.css(prop) || transparent;
                if (compare && val === elem.css(compare)) { return FALSE; }
                else { return invalid.test(val) ? FALSE : val; }
            }

            // Ensure tooltip is visible then...
            whileVisible(function () {
                // Attempt to detect the background colour from various elements, left-to-right precedance
                color.fill = css(tip, bgColor) || css(colorElem, bgColor) || css(elems.content, bgColor) ||
				css(tooltip, bgColor) || tip.css(bgColor);

                // Attempt to detect the correct border side colour from various elements, left-to-right precedance
                color.border = css(tip, borderSide, 'color') || css(colorElem, borderSide, 'color') ||
				css(elems.content, borderSide, 'color') || css(tooltip, borderSide, 'color') || tooltip.css(borderSide);

                // Reset background and border colours
                $('*', tip).add(tip).css('cssText', bgColor + ':' + transparent + important + ';border:0' + important + ';');
            });
        }

        function calculateSize(corner) {
            var y = corner.precedance === Y,
			width = size[y ? WIDTH : HEIGHT],
			height = size[y ? HEIGHT : WIDTH],
			isCenter = corner.string().indexOf(CENTER) > -1,
			base = width * (isCenter ? 0.5 : 1),
			pow = Math.pow,
			round = Math.round,
			bigHyp, ratio, result,

		smallHyp = Math.sqrt(pow(base, 2) + pow(height, 2)),

		hyp = [
			(border / base) * smallHyp, (border / height) * smallHyp
		];
            hyp[2] = Math.sqrt(pow(hyp[0], 2) - pow(border, 2));
            hyp[3] = Math.sqrt(pow(hyp[1], 2) - pow(border, 2));

            bigHyp = smallHyp + hyp[2] + hyp[3] + (isCenter ? 0 : hyp[0]);
            ratio = bigHyp / smallHyp;

            result = [round(ratio * height), round(ratio * width)];
            return { height: result[y ? 0 : 1], width: result[y ? 1 : 0] };
        }

        function createVML(tag, props, style) {
            return '<qvml:' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="qtip-vml" ' + (props || '') +
			' style="behavior: url(#default#VML); ' + (style || '') + '" />';
        }

        $.extend(self, {
            init: function () {
                var enabled = parseCorner() && (hasCanvas || PLUGINS.ie);

                // Determine tip corner and type
                if (enabled) {
                    // Create a new tip and draw it
                    self.create();
                    self.update();

                    // Bind update events
                    tooltip.unbind(namespace).bind('tooltipmove' + namespace, reposition);
                }

                return enabled;
            },

            create: function () {
                var width = size.width,
				height = size.height,
				vml;

                // Remove previous tip element if present
                if (elems.tip) { elems.tip.remove(); }

                // Create tip element and prepend to the tooltip
                elems.tip = $('<div />', { 'class': 'qtip-tip' }).css({ width: width, height: height }).prependTo(tooltip);

                // Create tip drawing element(s)
                if (hasCanvas) {
                    // save() as soon as we create the canvas element so FF2 doesn't bork on our first restore()!
                    $('<canvas />').appendTo(elems.tip)[0].getContext('2d').save();
                }
                else {
                    vml = createVML('shape', 'coordorigin="0,0"', 'position:absolute;');
                    elems.tip.html(vml + vml);

                    // Prevent mousing down on the tip since it causes problems with .live() handling in IE due to VML
                    $('*', elems.tip).bind('click mousedown', function (event) { event.stopPropagation(); });
                }
            },

            update: function (corner, position) {
                var tip = elems.tip,
				inner = tip.children(),
				width = size.width,
				height = size.height,
				mimic = opts.mimic,
				round = Math.round,
				precedance, context, coords, translate, newSize;

                // Re-determine tip if not already set
                if (!corner) { corner = cache.corner || self.corner; }

                // Use corner property if we detect an invalid mimic value
                if (mimic === FALSE) { mimic = corner; }

                // Otherwise inherit mimic properties from the corner object as necessary
                else {
                    mimic = new PLUGINS.Corner(mimic);
                    mimic.precedance = corner.precedance;

                    if (mimic.x === 'inherit') { mimic.x = corner.x; }
                    else if (mimic.y === 'inherit') { mimic.y = corner.y; }
                    else if (mimic.x === mimic.y) {
                        mimic[corner.precedance] = corner[corner.precedance];
                    }
                }
                precedance = mimic.precedance;

                // Ensure the tip width.height are relative to the tip position
                if (corner.precedance === X) { swapDimensions(); }
                else { resetDimensions(); }

                // Set the tip dimensions
                elems.tip.css({
                    width: (width = size.width),
                    height: (height = size.height)
                });

                // Update our colours
                parseColours(corner);

                // Detect border width, taking into account colours
                if (color.border !== 'transparent') {
                    // Grab border width
                    border = parseWidth(corner, NULL);

                    // If border width isn't zero, use border color as fill (1.0 style tips)
                    if (opts.border === 0 && border > 0) { color.fill = color.border; }

                    // Set border width (use detected border width if opts.border is true)
                    self.border = border = opts.border !== TRUE ? opts.border : border;
                }

                // Border colour was invalid, set border to zero
                else { self.border = border = 0; }

                // Calculate coordinates
                coords = calculateTip(mimic, width, height);

                // Determine tip size
                self.size = newSize = calculateSize(corner);
                tip.css(newSize).css('line-height', newSize.height + 'px');

                // Calculate tip translation
                if (corner.precedance === Y) {
                    translate = [
					round(mimic.x === LEFT ? border : mimic.x === RIGHT ? newSize.width - width - border : (newSize.width - width) / 2),
					round(mimic.y === TOP ? newSize.height - height : 0)
				];
                }
                else {
                    translate = [
					round(mimic.x === LEFT ? newSize.width - width : 0),
					round(mimic.y === TOP ? border : mimic.y === BOTTOM ? newSize.height - height - border : (newSize.height - height) / 2)
				];
                }

                // Canvas drawing implementation
                if (hasCanvas) {
                    // Set the canvas size using calculated size
                    inner.attr(newSize);

                    // Grab canvas context and clear/save it
                    context = inner[0].getContext('2d');
                    context.restore(); context.save();
                    context.clearRect(0, 0, 3000, 3000);

                    // Set properties
                    context.fillStyle = color.fill;
                    context.strokeStyle = color.border;
                    context.lineWidth = border * 2;
                    context.lineJoin = 'miter';
                    context.miterLimit = 100;

                    // Translate origin
                    context.translate(translate[0], translate[1]);

                    // Draw the tip
                    context.beginPath();
                    context.moveTo(coords[0][0], coords[0][1]);
                    context.lineTo(coords[1][0], coords[1][1]);
                    context.lineTo(coords[2][0], coords[2][1]);
                    context.closePath();

                    // Apply fill and border
                    if (border) {
                        // Make sure transparent borders are supported by doing a stroke
                        // of the background colour before the stroke colour
                        if (tooltip.css('background-clip') === 'border-box') {
                            context.strokeStyle = color.fill;
                            context.stroke();
                        }
                        context.strokeStyle = color.border;
                        context.stroke();
                    }
                    context.fill();
                }

                // VML (IE Proprietary implementation)
                else {
                    // Setup coordinates string
                    coords = 'm' + coords[0][0] + ',' + coords[0][1] + ' l' + coords[1][0] +
					',' + coords[1][1] + ' ' + coords[2][0] + ',' + coords[2][1] + ' xe';

                    // Setup VML-specific offset for pixel-perfection
                    translate[2] = border && /^(r|b)/i.test(corner.string()) ?
					PLUGINS.ie === 8 ? 2 : 1 : 0;

                    // Set initial CSS
                    inner.css({
                        coordsize: (width + border) + ' ' + (height + border),
                        antialias: '' + (mimic.string().indexOf(CENTER) > -1),
                        left: translate[0],
                        top: translate[1],
                        width: width + border,
                        height: height + border
                    })
				.each(function (i) {
				    var $this = $(this);

				    // Set shape specific attributes
				    $this[$this.prop ? 'prop' : 'attr']({
				        coordsize: (width + border) + ' ' + (height + border),
				        path: coords,
				        fillcolor: color.fill,
				        filled: !!i,
				        stroked: !i
				    })
					.toggle(!!(border || i));

				    // Check if border is enabled and add stroke element
				    if (!i && $this.html() === '') {
				        $this.html(
							createVML('stroke', 'weight="' + (border * 2) + 'px" color="' + color.border + '" miterlimit="1000" joinstyle="miter"')
						);
				    }
				});
                }

                // Position if needed
                if (position !== FALSE) { self.position(corner); }
            },

            // Tip positioning method
            position: function (corner) {
                var tip = elems.tip,
				position = {},
				userOffset = Math.max(0, opts.offset),
				precedance, dimensions, corners;

                // Return if tips are disabled or tip is not yet rendered
                if (opts.corner === FALSE || !tip) { return FALSE; }

                // Inherit corner if not provided
                corner = corner || self.corner;
                precedance = corner.precedance;

                // Determine which tip dimension to use for adjustment
                dimensions = calculateSize(corner);

                // Setup corners and offset array
                corners = [corner.x, corner.y];
                if (precedance === X) { corners.reverse(); }

                // Calculate tip position
                $.each(corners, function (i, side) {
                    var b, bc, br;

                    if (side === CENTER) {
                        b = precedance === Y ? LEFT : TOP;
                        position[b] = '50%';
                        position['margin-' + b] = -Math.round(dimensions[precedance === Y ? WIDTH : HEIGHT] / 2) + userOffset;
                    }
                    else {
                        b = parseWidth(corner, side);
                        bc = parseWidth(corner, side, elems.content);
                        br = parseRadius(corner);

                        position[side] = i ? bc : (userOffset + (br > b ? br : -b));
                    }
                });

                // Adjust for tip dimensions
                position[corner[precedance]] -= dimensions[precedance === X ? WIDTH : HEIGHT];

                // Set and return new position
                tip.css({ top: '', bottom: '', left: '', right: '', margin: '' }).css(position);
                return position;
            },

            destroy: function () {
                // Remove the tip element
                if (elems.tip) { elems.tip.remove(); }
                elems.tip = false;

                // Unbind events
                tooltip.unbind(namespace);
            }
        });

        self.init();
    }

    PLUGINS.tip = function (api) {
        var self = api.plugins.tip;

        return 'object' === typeof self ? self : (api.plugins.tip = new Tip(api));
    };

    // Initialize tip on render
    PLUGINS.tip.initialize = 'render';

    // Setup plugin sanitization options
    PLUGINS.tip.sanitize = function (options) {
        var style = options.style, opts;
        if (style && 'tip' in style) {
            opts = options.style.tip;
            if (typeof opts !== 'object') { options.style.tip = { corner: opts }; }
            if (!(/string|boolean/i).test(typeof opts.corner)) { opts.corner = TRUE; }
            if (typeof opts.width !== 'number') { delete opts.width; }
            if (typeof opts.height !== 'number') { delete opts.height; }
            if (typeof opts.border !== 'number' && opts.border !== TRUE) { delete opts.border; }
            if (typeof opts.offset !== 'number') { delete opts.offset; }
        }
    };

    // Extend original qTip defaults
    $.extend(TRUE, QTIP.defaults, {
        style: {
            tip: {
                corner: TRUE,
                mimic: FALSE,
                width: 6,
                height: 6,
                border: TRUE,
                offset: 0
            }
        }
    });


    function Modal(api) {
        var self = this,
		options = api.options.show.modal,
		elems = api.elements,
		tooltip = elems.tooltip,
		overlaySelector = '#qtip-overlay',
		globalNamespace = '.qtipmodal',
		namespace = globalNamespace + api.id,
		attr = 'is-modal-qtip',
		docBody = $(document.body),
		focusableSelector = PLUGINS.modal.focusable.join(','),
		focusableElems = {}, overlay;

        // Setup option set checks
        api.checks.modal = {
            '^show.modal.(on|blur)$': function () {
                // Initialise
                self.init();

                // Show the modal if not visible already and tooltip is visible
                elems.overlay.toggle(tooltip.is(':visible'));
            },
            '^content.text$': function () {
                updateFocusable();
            }
        };

        function updateFocusable() {
            focusableElems = $(focusableSelector, tooltip).not('[disabled]').map(function () {
                return typeof this.focus === 'function' ? this : null;
            });
        }

        function focusInputs(blurElems) {
            // Blurring body element in IE causes window.open windows to unfocus!
            if (focusableElems.length < 1 && blurElems.length) { blurElems.not('body').blur(); }

            // Focus the inputs
            else { focusableElems.first().focus(); }
        }

        function stealFocus(event) {
            var target = $(event.target),
			container = target.closest('.qtip'),
			targetOnTop;

            // Determine if input container target is above this
            targetOnTop = container.length < 1 ? FALSE :
			(parseInt(container[0].style.zIndex, 10) > parseInt(tooltip[0].style.zIndex, 10));

            // If we're showing a modal, but focus has landed on an input below
            // this modal, divert focus to the first visible input in this modal
            // or if we can't find one... the tooltip itself
            if (!targetOnTop && ($(event.target).closest(selector)[0] !== tooltip[0])) {
                focusInputs(target);
            }
        }

        $.extend(self, {
            init: function () {
                // If modal is disabled... return
                if (!options.on) { return self; }

                // Create the overlay if needed
                overlay = self.create();

                // Add unique attribute so we can grab modal tooltips easily via a selector
                tooltip.attr(attr, TRUE)

                // Set z-index
			.css('z-index', PLUGINS.modal.zindex + $(selector + '[' + attr + ']').length)

                // Remove previous bound events in globalNamespace
			.unbind(globalNamespace).unbind(namespace)

                // Apply our show/hide/focus modal events
			.bind('tooltipshow' + globalNamespace + ' tooltiphide' + globalNamespace, function (event, api, duration) {
			    var oEvent = event.originalEvent;

			    // Make sure mouseout doesn't trigger a hide when showing the modal and mousing onto backdrop
			    if (event.target === tooltip[0]) {
			        if (oEvent && event.type === 'tooltiphide' && /mouse(leave|enter)/.test(oEvent.type) && $(oEvent.relatedTarget).closest(overlay[0]).length) {
			            try { event.preventDefault(); } catch (e) { }
			        }
			        else if (!oEvent || (oEvent && !oEvent.solo)) {
			            self[event.type.replace('tooltip', '')](event, duration);
			        }
			    }
			})

                // Adjust modal z-index on tooltip focus
			.bind('tooltipfocus' + globalNamespace, function (event) {
			    // If focus was cancelled before it reearch us, don't do anything
			    if (event.isDefaultPrevented() || event.target !== tooltip[0]) { return; }

			    var qtips = $(selector).filter('[' + attr + ']'),

			    // Keep the modal's lower than other, regular qtips
				newIndex = PLUGINS.modal.zindex + qtips.length,
				curIndex = parseInt(tooltip[0].style.zIndex, 10);

			    // Set overlay z-index
			    overlay[0].style.zIndex = newIndex - 2;

			    // Reduce modal z-index's and keep them properly ordered
			    qtips.each(function () {
			        if (this.style.zIndex > curIndex) {
			            this.style.zIndex -= 1;
			        }
			    });

			    // Fire blur event for focused tooltip
			    qtips.end().filter('.' + focusClass).qtip('blur', event.originalEvent);

			    // Set the new z-index
			    tooltip.addClass(focusClass)[0].style.zIndex = newIndex;

			    // Prevent default handling
			    try { event.preventDefault(); } catch (e) { }
			})

                // Focus any other visible modals when this one hides
			.bind('tooltiphide' + globalNamespace, function (event) {
			    if (event.target === tooltip[0]) {
			        $('[' + attr + ']').filter(':visible').not(tooltip).last().qtip('focus', event);
			    }
			});

                // Apply keyboard "Escape key" close handler
                if (options.escape) {
                    $(document).unbind(namespace).bind('keydown' + namespace, function (event) {
                        if (event.keyCode === 27 && tooltip.hasClass(focusClass)) {
                            api.hide(event);
                        }
                    });
                }

                // Apply click handler for blur option
                if (options.blur) {
                    elems.overlay.unbind(namespace).bind('click' + namespace, function (event) {
                        if (tooltip.hasClass(focusClass)) { api.hide(event); }
                    });
                }

                // Update focusable elements
                updateFocusable();

                return self;
            },

            create: function () {
                var elem = $(overlaySelector), win = $(window);

                // Return if overlay is already rendered
                if (elem.length) {
                    // Modal overlay should always be below all tooltips if possible
                    return (elems.overlay = elem.insertAfter($(selector).last()));
                }

                // Create document overlay
                overlay = elems.overlay = $('<div />', {
                    id: overlaySelector.substr(1),
                    html: '<div></div>',
                    mousedown: function () { return FALSE; }
                })
			.hide()
			.insertAfter($(selector).last());

                // Update position on window resize or scroll
                function resize() {
                    overlay.css({
                        height: win.height(),
                        width: win.width()
                    });
                }
                win.unbind(globalNamespace).bind('resize' + globalNamespace, resize);
                resize(); // Fire it initially too

                return overlay;
            },

            toggle: function (event, state, duration) {
                // Make sure default event hasn't been prevented
                if (event && event.isDefaultPrevented()) { return self; }

                var effect = options.effect,
				type = state ? 'show' : 'hide',
				visible = overlay.is(':visible'),
				modals = $('[' + attr + ']').filter(':visible').not(tooltip),
				zindex;

                // Create our overlay if it isn't present already
                if (!overlay) { overlay = self.create(); }

                // Prevent modal from conflicting with show.solo, and don't hide backdrop is other modals are visible
                if ((overlay.is(':animated') && visible === state && overlay.data('toggleState') !== FALSE) || (!state && modals.length)) {
                    return self;
                }

                // State specific...
                if (state) {
                    // Set position
                    overlay.css({ left: 0, top: 0 });

                    // Toggle backdrop cursor style on show
                    overlay.toggleClass('blurs', options.blur);

                    // IF the modal can steal the focus
                    if (options.stealfocus !== FALSE) {
                        // Make sure we can't focus anything outside the tooltip
                        docBody.bind('focusin' + namespace, stealFocus);

                        // Blur the current item and focus anything in the modal we an
                        focusInputs($('body :focus'));
                    }
                }
                else {
                    // Undelegate focus handler
                    docBody.unbind('focusin' + namespace);
                }

                // Stop all animations
                overlay.stop(TRUE, FALSE).data('toggleState', state);

                // Use custom function if provided
                if ($.isFunction(effect)) {
                    effect.call(overlay, state);
                }

                // If no effect type is supplied, use a simple toggle
                else if (effect === FALSE) {
                    overlay[type]();
                }

                // Use basic fade function
                else {
                    overlay.fadeTo(parseInt(duration, 10) || 90, state ? 1 : 0, function () {
                        if (!state) { $(this).hide(); }
                    });
                }

                // Reset position on hide
                if (!state) {
                    overlay.queue(function (next) {
                        overlay.css({ left: '', top: '' }).removeData('toggleState');
                        next();
                    });
                }

                return self;
            },

            show: function (event, duration) { return self.toggle(event, TRUE, duration); },
            hide: function (event, duration) { return self.toggle(event, FALSE, duration); },

            destroy: function () {
                var delBlanket = overlay;

                if (delBlanket) {
                    // Check if any other modal tooltips are present
                    delBlanket = $('[' + attr + ']').not(tooltip).length < 1;

                    // Remove overlay if needed
                    if (delBlanket) {
                        elems.overlay.remove();
                        $(document).unbind(globalNamespace);
                    }
                    else {
                        elems.overlay.unbind(globalNamespace + api.id);
                    }

                    // Undelegate focus handler
                    docBody.unbind('focusin' + namespace);
                }

                // Remove bound events
                return tooltip.removeAttr(attr).unbind(globalNamespace);
            }
        });

        self.init();
    }

    PLUGINS.modal = function (api) {
        var self = api.plugins.modal;

        return 'object' === typeof self ? self : (api.plugins.modal = new Modal(api));
    };

    // Plugin needs to be initialized on render
    PLUGINS.modal.initialize = 'render';

    // Setup sanitiztion rules
    PLUGINS.modal.sanitize = function (opts) {
        if (opts.show) {
            if (typeof opts.show.modal !== 'object') { opts.show.modal = { on: !!opts.show.modal }; }
            else if (typeof opts.show.modal.on === 'undefined') { opts.show.modal.on = TRUE; }
        }
    };

    // Base z-index for all modal tooltips (use qTip core z-index as a base)
    PLUGINS.modal.zindex = QTIP.zindex - 200;

    // Defines the selector used to select all 'focusable' elements within the modal when using the show.modal.stealfocus option.
    // Selectors initially taken from http://stackoverflow.com/questions/7668525/is-there-a-jquery-selector-to-get-all-elements-that-can-get-focus
    PLUGINS.modal.focusable = ['a[href]', 'area[href]', 'input', 'select', 'textarea', 'button', 'iframe', 'object', 'embed', '[tabindex]', '[contenteditable]'];

    // Extend original api defaults
    $.extend(TRUE, QTIP.defaults, {
        show: {
            modal: {
                on: FALSE,
                effect: TRUE,
                blur: TRUE,
                stealfocus: TRUE,
                escape: TRUE
            }
        }
    });


    PLUGINS.viewport = function (api, position, posOptions, targetWidth, targetHeight, elemWidth, elemHeight) {
        var target = posOptions.target,
		tooltip = api.elements.tooltip,
		my = posOptions.my,
		at = posOptions.at,
		adjust = posOptions.adjust,
		method = adjust.method.split(' '),
		methodX = method[0],
		methodY = method[1] || method[0],
		viewport = posOptions.viewport,
		container = posOptions.container,
		cache = api.cache,
		tip = api.plugins.tip,
		adjusted = { left: 0, top: 0 },
		fixed, newMy, newClass;

        // If viewport is not a jQuery element, or it's the window/document or no adjustment method is used... return
        if (!viewport.jquery || target[0] === window || target[0] === document.body || adjust.method === 'none') {
            return adjusted;
        }

        // Cache our viewport details
        fixed = tooltip.css('position') === 'fixed';
        viewport = {
            elem: viewport,
            height: viewport[(viewport[0] === window ? 'h' : 'outerH') + 'eight'](),
            width: viewport[(viewport[0] === window ? 'w' : 'outerW') + 'idth'](),
            scrollleft: fixed ? 0 : viewport.scrollLeft(),
            scrolltop: fixed ? 0 : viewport.scrollTop(),
            offset: viewport.offset() || { left: 0, top: 0 }
        };
        container = {
            elem: container,
            scrollLeft: container.scrollLeft(),
            scrollTop: container.scrollTop(),
            offset: container.offset() || { left: 0, top: 0 }
        };

        // Generic calculation method
        function calculate(side, otherSide, type, adjust, side1, side2, lengthName, targetLength, elemLength) {
            var initialPos = position[side1],
			mySide = my[side], atSide = at[side],
			isShift = type === SHIFT,
			viewportScroll = -container.offset[side1] + viewport.offset[side1] + viewport['scroll' + side1],
			myLength = mySide === side1 ? elemLength : mySide === side2 ? -elemLength : -elemLength / 2,
			atLength = atSide === side1 ? targetLength : atSide === side2 ? -targetLength : -targetLength / 2,
			tipLength = tip && tip.size ? tip.size[lengthName] || 0 : 0,
			tipAdjust = tip && tip.corner && tip.corner.precedance === side && !isShift ? tipLength : 0,
			overflow1 = viewportScroll - initialPos + tipAdjust,
			overflow2 = initialPos + elemLength - viewport[lengthName] - viewportScroll + tipAdjust,
			offset = myLength - (my.precedance === side || mySide === my[otherSide] ? atLength : 0) - (atSide === CENTER ? targetLength / 2 : 0);

            // shift
            if (isShift) {
                tipAdjust = tip && tip.corner && tip.corner.precedance === otherSide ? tipLength : 0;
                offset = (mySide === side1 ? 1 : -1) * myLength - tipAdjust;

                // Adjust position but keep it within viewport dimensions
                position[side1] += overflow1 > 0 ? overflow1 : overflow2 > 0 ? -overflow2 : 0;
                position[side1] = Math.max(
				-container.offset[side1] + viewport.offset[side1] + (tipAdjust && tip.corner[side] === CENTER ? tip.offset : 0),
				initialPos - offset,
				Math.min(
					Math.max(-container.offset[side1] + viewport.offset[side1] + viewport[lengthName], initialPos + offset),
					position[side1]
				)
			);
            }

            // flip/flipinvert
            else {
                // Update adjustment amount depending on if using flipinvert or flip
                adjust *= (type === FLIPINVERT ? 2 : 0);

                // Check for overflow on the left/top
                if (overflow1 > 0 && (mySide !== side1 || overflow2 > 0)) {
                    position[side1] -= offset + adjust;
                    newMy['invert' + side](side1);
                }

                // Check for overflow on the bottom/right
                else if (overflow2 > 0 && (mySide !== side2 || overflow1 > 0)) {
                    position[side1] -= (mySide === CENTER ? -offset : offset) + adjust;
                    newMy['invert' + side](side2);
                }

                // Make sure we haven't made things worse with the adjustment and reset if so
                if (position[side1] < viewportScroll && -position[side1] > overflow2) {
                    position[side1] = initialPos; newMy = my.clone();
                }
            }

            return position[side1] - initialPos;
        }

        // Set newMy if using flip or flipinvert methods
        if (methodX !== 'shift' || methodY !== 'shift') { newMy = my.clone(); }

        // Adjust position based onviewport and adjustment options
        adjusted = {
            left: methodX !== 'none' ? calculate(X, Y, methodX, adjust.x, LEFT, RIGHT, WIDTH, targetWidth, elemWidth) : 0,
            top: methodY !== 'none' ? calculate(Y, X, methodY, adjust.y, TOP, BOTTOM, HEIGHT, targetHeight, elemHeight) : 0
        };

        // Set tooltip position class if it's changed
        if (newMy && cache.lastClass !== (newClass = NAMESPACE + '-pos-' + newMy.abbrev())) {
            tooltip.removeClass(api.cache.lastClass).addClass((api.cache.lastClass = newClass));
        }

        return adjusted;
    };
    PLUGINS.imagemap = function (api, area, corner, adjustMethod) {
        if (!area.jquery) { area = $(area); }

        var cache = (api.cache.areas = {}),
		shape = (area[0].shape || area.attr('shape')).toLowerCase(),
		coordsString = area[0].coords || area.attr('coords'),
		baseCoords = coordsString.split(','),
		coords = [],
		image = $('img[usemap="#' + area.parent('map').attr('name') + '"]'),
		imageOffset = image.offset(),
		result = {
		    width: 0, height: 0,
		    position: {
		        top: 1e10, right: 0,
		        bottom: 0, left: 1e10
		    }
		},
		i = 0, next = 0, dimensions;

        // POLY area coordinate calculator
        //	Special thanks to Ed Cradock for helping out with this.
        //	Uses a binary search algorithm to find suitable coordinates.
        function polyCoordinates(result, coords, corner) {
            var i = 0,
			compareX = 1, compareY = 1,
			realX = 0, realY = 0,
			newWidth = result.width,
			newHeight = result.height;

            // Use a binary search algorithm to locate most suitable coordinate (hopefully)
            while (newWidth > 0 && newHeight > 0 && compareX > 0 && compareY > 0) {
                newWidth = Math.floor(newWidth / 2);
                newHeight = Math.floor(newHeight / 2);

                if (corner.x === LEFT) { compareX = newWidth; }
                else if (corner.x === RIGHT) { compareX = result.width - newWidth; }
                else { compareX += Math.floor(newWidth / 2); }

                if (corner.y === TOP) { compareY = newHeight; }
                else if (corner.y === BOTTOM) { compareY = result.height - newHeight; }
                else { compareY += Math.floor(newHeight / 2); }

                i = coords.length; while (i--) {
                    if (coords.length < 2) { break; }

                    realX = coords[i][0] - result.position.left;
                    realY = coords[i][1] - result.position.top;

                    if ((corner.x === LEFT && realX >= compareX) ||
				(corner.x === RIGHT && realX <= compareX) ||
				(corner.x === CENTER && (realX < compareX || realX > (result.width - compareX))) ||
				(corner.y === TOP && realY >= compareY) ||
				(corner.y === BOTTOM && realY <= compareY) ||
				(corner.y === CENTER && (realY < compareY || realY > (result.height - compareY)))) {
                        coords.splice(i, 1);
                    }
                }
            }

            return { left: coords[0][0], top: coords[0][1] };
        }

        // Make sure we account for padding and borders on the image
        imageOffset.left += Math.ceil((image.outerWidth() - image.width()) / 2);
        imageOffset.top += Math.ceil((image.outerHeight() - image.height()) / 2);

        // Parse coordinates into proper array
        if (shape === 'poly') {
            i = baseCoords.length; while (i--) {
                next = [parseInt(baseCoords[--i], 10), parseInt(baseCoords[i + 1], 10)];

                if (next[0] > result.position.right) { result.position.right = next[0]; }
                if (next[0] < result.position.left) { result.position.left = next[0]; }
                if (next[1] > result.position.bottom) { result.position.bottom = next[1]; }
                if (next[1] < result.position.top) { result.position.top = next[1]; }

                coords.push(next);
            }
        }
        else {
            i = -1; while (i++ < baseCoords.length) {
                coords.push(parseInt(baseCoords[i], 10));
            }
        }

        // Calculate details
        switch (shape) {
            case 'rect':
                result = {
                    width: Math.abs(coords[2] - coords[0]),
                    height: Math.abs(coords[3] - coords[1]),
                    position: {
                        left: Math.min(coords[0], coords[2]),
                        top: Math.min(coords[1], coords[3])
                    }
                };
                break;

            case 'circle':
                result = {
                    width: coords[2] + 2,
                    height: coords[2] + 2,
                    position: { left: coords[0], top: coords[1] }
                };
                break;

            case 'poly':
                result.width = Math.abs(result.position.right - result.position.left);
                result.height = Math.abs(result.position.bottom - result.position.top);

                if (corner.abbrev() === 'c') {
                    result.position = {
                        left: result.position.left + (result.width / 2),
                        top: result.position.top + (result.height / 2)
                    };
                }
                else {
                    // Calculate if we can't find a cached value
                    if (!cache[corner + coordsString]) {
                        result.position = polyCoordinates(result, coords.slice(), corner);

                        // If flip adjustment is enabled, also calculate the closest opposite point
                        if (adjustMethod && (adjustMethod[0] === 'flip' || adjustMethod[1] === 'flip')) {
                            result.offset = polyCoordinates(result, coords.slice(), {
                                x: corner.x === LEFT ? RIGHT : corner.x === RIGHT ? LEFT : CENTER,
                                y: corner.y === TOP ? BOTTOM : corner.y === BOTTOM ? TOP : CENTER
                            });

                            result.offset.left -= result.position.left;
                            result.offset.top -= result.position.top;
                        }

                        // Store the result
                        cache[corner + coordsString] = result;
                    }

                    // Grab the cached result
                    result = cache[corner + coordsString];
                }

                result.width = result.height = 0;
                break;
        }

        // Add image position to offset coordinates
        result.position.left += imageOffset.left;
        result.position.top += imageOffset.top;

        return result;
    };


    /* 
    * BGIFrame adaption (http://plugins.jquery.com/project/bgiframe)
    * Special thanks to Brandon Aaron
    */
    function IE6(api) {
        var self = this,
		elems = api.elements,
		options = api.options,
		tooltip = elems.tooltip,
		namespace = '.ie6-' + api.id,
		bgiframe = $('select, object').length < 1,
		isDrawing = 0,
		modalProcessed = FALSE,
		redrawContainer;

        api.checks.ie6 = {
            '^content|style$': function (obj, o, v) { redraw(); }
        };

        $.extend(self, {
            init: function () {
                var win = $(window), scroll;

                // Create the BGIFrame element if needed
                if (bgiframe) {
                    elems.bgiframe = $('<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:\'\';" ' +
					' style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=0); ' +
						'-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";"></iframe>');

                    // Append the new element to the tooltip
                    elems.bgiframe.appendTo(tooltip);

                    // Update BGIFrame on tooltip move
                    tooltip.bind('tooltipmove' + namespace, self.adjustBGIFrame);
                }

                // redraw() container for width/height calculations
                redrawContainer = $('<div/>', { id: 'qtip-rcontainer' })
				.appendTo(document.body);

                // Set dimensions
                self.redraw();

                // Fixup modal plugin if present too
                if (elems.overlay && !modalProcessed) {
                    scroll = function () {
                        elems.overlay[0].style.top = win.scrollTop() + 'px';
                    };
                    win.bind('scroll.qtip-ie6, resize.qtip-ie6', scroll);
                    scroll(); // Fire it initially too

                    elems.overlay.addClass('qtipmodal-ie6fix'); // Add fix class

                    modalProcessed = TRUE; // Set flag
                }
            },

            adjustBGIFrame: function () {
                var dimensions = api.get('dimensions'), // Determine current tooltip dimensions
				plugin = api.plugins.tip,
				tip = elems.tip,
				tipAdjust, offset;

                // Adjust border offset
                offset = parseInt(tooltip.css('border-left-width'), 10) || 0;
                offset = { left: -offset, top: -offset };

                // Adjust for tips plugin
                if (plugin && tip) {
                    tipAdjust = (plugin.corner.precedance === 'x') ? ['width', 'left'] : ['height', 'top'];
                    offset[tipAdjust[1]] -= tip[tipAdjust[0]]();
                }

                // Update bgiframe
                elems.bgiframe.css(offset).css(dimensions);
            },

            // Max/min width simulator function
            redraw: function () {
                if (api.rendered < 1 || isDrawing) { return self; }

                var style = options.style,
				container = options.position.container,
				perc, width, max, min;

                // Set drawing flag
                isDrawing = 1;

                // If tooltip has a set height/width, just set it... like a boss!
                if (style.height) { tooltip.css(HEIGHT, style.height); }
                if (style.width) { tooltip.css(WIDTH, style.width); }

                // Simulate max/min width if not set width present...
                else {
                    // Reset width and add fluid class
                    tooltip.css(WIDTH, '').appendTo(redrawContainer);

                    // Grab our tooltip width (add 1 if odd so we don't get wrapping problems.. huzzah!)
                    width = tooltip.width();
                    if (width % 2 < 1) { width += 1; }

                    // Grab our max/min properties
                    max = tooltip.css('max-width') || '';
                    min = tooltip.css('min-width') || '';

                    // Parse into proper pixel values
                    perc = (max + min).indexOf('%') > -1 ? container.width() / 100 : 0;
                    max = ((max.indexOf('%') > -1 ? perc : 1) * parseInt(max, 10)) || width;
                    min = ((min.indexOf('%') > -1 ? perc : 1) * parseInt(min, 10)) || 0;

                    // Determine new dimension size based on max/min/current values
                    width = max + min ? Math.min(Math.max(width, min), max) : width;

                    // Set the newly calculated width and remvoe fluid class
                    tooltip.css(WIDTH, Math.round(width)).appendTo(container);
                }

                // Set drawing flag
                isDrawing = 0;

                return self;
            },

            destroy: function () {
                // Remove iframe
                if (bgiframe) { elems.bgiframe.remove(); }

                // Remove bound events
                tooltip.unbind(namespace);
            }
        });

        self.init();
    }

    PLUGINS.ie6 = function (api) {
        var self = api.plugins.ie6;

        // Proceed only if the browser is IE6
        if (PLUGINS.ie !== 6) { return FALSE; }

        return 'object' === typeof self ? self : (api.plugins.ie6 = new IE6(api));
    };

    // Plugin needs to be initialized on render
    PLUGINS.ie6.initialize = 'render';


}));
} (window, document));
/**
 * jQuery plugin to produce the ripple effect from the Google Material Design spec:
 * http://www.google.com/design/spec/animation/responsive-interaction.html
 *
 * This plugin was modified from a codepen simulating the effect:
 * http://codepen.io/Craigtut/pen/dIfzv
 */
(function($, ua) {

    var
        // Better testing of touch support
        // See https://github.com/ngryman/jquery.finger/blob/v0.1.2/dist/jquery.finger.js#L7
        isChrome = /chrome/i.exec(ua),
        isFirefox = /firefox/i.exec(ua),
        isAndroid = /android/i.exec(ua),
        hasTouch = 'ontouchstart' in window && !(isChrome && !isAndroid);

    /**
     * jQuery.fn.ripple
     * @param {Object} options
     * @param {String} [options.color=#fff] The ripple effect color
     */
    $.fn.ripple = function(options) {
        
        var rippled = false,
            opts = $.extend({}, { color: '#fff' }, options);
        opts.event = (hasTouch && 'touchstart.ripple') || 'mousedown.ripple';
        opts.end_event = (hasTouch && 'touchend.ripple touchcancel.ripple') || 'mouseup.ripple mouseleave.ripple';
        
        if(isFirefox && !hasTouch){
            opts.event = 'click.ripple';
        }

        $(this)
            // Bind the event to run the effect
            .on(opts.event, function(ev) {
                var x, y, touch_ev,
                    $paper = $(this),
                    $ink = $('<div/>'),
                    size = Math.max($paper.width(), $paper.height());

                rippled = true;

                // Set up ripple effect styles
                $paper
                    .trigger('beforeripple')
                    .addClass('ripple-active');
                $ink
                    .addClass('ripple-effect')
                    .css({height: size, width: size});

                // get click coordinates
                // logic = click coordinates relative to page
                // - position relative to page - half of self height/width to make it controllable from the center
                touch_ev = hasTouch ? ev.originalEvent.touches[0] : ev;
                x = touch_ev.pageX - $paper.offset().left - $ink.width()/2;
                y = touch_ev.pageY - $paper.offset().top - $ink.height()/2;

                // Set up ripple position and place it in the DOM
                $ink
                    .css({top: y + 'px', left: x + 'px', backgroundColor: opts.color})
                    .appendTo($paper);
            })
            // Bind the event to end the paper-press ripple
            .on(opts.end_event, function() {
                var $paper = $(this),
                    $ink = $paper.find('.ripple-effect');

                // We don't want to run the afterripple
                // events if the user hasn't started a ripple
                if (!rippled) {
                    return;
                }
                rippled = false;

                // Remove ripple effect styles
                $paper
                    .trigger('afterripple')
                    .removeClass('ripple-active');
                $ink
                    .css({backgroundColor: 'transparent'})
                    .one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function() {
                        $ink.remove();
                    });
            });

        // Chaining
        return $(this);
    };

}(window.jQuery, navigator.userAgent));

/*
 * jQuery simple-color plugin
 * @requires jQuery v1.4.2 or later
 *
 * See https://github.com/recurser/jquery-simple-color
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Version: 1.2.1 (Sun, 05 Jan 2014 05:14:47 GMT)
 */
 (function ($) {
     /**
     * simpleColor() provides a mechanism for displaying simple color-choosers.
     *
     * If an options Object is provided, the following attributes are supported:
     *
     *  defaultColor:       Default (initially selected) color.
     *                      Default value: '#FFF'
     *
     *  cellWidth:          Width of each individual color cell.
     *                      Default value: 10
     *
     *  cellHeight:         Height of each individual color cell.
     *                      Default value: 10
     *
     *  cellMargin:         Margin of each individual color cell.
     *                      Default value: 1
     *
     *  boxWidth:           Width of the color display box.
     *                      Default value: 115px
     *
     *  boxHeight:          Height of the color display box.
     *                      Default value: 20px
     *
     *  columns:            Number of columns to display. Color order may look strange if this is altered.
     *                      Default value: 16
     *
     *  insert:             The position to insert the color chooser. 'before' or 'after'.
     *                      Default value: 'after'
     *
     *  colors:             An array of colors to display, if you want to customize the default color set.
     *                      Default value: default color set - see 'defaultColors' below.
     *
     *  displayColorCode:   Display the color code (eg #333333) as text inside the button. true or false.
     *                      Default value: false
     *
     *  colorCodeAlign:     Text alignment used to display the color code inside the button. Only used if
     *                      'displayColorCode' is true. 'left', 'center' or 'right'
     *                      Default value: 'center'
     *
     *  colorCodeColor:     Text color of the color code inside the button. Only used if 'displayColorCode'
     *                      is true.
     *                      Default value: '#FFF'
     *
     *  onSelect:           Callback function to call after a color has been chosen. The callback
     *                      function will be passed two arguments - the hex code of the selected color,
     *                      and the input element that triggered the chooser.
     *                      Default value: null
     *                      Returns:       hex value
     *
     *  onCellEnter:        Callback function that excecutes when the mouse enters a cell. The callback
     *                      function will be passed two arguments - the hex code of the current color,
     *                      and the input element that triggered the chooser.
     *                      Default value: null
     *                      Returns:       hex value
     *
     *  onClose:            Callback function that executes when the chooser is closed. The callback
     *                      function will be passed one argument - the input element that triggered
     *                      the chooser.
     *                      Default value: null
     *
     *  livePreview:        The color display will change to show the color of the hovered color cell.
     *                      The display will revert if no color is selected.
     *                      Default value: false
     *
     *  chooserCSS:         An associative array of CSS properties that will be applied to the pop-up
     *                      color chooser.
     *                      Default value: see options.chooserCSS in the source
     *
     *  displayCSS:         An associative array of CSS properties that will be applied to the color
     *                      display box.
     *                      Default value: see options.displayCSS in the source
     */
     $.fn.simpleColor = function (options) {

         var element = this;

         var defaultColors = [
      '990033', 'ff3366', 'cc0033', 'ff0033', 'ff9999', 'cc3366', 'ffccff', 'cc6699',
      '993366', '660033', 'cc3399', 'ff99cc', 'ff66cc', 'ff99ff', 'ff6699', 'cc0066',
      'ff0066', 'ff3399', 'ff0099', 'ff33cc', 'ff00cc', 'ff66ff', 'ff33ff', 'ff00ff',
      'cc0099', '990066', 'cc66cc', 'cc33cc', 'cc99ff', 'cc66ff', 'cc33ff', '993399',
      'cc00cc', 'cc00ff', '9900cc', '990099', 'cc99cc', '996699', '663366', '660099',
      '9933cc', '660066', '9900ff', '9933ff', '9966cc', '330033', '663399', '6633cc',
      '6600cc', '9966ff', '330066', '6600ff', '6633ff', 'ccccff', '9999ff', '9999cc',
      '6666cc', '6666ff', '666699', '333366', '333399', '330099', '3300cc', '3300ff',
      '3333ff', '3333cc', '0066ff', '0033ff', '3366ff', '3366cc', '000066', '000033',
      '0000ff', '000099', '0033cc', '0000cc', '336699', '0066cc', '99ccff', '6699ff',
      '003366', '6699cc', '006699', '3399cc', '0099cc', '66ccff', '3399ff', '003399',
      '0099ff', '33ccff', '00ccff', '99ffff', '66ffff', '33ffff', '00ffff', '00cccc',
      '009999', '669999', '99cccc', 'ccffff', '33cccc', '66cccc', '339999', '336666',
      '006666', '003333', '00ffcc', '33ffcc', '33cc99', '00cc99', '66ffcc', '99ffcc',
      '00ff99', '339966', '006633', '336633', '669966', '66cc66', '99ff99', '66ff66',
      '339933', '99cc99', '66ff99', '33ff99', '33cc66', '00cc66', '66cc99', '009966',
      '009933', '33ff66', '00ff66', 'ccffcc', 'ccff99', '99ff66', '99ff33', '00ff33',
      '33ff33', '00cc33', '33cc33', '66ff33', '00ff00', '66cc33', '006600', '003300',
      '009900', '33ff00', '66ff00', '99ff00', '66cc00', '00cc00', '33cc00', '339900',
      '99cc66', '669933', '99cc33', '336600', '669900', '99cc00', 'ccff66', 'ccff33',
      'ccff00', '999900', 'cccc00', 'cccc33', '333300', '666600', '999933', 'cccc66',
      '666633', '999966', 'cccc99', 'ffffcc', 'ffff99', 'ffff66', 'ffff33', 'ffff00',
      'ffcc00', 'ffcc66', 'ffcc33', 'cc9933', '996600', 'cc9900', 'ff9900', 'cc6600',
      '993300', 'cc6633', '663300', 'ff9966', 'ff6633', 'ff9933', 'ff6600', 'cc3300',
      '996633', '330000', '663333', '996666', 'cc9999', '993333', 'cc6666', 'ffcccc',
      'ff3333', 'cc3333', 'ff6666', '660000', '990000', 'cc0000', 'ff0000', 'ff3300',
      'cc9966', 'ffcc99', 'ffffff', 'cccccc', '999999', '666666', '333333', '000000',
      'F5F5F5', '000000', '000000', '000000', '000000', '000000', '000000', '000000'
    ];

         // Option defaults
         options = $.extend({
             defaultColor: this.attr('defaultColor') || '#FFF',
             cellWidth: this.attr('cellWidth') || 20,
             cellHeight: this.attr('cellHeight') || 20,
             cellMargin: this.attr('cellMargin') || 0,
             boxWidth: this.attr('boxWidth') || '115px',
             boxHeight: this.attr('boxHeight') || '20px',
             columns: this.attr('columns') || 16,
             insert: this.attr('insert') || 'after',
             colors: this.attr('colors') || defaultColors,
             displayColorCode: this.attr('displayColorCode') || false,
             colorCodeAlign: this.attr('colorCodeAlign') || 'center',
             colorCodeColor: this.attr('colorCodeColor') || '#FFF',
             onSelect: null,
             onCellEnter: null,
             onClose: null,
             livePreview: true
         }, options || {});

         // Figure out the cell dimensions
         options.totalWidth = options.columns * (options.cellWidth + (2 * options.cellMargin));

         // Custom CSS for the chooser, which relies on previously defined options.
         options.chooserCSS = $.extend({
             'border': '1px solid #000',
             'margin': '0 0 0 5px',
             'width': options.totalWidth,
             'height': options.totalHeight,
             'top': 0,
             'left': options.boxWidth,
             'position': 'absolute',
             'background-color': '#fff'
         }, options.chooserCSS || {});

         // Custom CSS for the display box, which relies on previously defined options.
         options.displayCSS = $.extend({
             'background-color': options.defaultColor,
             'border': '1px solid #000',
             'width': options.boxWidth,
             'height': options.boxHeight,
             'line-height': options.boxHeight + 'px',
             'cursor': 'pointer'
         }, options.displayCSS || {});

         // Hide the input
         //this.hide();

         // this should probably do feature detection - I don't know why we need +2 for IE
         // but this works for jQuery 1.9.1
         if (navigator.userAgent.indexOf("MSIE") != -1) {
             options.totalWidth += 2;
         }

         options.totalHeight = Math.ceil(options.colors.length / options.columns) * (options.cellHeight + (2 * options.cellMargin));

         // Store these options so they'll be available to the other functions
         // TODO - must be a better way to do this, not sure what the 'official'
         // jQuery method is. Ideally i want to pass these as a parameter to the
         // each() function but i'm not sure how
         $.simpleColorOptions = options;

         function buildChooser(index) {
             options = $.simpleColorOptions;

             // Create a container to hold everything
             var container = $("<div class='simpleColorContainer' />");

             // Absolutely positioned child elements now 'work'.
             container.css({
                 position: 'relative',
                 left: '6px',
                 top: '6px',
                 display: 'inline-block'
             });

             // Create the color display box
             var defaultColor = (this.value && this.value != '') ? this.value : options.defaultColor;

             var displayBox = $("<div class='simpleColorDisplay' />");
             displayBox.css($.extend(options.displayCSS, { 'background-color': defaultColor }));
             displayBox.data('color', defaultColor);
             container.append(displayBox);

             // If 'displayColorCode' is turned on, display the currently selected color code as text inside the button.
             if (options.displayColorCode) {
                 displayBox.data('displayColorCode', true);
                 displayBox.text(this.value);
                 displayBox.css({
                     'color': options.colorCodeColor,
                     'textAlign': options.colorCodeAlign
                 });
             }

             var selectCallback = function (event) {
                 // Bind and namespace the click listener only when the chooser is
                 // displayed. Unbind when the chooser is closed.
                 $('html').bind("click.simpleColorDisplay", function (e) {
                     $('html').unbind("click.simpleColorDisplay");
                     $('.simpleColorChooser').hide();

                     // If the user has not selected a new color, then revert the display.
                     // Makes sure the selected cell is within the current color chooser.
                     var target = $(e.target);
                     if (target.is('.simpleColorCell') === false || $.contains($(event.target).closest('.simpleColorContainer')[0], target[0]) === false) {
                         displayBox.css('background-color', displayBox.data('color'));
                         if (options.displayColorCode) {
                             displayBox.text(displayBox.data('color'));
                         }
                     }
                     // Execute onClose callback whenever the color chooser is closed.
                     if (options.onClose) {
                         options.onClose(element);
                     }
                 });

                 // Use an existing chooser if there is one
                 if (event.data.container.chooser) {
                     event.data.container.chooser.toggle();

                     // Build the chooser.
                 } else {
                     // Make a chooser div to hold the cells
                     var chooser = $("<div class='simpleColorChooser'/>");
                     chooser.css(options.chooserCSS);
                     event.data.container.chooser = chooser;
                     $("body").append(chooser);
                     chooser.css("left", displayBox.offset().left);
                     chooser.css("top", displayBox.offset().top + 25);

                     // Create the cells
                     for (var i = 0; i < options.colors.length; i++) {
                         var cell = $("<div class='simpleColorCell' id='" + options.colors[i] + "'/>");
                         cell.css({
                             'width': options.cellWidth + 'px',
                             'height': options.cellHeight + 'px',
                             'margin': options.cellMargin + 'px',
                             'cursor': 'pointer',
                             'lineHeight': options.cellHeight + 'px',
                             'fontSize': '1px',
                             'float': 'left',
                             'background-color': '#' + options.colors[i]
                         });
                         chooser.append(cell);
                         if (options.onCellEnter || options.livePreview) {
                             cell.bind('mouseenter', function (event) {
                                 if (options.onCellEnter) {
                                     options.onCellEnter(this.id, element);
                                 }
                                 if (options.livePreview) {
                                     displayBox.css('background-color', '#' + this.id);
                                     if (options.displayColorCode) {
                                         displayBox.text('#' + this.id);
                                     }
                                 }
                             });
                         }
                         cell.bind('click', {
                             input: event.data.input,
                             chooser: chooser,
                             displayBox: displayBox
                         },
            function (event) {
                var color = '#' + this.id
                event.data.input.value = color;
                $(event.data.input).change();
                $(event.data.displayBox).data('color', color);
                event.data.displayBox.css('background-color', color);
                event.data.chooser.hide();

                // If 'displayColorCode' is turned on, display the currently selected color code as text inside the button.
                if (options.displayColorCode) {
                    event.data.displayBox.text(color);
                }

                // If an onSelect callback function is defined then excecute it.
                if (options.onSelect) {
                    options.onSelect(this.id, element);
                }
            });
                     }
                 }
             };

             // Also bind the display box button to display the chooser.
             var callbackParams = {
                 input: this,
                 container: container,
                 displayBox: displayBox
             };
             displayBox.bind('click', callbackParams, selectCallback);

             $(this).after(container);
             $(this).data('container', container);
         };

         this.each(buildChooser);

         $('.simpleColorDisplay').each(function () {
             $(this).click(function (e) {
                 e.stopPropagation();
             });
         });

         return this;
     };

     /*
     * Close the given color choosers.
     */
     $.fn.closeChooser = function () {
         this.each(function (index) {
             $(this).data('container').find('.simpleColorChooser').hide();
         });

         return this;
     };

     /*
     * Set the color of the given color choosers.
     */
     $.fn.setColor = function (color) {
         this.each(function (index) {
             var displayBox = $(this).data('container').find('.simpleColorDisplay');
             displayBox.css('background-color', color).data('color', color);
             if (displayBox.data('displayColorCode') === true) {
                 displayBox.text(color);
             }
         });

         return this;
     };

     /*
     * Get the color of the given color choosers.
     */
     $.fn.getColor = function () {
         this.each(function (index) {
             var displayBox = $(this).data('container').find('.simpleColorDisplay');
             return displayBox.data('color', color);
         });

         return this;
     };
 })(jQuery);


// SweetAlert
// 2014 (c) - Tristan Edwards
// github.com/t4t5/sweetalert
;(function(window, document) {

  var modalClass   = '.sweet-alert',
      overlayClass = '.sweet-overlay',
      alertTypes   = ['error', 'warning', 'info', 'success','question'],
      defaultParams = {
        title: '',
        text: '',
        type: null,
        allowOutsideClick: false,
        showCancelButton: false,
		hideOKButton: false,
        closeOnConfirm: true,
        closeOnCancel: true,
        confirmButtonText: 'OK',
        confirmButtonColor: '#AEDEF4',
        cancelButtonText: 'Cancel',
        imageUrl: null,
        imageSize: null,
        timer: null,
		width: 478
      };


  /*
   * Manipulate DOM
   */

  var getModal = function() {
      return document.querySelector(modalClass);
    },
    getOverlay = function() {
      return document.querySelector(overlayClass);
    },
    hasClass = function(elem, className) {
      return new RegExp(' ' + className + ' ').test(' ' + elem.className + ' ');
    },
    addClass = function(elem, className) {
      if (!hasClass(elem, className)) {
        elem.className += ' ' + className;
      }
    },
    removeClass = function(elem, className) {
      var newClass = ' ' + elem.className.replace(/[\t\r\n]/g, ' ') + ' ';
      if (hasClass(elem, className)) {
        while (newClass.indexOf(' ' + className + ' ') >= 0) {
          newClass = newClass.replace(' ' + className + ' ', ' ');
        }
        elem.className = newClass.replace(/^\s+|\s+$/g, '');
      }
    },
    escapeHtml = function(str) {
        return str;
      var div = document.createElement('div');
      div.appendChild(document.createTextNode(str));
      return div.innerHTML;
    },
    _show = function(elem) {
      elem.style.opacity = '';
      elem.style.display = 'block';
    },
    show = function(elems) {
      if (elems && !elems.length) {
        return _show(elems);
      }
      for (var i = 0; i < elems.length; ++i) {
        _show(elems[i]);
      }
    },
    _hide = function(elem) {
      elem.style.opacity = '';
      elem.style.display = 'none';
    },
    hide = function(elems) {
      if (elems && !elems.length) {
        return _hide(elems);
      }
      for (var i = 0; i < elems.length; ++i) {
        _hide(elems[i]);
      }
    },
    isDescendant = function(parent, child) {
      var node = child.parentNode;
      while (node !== null) {
        if (node === parent) {
          return true;
        }
        node = node.parentNode;
      }
      return false;
    },
    getTopMargin = function(elem) {
      elem.style.left = '-9999px';
      elem.style.display = 'block';

      var height = elem.clientHeight,
          padding;
      if (typeof getComputedStyle !== "undefined") { /* IE 8 */
        padding = parseInt(getComputedStyle(elem).getPropertyValue('padding'), 10);
      } else{
        padding = parseInt(elem.currentStyle.padding);
      }

      elem.style.left = '';
      elem.style.display = 'none';
      return ('-' + parseInt(height / 2 + padding) + 'px');
    },
    fadeIn = function(elem, interval) {
      if (+elem.style.opacity < 1) {
        interval = interval || 16;
        elem.style.opacity = 0;
        elem.style.display = 'block';
        var last = +new Date();
        var tick = function() {
          elem.style.opacity = +elem.style.opacity + (new Date() - last) / 100;
          last = +new Date();

          if (+elem.style.opacity < 1) {
            setTimeout(tick, interval);
          }
        };
        tick();
      }
      elem.style.display = 'block'; //fallback IE8
    },
    fadeOut = function(elem, interval) {
      interval = interval || 16;
      elem.style.opacity = 1;
      var last = +new Date();
      var tick = function() {
        elem.style.opacity = +elem.style.opacity - (new Date() - last) / 100;
        last = +new Date();

        if (+elem.style.opacity > 0) {
          setTimeout(tick, interval);
        } else {
          elem.style.display = 'none';
        }
      };
      tick();
    },
    fireClick = function(node) {
      // Taken from http://www.nonobtrusive.com/2011/11/29/programatically-fire-crossbrowser-click-event-with-javascript/
      // Then fixed for today's Chrome browser.
//      if (MouseEvent) {
//        // Up-to-date approach
//        var mevt = new MouseEvent('click', {
//          view: window,
//          bubbles: false,
//          cancelable: true
//        });
//        node.dispatchEvent(mevt);
//      } else 
      if ( document.createEvent ) {
        // Fallback
        var evt = document.createEvent('MouseEvents');
        evt.initEvent('click', false, false);
        node.dispatchEvent(evt);
      } else if( document.createEventObject ) {
        node.fireEvent('onclick') ;
      } else if (typeof node.onclick === 'function' ) {
        node.onclick();
      }
    },
    stopEventPropagation = function(e) {
      // In particular, make sure the space bar doesn't scroll the main window.
      if (typeof e.stopPropagation === 'function') {
        e.stopPropagation();
        e.preventDefault();
      } else if (window.event && window.event.hasOwnProperty('cancelBubble')) {
        window.event.cancelBubble = true;
      }
    };

  // Remember state in cases where opening and handling a modal will fiddle with it.
  var previousActiveElement,
      previousDocumentClick,
      previousWindowKeyDown,
      lastFocusedButton;

  /*
   * Add modal + overlay to DOM
   */

  window.sweetAlertInitialize = function() {
	  
    var sweetHTML = '<div class="sweet-overlay" tabIndex="-1"></div><div class="sweet-alert" tabIndex="-1"><div class="icon error"><span class="x-mark"><span class="line left"></span><span class="line right"></span></span></div><div class="icon warning"> <span class="body"></span> <span class="dot"></span> </div> <div class="icon info"></div> <div class="icon question"> <span class="qm">?</span> </div> <div class="icon success"> <span class="line tip"></span> <span class="line long"></span> <div class="placeholder"></div> <div class="fix"></div> </div> <div class="icon custom"></div> <h2>Title</h2><p>Text</p><button class="cancel" tabIndex="2">Cancel</button><button class="confirm" tabIndex="1">OK</button></div>',
        sweetWrap = document.createElement('div');

    sweetWrap.innerHTML = sweetHTML;

    // For readability: check sweet-alert.html
    document.body.appendChild(sweetWrap);
  };

  /*
   * Global sweetAlert function
   */

  window.sweetAlert = window.swal = function() {
    if (arguments[0] === undefined) {
      window.console.error('sweetAlert expects at least 1 attribute!');
      return false;
    }

    var params = extend({}, defaultParams);

    switch (typeof arguments[0]) {

      case 'string':
        params.title = arguments[0];
        params.text  = arguments[1] || '';
        params.type  = arguments[2] || '';

        break;

      case 'object':
        if (arguments[0].title === undefined) {
          window.console.error('Missing "title" argument!');
          return false;
        }

        params.title              = arguments[0].title;
        params.text               = arguments[0].text || defaultParams.text;
        params.type               = arguments[0].type || defaultParams.type;
        params.allowOutsideClick  = arguments[0].allowOutsideClick || defaultParams.allowOutsideClick;
        params.showCancelButton   = arguments[0].showCancelButton !== undefined ? arguments[0].showCancelButton : defaultParams.showCancelButton;
        params.hideOKButton   = arguments[0].hideOKButton !== undefined ? arguments[0].hideOKButton : defaultParams.hideOKButton;
		params.closeOnConfirm     = arguments[0].closeOnConfirm !== undefined ? arguments[0].closeOnConfirm : defaultParams.closeOnConfirm;
        params.closeOnCancel      = arguments[0].closeOnCancel !== undefined ? arguments[0].closeOnCancel : defaultParams.closeOnCancel;
        params.timer              = arguments[0].timer || defaultParams.timer;
		params.width			  = arguments[0].width || defaultParams.width; //Liveapp v4

        // Show "Confirm" instead of "OK" if cancel button is visible
        params.confirmButtonText  = (defaultParams.showCancelButton) ? 'Confirm' : defaultParams.confirmButtonText;
        params.confirmButtonText  = arguments[0].confirmButtonText || defaultParams.confirmButtonText;
        params.confirmButtonColor = arguments[0].confirmButtonColor || defaultParams.confirmButtonColor;
        params.cancelButtonText   = arguments[0].cancelButtonText || defaultParams.cancelButtonText;
        params.imageUrl           = arguments[0].imageUrl || defaultParams.imageUrl;
        params.imageSize          = arguments[0].imageSize || defaultParams.imageSize;
        params.doneFunction       = arguments[1] || null;

        break;

      default:
        window.console.error('Unexpected type of argument! Expected "string" or "object", got ' + typeof arguments[0]);
        return false;

    }

    setParameters(params);
    fixVerticalPosition();
    openModal();


    // Modal interactions
    var modal = getModal();

    // Mouse interactions
    var onButtonEvent = function(event) {
      var e = event || window.event;
      var target = e.target || e.srcElement,
          targetedConfirm    = (target.className === 'confirm'),
          modalIsVisible     = hasClass(modal, 'visible'),
          doneFunctionExists = (params.doneFunction && modal.getAttribute('data-has-done-function') === 'true');

      switch (e.type) {
        case ("mouseover"):
          if (targetedConfirm) {
            target.style.backgroundColor = colorLuminance(params.confirmButtonColor, -0.04);
          }
          break;
        case ("mouseout"):
          if (targetedConfirm) {
            target.style.backgroundColor = params.confirmButtonColor;
          }
          break;
        case ("mousedown"):
          if (targetedConfirm) {
            target.style.backgroundColor = colorLuminance(params.confirmButtonColor, -0.14);
          }
          break;
        case ("mouseup"):
          if (targetedConfirm) {
            target.style.backgroundColor = colorLuminance(params.confirmButtonColor, -0.04);
          }
          break;
        case ("focus"):
          var $confirmButton = modal.querySelector('button.confirm'),
              $cancelButton  = modal.querySelector('button.cancel');

          if (targetedConfirm) {
            $cancelButton.style.border = 'none';
          } else {
            $confirmButton.style.border = 'none';
          }
          break;
        case ("click"):
          if (targetedConfirm && doneFunctionExists && modalIsVisible) { // Clicked "confirm"

            e.preventDefault();

            params.doneFunction(true);

            if (params.closeOnConfirm) {
              closeModal();
            }
          } else if (doneFunctionExists && modalIsVisible) { // Clicked "cancel"

            e.preventDefault();

            // Check if callback function expects a parameter (to track cancel actions)
            var functionAsStr          = String(params.doneFunction).replace(/\s/g, '');
            var functionHandlesCancel  = functionAsStr.substring(0, 9) === "function(" && functionAsStr.substring(9, 10) !== ")";

            if (functionHandlesCancel) {
              params.doneFunction(false);
            }

            if (params.closeOnCancel) {
              closeModal();
            }
          } else {
            closeModal();
          }

          break;
      }
    };

    var $buttons = modal.querySelectorAll('button');
    for (var i = 0; i < $buttons.length; i++) {
      $buttons[i].onclick     = onButtonEvent;
      $buttons[i].onmouseover = onButtonEvent;
      $buttons[i].onmouseout  = onButtonEvent;
      $buttons[i].onmousedown = onButtonEvent;
      //$buttons[i].onmouseup   = onButtonEvent;
      $buttons[i].onfocus     = onButtonEvent;
    }

    // Remember the current document.onclick event.
    previousDocumentClick = document.onclick;
    document.onclick = function(event) {
      var e = event || window.event;
      var target = e.target || e.srcElement;

      var clickedOnModal = (modal === target),
          clickedOnModalChild = isDescendant(modal, target),
          modalIsVisible = hasClass(modal, 'visible'),
          outsideClickIsAllowed = modal.getAttribute('data-allow-ouside-click') === 'true';

      if (!clickedOnModal && !clickedOnModalChild && modalIsVisible && outsideClickIsAllowed) {
        closeModal();
      }
    };


    // Keyboard interactions
    var $okButton = modal.querySelector('button.confirm'),
        $cancelButton = modal.querySelector('button.cancel');
        
    var $modalButtons = [];
    try{
        $modalButtons = modal.querySelectorAll('button:not([type=hidden])');
    }catch(e){
    }

    function handleKeyDown(event) {
      var e = event || window.event;
      var keyCode = e.keyCode || e.which;

      if ([9,13,32,27].indexOf(keyCode) === -1) {
        // Don't do work on keys we don't care about.
        return;
      }

      var $targetElement = e.target || e.srcElement;

      var btnIndex = -1; // Find the button - note, this is a nodelist, not an array.
      for (var i = 0; i < $modalButtons.length; i++) {
        if ($targetElement === $modalButtons[i]) {
          btnIndex = i;
          break;
        }
      }

      if (keyCode === 9) {
        // TAB
        if (btnIndex === -1) {
          // No button focused. Jump to the confirm button.                    
          $targetElement = $okButton;
        } else {
          // Cycle to the next button
          if (btnIndex === $modalButtons.length - 1) {
            $targetElement = $modalButtons[0];
          } else {
            $targetElement = $modalButtons[btnIndex + 1];
          }
        }

        stopEventPropagation(e);
        $targetElement.focus();
        setFocusStyle($targetElement, "Gainsboro"); // TODO - DONE!

      } else {
        if (keyCode === 13 || keyCode === 32) {
            if (btnIndex === -1) {
              // ENTER/SPACE clicked outside of a button.
              $targetElement = $okButton;
            } else {
              // Do nothing - let the browser handle it.
              $targetElement = undefined;
            }
        } else if (keyCode === 27 && !($cancelButton.hidden || $cancelButton.style.display === 'none')) {
          // ESC to cancel only if there's a cancel button displayed (like the alert() window).
          $targetElement = $cancelButton;
        } else {
          // Fallback - let the browser handle it.
          $targetElement = undefined;
        }

        if ($targetElement !== undefined) {
          fireClick($targetElement, e);
        }
      }
    }

    previousWindowKeyDown = window.onkeydown;
    window.onkeydown = handleKeyDown;

    function handleOnBlur(event) {
      var e = event || window.event;
      var $targetElement = e.target || e.srcElement,
          $focusElement = e.relatedTarget,
          modalIsVisible = hasClass(modal, 'visible');

      if (modalIsVisible) {
        var btnIndex = -1; // Find the button - note, this is a nodelist, not an array.

        if ($focusElement !== null) {
          // If we picked something in the DOM to focus to, let's see if it was a button.
          for (var i = 0; i < $modalButtons.length; i++) {
            if ($focusElement === $modalButtons[i]) {
              btnIndex = i;
              break;
            }
          }

          if (btnIndex === -1) {
            // Something in the dom, but not a visible button. Focus back on the button.
            $targetElement.focus();
          }
        } else {
          // Exiting the DOM (e.g. clicked in the URL bar);
          lastFocusedButton = $targetElement;
        }
      }
    }

    $okButton.onblur = handleOnBlur;
    $cancelButton.onblur = handleOnBlur;

    window.onfocus = function() {
      // When the user has focused away and focused back from the whole window.
      window.setTimeout(function() {
        // Put in a timeout to jump out of the event sequence. Calling focus() in the event
        // sequence confuses things.
        if (lastFocusedButton !== undefined) {
          lastFocusedButton.focus();
          lastFocusedButton = undefined;
        }
      }, 0);
    };
  };

  /**
   * Set default params for each popup
   * @param {Object} userParams
   */
  window.swal.setDefaults = function(userParams) {
    if (!userParams) {
      throw new Error('userParams is required');
    }
    if (typeof userParams !== 'object') {
      throw new Error('userParams has to be a object');
    }

    extend(defaultParams, userParams);
  };

  /*
   * Set type, text and actions on modal
   */

  function setParameters(params) {
    var modal = getModal();

    var $title = modal.querySelector('h2'),
        $text = modal.querySelector('p'),
        $cancelBtn = modal.querySelector('button.cancel'),
        $confirmBtn = modal.querySelector('button.confirm');

	//Width
	$(modal).css('width', params.width); //Liveapp v4
	
    // Title
    $title.innerHTML = escapeHtml(params.title).split("\n").join("<br>");

    // Text
    $text.innerHTML = escapeHtml(params.text || '').split("\n").join("<br>");
    if (params.text) {
      show($text);
    }

    // Icon
    hide(modal.querySelectorAll('.icon'));
    if (params.type) {
      var validType = false;
      for (var i = 0; i < alertTypes.length; i++) {
        if (params.type === alertTypes[i]) {
          validType = true;
          break;
        }
      }
      if (!validType) {
        window.console.error('Unknown alert type: ' + params.type);
        return false;
      }
      var $icon = modal.querySelector('.icon.' + params.type);
      show($icon);

      // Animate icon
      switch (params.type) {
        case "success":
          addClass($icon, 'animate');
          addClass($icon.querySelector('.tip'), 'animateSuccessTip');
          addClass($icon.querySelector('.long'), 'animateSuccessLong');
          break;
        case "error":
          addClass($icon, 'animateErrorIcon');
          addClass($icon.querySelector('.x-mark'), 'animateXMark');
          break;
        case "warning":
          addClass($icon, 'pulseWarning');
          addClass($icon.querySelector('.body'), 'pulseWarningIns');
          addClass($icon.querySelector('.dot'), 'pulseWarningIns');
          break;
        case "question":
          addClass($icon.querySelector('.qm'), 'animateQuestionIcon');
          break;
      }

    }

    // Custom image
    if (params.imageUrl) {
      var $customIcon = modal.querySelector('.icon.custom');

      $customIcon.style.backgroundImage = 'url(' + params.imageUrl + ')';
      show($customIcon);

      var _imgWidth  = 80,
          _imgHeight = 80;

      if (params.imageSize) {
        var imgWidth  = params.imageSize.split('x')[0];
        var imgHeight = params.imageSize.split('x')[1];

        if (!imgWidth || !imgHeight) {
          window.console.error("Parameter imageSize expects value with format WIDTHxHEIGHT, got " + params.imageSize);
        } else {
          _imgWidth  = imgWidth;
          _imgHeight = imgHeight;

          $customIcon.css({
            'width': imgWidth + 'px',
            'height': imgHeight + 'px'
          });
        }
      }
      $customIcon.setAttribute('style', $customIcon.getAttribute('style') + 'width:' + _imgWidth + 'px; height:' + _imgHeight + 'px');
    }

    // Cancel button
    modal.setAttribute('data-has-cancel-button', params.showCancelButton);
    if (params.showCancelButton) {
      $cancelBtn.style.display = 'inline-block';
    } else {
      hide($cancelBtn);
    }

    // Edit text on cancel and confirm buttons
    if (params.cancelButtonText) {
      $cancelBtn.innerHTML = escapeHtml(params.cancelButtonText);
    }
    if (params.confirmButtonText) {
      $confirmBtn.innerHTML = escapeHtml(params.confirmButtonText);
    }

    // Set confirm button to selected background color
    $confirmBtn.style.backgroundColor = params.confirmButtonColor;

    // Set box-shadow to default focused button
    if (params.showCancelButton) {        
        setFocusStyle($cancelBtn, params.confirmButtonColor);
    }else{
        setFocusStyle($confirmBtn, params.confirmButtonColor);
    }

	// OK button
	if (!params.hideOKButton) {
      $confirmBtn.style.display = 'inline-block';
    } else {
      hide($confirmBtn);
    }

    // Allow outside click?
    modal.setAttribute('data-allow-ouside-click', params.allowOutsideClick);

    // Done-function
    var hasDoneFunction = (params.doneFunction) ? true : false;
    modal.setAttribute('data-has-done-function', hasDoneFunction);

    // Close timer
    modal.setAttribute('data-timer', params.timer);
  }


  /*
   * Set hover, active and focus-states for buttons (source: http://www.sitepoint.com/javascript-generate-lighter-darker-color)
   */

  function colorLuminance(hex, lum) {
    // Validate hex string
    hex = String(hex).replace(/[^0-9a-f]/gi, '');
    if (hex.length < 6) {
      hex = hex[0]+hex[0]+hex[1]+hex[1]+hex[2]+hex[2];
    }
    lum = lum || 0;

    // Convert to decimal and change luminosity
    var rgb = "#", c, i;
    for (i = 0; i < 3; i++) {
      c = parseInt(hex.substr(i*2,2), 16);
      c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16);
      rgb += ("00"+c).substr(c.length);
    }

    return rgb;
  }

  function extend(a, b){
    for (var key in b) {
      if (b.hasOwnProperty(key)) {
        a[key] = b[key];
      }
    }

    return a;
  }

  function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) : null;
  }

  // Add box-shadow style to button (depending on its chosen bg-color)
  function setFocusStyle($button, bgColor) {
    var rgbColor = hexToRgb(bgColor);
    //$button.style.boxShadow = '0 0 2px rgba(' + rgbColor +', 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)';
    $button.style.border = "solid 3px Gray";
  }



  /*
   * Animations
   */

  function openModal() {
    var modal = getModal();
    fadeIn(getOverlay(), 10);
    show(modal);
    addClass(modal, 'showSweetAlert');
    removeClass(modal, 'hideSweetAlert');

    previousActiveElement = document.activeElement;
    var $okButton = modal.querySelector('button.confirm');
    var $cancelButton = modal.querySelector('button.cancel');

    if(!($cancelButton.hidden || $cancelButton.style.display === 'none')){
        $cancelButton.focus();
    }else{
        $okButton.focus();
    }
    
    setTimeout(function() {
      addClass(modal, 'visible');
    }, 80);

    var timer = modal.getAttribute('data-timer');

    if (timer !== "null" && timer !== "") {
      modal.timeout = setTimeout(function() {
        closeModal();
      }, timer);
    }
  }

  function closeModal() {
    var modal = getModal();
    fadeOut(getOverlay(), 5);
    fadeOut(modal, 5);
    removeClass(modal, 'showSweetAlert');
    addClass(modal, 'hideSweetAlert');
    removeClass(modal, 'visible');


    // Reset icon animations

    var $successIcon = modal.querySelector('.icon.success');
    removeClass($successIcon, 'animate');
    removeClass($successIcon.querySelector('.tip'), 'animateSuccessTip');
    removeClass($successIcon.querySelector('.long'), 'animateSuccessLong');

    var $errorIcon = modal.querySelector('.icon.error');
    removeClass($errorIcon, 'animateErrorIcon');
    removeClass($errorIcon.querySelector('.x-mark'), 'animateXMark');

    var $warningIcon = modal.querySelector('.icon.warning');
    removeClass($warningIcon, 'pulseWarning');
    removeClass($warningIcon.querySelector('.body'), 'pulseWarningIns');
    removeClass($warningIcon.querySelector('.dot'), 'pulseWarningIns');

    var $questionIcon = modal.querySelector('.icon.question');
    removeClass($questionIcon.querySelector('.qm'), 'animateQuestionIcon');
	
    // Reset the page to its previous state
    window.onkeydown = previousWindowKeyDown;
    document.onclick = previousDocumentClick;
    if (previousActiveElement && previousActiveElement.focus) { //Liveapp v4
      previousActiveElement.focus();
    }
    lastFocusedButton = undefined;
    clearTimeout(modal.timeout);
	
	Application.Fire("ModalClose");
  }


  /*
   * Set "margin-top"-property on modal based on its computed height
   */

  function fixVerticalPosition() {
    var modal = getModal();

    modal.style.marginTop = getTopMargin(getModal());
  }



  /*
   * If library is injected after page has loaded
   */

  (function () {
	  if (document.readyState === "complete" || document.readyState === "interactive" && document.body) {
		  window.sweetAlertInitialize();
	  } else {
		  if (document.addEventListener) {
			  document.addEventListener('DOMContentLoaded', function factorial() {
				  document.removeEventListener('DOMContentLoaded', arguments.callee, false);
				  window.sweetAlertInitialize();
			  }, false);
		  } else if (document.attachEvent) {
			  document.attachEvent('onreadystatechange', function() {
				  if (document.readyState === 'complete') {
					  document.detachEvent('onreadystatechange', arguments.callee);
					  window.sweetAlertInitialize();
				  }
			  });
		  }
	  }
  })();

  //Liveapp v4
  window.swalclose = closeModal;

})(window, document);

/**
 * Trumbowyg v2.0.0-beta.4 - A lightweight WYSIWYG editor
 * Trumbowyg core file
 * ------------------------
 * @link http://alex-d.github.io/Trumbowyg
 * @license MIT
 * @author Alexandre Demode (Alex-D)
 *         Twitter : @AlexandreDemode
 *         Website : alex-d.fr
 */

jQuery.trumbowyg = {
    langs: {
        en: {
            viewHTML: "View HTML",

            formatting: "Formatting",
            p: "Paragraph",
            blockquote: "Quote",
            code: "Code",
            header: "Header",

            bold: "Bold",
            italic: "Italic",
            strikethrough: "Stroke",
            underline: "Underline",

            strong: "Strong",
            em: "Emphasis",
            del: "Deleted",

            unorderedList: "Unordered list",
            orderedList: "Ordered list",

            insertImage: "Insert Image",
            insertVideo: "Insert Video",
            link: "Link",
            createLink: "Insert link",
            unlink: "Remove link",

            justifyLeft: "Align Left",
            justifyCenter: "Align Center",
            justifyRight: "Align Right",
            justifyFull: "Align Justify",

            horizontalRule: "Insert horizontal rule",
            removeformat: "Remove format",

            fullscreen: "fullscreen",

            close: "Close",

            submit: "Confirm",
            reset: "Cancel",

            required: "Required",
            description: "Description",
            title: "Title",
            text: "Text",
            target: "Target"
        }
    },

    // User default options
    opts: {},

    btnsGrps: {
        design: ['bold', 'italic', 'underline', 'strikethrough'],
        semantic: ['strong', 'em', 'del'],
        justify: ['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull'],
        lists: ['unorderedList', 'orderedList']
    }
};



(function (navigator, window, document, $, undefined) {
    'use strict';

    // @param : o are options
    // @param : p are params
    $.fn.trumbowyg = function (o, p) {
        if (o === Object(o) || !o) {
            return this.each(function () {
                if (!$(this).data('trumbowyg'))
                    $(this).data('trumbowyg', new Trumbowyg(this, o));
            });
        }
        if (this.length === 1) {
            try {
                var t = $(this).data('trumbowyg');
                switch (o) {
                    // Modal box
                    case 'openModal':
                        return t.openModal(p.title, p.content);
                    case 'closeModal':
                        return t.closeModal();
                    case 'openModalInsert':
                        return t.openModalInsert(p.title, p.fields, p.callback);

                        // Selection
                    case 'saveSelection':
                        return t.saveSelection();
                    case 'getSelection':
                        return t.selection;
                    case 'getSelectedText':
                        return t.getSelectedText();
                    case 'restoreSelection':
                        return t.restoreSelection();

                        // Destroy
                    case 'destroy':
                        return t.destroy();

                        // Empty
                    case 'empty':
                        return t.empty();

                        // Public options
                    case 'lang':
                        return t.lang;

                        // HTML
                    case 'html':
                        return t.html(p);
                }
            } catch (e) { }
        }

        return false;
    };

    // @param : editorElem is the DOM element
    // @param : o are options
    var Trumbowyg = function (editorElem, o) {
        var t = this;
        // Get the document of the element. It use to makes the plugin
        // compatible on iframes.
        t.doc = editorElem.ownerDocument || document;
        // jQuery object of the editor
        t.$ta = $(editorElem); // $ta : Textarea
        t.$c = $(editorElem); // $c : creator

        // Extend with options
        o = $.extend(true, {}, o, $.trumbowyg.opts);

        // Localization management
        if (typeof o.lang === 'undefined' || typeof $.trumbowyg.langs[o.lang] === 'undefined')
            t.lang = $.trumbowyg.langs.en;
        else
            t.lang = $.extend(true, {}, $.trumbowyg.langs.en, $.trumbowyg.langs[o.lang]);

        // Header translation
        var h = t.lang.header;

        // Defaults Options
        t.o = $.extend(true, {}, {
            lang: 'en',
            dir: 'ltr',

            closable: false,
            fullscreenable: true,
            fixedBtnPane: false,
            fixedFullWidth: false,
            autogrow: false,

            prefix: 'trumbowyg-',

            // WYSIWYG only
            semantic: false,
            resetCss: false,
            removeformatPasted: false,

            btns: [
                'viewHTML',
                '|', 'formatting',
                '|', 'btnGrp-design',
                '|', 'link',
                '|', 'insertImage',
                '|', 'btnGrp-justify',
                '|', 'btnGrp-lists',
                '|', 'horizontalRule',
                '|', 'removeformat'
            ],
            btnsAdd: [],

            /**
             * When the button is associated to a empty object
             * func and title attributs are defined from the button key value
             *
             * For example
             *      foo: {}
             * is equivalent to :
             *      foo: {
             *          func: 'foo',
             *          title: this.lang.foo
             *      }
             */
            btnsDef: {
                viewHTML: {
                    func: 'toggle'
                },

                p: {
                    func: 'formatBlock'
                },
                blockquote: {
                    func: 'formatBlock'
                },
                h1: {
                    func: 'formatBlock',
                    title: h + ' 1'
                },
                h2: {
                    func: 'formatBlock',
                    title: h + ' 2'
                },
                h3: {
                    func: 'formatBlock',
                    title: h + ' 3'
                },
                h4: {
                    func: 'formatBlock',
                    title: h + ' 4'
                },

                bold: {
                    key: 'B'
                },
                italic: {
                    key: 'I'
                },
                underline: {},
                strikethrough: {},

                strong: {
                    func: 'bold',
                    key: 'B'
                },
                em: {
                    func: 'italic',
                    key: 'I'
                },
                del: {
                    func: 'strikethrough'
                },

                createLink: {
                    key: 'K'
                },
                unlink: {},

                insertImage: {},

                justifyLeft: {},
                justifyCenter: {},
                justifyRight: {},
                justifyFull: {},

                unorderedList: {
                    func: 'insertUnorderedList'
                },
                orderedList: {
                    func: 'insertOrderedList'
                },

                horizontalRule: {
                    func: 'insertHorizontalRule'
                },

                removeformat: {},

                // Dropdowns
                formatting: {
                    dropdown: ['p', 'blockquote', 'h1', 'h2', 'h3', 'h4']
                },
                link: {
                    dropdown: ['createLink', 'unlink']
                }
            },

            blockLevelElements: ['br', 'p', 'div', 'ul', 'ol', 'table', 'img', 'address', 'article', 'aside', 'audio', 'blockquote', 'canvas', 'dl', 'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'nav', 'noscript', 'output', 'pre', 'section', 'tfoot', 'video']

        }, o);

        if (o.btns)
            t.o.btns = o.btns;
        else if (t.o.semantic)
            t.o.btns[4] = 'btnGrp-semantic';

        // Keyboard shortcuts are load in this array
        t.keys = [];

        t.init();
    };

    Trumbowyg.prototype = {
        init: function () {
            var t = this;
            t.height = t.$ta.height();

            t.buildEditor();
            t.buildBtnPane();

            t.fixedBtnPaneEvents();

            t.buildOverlay();
        },

        buildEditor: function () {
            var t = this,
                prefix = t.o.prefix,
                html = '';

            t.$box = $('<div/>', {
                'class': prefix + 'box ' + prefix + 'editor-visible ' + prefix + t.o.lang + ' trumbowyg'
            });

            // $ta = Textarea
            // $ed = Editor
            t.isTextarea = t.$ta.is('textarea');
            if (t.isTextarea) {
                html = t.$ta.val();
                t.$ed = $('<div/>');
                t.$box
                    .insertAfter(t.$ta)
                    .append(t.$ed, t.$ta);
            } else {
                t.$ed = t.$ta;
                html = t.$ed.html();

                t.$ta = $('<textarea/>', {
                    name: t.$ta.attr('id'),
                    height: t.height
                }).val(html);

                t.$box
                    .insertAfter(t.$ed)
                    .append(t.$ta, t.$ed);
                t.syncCode();
            }

            t.$ta
                .addClass(prefix + 'textarea')
                .attr('tabindex', -1)
            ;

            t.$ed
                .addClass(prefix + 'editor')
                .attr({
                    'contenteditable': true,
                    'dir': t.lang._dir || t.o.dir
                })
                .html(html)
            ;

            if(t.o.tabindex){
                t.$ed.attr('tabindex', t.o.tabindex);
            }

            if(t.$c.is('[placeholder]')){
                t.$ed.attr('placeholder', t.$c.attr('placeholder'));
            }

            if(t.o.resetCss){
                t.$ed.addClass(prefix + 'reset-css');
            }

            if (!t.o.autogrow) {
                t.$ta.add(t.$ed).css({
                    height: t.height,
                    overflow: 'auto'
                });
            }

            if (t.o.semantic) {
                t.semanticCode();
            }


            t._ctrl = false;
            t.$ed
            .on('dblclick', 'img', function () {
                var $img = $(this);
                t.openModalInsert(t.lang.insertImage, {
                    url: {
                        label: 'URL',
                        value: $img.attr('src'),
                        required: true
                    },
                    alt: {
                        label: t.lang.description,
                        value: $img.attr('alt')
                    }
                }, function (v) {
                    return $img.attr({
                        src: v.url,
                        alt: v.alt
                    });
                });
                return false;
            })
            .on('keydown', function (e) {
                t._composition = (e.which === 229);

                if (e.ctrlKey) {
                    t._ctrl = true;
                    var k = t.keys[String.fromCharCode(e.which).toUpperCase()];

                    try {
                        t.execCmd(k.func, k.param);
                        return false;
                    } catch (e) { }
                }
            })
            .on('keyup', function (e) {
                if (!t._ctrl && e.which !== 17 && !t._composition) {
                    t.semanticCode(false, e.which === 13);
                    t.$c.trigger('tbwchange');
                }
				
				//Liveapp v4
				if (t._ctrl && e.which === 13 && !t._composition) {
                    var br = $("<br>");                
					t.doc.getSelection().getRangeAt(0).insertNode(br.get(0));
                    t.$c.trigger('tbwchange');
                }

                setTimeout(function () {
                    t._ctrl = false;
                }, 200);
            })
            .on('focus blur', function (e) {
                t.$c.trigger('tbw' + e.type);
            })
            .on('paste', function (e) {
                if (t.o.removeformatPasted) {
                    e.preventDefault();

                    try {
                        // IE
                        var text = window.clipboardData.getData("Text");

                        try {
                            // <= IE10
                            t.doc.selection.createRange().pasteHTML(text);
                        } catch (err) {
                            // IE 11
                            t.doc.getSelection().getRangeAt(0).insertNode(document.createTextNode(text));
                        }
                    } catch (err) {
                        // Not IE
                        t.execCmd('insertText', (e.originalEvent || e).clipboardData.getData('text/plain'));
                    }
                }

                setTimeout(function () {
                    if (t.o.semantic) {
                        t.semanticCode(false, true);
                    } else {
                        t.syncCode();
                    }
                    t.$c.trigger('tbwpaste', e);
                }, 0);

            });
            t.$ta.on('keyup paste', function () {
                t.$c.trigger('tbwchange');
            });

            $(t.doc).on('keydown', function (e) {
                if (e.which === 27) {
                    t.closeModal();
                    return false;
                }
            });
        },


        // Build button pane, use o.btns and o.btnsAdd options
        buildBtnPane: function () {
            var t = this,
                prefix = t.o.prefix;

            if (t.o.btns === false)
                return;

            t.$btnPane = $('<ul/>', {
                'class': prefix + 'button-pane'
            });

            $.each(t.o.btns.concat(t.o.btnsAdd), function (i, btn) {
                // Managment of group of buttons
                try {
                    var b = btn.split('btnGrp-');
                    if (b[1] !== undefined)
                        btn = $.trumbowyg.btnsGrps[b[1]];
                } catch (e) { }

                if (!$.isArray(btn))
                    btn = [btn];

                $.each(btn, function (i, b) {
                    try { // Prevent buildBtn error
                        var $li = $('<li/>');

                        if (b === '|') // It's a separator
                            $li.addClass(prefix + 'separator');
                        else if (t.isSupportedBtn(b)) // It's a supported button
                            $li.append(t.buildBtn(b));

                        t.$btnPane.append($li);
                    } catch (e) { }
                });
            });

            // Build right li for fullscreen and close buttons
            var $liRight = $('<li/>', {
                'class': prefix + 'not-disable ' + prefix + 'buttons-right'
            });

            // Add the fullscreen button
            if (t.o.fullscreenable)
                $liRight.append(
                    t.buildRightBtn('fullscreen')
                    .on('click', function () {
                        var cssClass = prefix + 'fullscreen';
                        t.$box.toggleClass(cssClass);

                        if (t.$box.hasClass(cssClass)) {
                            $('body').addClass(prefix + 'body-fullscreen');
                            $.each([t.$ta, t.$ed], function () {
                                $(this).css({
                                    height: 'calc(100% - 35px)',
                                    overflow: 'auto'
                                });
                            });
                            t.$btnPane.css('width', '100%');
                        } else {
                            $('body').removeClass(prefix + 'body-fullscreen');
                            t.$box.removeAttr('style');
                            if (!t.o.autogrow)
                                $.each([t.$ta, t.$ed], function () {
                                    $(this).css('height', t.height);
                                });
							t.$c.trigger('tbwblur'); //LIveapp v4
                        }
                        $(window).trigger('scroll');
                    })
                );

            // Build and add close button
            if (t.o.closable)
                $liRight
                    .append(
                        t.buildRightBtn('close')
                        .on('click', function () {
                            if (t.$box.hasClass(prefix + 'fullscreen'))
                                $('body').css('overflow', 'auto');
                            t.destroy();
                            t.$c.trigger('tbwclose');
                        })
                    );


            // Add right li only if isn't empty
            if ($liRight.not(':empty'))
                t.$btnPane.append($liRight);

            t.$box.prepend(t.$btnPane);
        },


        // Build a button and his action
        buildBtn: function (n) { // n is name of the button
            var t = this,
                prefix = t.o.prefix,
                btn = t.o.btnsDef[n],
                d = btn.dropdown,
                textDef = t.lang[n] || n,

                $btn = $('<button/>', {
                    type: 'button',
                    'class': prefix + n + '-button' + (btn.ico ? ' ' + prefix + btn.ico + '-button' : ''),
                    text: btn.text || btn.title || textDef,
                    title: btn.title || btn.text || textDef + ((btn.key) ? ' (Ctrl + ' + btn.key + ')' : ''),
                    tabindex: -1,
                    mousedown: function () {
                        if (!d || $('.' + n + '-' + prefix + 'dropdown', t.$box).is(':hidden'))
                            $('body', t.doc).trigger('mousedown');

                        if (t.$btnPane.hasClass(prefix + 'disable') && !$(this).hasClass(prefix + 'active') && !$(this).parent().hasClass(prefix + 'not-disable'))
                            return false;

                        t.execCmd((d ? 'dropdown' : false) || btn.func || n,
                                  btn.param || n);

                        return false;
                    }
                });

            if (d) {
                $btn.addClass(prefix + 'open-dropdown');
                var c = prefix + 'dropdown',
                    dd = $('<div/>', { // the dropdown
                        'class': n + '-' + c + ' ' + c + ' ' + prefix + 'fixed-top'
                    });
                $.each(d, function (i, def) {
                    if (t.o.btnsDef[def] && t.isSupportedBtn(def))
                        dd.append(t.buildSubBtn(def));
                });
                t.$box.append(dd.hide());
            } else if (btn.key) {
                t.keys[btn.key] = {
                    func: btn.func || n,
                    param: btn.param || n
                };
            }

            return $btn;
        },
        // Build a button for dropdown menu
        // @param n : name of the subbutton
        buildSubBtn: function (n) {
            var t = this,
                b = t.o.btnsDef[n];

            if (b.key) {
                t.keys[b.key] = {
                    func: b.func || n,
                    param: b.param || n
                };
            }

            return $('<button/>', {
                type: 'button',
                'class': t.o.prefix + n + '-dropdown-button' + (b.ico ? ' ' + t.o.prefix + b.ico + '-button' : ''),
                text: b.text || b.title || t.lang[n] || n,
                title: ((b.key) ? ' (Ctrl + ' + b.key + ')' : null),
                style: b.style || null,
                mousedown: function () {
                    $('body', t.doc).trigger('mousedown');

                    t.execCmd(b.func || n,
                              b.param || n);

                    return false;
                }
            });
        },
        // Build a button for right li
        // @param n : name of the right button
        buildRightBtn: function (n) {
            var l = this.lang[n];
            return $('<button/>', {
                type: 'button',
                'class': this.o.prefix + n + '-button',
                title: l,
                text: l,
                tabindex: -1
            });
        },
        // Check if button is supported
        isSupportedBtn: function (b) {
            try {
                return this.o.btnsDef[b].isSupported();
            } catch (e) { }
            return true;
        },

        // Build overlay for modal box
        buildOverlay: function () {
            var t = this;
            t.$overlay = $('<div/>', {
                'class': t.o.prefix + 'overlay'
            }).css({
                top: t.$btnPane.outerHeight(),
                height: (t.$ed.outerHeight() + 1) + 'px'
            }).appendTo(t.$box);
            return t.$overlay;
        },
        showOverlay: function () {
            var t = this;
            $(window).trigger('scroll');
            t.$overlay.fadeIn(200);
            t.$box.addClass(t.o.prefix + 'box-blur');
        },
        hideOverlay: function () {
            var t = this;
            t.$overlay.fadeOut(50);
            t.$box.removeClass(t.o.prefix + 'box-blur');
        },

        // Management of fixed button pane
        fixedBtnPaneEvents: function () {
            var t = this,
                fixedFullWidth = t.o.fixedFullWidth,
                box = t.$box;
            if (!t.o.fixedBtnPane)
                return;

            t.isFixed = false;

            $(window)
            .on('scroll resize', function () {
                if (!box)
                    return;

                t.syncCode();

                var scrollTop = $(window).scrollTop(),
                    offset = box.offset().top + 1,
                    bp = t.$btnPane,
                    oh = bp.outerHeight();

                if ((scrollTop - offset > 0) && ((scrollTop - offset - t.height) < 0)) {
                    if (!t.isFixed) {
                        t.isFixed = true;
                        bp.css({
                            position: 'fixed',
                            top: 0,
                            left: fixedFullWidth ? '0' : 'auto',
                            zIndex: 7
                        });
                        $([t.$ta, t.$ed]).css({ marginTop: bp.height() });
                    }
                    bp.css({
                        width: fixedFullWidth ? '100%' : ((box.width() - 1) + 'px')
                    });

                    $('.' + t.o.prefix + 'fixed-top', box).css({
                        position: fixedFullWidth ? 'fixed' : 'absolute',
                        top: fixedFullWidth ? oh : oh + (scrollTop - offset) + 'px',
                        zIndex: 15
                    });
                } else if (t.isFixed) {
                    t.isFixed = false;
                    bp.removeAttr('style');
                    $([t.$ta, t.$ed]).css({ marginTop: 0 });
                    $('.' + t.o.prefix + 'fixed-top', box).css({
                        position: 'absolute',
                        top: oh
                    });
                }
            });
        },



        // Destroy the editor
        destroy: function () {
            var t = this,
                prefix = t.o.prefix,
                height = t.height,
                html = t.html();

            if (t.isTextarea)
                t.$box.after(
                    t.$ta.css({ height: height })
                        .val(html)
                        .removeClass(prefix + 'textarea')
                        .show()
                );
            else
                t.$box.after(
                    t.$ed
                        .css({ height: height })
                        .removeClass(prefix + 'editor')
                        .removeAttr('contenteditable')
                        .html(html)
                        .show()
                );

            t.$box.remove();
            t.$c.removeData('trumbowyg');
        },



        // Empty the editor
        empty: function () {
            this.$ta.val('');
            this.syncCode(true);
        },



        // Function call when click on viewHTML button
        toggle: function () {
            var t = this,
                prefix = t.o.prefix;
            t.semanticCode(false, true);
            t.$box.toggleClass(prefix + 'editor-hidden ' + prefix + 'editor-visible');
            t.$btnPane.toggleClass(prefix + 'disable');
            $('.' + prefix + 'viewHTML-button', t.$btnPane).toggleClass(prefix + 'active');
            if (t.$box.hasClass(prefix + 'editor-visible'))
                t.$ta.attr('tabindex', -1);
            else
                t.$ta.removeAttr('tabindex');
        },

        // Open dropdown when click on a button which open that
        dropdown: function (name) {
            var t = this,
                d = t.doc,
                prefix = t.o.prefix,
                $dd = $('.' + name + '-' + prefix + 'dropdown', t.$box),
                $btn = $('.' + prefix + name + '-button', t.$btnPane);

            if ($dd.is(':hidden')) {
                var o = $btn.offset().left;
                $btn.addClass(prefix + 'active');

                $dd.css({
                    position: 'absolute',
                    top: t.$btnPane.outerHeight(),
                    left: (t.o.fixedFullWidth && t.isFixed) ? o + 'px' : (o - t.$btnPane.offset().left) + 'px'
                }).show();

                $(window).trigger('scroll');

                $('body', d).on('mousedown', function () {
                    $('.' + prefix + 'dropdown', d).hide();
                    $('.' + prefix + 'active', d).removeClass(prefix + 'active');
                    $('body', d).off('mousedown');
                });
            } else
                $('body', d).trigger('mousedown');
        },



        // HTML Code management
        html: function (html) {
            var t = this;
            if (html) {
                t.$ta.val(html);
                t.syncCode(true);
                return t;
            } else
                return t.$ta.val();
        },
        syncCode: function (force) {
            var t = this;
            if (!force && t.$ed.is(':visible')) {
                t.$ta.val(t.$ed.html());
                t.$c.trigger('tbwchange');
            } else {
                t.$ed.html(t.$ta.val());
            }

            if (t.o.autogrow) {
                t.height = t.$ed.height();
                if (t.height != t.$ta.css('height')) {
                    t.$ta.css({ height: t.height });
                    t.$c.trigger('tbwresize');
                }
            }
        },

        // Analyse and update to semantic code
        // @param force : force to sync code from textarea
        // @param full  : wrap text nodes in <p>
        semanticCode: function (force, full) {
            var t = this;
            t.syncCode(force);
            t.saveSelection();

            if (t.o.semantic) {
                t.semanticTag('b', 'strong');
                t.semanticTag('i', 'em');
                t.semanticTag('strike', 'del');

                if (full) {
                    var blockElementsSelector = t.o.blockLevelElements.join(', '),
                        inlineElementsSelector = ':not(' + blockElementsSelector + ')';

                    // Wrap text nodes in span for easier processing
                    t.$ed.contents().filter(function () {
                        return this.nodeType === 3 && $.trim(this.nodeValue).length > 0;
                    }).wrap('<span data-trumbowyg-textnode/>');

                    // Wrap groups of inline elements in paragraphs (recursive)
                    var wrapInlinesInParagraphsFrom = function ($from) {
                        if ($from.length !== 0) {
                            var $finalParagraph = $from.nextUntil(blockElementsSelector + ', br').andSelf()
                                .wrapAll('<p/>').parent();

                            $finalParagraph.next('br').remove();

                            var $nextElement = $finalParagraph.nextAll(inlineElementsSelector).first();
                            if ($nextElement.length) {
                                wrapInlinesInParagraphsFrom($nextElement);
                            }
                        }
                    };
                    wrapInlinesInParagraphsFrom(t.$ed.children(inlineElementsSelector).first());

                    t.semanticTag('div', 'p', true);

                    // Unwrap paragraphs content, containing nothing usefull
                    t.$ed.find('p').filter(function () {
                        if (t.selection && this === t.selection.startContainer) {
                            // Don't remove currently being edited element
                            return false;
                        }
                        return $(this).text().trim().length === 0 && $(this).children().not('br, span').length === 0;
                    }).contents().unwrap();

                    // Get rid of temporial span's
                    $('[data-trumbowyg-textnode]', t.$ed).contents().unwrap();

                    // Replace empty <p> with <br> (IE loves adding empty <p>)
                    t.$ed.find('p:empty').replaceWith('<br/>');
                }

                t.restoreSelection();

                t.$ta.val(t.$ed.html());
            }
        },

        semanticTag: function (oldTag, newTag, copyAttributes) {
            $(oldTag, this.$ed).each(function () {
                var $oldTag = $(this);
                $oldTag.wrap('<' + newTag + '/>');
                if (copyAttributes) {
                    $.each($oldTag.prop('attributes'), function () {
                        $oldTag.parent().attr(this.name, this.value);
                    });
                }
                $oldTag.contents().unwrap();
            });
        },

        // Function call when user click on "Insert Link"
        createLink: function () {
            var t = this;
            t.saveSelection();
            t.openModalInsert(t.lang.createLink, {
                url: {
                    label: 'URL',
                    required: true
                },
                title: {
                    label: t.lang.title
                },
                text: {
                    label: t.lang.text,
                    value: t.getSelectedText()
                },
                target: {
                    label: t.lang.target
                }
            }, function (v) { // v is value
                var link = $(['<a href="', v.url, '">', v.text, '</a>'].join(''));
                if (v.title.length > 0)
                    link.attr('title', v.title);
                if (v.target.length > 0)
                    link.attr('target', v.target);
                t.selection.deleteContents();
                t.selection.insertNode(link.get(0));
                t.restoreSelection();
                return true;
            });
        },
        insertImage: function () {
            var t = this;
            t.saveSelection();
            t.openModalInsert(t.lang.insertImage, {
                url: {
                    label: 'URL',
                    required: true
                },
                alt: {
                    label: t.lang.description,
                    value: t.getSelectedText()
                }
            }, function (v) { // v are values
                t.execCmd('insertImage', v.url);
                $('img[src="' + v.url + '"]:not([alt])', t.$box).attr('alt', v.alt);
                return true;
            });
        },


        /*
         * Call method of trumbowyg if exist
         * else try to call anonymous function
         * and finaly native execCommand
         */
        execCmd: function (cmd, param) {
            var t = this;
            if (cmd != 'dropdown')
                t.$ed.focus();

            try {
                t[cmd](param);
            } catch (e) {
                try {
                    cmd(param, t);
                } catch (e2) {
                    if (cmd == 'insertHorizontalRule')
                        param = null;
                    else if (cmd == 'formatBlock' && (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0))
                        param = '<' + param + '>';

                    t.doc.execCommand(cmd, false, param);
                }
            }

            if (cmd != 'dropdown')
                t.syncCode();
        },


        // Open a modal box
        openModal: function (title, content) {
            var t = this,
                prefix = t.o.prefix;

            // No open a modal box when exist other modal box
            if ($('.' + prefix + 'modal-box', t.$box).length > 0)
                return false;

            t.saveSelection();
            t.showOverlay();

            // Disable all btnPane btns
            t.$btnPane.addClass(prefix + 'disable');

            // Build out of ModalBox, it's the mask for animations
            var $modal = $('<div/>', {
                'class': prefix + 'modal ' + prefix + 'fixed-top'
            }).css({
                top: (t.$btnPane.height() + 1) + 'px'
            }).appendTo(t.$box);

            // Click on overlay close modal by cancelling them
            t.$overlay.one('click', function () {
                $modal.trigger(prefix + 'cancel');
                return false;
            });

            // Build the form
            var $form = $('<form/>', {
                action: '',
                html: content
            })
            .on('submit', function () {
                $modal.trigger(prefix + 'confirm');
                return false;
            })
            .on('reset', function () {
                $modal.trigger(prefix + 'cancel');
                return false;
            });


            // Build ModalBox and animate to show them
            var $box = $('<div/>', {
                'class': prefix + 'modal-box',
                html: $form
            })
            .css({
                top: '-' + t.$btnPane.outerHeight() + 'px',
                opacity: 0
            })
            .appendTo($modal)
            .animate({
                top: 0,
                opacity: 1
            }, 100);


            // Append title
            $('<span/>', {
                text: title,
                'class': prefix + 'modal-title'
            }).prependTo($box);

            $modal.height($box.outerHeight() + 10);


            // Focus in modal box
            $('input:first', $box).focus();


            // Append Confirm and Cancel buttons
            t.buildModalBtn('submit', $box);
            t.buildModalBtn('reset', $box);


            $(window).trigger('scroll');

            return $modal;
        },
        // @param n is name of modal
        buildModalBtn: function (n, $modal) {
            var t = this,
                prefix = t.o.prefix;

            return $('<button/>', {
                'class': prefix + 'modal-button ' + prefix + 'modal-' + n,
                type: n,
                text: t.lang[n] || n
            }).appendTo($('form', $modal));
        },
        // close current modal box
        closeModal: function () {
            var t = this,
                prefix = t.o.prefix;

            t.$btnPane.removeClass(prefix + 'disable');
            t.$overlay.off();

            // Find the modal box
            var $mb = $('.' + prefix + 'modal-box', t.$box);

            $mb.animate({
                top: '-' + $mb.height()
            }, 100, function () {
                $mb.parent().remove();
                t.hideOverlay();
            });

            t.restoreSelection();
        },
        // Preformated build and management modal
        openModalInsert: function (title, fields, cmd) {
            var t = this,
                prefix = t.o.prefix,
                lg = t.lang,
                html = '';

            for (var f in fields) {
                var fd = fields[f], // field definition
                    l = fd.label,
                    n = (fd.name) ? fd.name : f;

                html += '<label><input type="' + (fd.type || 'text') + '" name="' + n + '" value="' + (fd.value || '') + '"><span class="' + prefix + 'input-infos"><span>' +
                            ((!l) ? (lg[f] ? lg[f] : f) : (lg[l] ? lg[l] : l)) +
                            '</span></span></label>';
            }

            return t.openModal(title, html)
            .on(prefix + 'confirm', function () {
                var $form = $('form', $(this)),
                    valid = true,
                    v = {}; // values

                for (var f in fields) {
                    var $field = $('input[name="' + f + '"]', $form);

                    v[f] = $.trim($field.val());

                    // Validate value
                    if (fields[f].required && v[f] === '') {
                        valid = false;
                        t.addErrorOnModalField($field, t.lang.required);
                    } else if (fields[f].pattern && !fields[f].pattern.test(v[f])) {
                        valid = false;
                        t.addErrorOnModalField($field, fields[f].patternError);
                    }
                }

                if (valid) {
                    t.restoreSelection();

                    if (cmd(v, fields)) {
                        t.syncCode();
                        t.closeModal();
                        $(this).off(prefix + 'confirm');
                    }
                }
            })
            .one(prefix + 'cancel', function () {
                $(this).off(prefix + 'confirm');
                t.closeModal();
            });
        },
        addErrorOnModalField: function ($field, err) {
            var prefix = this.o.prefix,
                $label = $field.parent();

            $field
            .on('change keyup', function () {
                $label.removeClass(prefix + 'input-error');
            });

            $label
            .addClass(prefix + 'input-error')
            .find('input+span')
            .append(
                $('<span/>', {
                    'class': prefix + 'msg-error',
                    text: err
                })
            );
        },




        // Selection management
        saveSelection: function(){
            var t = this,
                ds = t.doc.selection;

            t.selection = null;
            if(t.doc.getSelection){
                var s = t.doc.getSelection();
                if(s.getRangeAt && s.rangeCount)
                    t.selection = s.getRangeAt(0);
            } else if(ds && ds.createRange)
                t.selection = ds.createRange();
        },
        restoreSelection: function(){
            var t = this,
                range = t.selection;

            if(range){
                if(t.doc.getSelection){
                    var s = t.doc.getSelection();
                    s.removeAllRanges();
                    s.addRange(range);
                } else if (t.doc.selection && range.select)
                    range.select();
            }
        },
        getSelectedText: function () {
            var s = this.selection;
            return (s.text !== undefined) ? s.text : s + '';
        }
    };
})(navigator, window, document, jQuery);

/* ===========================================================
* jquery-wheelmenu.js v1
* ===========================================================
* Copyright 2013 Pete Rojwongsuriya.
* http://www.thepetedesign.com
*
* A small jQuery plugin that adds a beautiful
* Path-like menu button to your website
* https://github.com/peachananr/wheel-menu
*
* ========================================================== */

!function ($) {

    var defaults = {
        trigger: "click",
        animation: "fade",
        angle: [0, 360],
        animationSpeed: "medium"
    };

    $.fn.centerAround = function (button) {
        var offset = button.offset(),
        width = button.outerWidth(),
        height = button.outerHeight(),
        buttonX = (offset.left - $(document).scrollLeft()) + width / 2,
        buttonY = (offset.top - $(document).scrollTop()) + height / 2,
        objectOffset = this.offset();
        this.css("position", "fixed");
        this.css("top", buttonY - (this.outerHeight() / 2) + "px");
        this.css("left", buttonX - (this.outerWidth() / 2) + "px");
        return this;
    }

    $.fn.flyIn = function (el, button, width, height, angle, step, radius, settings) {
        var d = 0;
        this.stop(true, true);
        this.each(function (index) {
            angle = (settings.angle[0] + (step * index)) * (Math.PI / 180);
            var x = Math.round(width / 2 + radius * Math.cos(angle) - $(this).find("a").outerWidth() / 2),
          y = Math.round(height / 2 + radius * Math.sin(angle) - $(this).find("a").outerHeight() / 2);
            $(this).animateRotate(360).css({
                position: 'absolute',
                opacity: 0,
                left: "50%",
                top: "50%",
                marginLeft: "-" + $(this).outerWidth() / 2,
                marginTop: "-" + $(this).outerHeight() / 2
            }).delay(d).animate({
                opacity: 1,
                left: x + 'px',
                top: y + 'px'
            }, settings.animationSpeed[1]);
            d += settings.animationSpeed[0];
        });
    }

    $.fn.flyOut = function (el, button) {
        var d = 0;
        this.stop(true, true);
        $(this.get().reverse()).each(function () {
            $(this).animateRotate(-360).delay(d).animate({
                opacity: 0,
                left: el.outerWidth() / 2 + "px",
                top: el.outerHeight() / 2 + "px"
            }, 150);
            d += 15;
        }).promise().done(function () {
            el.removeClass("active").css("visibility", "hidden").hide();
            button.removeClass("active")
        });
    }

    $.fn.fadeInIcon = function (el, button, width, height, angle, step, radius, settings) {
        var d = 0;
        this.stop(true, true);
        this.each(function (index) {
            angle = (settings.angle[0] + (step * index)) * (Math.PI / 180);
            var x = Math.round(width / 2 + radius * Math.cos(angle) - $(this).find("a").outerWidth() / 2),
          y = Math.round(height / 2 + radius * Math.sin(angle) - $(this).find("a").outerHeight() / 2);
            $(this).css({
                position: 'absolute',
                left: x + 'px',
                top: y + 'px',
                opacity: 0
            }).delay(d).animate({ opacity: 1 }, settings.animationSpeed[1]);

            d += settings.animationSpeed[0];
        });
    }

    $.fn.fadeOutIcon = function (el, button) {
        var d = 0;
        this.stop(true, true);

        $(this.get().reverse()).each(function () {
            $(this).delay(d).animate({ opacity: 0 }, 150);
            d += 15;
        }).promise().done(function () {
            el.removeClass("active").css("visibility", "hidden").hide();
            button.removeClass("active")
        });
    }

    $.fn.hideIcon = function (button, settings) {
        var fields = this.find(".item"),
	      el = this;
        switch (settings.animation) {
            case 'fade':
                fields.fadeOutIcon(el, button)
                break;

            case 'fly':
                fields.flyOut(el, button)
                break;
        }

    }

    $.fn.showIcon = function (button, settings) {
        var el = this,
	      zindex = '6';
        if (settings.trigger == "hover") {
            var zindex = '3';
        }
        button.addClass("active").css({
            'z-index': zindex
        });



        el.show().css({
            position: 'absolute',
            'z-index': '5',
            'padding': '30px' // add safe zone for mouseover
        }).centerAround(button);
        el.addClass("wheel active").css("visibility", "visible").show();

        if (el.attr('data-angle')) {
            settings.angle = el.attr('data-angle')
        }

        settings = predefineAngle(settings);
        var radius = el.width() / 2,
      fields = el.find(".item"),
      container = el,
      width = container.innerWidth(),
      height = container.innerHeight(),
      angle = 0,
      step = (settings.angle[1] - settings.angle[0]) / fields.length;


        switch (settings.animation) {
            case 'fade':
                fields.fadeInIcon(el, button, width, height, angle, step, radius, settings)
                break;

            case 'fly':
                fields.flyIn(el, button, width, height, angle, step, radius, settings)
                break;
        }

    }

    $.fn.animateRotate = function (angle, duration, easing, complete) {
        return this.each(function () {
            var $elem = $(this);

            $({ deg: 0 }).animate({ deg: angle }, {
                duration: duration,
                easing: easing,
                step: function (now) {
                    $elem.css({
                        transform: 'rotate(' + now + 'deg)'
                    });
                },
                complete: complete || $.noop
            });
        });
    };


    function predefineAngle(settings) {
        var convert = false
        if ($.type(settings.angle) == "string") {
            try {
                if (eval(settings.angle).length > 1) convert = true
            }
            catch (err) {
                convert = false
            }
            if (convert == true) {
                settings.angle = JSON.parse(settings.angle);
            } else {
                switch (settings.angle) {
                    case 'N':
                        settings.angle = [180, 380]
                        break;
                    case 'NE':
                        settings.angle = [270, 380]
                        break;
                    case 'E':
                        settings.angle = [270, 470]
                        break;
                    case 'SE':
                        settings.angle = [360, 470]
                        break;
                    case 'S':
                        settings.angle = [360, 560]
                        break;
                    case 'SW':
                        settings.angle = [90, 200]
                        break;
                    case 'W':
                        settings.angle = [90, 290]
                        break;
                    case 'NW':
                        settings.angle = [180, 290]
                        break;
                    case 'all':
                        settings.angle = [0, 360]
                        break;
                }
            }
        }
        return settings;
    }

    function predefineSpeed(settings) {
        if ($.type(settings.animationSpeed) == "string") {
            switch (settings.animationSpeed) {
                case 'slow':
                    settings.animationSpeed = [75, 700]
                    break;
                case 'medium':
                    settings.animationSpeed = [50, 500]
                    break;
                case 'fast':
                    settings.animationSpeed = [25, 250]
                    break;
                case 'instant':
                    settings.animationSpeed = [0, 0]
                    break;
            }
        }
        return settings;
    }

    $.fn.wheelmenu = function (options) {
        var settings = $.extend({}, defaults, options);

        settings = predefineSpeed(settings);

        return this.each(function () {
            var button = $(this)
            var el = $($(this).attr("href"));
            el.addClass("wheel");

            button.css("opacity", 0).animate({
                opacity: 1
            })
            if (settings.trigger == "hover") {

                button.bind({
                    mouseenter: function () {
                        el.showIcon(button, settings);
                    }
                });

                el.bind({
                    mouseleave: function () {
                        el.hideIcon(button, settings);
                    }
                });

            } else {
                button.click(function () {
                    if (el.css('visibility') == "visible") {
                        el.hideIcon(button, settings);
                    } else {
                        el.showIcon(button, settings);
                    }
                });
            }
        });
    }

} (window.jQuery);
;(function($){$.jgrid=$.jgrid||{};$.extend($.jgrid,{defaults:{recordtext:"View {0} - {1} of {2}",emptyrecords:"No records to view",loadtext:"Loading...",pgtext:"Page {0} of {1}"},search:{caption:"Search...",Find:"Find",Reset:"Reset",odata:[{oper:'eq',text:'equal'},{oper:'ne',text:'not equal'},{oper:'lt',text:'less'},{oper:'le',text:'less or equal'},{oper:'gt',text:'greater'},{oper:'ge',text:'greater or equal'},{oper:'bw',text:'begins with'},{oper:'bn',text:'does not begin with'},{oper:'in',text:'is in'},{oper:'ni',text:'is not in'},{oper:'ew',text:'ends with'},{oper:'en',text:'does not end with'},{oper:'cn',text:'contains'},{oper:'nc',text:'does not contain'}],groupOps:[{op:"AND",text:"all"},{op:"OR",text:"any"}]},edit:{addCaption:"Add Record",editCaption:"Edit Record",bSubmit:"Submit",bCancel:"Cancel",bClose:"Close",saveData:"Data has been changed! Save changes?",bYes:"Yes",bNo:"No",bExit:"Cancel",msg:{required:"Field is required",number:"Please, enter valid number",minValue:"value must be greater than or equal to ",maxValue:"value must be less than or equal to",email:"is not a valid e-mail",integer:"Please, enter valid integer value",date:"Please, enter valid date value",url:"is not a valid URL. Prefix required ('http://' or 'https://')",nodefined:" is not defined!",novalue:" return value is required!",customarray:"Custom function should return array!",customfcheck:"Custom function should be present in case of custom checking!"}},view:{caption:"View Record",bClose:"Close"},del:{caption:"Delete",msg:"Delete selected record(s)?",bSubmit:"Delete",bCancel:"Cancel"},nav:{edittext:"",edittitle:"Edit selected row",addtext:"",addtitle:"Add new row",deltext:"",deltitle:"Delete selected row",searchtext:"",searchtitle:"Find records",refreshtext:"",refreshtitle:"Reload Grid",alertcap:"Warning",alerttext:"Please, select row",viewtext:"",viewtitle:"View selected row"},col:{caption:"Select columns",bSubmit:"Ok",bCancel:"Cancel"},errors:{errcap:"Error",nourl:"No url is set",norecords:"No records to process",model:"Length of colNames <> colModel!"},formatter:{integer:{thousandsSeparator:",",defaultValue:'0'},number:{decimalSeparator:".",thousandsSeparator:",",decimalPlaces:2,defaultValue:'0.00'},currency:{decimalSeparator:".",thousandsSeparator:",",decimalPlaces:2,prefix:"",suffix:"",defaultValue:'0.00'},date:{dayNames:["Sun","Mon","Tue","Wed","Thr","Fri","Sat","Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],monthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec","January","February","March","April","May","June","July","August","September","October","November","December"],AmPm:["am","pm","AM","PM"],S:function(j){return j<11||j>13?['st','nd','rd','th'][Math.min((j-1)%10,3)]:'th';},srcformat:'Y-m-d',newformat:'j/n/Y',parseRe:/[Tt\\\/:_;.,\t\s-]/,masks:{ISO8601Long:"Y-m-d H:i:s",ISO8601Short:"Y-m-d",ShortDate:"j/n/Y",LongDate:"l, d F, Y",FullDateTime:"l, d F, Y g:i:s A",MonthDay:"d F",ShortTime:"g:i A",LongTime:"g:i:s A",SortableDateTime:"Y-m-d\\TH:i:s",UniversalSortableDateTime:"Y-m-d H:i:sO",YearMonth:"F, Y"},reformatAfterEdit:false},baseLinkUrl:'',showAction:'',target:'',checkbox:{disabled:true},idName:'id'}});})(jQuery);(function($){"use strict";$.jgrid=$.jgrid||{};$.extend($.jgrid,{version:"4.5.4",htmlDecode:function(value){if(value&&(value==='&nbsp;'||value==='&#160;'||(value.length===1&&value.charCodeAt(0)===160))){return"";}
return!value?value:String(value).replace(/&gt;/g,">").replace(/&lt;/g,"<").replace(/&quot;/g,'"').replace(/&amp;/g,"&");},htmlEncode:function(value){return!value?value:String(value).replace(/&/g,"&amp;").replace(/\"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;");},format:function(format){var args=$.makeArray(arguments).slice(1);if(format==null){format="";}
return format.replace(/\{(\d+)\}/g,function(m,i){return args[i];});},msie:navigator.appName==='Microsoft Internet Explorer',msiever:function(){var rv=-1;var ua=navigator.userAgent;var re=new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");if(re.exec(ua)!=null){rv=parseFloat(RegExp.$1);}
return rv;},getCellIndex:function(cell){var c=$(cell);if(c.is('tr')){return-1;}
c=(!c.is('td')&&!c.is('th')?c.closest("td,th"):c)[0];if($.jgrid.msie){return $.inArray(c,c.parentNode.cells);}
return c.cellIndex;},stripHtml:function(v){v=String(v);var regexp=/<("[^"]*"|'[^']*'|[^'">])*>/gi;if(v){v=v.replace(regexp,"");return(v&&v!=='&nbsp;'&&v!=='&#160;')?v.replace(/\"/g,"'"):"";}
return v;},stripPref:function(pref,id){var obj=$.type(pref);if(obj==="string"||obj==="number"){pref=String(pref);id=pref!==""?String(id).replace(String(pref),""):id;}
return id;},parse:function(jsonString){var js=jsonString;if(js.substr(0,9)==="while(1);"){js=js.substr(9);}
if(js.substr(0,2)==="/*"){js=js.substr(2,js.length-4);}
if(!js){js="{}";}
return($.jgrid.useJSON===true&&typeof JSON==='object'&&typeof JSON.parse==='function')?JSON.parse(js):eval('('+js+')');},parseDate:function(format,date,newformat,opts){var token=/\\.|[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]/g,timezone=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,timezoneClip=/[^-+\dA-Z]/g,msDateRegExp=new RegExp("^\/Date\\((([-+])?[0-9]+)(([-+])([0-9]{2})([0-9]{2}))?\\)\/$"),msMatch=((typeof date==='string')?date.match(msDateRegExp):null),pad=function(value,length){value=String(value);length=parseInt(length,10)||2;while(value.length<length){value='0'+value;}
return value;},ts={m:1,d:1,y:1970,h:0,i:0,s:0,u:0},timestamp=0,dM,k,hl,h12to24=function(ampm,h){if(ampm===0){if(h===12){h=0;}}else{if(h!==12){h+=12;}}
return h;};if(opts===undefined){opts=$.jgrid.formatter.date;}
if(opts.parseRe===undefined){opts.parseRe=/[Tt\\\/:_;.,\t\s-]/;}
if(opts.masks.hasOwnProperty(format)){format=opts.masks[format];}
if(date&&date!=null){if(!isNaN(date-0)&&String(format).toLowerCase()==="u"){timestamp=new Date(parseFloat(date)*1000);}else if(date.constructor===Date){timestamp=date;}else if(msMatch!==null){timestamp=new Date(parseInt(msMatch[1],10));if(msMatch[3]){var offset=Number(msMatch[5])*60+Number(msMatch[6]);offset*=((msMatch[4]==='-')?1:-1);offset-=timestamp.getTimezoneOffset();timestamp.setTime(Number(Number(timestamp)+(offset*60*1000)));}}else{date=String(date).replace(/\\T/g,"T").replace(/\\t/,"t").split(opts.parseRe);format=format.replace(/\\T/g,"T").replace(/\\t/,"t").split(opts.parseRe);for(k=0,hl=format.length;k<hl;k++){if(format[k]==='M'){dM=$.inArray(date[k],opts.monthNames);if(dM!==-1&&dM<12){date[k]=dM+1;ts.m=date[k];}}
if(format[k]==='F'){dM=$.inArray(date[k],opts.monthNames,12);if(dM!==-1&&dM>11){date[k]=dM+1-12;ts.m=date[k];}}
if(format[k]==='a'){dM=$.inArray(date[k],opts.AmPm);if(dM!==-1&&dM<2&&date[k]===opts.AmPm[dM]){date[k]=dM;ts.h=h12to24(date[k],ts.h);}}
if(format[k]==='A'){dM=$.inArray(date[k],opts.AmPm);if(dM!==-1&&dM>1&&date[k]===opts.AmPm[dM]){date[k]=dM-2;ts.h=h12to24(date[k],ts.h);}}
if(format[k]==='g'){ts.h=parseInt(date[k],10);}
if(date[k]!==undefined){ts[format[k].toLowerCase()]=parseInt(date[k],10);}}
if(ts.f){ts.m=ts.f;}
if(ts.m===0&&ts.y===0&&ts.d===0){return"&#160;";}
ts.m=parseInt(ts.m,10)-1;var ty=ts.y;if(ty>=70&&ty<=99){ts.y=1900+ts.y;}else if(ty>=0&&ty<=69){ts.y=2000+ts.y;}
timestamp=new Date(ts.y,ts.m,ts.d,ts.h,ts.i,ts.s,ts.u);}}else{timestamp=new Date(ts.y,ts.m,ts.d,ts.h,ts.i,ts.s,ts.u);}
if(newformat===undefined){return timestamp;}
if(opts.masks.hasOwnProperty(newformat)){newformat=opts.masks[newformat];}else if(!newformat){newformat='Y-m-d';}
var
G=timestamp.getHours(),i=timestamp.getMinutes(),j=timestamp.getDate(),n=timestamp.getMonth()+1,o=timestamp.getTimezoneOffset(),s=timestamp.getSeconds(),u=timestamp.getMilliseconds(),w=timestamp.getDay(),Y=timestamp.getFullYear(),N=(w+6)%7+1,z=(new Date(Y,n-1,j)-new Date(Y,0,1))/86400000,flags={d:pad(j),D:opts.dayNames[w],j:j,l:opts.dayNames[w+7],N:N,S:opts.S(j),w:w,z:z,W:N<5?Math.floor((z+N-1)/7)+1:Math.floor((z+N-1)/7)||((new Date(Y-1,0,1).getDay()+6)%7<4?53:52),F:opts.monthNames[n-1+12],m:pad(n),M:opts.monthNames[n-1],n:n,t:'?',L:'?',o:'?',Y:Y,y:String(Y).substring(2),a:G<12?opts.AmPm[0]:opts.AmPm[1],A:G<12?opts.AmPm[2]:opts.AmPm[3],B:'?',g:G%12||12,G:G,h:pad(G%12||12),H:pad(G),i:pad(i),s:pad(s),u:u,e:'?',I:'?',O:(o>0?"-":"+")+pad(Math.floor(Math.abs(o)/60)*100+Math.abs(o)%60,4),P:'?',T:(String(timestamp).match(timezone)||[""]).pop().replace(timezoneClip,""),Z:'?',c:'?',r:'?',U:Math.floor(timestamp/1000)};return newformat.replace(token,function($0){return flags.hasOwnProperty($0)?flags[$0]:$0.substring(1);});},jqID:function(sid){return String(sid).replace(/[!"#$%&'()*+,.\/:; <=>?@\[\\\]\^`{|}~]/g,"\\$&");},guid:1,uidPref:'jqg',randId:function(prefix){return(prefix||$.jgrid.uidPref)+($.jgrid.guid++);},getAccessor:function(obj,expr){var ret,p,prm=[],i;if(typeof expr==='function'){return expr(obj);}
ret=obj[expr];if(ret===undefined){try{if(typeof expr==='string'){prm=expr.split('.');}
i=prm.length;if(i){ret=obj;while(ret&&i--){p=prm.shift();ret=ret[p];}}}catch(e){}}
return ret;},getXmlData:function(obj,expr,returnObj){var ret,m=typeof expr==='string'?expr.match(/^(.*)\[(\w+)\]$/):null;if(typeof expr==='function'){return expr(obj);}
if(m&&m[2]){return m[1]?$(m[1],obj).attr(m[2]):$(obj).attr(m[2]);}
ret=$(expr,obj);if(returnObj){return ret;}
return ret.length>0?$(ret).text():undefined;},cellWidth:function(){var $testDiv=$("<div class='ui-jqgrid' style='left:10000px'><table class='ui-jqgrid-btable' style='width:5px;'><tr class='jqgrow'><td style='width:5px;display:block;'></td></tr></table></div>"),testCell=$testDiv.appendTo("body").find("td").width();$testDiv.remove();return Math.abs(testCell-5)>0.1;},cell_width:true,ajaxOptions:{},from:function(source){var QueryObject=function(d,q){if(typeof d==="string"){d=$.data(d);}
var self=this,_data=d,_usecase=true,_trim=false,_query=q,_stripNum=/[\$,%]/g,_lastCommand=null,_lastField=null,_orDepth=0,_negate=false,_queuedOperator="",_sorting=[],_useProperties=true;if(typeof d==="object"&&d.push){if(d.length>0){if(typeof d[0]!=="object"){_useProperties=false;}else{_useProperties=true;}}}else{throw"data provides is not an array";}
this._hasData=function(){return _data===null?false:_data.length===0?false:true;};this._getStr=function(s){var phrase=[];if(_trim){phrase.push("jQuery.trim(");}
phrase.push("String("+s+")");if(_trim){phrase.push(")");}
if(!_usecase){phrase.push(".toLowerCase()");}
return phrase.join("");};this._strComp=function(val){if(typeof val==="string"){return".toString()";}
return"";};this._group=function(f,u){return({field:f.toString(),unique:u,items:[]});};this._toStr=function(phrase){if(_trim){phrase=$.trim(phrase);}
phrase=phrase.toString().replace(/\\/g,'\\\\').replace(/\"/g,'\\"');return _usecase?phrase:phrase.toLowerCase();};this._funcLoop=function(func){var results=[];$.each(_data,function(i,v){results.push(func(v));});return results;};this._append=function(s){var i;if(_query===null){_query="";}else{_query+=_queuedOperator===""?" && ":_queuedOperator;}
for(i=0;i<_orDepth;i++){_query+="(";}
if(_negate){_query+="!";}
_query+="("+s+")";_negate=false;_queuedOperator="";_orDepth=0;};this._setCommand=function(f,c){_lastCommand=f;_lastField=c;};this._resetNegate=function(){_negate=false;};this._repeatCommand=function(f,v){if(_lastCommand===null){return self;}
if(f!==null&&v!==null){return _lastCommand(f,v);}
if(_lastField===null){return _lastCommand(f);}
if(!_useProperties){return _lastCommand(f);}
return _lastCommand(_lastField,f);};this._equals=function(a,b){return(self._compare(a,b,1)===0);};this._compare=function(a,b,d){var toString=Object.prototype.toString;if(d===undefined){d=1;}
if(a===undefined){a=null;}
if(b===undefined){b=null;}
if(a===null&&b===null){return 0;}
if(a===null&&b!==null){return 1;}
if(a!==null&&b===null){return-1;}
if(toString.call(a)==='[object Date]'&&toString.call(b)==='[object Date]'){if(a<b){return-d;}
if(a>b){return d;}
return 0;}
if(!_usecase&&typeof a!=="number"&&typeof b!=="number"){a=String(a);b=String(b);}
if(a<b){return-d;}
if(a>b){return d;}
return 0;};this._performSort=function(){if(_sorting.length===0){return;}
_data=self._doSort(_data,0);};this._doSort=function(d,q){var by=_sorting[q].by,dir=_sorting[q].dir,type=_sorting[q].type,dfmt=_sorting[q].datefmt;if(q===_sorting.length-1){return self._getOrder(d,by,dir,type,dfmt);}
q++;var values=self._getGroup(d,by,dir,type,dfmt),results=[],i,j,sorted;for(i=0;i<values.length;i++){sorted=self._doSort(values[i].items,q);for(j=0;j<sorted.length;j++){results.push(sorted[j]);}}
return results;};this._getOrder=function(data,by,dir,type,dfmt){var sortData=[],_sortData=[],newDir=dir==="a"?1:-1,i,ab,j,findSortKey;if(type===undefined){type="text";}
if(type==='float'||type==='number'||type==='currency'||type==='numeric'){findSortKey=function($cell){var key=parseFloat(String($cell).replace(_stripNum,''));return isNaN(key)?0.00:key;};}else if(type==='int'||type==='integer'){findSortKey=function($cell){return $cell?parseFloat(String($cell).replace(_stripNum,'')):0;};}else if(type==='date'||type==='datetime'){findSortKey=function($cell){return $.jgrid.parseDate(dfmt,$cell).getTime();};}else if($.isFunction(type)){findSortKey=type;}else{findSortKey=function($cell){$cell=$cell?$.trim(String($cell)):"";return _usecase?$cell:$cell.toLowerCase();};}
$.each(data,function(i,v){ab=by!==""?$.jgrid.getAccessor(v,by):v;if(ab===undefined){ab="";}
ab=findSortKey(ab,v);_sortData.push({'vSort':ab,'index':i});});_sortData.sort(function(a,b){a=a.vSort;b=b.vSort;return self._compare(a,b,newDir);});j=0;var nrec=data.length;while(j<nrec){i=_sortData[j].index;sortData.push(data[i]);j++;}
return sortData;};this._getGroup=function(data,by,dir,type,dfmt){var results=[],group=null,last=null,val;$.each(self._getOrder(data,by,dir,type,dfmt),function(i,v){val=$.jgrid.getAccessor(v,by);if(val==null){val="";}
if(!self._equals(last,val)){last=val;if(group!==null){results.push(group);}
group=self._group(by,val);}
group.items.push(v);});if(group!==null){results.push(group);}
return results;};this.ignoreCase=function(){_usecase=false;return self;};this.useCase=function(){_usecase=true;return self;};this.trim=function(){_trim=true;return self;};this.noTrim=function(){_trim=false;return self;};this.execute=function(){var match=_query,results=[];if(match===null){return self;}
$.each(_data,function(){if(eval(match)){results.push(this);}});_data=results;return self;};this.data=function(){return _data;};this.select=function(f){self._performSort();if(!self._hasData()){return[];}
self.execute();if($.isFunction(f)){var results=[];$.each(_data,function(i,v){results.push(f(v));});return results;}
return _data;};this.hasMatch=function(){if(!self._hasData()){return false;}
self.execute();return _data.length>0;};this.andNot=function(f,v,x){_negate=!_negate;return self.and(f,v,x);};this.orNot=function(f,v,x){_negate=!_negate;return self.or(f,v,x);};this.not=function(f,v,x){return self.andNot(f,v,x);};this.and=function(f,v,x){_queuedOperator=" && ";if(f===undefined){return self;}
return self._repeatCommand(f,v,x);};this.or=function(f,v,x){_queuedOperator=" || ";if(f===undefined){return self;}
return self._repeatCommand(f,v,x);};this.orBegin=function(){_orDepth++;return self;};this.orEnd=function(){if(_query!==null){_query+=")";}
return self;};this.isNot=function(f){_negate=!_negate;return self.is(f);};this.is=function(f){self._append('this.'+f);self._resetNegate();return self;};this._compareValues=function(func,f,v,how,t){var fld;if(_useProperties){fld='jQuery.jgrid.getAccessor(this,\''+f+'\')';}else{fld='this';}
if(v===undefined){v=null;}
var val=v,swst=t.stype===undefined?"text":t.stype;if(v!==null){switch(swst){case'int':case'integer':val=(isNaN(Number(val))||val==="")?'0':val;fld='parseInt('+fld+',10)';val='parseInt('+val+',10)';break;case'float':case'number':case'numeric':val=String(val).replace(_stripNum,'');val=(isNaN(Number(val))||val==="")?'0':val;fld='parseFloat('+fld+')';val='parseFloat('+val+')';break;case'date':case'datetime':val=String($.jgrid.parseDate(t.newfmt||'Y-m-d',val).getTime());fld='jQuery.jgrid.parseDate("'+t.srcfmt+'",'+fld+').getTime()';break;default:fld=self._getStr(fld);val=self._getStr('"'+self._toStr(val)+'"');}}
self._append(fld+' '+how+' '+val);self._setCommand(func,f);self._resetNegate();return self;};this.equals=function(f,v,t){return self._compareValues(self.equals,f,v,"==",t);};this.notEquals=function(f,v,t){return self._compareValues(self.equals,f,v,"!==",t);};this.isNull=function(f,v,t){return self._compareValues(self.equals,f,null,"===",t);};this.greater=function(f,v,t){return self._compareValues(self.greater,f,v,">",t);};this.less=function(f,v,t){return self._compareValues(self.less,f,v,"<",t);};this.greaterOrEquals=function(f,v,t){return self._compareValues(self.greaterOrEquals,f,v,">=",t);};this.lessOrEquals=function(f,v,t){return self._compareValues(self.lessOrEquals,f,v,"<=",t);};this.startsWith=function(f,v){var val=(v==null)?f:v,length=_trim?$.trim(val.toString()).length:val.toString().length;if(_useProperties){self._append(self._getStr('jQuery.jgrid.getAccessor(this,\''+f+'\')')+'.substr(0,'+length+') == '+self._getStr('"'+self._toStr(v)+'"'));}else{length=_trim?$.trim(v.toString()).length:v.toString().length;self._append(self._getStr('this')+'.substr(0,'+length+') == '+self._getStr('"'+self._toStr(f)+'"'));}
self._setCommand(self.startsWith,f);self._resetNegate();return self;};this.endsWith=function(f,v){var val=(v==null)?f:v,length=_trim?$.trim(val.toString()).length:val.toString().length;if(_useProperties){self._append(self._getStr('jQuery.jgrid.getAccessor(this,\''+f+'\')')+'.substr('+self._getStr('jQuery.jgrid.getAccessor(this,\''+f+'\')')+'.length-'+length+','+length+') == "'+self._toStr(v)+'"');}else{self._append(self._getStr('this')+'.substr('+self._getStr('this')+'.length-"'+self._toStr(f)+'".length,"'+self._toStr(f)+'".length) == "'+self._toStr(f)+'"');}
self._setCommand(self.endsWith,f);self._resetNegate();return self;};this.contains=function(f,v){if(_useProperties){self._append(self._getStr('jQuery.jgrid.getAccessor(this,\''+f+'\')')+'.indexOf("'+self._toStr(v)+'",0) > -1');}else{self._append(self._getStr('this')+'.indexOf("'+self._toStr(f)+'",0) > -1');}
self._setCommand(self.contains,f);self._resetNegate();return self;};this.groupBy=function(by,dir,type,datefmt){if(!self._hasData()){return null;}
return self._getGroup(_data,by,dir,type,datefmt);};this.orderBy=function(by,dir,stype,dfmt){dir=dir==null?"a":$.trim(dir.toString().toLowerCase());if(stype==null){stype="text";}
if(dfmt==null){dfmt="Y-m-d";}
if(dir==="desc"||dir==="descending"){dir="d";}
if(dir==="asc"||dir==="ascending"){dir="a";}
_sorting.push({by:by,dir:dir,type:stype,datefmt:dfmt});return self;};return self;};return new QueryObject(source,null);},getMethod:function(name){return this.getAccessor($.fn.jqGrid,name);},extend:function(methods){$.extend($.fn.jqGrid,methods);if(!this.no_legacy_api){$.fn.extend(methods);}}});$.fn.jqGrid=function(pin){if(typeof pin==='string'){var fn=$.jgrid.getMethod(pin);if(!fn){throw("jqGrid - No such method: "+pin);}
var args=$.makeArray(arguments).slice(1);return fn.apply(this,args);}
return this.each(function(){if(this.grid){return;}
var p=$.extend(true,{url:"",height:150,page:1,rowNum:20,rowTotal:null,records:0,pager:"",pgbuttons:true,pginput:true,colModel:[],rowList:[],colNames:[],sortorder:"asc",sortname:"",datatype:"xml",mtype:"GET",altRows:false,selarrrow:[],savedRow:[],shrinkToFit:true,xmlReader:{},jsonReader:{},subGrid:false,subGridModel:[],reccount:0,lastpage:0,lastsort:0,selrow:null,onColumnChooserDone:null,beforeSelectRow:null,onSelectRow:null,onSortCol:null,ondblClickRow:null,onRightClickRow:null,onPaging:null,onSelectAll:null,onInitGrid:null,loadComplete:null,gridComplete:null,loadError:null,loadBeforeSend:null,afterInsertRow:null,beforeRequest:null,beforeProcessing:null,onHeaderClick:null,viewrecords:false,loadonce:false,multiselect:false,multikey:false,editurl:null,search:false,caption:"",hidegrid:true,hiddengrid:false,postData:{},userData:{},treeGrid:false,treeGridModel:'nested',treeReader:{},treeANode:-1,ExpandColumn:null,tree_root_level:0,prmNames:{page:"page",rows:"rows",sort:"sidx",order:"sord",search:"_search",nd:"nd",id:"id",oper:"oper",editoper:"edit",addoper:"add",deloper:"del",subgridid:"id",npage:null,totalrows:"totalrows"},forceFit:false,gridstate:"visible",cellEdit:false,cellsubmit:"remote",nv:0,loadui:"enable",toolbar:[false,""],scroll:false,multiboxonly:false,deselectAfterSort:true,scrollrows:false,autowidth:false,scrollOffset:18,cellLayout:5,subGridWidth:20,multiselectWidth:20,gridview:false,rownumWidth:25,rownumbers:false,pagerpos:'center',recordpos:'right',footerrow:false,userDataOnFooter:false,hoverrows:true,altclass:'ui-priority-secondary',viewsortcols:[false,'vertical',true],resizeclass:'',autoencode:false,remapColumns:[],ajaxGridOptions:{},direction:"ltr",toppager:false,headertitles:false,scrollTimeout:40,data:[],_index:{},grouping:false,groupingView:{groupField:[],groupOrder:[],groupText:[],groupColumnShow:[],groupSummary:[],showSummaryOnHide:false,sortitems:[],sortnames:[],summary:[],summaryval:[],plusicon:'ui-icon-circlesmall-plus',minusicon:'ui-icon-circlesmall-minus',displayField:[],colspan:4,groupFieldCaption:[]},ignoreCase:false,cmTemplate:{},idPrefix:"",multiSort:false},$.jgrid.defaults,pin||{});var ts=this,grid={headers:[],cols:[],footers:[],dragStart:function(i,x,y){this.resizing={idx:i,startX:x.clientX,sOL:x.clientX-6};this.hDiv.style.cursor="col-resize";this.curGbox=$("#rs_m"+$.jgrid.jqID(p.id),"#gbox_"+$.jgrid.jqID(p.id));this.curGbox.css({display:"block",left:x.clientX-6,top:y[1],height:y[2]});$(ts).triggerHandler("jqGridResizeStart",[x,i]);if($.isFunction(p.resizeStart)){p.resizeStart.call(ts,x,i);}
document.onselectstart=function(){return false;};},dragMove:function(x){if(this.resizing){var diff=x.clientX-this.resizing.startX,h=this.headers[this.resizing.idx],newWidth=p.direction==="ltr"?h.width+diff:h.width-diff,hn,nWn;if(newWidth>33){this.curGbox.css({left:this.resizing.sOL+diff});if(p.forceFit===true){hn=this.headers[this.resizing.idx+p.nv];nWn=p.direction==="ltr"?hn.width-diff:hn.width+diff;if(nWn>33){h.newWidth=newWidth;hn.newWidth=nWn;}}else{this.newWidth=p.direction==="ltr"?p.tblwidth+diff:p.tblwidth-diff;h.newWidth=newWidth;}}}},dragEnd:function(){this.hDiv.style.cursor="default";if(this.resizing){var idx=this.resizing.idx,nw=this.headers[idx].newWidth||this.headers[idx].width;nw=parseInt(nw,10);this.resizing=false;$("#rs_m"+$.jgrid.jqID(p.id)).css("display","none");p.colModel[idx].width=nw;this.headers[idx].width=nw;this.headers[idx].el.style.width=nw+"px";this.cols[idx].style.width=nw+"px";if(this.footers.length>0){this.footers[idx].style.width=nw+"px";}
if(p.forceFit===true){nw=this.headers[idx+p.nv].newWidth||this.headers[idx+p.nv].width;this.headers[idx+p.nv].width=nw;this.headers[idx+p.nv].el.style.width=nw+"px";this.cols[idx+p.nv].style.width=nw+"px";if(this.footers.length>0){this.footers[idx+p.nv].style.width=nw+"px";}
p.colModel[idx+p.nv].width=nw;}else{p.tblwidth=this.newWidth||p.tblwidth;$('table:first',this.bDiv).css("width",p.tblwidth+"px");$('table:first',this.hDiv).css("width",p.tblwidth+"px");this.hDiv.scrollLeft=this.bDiv.scrollLeft;if(p.footerrow){$('table:first',this.sDiv).css("width",p.tblwidth+"px");this.sDiv.scrollLeft=this.bDiv.scrollLeft;}}
$(ts).triggerHandler("jqGridResizeStop",[nw,idx]);if($.isFunction(p.resizeStop)){p.resizeStop.call(ts,nw,idx);}}
this.curGbox=null;document.onselectstart=function(){return true;};},populateVisible:function(){if(grid.timer){clearTimeout(grid.timer);}
grid.timer=null;var dh=$(grid.bDiv).height();if(!dh){return;}
var table=$("table:first",grid.bDiv);var rows,rh;if(table[0].rows.length){try{rows=table[0].rows[1];rh=rows?$(rows).outerHeight()||grid.prevRowHeight:grid.prevRowHeight;}catch(pv){rh=grid.prevRowHeight;}}
if(!rh){return;}
grid.prevRowHeight=rh;var rn=p.rowNum;var scrollTop=grid.scrollTop=grid.bDiv.scrollTop;var ttop=Math.round(table.position().top)-scrollTop;var tbot=ttop+table.height();var div=rh*rn;var page,npage,empty;if(tbot<dh&&ttop<=0&&(p.lastpage===undefined||parseInt((tbot+scrollTop+div-1)/div,10)<=p.lastpage)){npage=parseInt((dh-tbot+div-1)/div,10);if(tbot>=0||npage<2||p.scroll===true){page=Math.round((tbot+scrollTop)/div)+1;ttop=-1;}else{ttop=1;}}
if(ttop>0){page=parseInt(scrollTop/div,10)+1;npage=parseInt((scrollTop+dh)/div,10)+2-page;empty=true;}
if(npage){if(p.lastpage&&(page>p.lastpage||p.lastpage===1||(page===p.page&&page===p.lastpage))){return;}
if(grid.hDiv.loading){grid.timer=setTimeout(grid.populateVisible,p.scrollTimeout);}else{p.page=page;if(empty){grid.selectionPreserver(table[0]);grid.emptyRows.call(table[0],false,false);}
grid.populate(npage);}}},scrollGrid:function(e){if(p.scroll){var scrollTop=grid.bDiv.scrollTop;if(grid.scrollTop===undefined){grid.scrollTop=0;}
if(scrollTop!==grid.scrollTop){grid.scrollTop=scrollTop;if(grid.timer){clearTimeout(grid.timer);}
grid.timer=setTimeout(grid.populateVisible,p.scrollTimeout);}}
grid.hDiv.scrollLeft=grid.bDiv.scrollLeft;if(p.footerrow){grid.sDiv.scrollLeft=grid.bDiv.scrollLeft;}
if(e){e.stopPropagation();}},selectionPreserver:function(ts){var p=ts.p,sr=p.selrow,sra=p.selarrrow?$.makeArray(p.selarrrow):null,left=ts.grid.bDiv.scrollLeft,restoreSelection=function(){var i;p.selrow=null;p.selarrrow=[];if(p.multiselect&&sra&&sra.length>0){for(i=0;i<sra.length;i++){if(sra[i]!==sr){$(ts).jqGrid("setSelection",sra[i],false,null);}}}
if(sr){$(ts).jqGrid("setSelection",sr,false,null);}
ts.grid.bDiv.scrollLeft=left;$(ts).unbind('.selectionPreserver',restoreSelection);};$(ts).bind('jqGridGridComplete.selectionPreserver',restoreSelection);}};if(this.tagName.toUpperCase()!=='TABLE'){alert("Element is not a table");return;}
if(document.documentMode!==undefined){if(document.documentMode<=5){alert("Grid can not be used in this ('quirks') mode!");return;}}
$(this).empty().attr("tabindex","0");this.p=p;this.p.useProp=!!$.fn.prop;var i,dir;if(this.p.colNames.length===0){for(i=0;i<this.p.colModel.length;i++){this.p.colNames[i]=this.p.colModel[i].label||this.p.colModel[i].name;}}
if(this.p.colNames.length!==this.p.colModel.length){alert($.jgrid.errors.model);return;}
var gv=$("<div class='ui-jqgrid-view'></div>"),isMSIE=$.jgrid.msie;ts.p.direction=$.trim(ts.p.direction.toLowerCase());if($.inArray(ts.p.direction,["ltr","rtl"])===-1){ts.p.direction="ltr";}
dir=ts.p.direction;$(gv).insertBefore(this);$(this).removeClass("scroll").appendTo(gv);var eg=$("<div class='ui-jqgrid ui-widget ui-widget-content ui-corner-all'></div>");$(eg).attr({"id":"gbox_"+this.id,"dir":dir}).insertBefore(gv);$(gv).attr("id","gview_"+this.id).appendTo(eg);$("<div class='ui-widget-overlay jqgrid-overlay' id='lui_"+this.id+"'></div>").insertBefore(gv);$("<div class='loading ui-state-default ui-state-active' id='load_"+this.id+"'>"+this.p.loadtext+"</div>").insertBefore(gv);$(this).attr({cellspacing:"0",cellpadding:"0",border:"0","role":"grid","aria-multiselectable":!!this.p.multiselect,"aria-labelledby":"gbox_"+this.id});var sortkeys=["shiftKey","altKey","ctrlKey"],intNum=function(val,defval){val=parseInt(val,10);if(isNaN(val)){return defval||0;}
return val;},formatCol=function(pos,rowInd,tv,rawObject,rowId,rdata){var cm=ts.p.colModel[pos],ral=cm.align,result="style=\"",clas=cm.classes,nm=cm.name,celp,acp=[];if(ral){result+="text-align:"+ral+";";}
if(cm.hidden===true){result+="display:none;";}
if(rowInd===0){result+="width: "+grid.headers[pos].width+"px;";}else if(cm.cellattr&&$.isFunction(cm.cellattr)){celp=cm.cellattr.call(ts,rowId,tv,rawObject,cm,rdata);if(celp&&typeof celp==="string"){celp=celp.replace(/style/i,'style').replace(/title/i,'title');if(celp.indexOf('title')>-1){cm.title=false;}
if(celp.indexOf('class')>-1){clas=undefined;}
acp=celp.replace('-style','-sti').split(/style/);if(acp.length===2){acp[1]=$.trim(acp[1].replace('-sti','-style').replace("=",""));if(acp[1].indexOf("'")===0||acp[1].indexOf('"')===0){acp[1]=acp[1].substring(1);}
result+=acp[1].replace(/'/gi,'"');}else{result+="\"";}}}
if(!acp.length){acp[0]="";result+="\"";}
result+=(clas!==undefined?(" class=\""+clas+"\""):"")+((cm.title&&tv)?(" title=\""+$.jgrid.stripHtml(tv)+"\""):"");result+=" aria-describedby=\""+ts.p.id+"_"+nm+"\"";return result+acp[0];},cellVal=function(val){return val==null||val===""?"&#160;":(ts.p.autoencode?$.jgrid.htmlEncode(val):String(val));},formatter=function(rowId,cellval,colpos,rwdat,_act){var cm=ts.p.colModel[colpos],v;if(cm.formatter!==undefined){rowId=String(ts.p.idPrefix)!==""?$.jgrid.stripPref(ts.p.idPrefix,rowId):rowId;var opts={rowId:rowId,colModel:cm,gid:ts.p.id,pos:colpos};if($.isFunction(cm.formatter)){v=cm.formatter.call(ts,cellval,opts,rwdat,_act);}else if($.fmatter){v=$.fn.fmatter.call(ts,cm.formatter,cellval,opts,rwdat,_act);}else{v=cellVal(cellval);}}else{v=cellVal(cellval);}
return v;},addCell=function(rowId,cell,pos,irow,srvr,rdata){var v,prp;v=formatter(rowId,cell,pos,srvr,'add');prp=formatCol(pos,irow,v,srvr,rowId,rdata);return"<td role=\"gridcell\" "+prp+">"+v+"</td>";},addMulti=function(rowid,pos,irow,checked){var v="<input role=\"checkbox\" type=\"checkbox\""+" id=\"jqg_"+ts.p.id+"_"+rowid+"\" class=\"cbox\" name=\"jqg_"+ts.p.id+"_"+rowid+"\""+(checked?"checked=\"checked\"":"")+"/>",prp=formatCol(pos,irow,'',null,rowid,true);return"<td role=\"gridcell\" "+prp+">"+v+"</td>";},addRowNum=function(pos,irow,pG,rN){var v=(parseInt(pG,10)-1)*parseInt(rN,10)+1+irow,prp=formatCol(pos,irow,v,null,irow,true);return"<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" "+prp+">"+v+"</td>";},reader=function(datatype){var field,f=[],j=0,i;for(i=0;i<ts.p.colModel.length;i++){field=ts.p.colModel[i];if(field.name!=='cb'&&field.name!=='subgrid'&&field.name!=='rn'){f[j]=datatype==="local"?field.name:((datatype==="xml"||datatype==="xmlstring")?field.xmlmap||field.name:field.jsonmap||field.name);if(ts.p.keyIndex!==false&&field.key===true){ts.p.keyName=f[j];}
j++;}}
return f;},orderedCols=function(offset){var order=ts.p.remapColumns;if(!order||!order.length){order=$.map(ts.p.colModel,function(v,i){return i;});}
if(offset){order=$.map(order,function(v){return v<offset?null:v-offset;});}
return order;},emptyRows=function(scroll,locdata){var firstrow;if(this.p.deepempty){$(this.rows).slice(1).remove();}else{firstrow=this.rows.length>0?this.rows[0]:null;$(this.firstChild).empty().append(firstrow);}
if(scroll&&this.p.scroll){$(this.grid.bDiv.firstChild).css({height:"auto"});$(this.grid.bDiv.firstChild.firstChild).css({height:0,display:"none"});if(this.grid.bDiv.scrollTop!==0){this.grid.bDiv.scrollTop=0;}}
if(locdata===true&&this.p.treeGrid){this.p.data=[];this.p._index={};}},refreshIndex=function(){var datalen=ts.p.data.length,idname,i,val,ni=ts.p.rownumbers===true?1:0,gi=ts.p.multiselect===true?1:0,si=ts.p.subGrid===true?1:0;if(ts.p.keyIndex===false||ts.p.loadonce===true){idname=ts.p.localReader.id;}else{idname=ts.p.colModel[ts.p.keyIndex+gi+si+ni].name;}
for(i=0;i<datalen;i++){val=$.jgrid.getAccessor(ts.p.data[i],idname);if(val===undefined){val=String(i+1);}
ts.p._index[val]=i;}},constructTr=function(id,hide,altClass,rd,cur,selected){var tabindex='-1',restAttr='',attrName,style=hide?'display:none;':'',classes='ui-widget-content jqgrow ui-row-'+ts.p.direction+(altClass?' '+altClass:'')+(selected?' ui-state-highlight':''),rowAttrObj=$(ts).triggerHandler("jqGridRowAttr",[rd,cur,id]);if(typeof rowAttrObj!=="object"){rowAttrObj=$.isFunction(ts.p.rowattr)?ts.p.rowattr.call(ts,rd,cur,id):{};}
if(!$.isEmptyObject(rowAttrObj)){if(rowAttrObj.hasOwnProperty("id")){id=rowAttrObj.id;delete rowAttrObj.id;}
if(rowAttrObj.hasOwnProperty("tabindex")){tabindex=rowAttrObj.tabindex;delete rowAttrObj.tabindex;}
if(rowAttrObj.hasOwnProperty("style")){style+=rowAttrObj.style;delete rowAttrObj.style;}
if(rowAttrObj.hasOwnProperty("class")){classes+=' '+rowAttrObj['class'];delete rowAttrObj['class'];}
try{delete rowAttrObj.role;}catch(ra){}
for(attrName in rowAttrObj){if(rowAttrObj.hasOwnProperty(attrName)){restAttr+=' '+attrName+'='+rowAttrObj[attrName];}}}
return'<tr role="row" id="'+cur.RowId+'" tabindex="'+tabindex+'" class="'+classes+'"'+
(style===''?'':' style="'+style+'"')+restAttr+'>';},addXmlData=function(xml,t,rcnt,more,adjust){var startReq=new Date(),locdata=(ts.p.datatype!=="local"&&ts.p.loadonce)||ts.p.datatype==="xmlstring",xmlid="_id_",xmlRd=ts.p.xmlReader,frd=ts.p.datatype==="local"?"local":"xml";if(locdata){ts.p.data=[];ts.p._index={};ts.p.localReader.id=xmlid;}
ts.p.reccount=0;if($.isXMLDoc(xml)){if(ts.p.treeANode===-1&&!ts.p.scroll){emptyRows.call(ts,false,true);rcnt=1;}else{rcnt=rcnt>1?rcnt:1;}}else{return;}
var self=$(ts),i,fpos,ir=0,v,gi=ts.p.multiselect===true?1:0,si=0,addSubGridCell,ni=ts.p.rownumbers===true?1:0,idn,getId,f=[],F,rd={},xmlr,rid,rowData=[],cn=(ts.p.altRows===true)?ts.p.altclass:"",cn1;if(ts.p.subGrid===true){si=1;addSubGridCell=$.jgrid.getMethod("addSubGridCell");}
if(!xmlRd.repeatitems){f=reader(frd);}
if(ts.p.keyIndex===false){idn=$.isFunction(xmlRd.id)?xmlRd.id.call(ts,xml):xmlRd.id;}else{idn=ts.p.keyIndex;}
if(f.length>0&&!isNaN(idn)){idn=ts.p.keyName;}
if(String(idn).indexOf("[")===-1){if(f.length){getId=function(trow,k){return $(idn,trow).text()||k;};}else{getId=function(trow,k){return $(xmlRd.cell,trow).eq(idn).text()||k;};}}else{getId=function(trow,k){return trow.getAttribute(idn.replace(/[\[\]]/g,""))||k;};}
ts.p.userData={};ts.p.page=intNum($.jgrid.getXmlData(xml,xmlRd.page),ts.p.page);ts.p.lastpage=intNum($.jgrid.getXmlData(xml,xmlRd.total),1);ts.p.records=intNum($.jgrid.getXmlData(xml,xmlRd.records));if($.isFunction(xmlRd.userdata)){ts.p.userData=xmlRd.userdata.call(ts,xml)||{};}else{$.jgrid.getXmlData(xml,xmlRd.userdata,true).each(function(){ts.p.userData[this.getAttribute("name")]=$(this).text();});}
var gxml=$.jgrid.getXmlData(xml,xmlRd.root,true);gxml=$.jgrid.getXmlData(gxml,xmlRd.row,true);if(!gxml){gxml=[];}
var gl=gxml.length,j=0,grpdata=[],rn=parseInt(ts.p.rowNum,10),br=ts.p.scroll?$.jgrid.randId():1,altr;if(gl>0&&ts.p.page<=0){ts.p.page=1;}
if(gxml&&gl){if(adjust){rn*=adjust+1;}
var afterInsRow=$.isFunction(ts.p.afterInsertRow),hiderow=false,groupingPrepare;if(ts.p.grouping){hiderow=ts.p.groupingView.groupCollapse===true;groupingPrepare=$.jgrid.getMethod("groupingPrepare");}
while(j<gl){xmlr=gxml[j];rid=getId(xmlr,br+j);rid=ts.p.idPrefix+rid;altr=rcnt===0?0:rcnt+1;cn1=(altr+j)%2===1?cn:'';var iStartTrTag=rowData.length;rowData.push("");if(ni){rowData.push(addRowNum(0,j,ts.p.page,ts.p.rowNum));}
if(gi){rowData.push(addMulti(rid,ni,j,false));}
if(si){rowData.push(addSubGridCell.call(self,gi+ni,j+rcnt));}
if(xmlRd.repeatitems){if(!F){F=orderedCols(gi+si+ni);}
var cells=$.jgrid.getXmlData(xmlr,xmlRd.cell,true);$.each(F,function(k){var cell=cells[this];if(!cell){return false;}
v=cell.textContent||cell.text;rd[ts.p.colModel[k+gi+si+ni].name]=v;rowData.push(addCell(rid,v,k+gi+si+ni,j+rcnt,xmlr,rd));});}else{for(i=0;i<f.length;i++){v=$.jgrid.getXmlData(xmlr,f[i]);rd[ts.p.colModel[i+gi+si+ni].name]=v;rowData.push(addCell(rid,v,i+gi+si+ni,j+rcnt,xmlr,rd));}}
rowData[iStartTrTag]=constructTr(rid,hiderow,cn1,rd,xmlr,false);rowData.push("</tr>");if(ts.p.grouping){grpdata=groupingPrepare.call(self,rowData,grpdata,rd,j);rowData=[];}
if(locdata||ts.p.treeGrid===true){rd[xmlid]=$.jgrid.stripPref(ts.p.idPrefix,rid);ts.p.data.push(rd);ts.p._index[rd[xmlid]]=ts.p.data.length-1;}
if(ts.p.gridview===false){$("tbody:first",t).append(rowData.join(''));self.triggerHandler("jqGridAfterInsertRow",[rid,rd,xmlr]);if(afterInsRow){ts.p.afterInsertRow.call(ts,rid,rd,xmlr);}
rowData=[];}
rd={};ir++;j++;if(ir===rn){break;}}}
if(ts.p.gridview===true){fpos=ts.p.treeANode>-1?ts.p.treeANode:0;if(ts.p.grouping){self.jqGrid('groupingRender',grpdata,ts.p.colModel.length);grpdata=null;}else if(ts.p.treeGrid===true&&fpos>0){$(ts.rows[fpos]).after(rowData.join(''));}else{$("tbody:first",t).append(rowData.join(''));}}
if(ts.p.subGrid===true){try{self.jqGrid("addSubGrid",gi+ni);}catch(_){}}
ts.p.totaltime=new Date()-startReq;if(ir>0){if(ts.p.records===0){ts.p.records=gl;}}
rowData=null;if(ts.p.treeGrid===true){try{self.jqGrid("setTreeNode",fpos+1,ir+fpos+1);}catch(e){}}
if(!ts.p.treeGrid&&!ts.p.scroll){ts.grid.bDiv.scrollTop=0;}
ts.p.reccount=ir;ts.p.treeANode=-1;if(ts.p.userDataOnFooter){self.jqGrid("footerData","set",ts.p.userData,true);}
if(locdata){ts.p.records=gl;ts.p.lastpage=Math.ceil(gl/rn);}
if(!more){ts.updatepager(false,true);}
if(locdata){while(ir<gl){xmlr=gxml[ir];rid=getId(xmlr,ir+br);rid=ts.p.idPrefix+rid;if(xmlRd.repeatitems){if(!F){F=orderedCols(gi+si+ni);}
var cells2=$.jgrid.getXmlData(xmlr,xmlRd.cell,true);$.each(F,function(k){var cell=cells2[this];if(!cell){return false;}
v=cell.textContent||cell.text;rd[ts.p.colModel[k+gi+si+ni].name]=v;});}else{for(i=0;i<f.length;i++){v=$.jgrid.getXmlData(xmlr,f[i]);rd[ts.p.colModel[i+gi+si+ni].name]=v;}}
rd[xmlid]=$.jgrid.stripPref(ts.p.idPrefix,rid);ts.p.data.push(rd);ts.p._index[rd[xmlid]]=ts.p.data.length-1;rd={};ir++;}}},addJSONData=function(data,t,rcnt,more,adjust){var startReq=new Date();if(data){if(ts.p.treeANode===-1&&!ts.p.scroll){emptyRows.call(ts,false,true);rcnt=1;}else{rcnt=rcnt>1?rcnt:1;}}else{return;}
var dReader,locid="_id_",frd,locdata=(ts.p.datatype!=="local"&&ts.p.loadonce)||ts.p.datatype==="jsonstring";if(locdata){ts.p.data=[];ts.p._index={};ts.p.localReader.id=locid;}
ts.p.reccount=0;if(ts.p.datatype==="local"){dReader=ts.p.localReader;frd='local';}else{dReader=ts.p.jsonReader;frd='json';}
var self=$(ts),ir=0,v,i,j,f=[],cur,gi=ts.p.multiselect?1:0,si=ts.p.subGrid===true?1:0,addSubGridCell,ni=ts.p.rownumbers===true?1:0,arrayReader=orderedCols(gi+si+ni),objectReader=reader(frd),rowReader,len,drows,idn,rd={},fpos,idr,rowData=[],cn=(ts.p.altRows===true)?ts.p.altclass:"",cn1;ts.p.page=intNum($.jgrid.getAccessor(data,dReader.page),ts.p.page);ts.p.lastpage=intNum($.jgrid.getAccessor(data,dReader.total),1);ts.p.records=intNum($.jgrid.getAccessor(data,dReader.records));ts.p.userData=$.jgrid.getAccessor(data,dReader.userdata)||{};if(si){addSubGridCell=$.jgrid.getMethod("addSubGridCell");}
if(ts.p.keyIndex===false){idn=$.isFunction(dReader.id)?dReader.id.call(ts,data):dReader.id;}else{idn=ts.p.keyIndex;}
if(!dReader.repeatitems){f=objectReader;if(f.length>0&&!isNaN(idn)){idn=ts.p.keyName;}}
drows=$.jgrid.getAccessor(data,dReader.root);if(drows==null&&$.isArray(data)){drows=data;}
if(!drows){drows=[];}
len=drows.length;i=0;if(len>0&&ts.p.page<=0){ts.p.page=1;}
var rn=parseInt(ts.p.rowNum,10),br=ts.p.scroll?$.jgrid.randId():1,altr,selected=false,selr;if(adjust){rn*=adjust+1;}
if(ts.p.datatype==="local"&&!ts.p.deselectAfterSort){selected=true;}
var afterInsRow=$.isFunction(ts.p.afterInsertRow),grpdata=[],hiderow=false,groupingPrepare;if(ts.p.grouping){hiderow=ts.p.groupingView.groupCollapse===true;groupingPrepare=$.jgrid.getMethod("groupingPrepare");}
while(i<len){cur=drows[i];idr=$.jgrid.getAccessor(cur,idn);if(idr===undefined){if(typeof idn==="number"&&ts.p.colModel[idn+gi+si+ni]!=null){idr=$.jgrid.getAccessor(cur,ts.p.colModel[idn+gi+si+ni].name);}
if(idr===undefined){idr=br+i;if(f.length===0){if(dReader.cell){var ccur=$.jgrid.getAccessor(cur,dReader.cell)||cur;idr=ccur!=null&&ccur[idn]!==undefined?ccur[idn]:idr;ccur=null;}}}}
idr=ts.p.idPrefix+idr;altr=rcnt===1?0:rcnt;cn1=(altr+i)%2===1?cn:'';if(selected){if(ts.p.multiselect){selr=($.inArray(idr,ts.p.selarrrow)!==-1);}else{selr=(idr===ts.p.selrow);}}
var iStartTrTag=rowData.length;rowData.push("");if(ni){rowData.push(addRowNum(0,i,ts.p.page,ts.p.rowNum));}
if(gi){rowData.push(addMulti(idr,ni,i,selr));}
if(si){rowData.push(addSubGridCell.call(self,gi+ni,i+rcnt));}
rowReader=objectReader;if(dReader.repeatitems){if(dReader.cell){cur=$.jgrid.getAccessor(cur,dReader.cell)||cur;}
if($.isArray(cur)){rowReader=arrayReader;}}
for(j=0;j<rowReader.length;j++){v=$.jgrid.getAccessor(cur,rowReader[j]);rd[ts.p.colModel[j+gi+si+ni].name]=v;rowData.push(addCell(idr,v,j+gi+si+ni,i+rcnt,cur,rd));}
rowData[iStartTrTag]=constructTr(idr,hiderow,cn1,rd,cur,selr);rowData.push("</tr>");if(ts.p.grouping){grpdata=groupingPrepare.call(self,rowData,grpdata,rd,i);rowData=[];}
if(locdata||ts.p.treeGrid===true){rd[locid]=$.jgrid.stripPref(ts.p.idPrefix,idr);ts.p.data.push(rd);ts.p._index[rd[locid]]=ts.p.data.length-1;}
if(ts.p.gridview===false){$("#"+$.jgrid.jqID(ts.p.id)+" tbody:first").append(rowData.join(''));self.triggerHandler("jqGridAfterInsertRow",[idr,rd,cur]);if(afterInsRow){ts.p.afterInsertRow.call(ts,idr,rd,cur);}
rowData=[];}
rd={};ir++;i++;if(ir===rn){break;}}
if(ts.p.gridview===true){fpos=ts.p.treeANode>-1?ts.p.treeANode:0;if(ts.p.grouping){self.jqGrid('groupingRender',grpdata,ts.p.colModel.length);grpdata=null;}else if(ts.p.treeGrid===true&&fpos>0){$(ts.rows[fpos]).after(rowData.join(''));}else{$("#"+$.jgrid.jqID(ts.p.id)+" tbody:first").append(rowData.join(''));}}
if(ts.p.subGrid===true){try{self.jqGrid("addSubGrid",gi+ni);}catch(_){}}
ts.p.totaltime=new Date()-startReq;if(ir>0){if(ts.p.records===0){ts.p.records=len;}}
rowData=null;if(ts.p.treeGrid===true){try{self.jqGrid("setTreeNode",fpos+1,ir+fpos+1);}catch(e){}}
if(!ts.p.treeGrid&&!ts.p.scroll){ts.grid.bDiv.scrollTop=0;}
ts.p.reccount=ir;ts.p.treeANode=-1;if(ts.p.userDataOnFooter){self.jqGrid("footerData","set",ts.p.userData,true);}
if(locdata){ts.p.records=len;ts.p.lastpage=Math.ceil(len/rn);}
if(!more){ts.updatepager(false,true);}
if(locdata){while(ir<len&&drows[ir]){cur=drows[ir];idr=$.jgrid.getAccessor(cur,idn);if(idr===undefined){if(typeof idn==="number"&&ts.p.colModel[idn+gi+si+ni]!=null){idr=$.jgrid.getAccessor(cur,ts.p.colModel[idn+gi+si+ni].name);}
if(idr===undefined){idr=br+ir;if(f.length===0){if(dReader.cell){var ccur2=$.jgrid.getAccessor(cur,dReader.cell)||cur;idr=ccur2!=null&&ccur2[idn]!==undefined?ccur2[idn]:idr;ccur2=null;}}}}
if(cur){idr=ts.p.idPrefix+idr;rowReader=objectReader;if(dReader.repeatitems){if(dReader.cell){cur=$.jgrid.getAccessor(cur,dReader.cell)||cur;}
if($.isArray(cur)){rowReader=arrayReader;}}
for(j=0;j<rowReader.length;j++){rd[ts.p.colModel[j+gi+si+ni].name]=$.jgrid.getAccessor(cur,rowReader[j]);}
rd[locid]=$.jgrid.stripPref(ts.p.idPrefix,idr);ts.p.data.push(rd);ts.p._index[rd[locid]]=ts.p.data.length-1;rd={};}
ir++;}}},addLocalData=function(){var st=ts.p.multiSort?[]:"",sto=[],fndsort=false,cmtypes={},grtypes=[],grindexes=[],srcformat,sorttype,newformat;if(!$.isArray(ts.p.data)){return;}
var grpview=ts.p.grouping?ts.p.groupingView:false,lengrp,gin;$.each(ts.p.colModel,function(){sorttype=this.sorttype||"text";if(sorttype==="date"||sorttype==="datetime"){if(this.formatter&&typeof this.formatter==='string'&&this.formatter==='date'){if(this.formatoptions&&this.formatoptions.srcformat){srcformat=this.formatoptions.srcformat;}else{srcformat=$.jgrid.formatter.date.srcformat;}
if(this.formatoptions&&this.formatoptions.newformat){newformat=this.formatoptions.newformat;}else{newformat=$.jgrid.formatter.date.newformat;}}else{srcformat=newformat=this.datefmt||"Y-m-d";}
cmtypes[this.name]={"stype":sorttype,"srcfmt":srcformat,"newfmt":newformat};}else{cmtypes[this.name]={"stype":sorttype,"srcfmt":'',"newfmt":''};}
if(ts.p.grouping){for(gin=0,lengrp=grpview.groupField.length;gin<lengrp;gin++){if(this.name===grpview.groupField[gin]){var grindex=this.name;if(this.index){grindex=this.index;}
grtypes[gin]=cmtypes[grindex];grindexes[gin]=grindex;}}}
if(ts.p.multiSort){if(this.lso){st.push(this.name);var tmplso=this.lso.split("-");sto.push(tmplso[tmplso.length-1]);}}else{if(!fndsort&&(this.index===ts.p.sortname||this.name===ts.p.sortname)){st=this.name;fndsort=true;}}});if(ts.p.treeGrid){$(ts).jqGrid("SortTree",st,ts.p.sortorder,cmtypes[st].stype||'text',cmtypes[st].srcfmt||'');return;}
var compareFnMap={'eq':function(queryObj){return queryObj.equals;},'ne':function(queryObj){return queryObj.notEquals;},'lt':function(queryObj){return queryObj.less;},'le':function(queryObj){return queryObj.lessOrEquals;},'gt':function(queryObj){return queryObj.greater;},'ge':function(queryObj){return queryObj.greaterOrEquals;},'cn':function(queryObj){return queryObj.contains;},'nc':function(queryObj,op){return op==="OR"?queryObj.orNot().contains:queryObj.andNot().contains;},'bw':function(queryObj){return queryObj.startsWith;},'bn':function(queryObj,op){return op==="OR"?queryObj.orNot().startsWith:queryObj.andNot().startsWith;},'en':function(queryObj,op){return op==="OR"?queryObj.orNot().endsWith:queryObj.andNot().endsWith;},'ew':function(queryObj){return queryObj.endsWith;},'ni':function(queryObj,op){return op==="OR"?queryObj.orNot().equals:queryObj.andNot().equals;},'in':function(queryObj){return queryObj.equals;},'nu':function(queryObj){return queryObj.isNull;},'nn':function(queryObj,op){return op==="OR"?queryObj.orNot().isNull:queryObj.andNot().isNull;}},query=$.jgrid.from(ts.p.data);if(ts.p.ignoreCase){query=query.ignoreCase();}
function tojLinq(group){var s=0,index,gor,ror,opr,rule;if(group.groups!=null){gor=group.groups.length&&group.groupOp.toString().toUpperCase()==="OR";if(gor){query.orBegin();}
for(index=0;index<group.groups.length;index++){if(s>0&&gor){query.or();}
try{tojLinq(group.groups[index]);}catch(e){alert(e);}
s++;}
if(gor){query.orEnd();}}
if(group.rules!=null){try{ror=group.rules.length&&group.groupOp.toString().toUpperCase()==="OR";if(ror){query.orBegin();}
for(index=0;index<group.rules.length;index++){rule=group.rules[index];opr=group.groupOp.toString().toUpperCase();if(compareFnMap[rule.op]&&rule.field){if(s>0&&opr&&opr==="OR"){query=query.or();}
query=compareFnMap[rule.op](query,opr)(rule.field,rule.data,cmtypes[rule.field]);}
s++;}
if(ror){query.orEnd();}}catch(g){alert(g);}}}
if(ts.p.search===true){var srules=ts.p.postData.filters;if(srules){if(typeof srules==="string"){srules=$.jgrid.parse(srules);}
tojLinq(srules);}else{try{query=compareFnMap[ts.p.postData.searchOper](query)(ts.p.postData.searchField,ts.p.postData.searchString,cmtypes[ts.p.postData.searchField]);}catch(se){}}}
if(ts.p.grouping){for(gin=0;gin<lengrp;gin++){query.orderBy(grindexes[gin],grpview.groupOrder[gin],grtypes[gin].stype,grtypes[gin].srcfmt);}}
if(ts.p.multiSort){$.each(st,function(i){query.orderBy(this,sto[i],cmtypes[this].stype,cmtypes[this].srcfmt);});}else{if(st&&ts.p.sortorder&&fndsort){if(ts.p.sortorder.toUpperCase()==="DESC"){query.orderBy(ts.p.sortname,"d",cmtypes[st].stype,cmtypes[st].srcfmt);}else{query.orderBy(ts.p.sortname,"a",cmtypes[st].stype,cmtypes[st].srcfmt);}}}
var queryResults=query.select(),recordsperpage=parseInt(ts.p.rowNum,10),total=queryResults.length,page=parseInt(ts.p.page,10),totalpages=Math.ceil(total/recordsperpage),retresult={};queryResults=queryResults.slice((page-1)*recordsperpage,page*recordsperpage);query=null;cmtypes=null;retresult[ts.p.localReader.total]=totalpages;retresult[ts.p.localReader.page]=page;retresult[ts.p.localReader.records]=total;retresult[ts.p.localReader.root]=queryResults;retresult[ts.p.localReader.userdata]=ts.p.userData;queryResults=null;return retresult;},updatepager=function(rn,dnd){var cp,last,base,from,to,tot,fmt,pgboxes="",sppg,tspg=ts.p.pager?"_"+$.jgrid.jqID(ts.p.pager.substr(1)):"",tspg_t=ts.p.toppager?"_"+ts.p.toppager.substr(1):"";base=parseInt(ts.p.page,10)-1;if(base<0){base=0;}
base=base*parseInt(ts.p.rowNum,10);to=base+ts.p.reccount;if(ts.p.scroll){var rows=$("tbody:first > tr:gt(0)",ts.grid.bDiv);base=to-rows.length;ts.p.reccount=rows.length;var rh=rows.outerHeight()||ts.grid.prevRowHeight;if(rh){var top=base*rh;var height=parseInt(ts.p.records,10)*rh;$(">div:first",ts.grid.bDiv).css({height:height}).children("div:first").css({height:top,display:top?"":"none"});if(ts.grid.bDiv.scrollTop==0&&ts.p.page>1){ts.grid.bDiv.scrollTop=ts.p.rowNum*(ts.p.page-1)*rh;}}
ts.grid.bDiv.scrollLeft=ts.grid.hDiv.scrollLeft;}
pgboxes=ts.p.pager||"";pgboxes+=ts.p.toppager?(pgboxes?","+ts.p.toppager:ts.p.toppager):"";if(pgboxes){fmt=$.jgrid.formatter.integer||{};cp=intNum(ts.p.page);last=intNum(ts.p.lastpage);$(".selbox",pgboxes)[this.p.useProp?'prop':'attr']("disabled",false);if(ts.p.pginput===true){$('.ui-pg-input',pgboxes).val(ts.p.page);sppg=ts.p.toppager?'#sp_1'+tspg+",#sp_1"+tspg_t:'#sp_1'+tspg;$(sppg).html($.fmatter?$.fmatter.util.NumberFormat(ts.p.lastpage,fmt):ts.p.lastpage);}
if(ts.p.viewrecords){if(ts.p.reccount===0){$(".ui-paging-info",pgboxes).html(ts.p.emptyrecords);}else{from=base+1;tot=ts.p.records;if($.fmatter){from=$.fmatter.util.NumberFormat(from,fmt);to=$.fmatter.util.NumberFormat(to,fmt);tot=$.fmatter.util.NumberFormat(tot,fmt);}
$(".ui-paging-info",pgboxes).html($.jgrid.format(ts.p.recordtext,from,to,tot));}}
if(ts.p.pgbuttons===true){if(cp<=0){cp=last=0;}
if(cp===1||cp===0){$("#first"+tspg+", #prev"+tspg).addClass('ui-state-disabled').removeClass('ui-state-hover');if(ts.p.toppager){$("#first_t"+tspg_t+", #prev_t"+tspg_t).addClass('ui-state-disabled').removeClass('ui-state-hover');}}else{$("#first"+tspg+", #prev"+tspg).removeClass('ui-state-disabled');if(ts.p.toppager){$("#first_t"+tspg_t+", #prev_t"+tspg_t).removeClass('ui-state-disabled');}}
if(cp===last||cp===0){$("#next"+tspg+", #last"+tspg).addClass('ui-state-disabled').removeClass('ui-state-hover');if(ts.p.toppager){$("#next_t"+tspg_t+", #last_t"+tspg_t).addClass('ui-state-disabled').removeClass('ui-state-hover');}}else{$("#next"+tspg+", #last"+tspg).removeClass('ui-state-disabled');if(ts.p.toppager){$("#next_t"+tspg_t+", #last_t"+tspg_t).removeClass('ui-state-disabled');}}}}
if(rn===true&&ts.p.rownumbers===true){$(">td.jqgrid-rownum",ts.rows).each(function(i){$(this).html(base+1+i);});}
if(dnd&&ts.p.jqgdnd){$(ts).jqGrid('gridDnD','updateDnD');}
$(ts).triggerHandler("jqGridGridComplete");if($.isFunction(ts.p.gridComplete)){ts.p.gridComplete.call(ts);}
$(ts).triggerHandler("jqGridAfterGridComplete");},beginReq=function(){ts.grid.hDiv.loading=true;if(ts.p.hiddengrid){return;}
switch(ts.p.loadui){case"disable":break;case"enable":$("#load_"+$.jgrid.jqID(ts.p.id)).show();break;case"block":$("#lui_"+$.jgrid.jqID(ts.p.id)).show();$("#load_"+$.jgrid.jqID(ts.p.id)).show();break;}},endReq=function(){ts.grid.hDiv.loading=false;switch(ts.p.loadui){case"disable":break;case"enable":$("#load_"+$.jgrid.jqID(ts.p.id)).hide();break;case"block":$("#lui_"+$.jgrid.jqID(ts.p.id)).hide();$("#load_"+$.jgrid.jqID(ts.p.id)).hide();break;}},populate=function(npage){if(!ts.grid.hDiv.loading){var pvis=ts.p.scroll&&npage===false,prm={},dt,dstr,pN=ts.p.prmNames;if(ts.p.page<=0){ts.p.page=Math.min(1,ts.p.lastpage);}
if(pN.search!==null){prm[pN.search]=ts.p.search;}
if(pN.nd!==null){prm[pN.nd]=new Date().getTime();}
if(pN.rows!==null){prm[pN.rows]=ts.p.rowNum;}
if(pN.page!==null){prm[pN.page]=ts.p.page;}
if(pN.sort!==null){prm[pN.sort]=ts.p.sortname;}
if(pN.order!==null){prm[pN.order]=ts.p.sortorder;}
if(ts.p.rowTotal!==null&&pN.totalrows!==null){prm[pN.totalrows]=ts.p.rowTotal;}
var lcf=$.isFunction(ts.p.loadComplete),lc=lcf?ts.p.loadComplete:null;var adjust=0;npage=npage||1;if(npage>1){if(pN.npage!==null){prm[pN.npage]=npage;adjust=npage-1;npage=1;}else{lc=function(req){ts.p.page++;ts.grid.hDiv.loading=false;if(lcf){ts.p.loadComplete.call(ts,req);}
populate(npage-1);};}}else if(pN.npage!==null){delete ts.p.postData[pN.npage];}
if(ts.p.grouping){$(ts).jqGrid('groupingSetup');var grp=ts.p.groupingView,gi,gs="";for(gi=0;gi<grp.groupField.length;gi++){var index=grp.groupField[gi];$.each(ts.p.colModel,function(cmIndex,cmValue){if(cmValue.name===index&&cmValue.index){index=cmValue.index;}});gs+=index+" "+grp.groupOrder[gi]+", ";}
prm[pN.sort]=gs+prm[pN.sort];}
$.extend(ts.p.postData,prm);var rcnt=!ts.p.scroll?1:ts.rows.length-1;var bfr=$(ts).triggerHandler("jqGridBeforeRequest");if(bfr===false||bfr==='stop'){return;}
if($.isFunction(ts.p.datatype)){ts.p.datatype.call(ts,ts.p.postData,"load_"+ts.p.id,rcnt,npage,adjust);return;}
if($.isFunction(ts.p.beforeRequest)){bfr=ts.p.beforeRequest.call(ts);if(bfr===undefined){bfr=true;}
if(bfr===false){return;}}
dt=ts.p.datatype.toLowerCase();switch(dt){case"json":case"jsonp":case"xml":case"script":$.ajax($.extend({url:ts.p.url,type:ts.p.mtype,dataType:dt,data:$.isFunction(ts.p.serializeGridData)?ts.p.serializeGridData.call(ts,ts.p.postData):ts.p.postData,success:function(data,st,xhr){if($.isFunction(ts.p.beforeProcessing)){if(ts.p.beforeProcessing.call(ts,data,st,xhr)===false){endReq();return;}}
if(dt==="xml"){addXmlData(data,ts.grid.bDiv,rcnt,npage>1,adjust);}else{addJSONData(data,ts.grid.bDiv,rcnt,npage>1,adjust);}
$(ts).triggerHandler("jqGridLoadComplete",[data]);if(lc){lc.call(ts,data);}
$(ts).triggerHandler("jqGridAfterLoadComplete",[data]);if(pvis){ts.grid.populateVisible();}
if(ts.p.loadonce||ts.p.treeGrid){ts.p.datatype="local";}
data=null;if(npage===1){endReq();}},error:function(xhr,st,err){if($.isFunction(ts.p.loadError)){ts.p.loadError.call(ts,xhr,st,err);}
if(npage===1){endReq();}
xhr=null;},beforeSend:function(xhr,settings){var gotoreq=true;if($.isFunction(ts.p.loadBeforeSend)){gotoreq=ts.p.loadBeforeSend.call(ts,xhr,settings);}
if(gotoreq===undefined){gotoreq=true;}
if(gotoreq===false){return false;}
beginReq();}},$.jgrid.ajaxOptions,ts.p.ajaxGridOptions));break;case"xmlstring":beginReq();dstr=typeof ts.p.datastr!=='string'?ts.p.datastr:$.parseXML(ts.p.datastr);addXmlData(dstr,ts.grid.bDiv);$(ts).triggerHandler("jqGridLoadComplete",[dstr]);if(lcf){ts.p.loadComplete.call(ts,dstr);}
$(ts).triggerHandler("jqGridAfterLoadComplete",[dstr]);ts.p.datatype="local";ts.p.datastr=null;endReq();break;case"jsonstring":beginReq();if(typeof ts.p.datastr==='string'){dstr=$.jgrid.parse(ts.p.datastr);}else{dstr=ts.p.datastr;}
addJSONData(dstr,ts.grid.bDiv);$(ts).triggerHandler("jqGridLoadComplete",[dstr]);if(lcf){ts.p.loadComplete.call(ts,dstr);}
$(ts).triggerHandler("jqGridAfterLoadComplete",[dstr]);ts.p.datatype="local";ts.p.datastr=null;endReq();break;case"local":case"clientside":beginReq();ts.p.datatype="local";var req=addLocalData();addJSONData(req,ts.grid.bDiv,rcnt,npage>1,adjust);$(ts).triggerHandler("jqGridLoadComplete",[req]);if(lc){lc.call(ts,req);}
$(ts).triggerHandler("jqGridAfterLoadComplete",[req]);if(pvis){ts.grid.populateVisible();}
endReq();break;}}},setHeadCheckBox=function(checked){$('#cb_'+$.jgrid.jqID(ts.p.id),ts.grid.hDiv)[ts.p.useProp?'prop':'attr']("checked",checked);var fid=ts.p.frozenColumns?ts.p.id+"_frozen":"";if(fid){$('#cb_'+$.jgrid.jqID(ts.p.id),ts.grid.fhDiv)[ts.p.useProp?'prop':'attr']("checked",checked);}},setPager=function(pgid,tp){var sep="<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>",pginp="",pgl="<table cellspacing='0' cellpadding='0' border='0' style='table-layout:auto;' class='ui-pg-table'><tbody><tr>",str="",pgcnt,lft,cent,rgt,twd,tdw,i,clearVals=function(onpaging){var ret;if($.isFunction(ts.p.onPaging)){ret=ts.p.onPaging.call(ts,onpaging);}
if(ret==='stop'){return false;}
ts.p.selrow=null;if(ts.p.multiselect){ts.p.selarrrow=[];setHeadCheckBox(false);}
ts.p.savedRow=[];return true;};pgid=pgid.substr(1);tp+="_"+pgid;pgcnt="pg_"+pgid;lft=pgid+"_left";cent=pgid+"_center";rgt=pgid+"_right";$("#"+$.jgrid.jqID(pgid)).append("<div id='"+pgcnt+"' class='ui-pager-control' role='group'><table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table' style='width:100%;table-layout:fixed;height:100%;' role='row'><tbody><tr><td id='"+lft+"' align='left'></td><td id='"+cent+"' align='center' style='white-space:pre;'></td><td id='"+rgt+"' align='right'></td></tr></tbody></table></div>").attr("dir","ltr");if(ts.p.rowList.length>0){str="<td dir='"+dir+"'>";str+="<select class='ui-pg-selbox' role='listbox'>";for(i=0;i<ts.p.rowList.length;i++){str+="<option role=\"option\" value=\""+ts.p.rowList[i]+"\""+((ts.p.rowNum===ts.p.rowList[i])?" selected=\"selected\"":"")+">"+ts.p.rowList[i]+"</option>";}
str+="</select></td>";}
if(dir==="rtl"){pgl+=str;}
if(ts.p.pginput===true){pginp="<td dir='"+dir+"'>"+$.jgrid.format(ts.p.pgtext||"","<input class='ui-pg-input' type='text' size='2' maxlength='7' value='0' role='textbox'/>","<span id='sp_1_"+$.jgrid.jqID(pgid)+"'></span>")+"</td>";}
if(ts.p.pgbuttons===true){var po=["first"+tp,"prev"+tp,"next"+tp,"last"+tp];if(dir==="rtl"){po.reverse();}
pgl+="<td id='"+po[0]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-first'></span></td>";pgl+="<td id='"+po[1]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-prev'></span></td>";pgl+=pginp!==""?sep+pginp+sep:"";pgl+="<td id='"+po[2]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-next'></span></td>";pgl+="<td id='"+po[3]+"' class='ui-pg-button ui-corner-all'><span class='ui-icon ui-icon-seek-end'></span></td>";}else if(pginp!==""){pgl+=pginp;}
if(dir==="ltr"){pgl+=str;}
pgl+="</tr></tbody></table>";if(ts.p.viewrecords===true){$("td#"+pgid+"_"+ts.p.recordpos,"#"+pgcnt).append("<div dir='"+dir+"' style='text-align:"+ts.p.recordpos+"' class='ui-paging-info'></div>");}
$("td#"+pgid+"_"+ts.p.pagerpos,"#"+pgcnt).append(pgl);tdw=$(".ui-jqgrid").css("font-size")||"11px";$(document.body).append("<div id='testpg' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+tdw+";visibility:hidden;' ></div>");twd=$(pgl).clone().appendTo("#testpg").width();$("#testpg").remove();if(twd>0){if(pginp!==""){twd+=50;}
$("td#"+pgid+"_"+ts.p.pagerpos,"#"+pgcnt).width(twd);}
ts.p._nvtd=[];ts.p._nvtd[0]=twd?Math.floor((ts.p.width-twd)/2):Math.floor(ts.p.width/3);ts.p._nvtd[1]=0;pgl=null;$('.ui-pg-selbox',"#"+pgcnt).bind('change',function(){if(!clearVals('records')){return false;}
ts.p.page=Math.round(ts.p.rowNum*(ts.p.page-1)/this.value-0.5)+1;ts.p.rowNum=this.value;if(ts.p.pager){$('.ui-pg-selbox',ts.p.pager).val(this.value);}
if(ts.p.toppager){$('.ui-pg-selbox',ts.p.toppager).val(this.value);}
populate();return false;});if(ts.p.pgbuttons===true){$(".ui-pg-button","#"+pgcnt).hover(function(){if($(this).hasClass('ui-state-disabled')){this.style.cursor='default';}else{$(this).addClass('ui-state-hover');this.style.cursor='pointer';}},function(){if(!$(this).hasClass('ui-state-disabled')){$(this).removeClass('ui-state-hover');this.style.cursor="default";}});$("#first"+$.jgrid.jqID(tp)+", #prev"+$.jgrid.jqID(tp)+", #next"+$.jgrid.jqID(tp)+", #last"+$.jgrid.jqID(tp)).click(function(){var cp=intNum(ts.p.page,1),last=intNum(ts.p.lastpage,1),selclick=false,fp=true,pp=true,np=true,lp=true;if(last===0||last===1){fp=false;pp=false;np=false;lp=false;}else if(last>1&&cp>=1){if(cp===1){fp=false;pp=false;}
else if(cp===last){np=false;lp=false;}}else if(last>1&&cp===0){np=false;lp=false;cp=last-1;}
if(!clearVals(this.id)){return false;}
if(this.id==='first'+tp&&fp){ts.p.page=1;selclick=true;}
if(this.id==='prev'+tp&&pp){ts.p.page=(cp-1);selclick=true;}
if(this.id==='next'+tp&&np){ts.p.page=(cp+1);selclick=true;}
if(this.id==='last'+tp&&lp){ts.p.page=last;selclick=true;}
if(selclick){populate();}
return false;});}
if(ts.p.pginput===true){$('input.ui-pg-input',"#"+pgcnt).keypress(function(e){var key=e.charCode||e.keyCode||0;if(key===13){if(!clearVals('user')){return false;}
$(this).val(intNum($(this).val(),1));ts.p.page=($(this).val()>0)?$(this).val():ts.p.page;populate();return false;}
return this;});}},multiSort=function(iCol,obj){var splas,sort="",cm=ts.p.colModel,fs=false,ls,selTh=ts.p.frozenColumns?obj:ts.grid.headers[iCol].el,so="";$("span.ui-grid-ico-sort",selTh).addClass('ui-state-disabled');$(selTh).attr("aria-selected","false");if(cm[iCol].lso){if(cm[iCol].lso==="asc"){cm[iCol].lso+="-desc";so="desc";}else if(cm[iCol].lso==="desc"){cm[iCol].lso+="-asc";so="asc";}else if(cm[iCol].lso==="asc-desc"||cm[iCol].lso==="desc-asc"){cm[iCol].lso="";}}else{cm[iCol].lso=so=cm[iCol].firstsortorder||'asc';}
if(so){$("span.s-ico",selTh).show();$("span.ui-icon-"+so,selTh).removeClass('ui-state-disabled');$(selTh).attr("aria-selected","true");}else{if(!ts.p.viewsortcols[0]){$("span.s-ico",selTh).hide();}}
ts.p.sortorder="";$.each(cm,function(i){if(this.lso){if(i>0&&fs){sort+=", ";}
splas=this.lso.split("-");sort+=cm[i].index||cm[i].name;sort+=" "+splas[splas.length-1];fs=true;ts.p.sortorder=splas[splas.length-1];}});ls=sort.lastIndexOf(ts.p.sortorder);sort=sort.substring(0,ls);ts.p.sortname=sort;},sortData=function(index,idxcol,reload,sor,obj){if(!ts.p.colModel[idxcol].sortable){return;}
if(ts.p.savedRow.length>0){return;}
if(!reload){if(ts.p.lastsort===idxcol){if(ts.p.sortorder==='asc'){ts.p.sortorder='desc';}else if(ts.p.sortorder==='desc'){ts.p.sortorder='asc';}}else{ts.p.sortorder=ts.p.colModel[idxcol].firstsortorder||'asc';}
ts.p.page=1;}
if(ts.p.multiSort){multiSort(idxcol,obj);}else{if(sor){if(ts.p.lastsort===idxcol&&ts.p.sortorder===sor&&!reload){return;}
ts.p.sortorder=sor;}
var previousSelectedTh=ts.grid.headers[ts.p.lastsort].el,newSelectedTh=ts.p.frozenColumns?obj:ts.grid.headers[idxcol].el;$("span.ui-grid-ico-sort",previousSelectedTh).addClass('ui-state-disabled');$(previousSelectedTh).attr("aria-selected","false");if(ts.p.frozenColumns){ts.grid.fhDiv.find("span.ui-grid-ico-sort").addClass('ui-state-disabled');ts.grid.fhDiv.find("th").attr("aria-selected","false");}
$("span.ui-icon-"+ts.p.sortorder,newSelectedTh).removeClass('ui-state-disabled');$(newSelectedTh).attr("aria-selected","true");if(!ts.p.viewsortcols[0]){if(ts.p.lastsort!==idxcol){if(ts.p.frozenColumns){ts.grid.fhDiv.find("span.s-ico").hide();}
$("span.s-ico",previousSelectedTh).hide();$("span.s-ico",newSelectedTh).show();}}
index=index.substring(5+ts.p.id.length+1);ts.p.sortname=ts.p.colModel[idxcol].index||index;}
if($(ts).triggerHandler("jqGridSortCol",[ts.p.sortname,idxcol,ts.p.sortorder])==='stop'){ts.p.lastsort=idxcol;return;}
if($.isFunction(ts.p.onSortCol)){if(ts.p.onSortCol.call(ts,ts.p.sortname,idxcol,ts.p.sortorder)==='stop'){ts.p.lastsort=idxcol;return;}}
if(ts.p.datatype==="local"){if(ts.p.deselectAfterSort){$(ts).jqGrid("resetSelection");}}else{ts.p.selrow=null;if(ts.p.multiselect){setHeadCheckBox(false);}
ts.p.selarrrow=[];ts.p.savedRow=[];}
if(ts.p.scroll){var sscroll=ts.grid.bDiv.scrollLeft;emptyRows.call(ts,true,false);ts.grid.hDiv.scrollLeft=sscroll;}
if(ts.p.subGrid&&ts.p.datatype==='local'){$("td.sgexpanded","#"+$.jgrid.jqID(ts.p.id)).each(function(){$(this).trigger("click");});}
populate();ts.p.lastsort=idxcol;if(ts.p.sortname!==index&&idxcol){ts.p.lastsort=idxcol;}},setColWidth=function(){var initwidth=0,brd=$.jgrid.cell_width?0:intNum(ts.p.cellLayout,0),vc=0,lvc,scw=intNum(ts.p.scrollOffset,0),cw,hs=false,aw,gw=0,cr;$.each(ts.p.colModel,function(){if(this.hidden===undefined){this.hidden=false;}
if(ts.p.grouping&&ts.p.autowidth){var ind=$.inArray(this.name,ts.p.groupingView.groupField);if(ind>=0&&ts.p.groupingView.groupColumnShow.length>ind){this.hidden=!ts.p.groupingView.groupColumnShow[ind];}}
this.widthOrg=cw=intNum(this.width,0);if(this.hidden===false){initwidth+=cw+brd;if(this.fixed){gw+=cw+brd;}else{vc++;}}});if(isNaN(ts.p.width)){ts.p.width=initwidth+((ts.p.shrinkToFit===false&&!isNaN(ts.p.height))?scw:0);}
grid.width=ts.p.width;ts.p.tblwidth=initwidth;if(ts.p.shrinkToFit===false&&ts.p.forceFit===true){ts.p.forceFit=false;}
if(ts.p.shrinkToFit===true&&vc>0){aw=grid.width-brd*vc-gw;if(!isNaN(ts.p.height)){aw-=scw;hs=true;}
initwidth=0;$.each(ts.p.colModel,function(i){if(this.hidden===false&&!this.fixed){cw=Math.round(aw*this.width/(ts.p.tblwidth-brd*vc-gw));this.width=cw;initwidth+=cw;lvc=i;}});cr=0;if(hs){if(grid.width-gw-(initwidth+brd*vc)!==scw){cr=grid.width-gw-(initwidth+brd*vc)-scw;}}else if(!hs&&Math.abs(grid.width-gw-(initwidth+brd*vc))!==1){cr=grid.width-gw-(initwidth+brd*vc);}
ts.p.colModel[lvc].width+=cr;ts.p.tblwidth=initwidth+cr+brd*vc+gw;if(ts.p.tblwidth>ts.p.width){ts.p.colModel[lvc].width-=(ts.p.tblwidth-parseInt(ts.p.width,10));ts.p.tblwidth=ts.p.width;}}},nextVisible=function(iCol){var ret=iCol,j=iCol,i;for(i=iCol+1;i<ts.p.colModel.length;i++){if(ts.p.colModel[i].hidden!==true){j=i;break;}}
return j-ret;},getOffset=function(iCol){var $th=$(ts.grid.headers[iCol].el),ret=[$th.position().left+$th.outerWidth()];if(ts.p.direction==="rtl"){ret[0]=ts.p.width-ret[0];}
ret[0]-=ts.grid.bDiv.scrollLeft;ret.push($(ts.grid.hDiv).position().top);ret.push($(ts.grid.bDiv).offset().top-$(ts.grid.hDiv).offset().top+$(ts.grid.bDiv).height());return ret;},getColumnHeaderIndex=function(th){var i,headers=ts.grid.headers,ci=$.jgrid.getCellIndex(th);for(i=0;i<headers.length;i++){if(th===headers[i].el){ci=i;break;}}
return ci;};this.p.id=this.id;if($.inArray(ts.p.multikey,sortkeys)===-1){ts.p.multikey=false;}
ts.p.keyIndex=false;ts.p.keyName=false;for(i=0;i<ts.p.colModel.length;i++){ts.p.colModel[i]=$.extend(true,{},ts.p.cmTemplate,ts.p.colModel[i].template||{},ts.p.colModel[i]);if(ts.p.keyIndex===false&&ts.p.colModel[i].key===true){ts.p.keyIndex=i;}}
ts.p.sortorder=ts.p.sortorder.toLowerCase();$.jgrid.cell_width=$.jgrid.cellWidth();if(ts.p.grouping===true){ts.p.scroll=false;ts.p.rownumbers=false;ts.p.treeGrid=false;ts.p.gridview=true;}
if(this.p.treeGrid===true){try{$(this).jqGrid("setTreeGrid");}catch(_){}
if(ts.p.datatype!=="local"){ts.p.localReader={id:"_id_"};}}
if(this.p.subGrid){try{$(ts).jqGrid("setSubGrid");}catch(s){}}
if(this.p.multiselect){this.p.colNames.unshift("<input role='checkbox' id='cb_"+this.p.id+"' class='cbox' type='checkbox'/>");this.p.colModel.unshift({name:'cb',width:$.jgrid.cell_width?ts.p.multiselectWidth+ts.p.cellLayout:ts.p.multiselectWidth,sortable:false,resizable:false,hidedlg:true,search:false,align:'center',fixed:true});}
if(this.p.rownumbers){this.p.colNames.unshift("");this.p.colModel.unshift({name:'rn',width:ts.p.rownumWidth,sortable:false,resizable:false,hidedlg:true,search:false,align:'center',fixed:true});}
ts.p.xmlReader=$.extend(true,{root:"rows",row:"row",page:"rows>page",total:"rows>total",records:"rows>records",repeatitems:true,cell:"cell",id:"[id]",userdata:"userdata",subgrid:{root:"rows",row:"row",repeatitems:true,cell:"cell"}},ts.p.xmlReader);ts.p.jsonReader=$.extend(true,{root:"rows",page:"page",total:"total",records:"records",repeatitems:true,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:true,cell:"cell"}},ts.p.jsonReader);ts.p.localReader=$.extend(true,{root:"rows",page:"page",total:"total",records:"records",repeatitems:false,cell:"cell",id:"id",userdata:"userdata",subgrid:{root:"rows",repeatitems:true,cell:"cell"}},ts.p.localReader);if(ts.p.scroll){ts.p.pgbuttons=false;ts.p.pginput=false;ts.p.rowList=[];}
if(ts.p.data.length){refreshIndex();}
var thead="<thead><tr class='ui-jqgrid-labels' role='rowheader'>",tdc,idn,w,res,sort,td,ptr,tbody,imgs,iac="",idc="",sortarr=[],sortord=[],sotmp=[];if(ts.p.shrinkToFit===true&&ts.p.forceFit===true){for(i=ts.p.colModel.length-1;i>=0;i--){if(!ts.p.colModel[i].hidden){ts.p.colModel[i].resizable=false;break;}}}
if(ts.p.viewsortcols[1]==='horizontal'){iac=" ui-i-asc";idc=" ui-i-desc";}
tdc=isMSIE?"class='ui-th-div-ie'":"";imgs="<span class='s-ico' style='display:none'><span sort='asc' class='ui-grid-ico-sort ui-icon-asc"+iac+" ui-state-disabled ui-icon ui-icon-triangle-1-n ui-sort-"+dir+"'></span>";imgs+="<span sort='desc' class='ui-grid-ico-sort ui-icon-desc"+idc+" ui-state-disabled ui-icon ui-icon-triangle-1-s ui-sort-"+dir+"'></span></span>";if(ts.p.multiSort){sortarr=ts.p.sortname.split(",");for(i=0;i<sortarr.length;i++){sotmp=$.trim(sortarr[i]).split(" ");sortarr[i]=$.trim(sotmp[0]);sortord[i]=sotmp[1]?$.trim(sotmp[1]):ts.p.sortorder||"asc";}}
for(i=0;i<this.p.colNames.length;i++){var tooltip=ts.p.headertitles?(" title=\""+$.jgrid.stripHtml(ts.p.colNames[i])+"\""):"";thead+="<th id='"+ts.p.id+"_"+ts.p.colModel[i].name+"' role='columnheader' class='ui-state-default ui-th-column ui-th-"+dir+"'"+tooltip+">";idn=ts.p.colModel[i].index||ts.p.colModel[i].name;thead+="<div id='jqgh_"+ts.p.id+"_"+ts.p.colModel[i].name+"' "+tdc+">"+ts.p.colNames[i];if(!ts.p.colModel[i].width){ts.p.colModel[i].width=150;}else{ts.p.colModel[i].width=parseInt(ts.p.colModel[i].width,10);}
if(typeof ts.p.colModel[i].title!=="boolean"){ts.p.colModel[i].title=true;}
ts.p.colModel[i].lso="";if(idn===ts.p.sortname){ts.p.lastsort=i;}
if(ts.p.multiSort){sotmp=$.inArray(idn,sortarr);if(sotmp!==-1){ts.p.colModel[i].lso=sortord[sotmp];}}
thead+=imgs+"</div></th>";}
thead+="</tr></thead>";imgs=null;$(this).append(thead);$("thead tr:first th",this).hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});if(this.p.multiselect){var emp=[],chk;$('#cb_'+$.jgrid.jqID(ts.p.id),this).bind('click',function(){ts.p.selarrrow=[];var froz=ts.p.frozenColumns===true?ts.p.id+"_frozen":"";if(this.checked){$(ts.rows).each(function(i){if(i>0){if(!$(this).hasClass("ui-subgrid")&&!$(this).hasClass("jqgroup")&&!$(this).hasClass('ui-state-disabled')){$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(this.id))[ts.p.useProp?'prop':'attr']("checked",true);$(this).addClass("ui-state-highlight").attr("aria-selected","true");ts.p.selarrrow.push(this.id);ts.p.selrow=this.id;if(froz){$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(this.id),ts.grid.fbDiv)[ts.p.useProp?'prop':'attr']("checked",true);$("#"+$.jgrid.jqID(this.id),ts.grid.fbDiv).addClass("ui-state-highlight");}}}});chk=true;emp=[];}else{$(ts.rows).each(function(i){if(i>0){if(!$(this).hasClass("ui-subgrid")&&!$(this).hasClass('ui-state-disabled')){$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(this.id))[ts.p.useProp?'prop':'attr']("checked",false);$(this).removeClass("ui-state-highlight").attr("aria-selected","false");emp.push(this.id);if(froz){$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(this.id),ts.grid.fbDiv)[ts.p.useProp?'prop':'attr']("checked",false);$("#"+$.jgrid.jqID(this.id),ts.grid.fbDiv).removeClass("ui-state-highlight");}}}});ts.p.selrow=null;chk=false;}
$(ts).triggerHandler("jqGridSelectAll",[chk?ts.p.selarrrow:emp,chk]);if($.isFunction(ts.p.onSelectAll)){ts.p.onSelectAll.call(ts,chk?ts.p.selarrrow:emp,chk);}});}
if(ts.p.autowidth===true){var pw=$(eg).innerWidth();ts.p.width=pw>0?pw:'nw';}
setColWidth();$(eg).css("width",grid.width+"px").append("<div class='ui-jqgrid-resize-mark' id='rs_m"+ts.p.id+"'>&#160;</div>");$(gv).css("width",grid.width+"px");thead=$("thead:first",ts).get(0);var tfoot="";if(ts.p.footerrow){tfoot+="<table role='grid' style='width:"+ts.p.tblwidth+"px' class='ui-jqgrid-ftable' cellspacing='0' cellpadding='0' border='0'><tbody><tr role='row' class='ui-widget-content footrow footrow-"+dir+" ui-state-default'>";}
var thr=$("tr:first",thead),firstr="<tr class='jqgfirstrow' role='row' style='height:auto'>";ts.p.disableClick=false;$("th",thr).each(function(j){w=ts.p.colModel[j].width;if(ts.p.colModel[j].resizable===undefined){ts.p.colModel[j].resizable=true;}
if(ts.p.colModel[j].resizable){res=document.createElement("span");$(res).html("&#160;").addClass('ui-jqgrid-resize ui-jqgrid-resize-'+dir).css("cursor","col-resize");$(this).addClass(ts.p.resizeclass);}else{res="";}
$(this).css("width",w+"px").prepend(res);res=null;var hdcol="";if(ts.p.colModel[j].hidden){$(this).css("display","none");hdcol="display:none;";}
firstr+="<td role='gridcell' style='height:0px;width:"+w+"px;"+hdcol+"'></td>";grid.headers[j]={width:w,el:this};sort=ts.p.colModel[j].sortable;if(typeof sort!=='boolean'){ts.p.colModel[j].sortable=true;sort=true;}
var nm=ts.p.colModel[j].name;if(!(nm==='cb'||nm==='subgrid'||nm==='rn')){if(ts.p.viewsortcols[2]){$(">div",this).addClass('ui-jqgrid-sortable');}}
if(sort){if(ts.p.multiSort){if(ts.p.viewsortcols[0]){$("div span.s-ico",this).show();if(ts.p.colModel[j].lso){$("div span.ui-icon-"+ts.p.colModel[j].lso,this).removeClass("ui-state-disabled");}}else if(ts.p.colModel[j].lso){$("div span.s-ico",this).show();$("div span.ui-icon-"+ts.p.colModel[j].lso,this).removeClass("ui-state-disabled");}}else{if(ts.p.viewsortcols[0]){$("div span.s-ico",this).show();if(j===ts.p.lastsort){$("div span.ui-icon-"+ts.p.sortorder,this).removeClass("ui-state-disabled");}}else if(j===ts.p.lastsort){$("div span.s-ico",this).show();$("div span.ui-icon-"+ts.p.sortorder,this).removeClass("ui-state-disabled");}}}
if(ts.p.footerrow){tfoot+="<td role='gridcell' "+formatCol(j,0,'',null,'',false)+">&#160;</td>";}}).mousedown(function(e){if($(e.target).closest("th>span.ui-jqgrid-resize").length!==1){return;}
var ci=getColumnHeaderIndex(this);if(ts.p.forceFit===true){ts.p.nv=nextVisible(ci);}
grid.dragStart(ci,e,getOffset(ci));return false;}).click(function(e){if(ts.p.disableClick){ts.p.disableClick=false;return false;}
var s="th>div.ui-jqgrid-sortable",r,d;if(!ts.p.viewsortcols[2]){s="th>div>span>span.ui-grid-ico-sort";}
var t=$(e.target).closest(s);if(t.length!==1){return;}
var ci;if(ts.p.frozenColumns){var tid=$(this)[0].id.substring(ts.p.id.length+1);$(ts.p.colModel).each(function(i){if(this.name===tid){ci=i;return false;}});}else{ci=getColumnHeaderIndex(this);}
if(!ts.p.viewsortcols[2]){r=true;d=t.attr("sort");}
if(ci!=null){sortData($('div',this)[0].id,ci,r,d,this);}
return false;}).bind("contextmenu",function(){$(ts).jqGrid('columnChooser',{done:function(){if($.isFunction(ts.p.onColumnChooserDone)){ts.p.onColumnChooserDone.call();}}});return false;});;if(ts.p.sortable&&$.fn.sortable){try{$(ts).jqGrid("sortableColumns",thr);}catch(e){}}
if(ts.p.footerrow){tfoot+="</tr></tbody></table>";}
firstr+="</tr>";tbody=document.createElement("tbody");this.appendChild(tbody);$(this).addClass('ui-jqgrid-btable').append(firstr);firstr=null;var hTable=$("<table class='ui-jqgrid-htable' style='width:"+ts.p.tblwidth+"px' role='grid' aria-labelledby='gbox_"+this.id+"' cellspacing='0' cellpadding='0' border='0'></table>").append(thead),hg=(ts.p.caption&&ts.p.hiddengrid===true)?true:false,hb=$("<div class='ui-jqgrid-hbox"+(dir==="rtl"?"-rtl":"")+"'></div>");thead=null;grid.hDiv=document.createElement("div");$(grid.hDiv).css({width:grid.width+"px"}).addClass("ui-state-default ui-jqgrid-hdiv").append(hb);$(hb).append(hTable);hTable=null;if(hg){$(grid.hDiv).hide();}
if(ts.p.pager){if(typeof ts.p.pager==="string"){if(ts.p.pager.substr(0,1)!=="#"){ts.p.pager="#"+ts.p.pager;}}else{ts.p.pager="#"+$(ts.p.pager).attr("id");}
$(ts.p.pager).css({width:grid.width+"px"}).addClass('ui-state-default ui-jqgrid-pager ui-corner-bottom').appendTo(eg);if(hg){$(ts.p.pager).hide();}
setPager(ts.p.pager,'');}
if(ts.p.cellEdit===false&&ts.p.hoverrows===true){$(ts).bind('mouseover',function(e){ptr=$(e.target).closest("tr.jqgrow");if($(ptr).attr("class")!=="ui-subgrid"){$(ptr).addClass("ui-state-hover");}}).bind('mouseout',function(e){ptr=$(e.target).closest("tr.jqgrow");$(ptr).removeClass("ui-state-hover");});}
var ri,ci,tdHtml;$(ts).before(grid.hDiv).click(function(e){td=e.target;ptr=$(td,ts.rows).closest("tr.jqgrow");if($(ptr).length===0||ptr[0].className.indexOf('ui-state-disabled')>-1||($(td,ts).closest("table.ui-jqgrid-btable").attr('id')||'').replace("_frozen","")!==ts.id){return this;}
var scb=$(td).hasClass("cbox"),cSel=$(ts).triggerHandler("jqGridBeforeSelectRow",[ptr[0].id,e]);cSel=(cSel===false||cSel==='stop')?false:true;if(cSel&&$.isFunction(ts.p.beforeSelectRow)){cSel=ts.p.beforeSelectRow.call(ts,ptr[0].id,e);}
if(td.tagName==='A'||((td.tagName==='INPUT'||td.tagName==='TEXTAREA'||td.tagName==='OPTION'||td.tagName==='SELECT')&&!scb)){return;}
if(cSel===true){ri=ptr[0].id;ci=$.jgrid.getCellIndex(td);tdHtml=$(td).closest("td,th").html();$(ts).triggerHandler("jqGridCellSelect",[ri,ci,tdHtml,e]);if($.isFunction(ts.p.onCellSelect)){ts.p.onCellSelect.call(ts,ri,ci,tdHtml,e);}
if(ts.p.cellEdit===true){if(ts.p.multiselect&&scb){$(ts).jqGrid("setSelection",ri,true,e);}else{ri=ptr[0].rowIndex;try{$(ts).jqGrid("editCell",ri,ci,true);}catch(_){}}}else if(!ts.p.multikey){if(ts.p.multiselect&&ts.p.multiboxonly){if(scb){$(ts).jqGrid("setSelection",ri,true,e);}else{var frz=ts.p.frozenColumns?ts.p.id+"_frozen":"";$(ts.p.selarrrow).each(function(i,n){var trid=$(ts).jqGrid('getGridRowById',n);$(trid).removeClass("ui-state-highlight");$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(n))[ts.p.useProp?'prop':'attr']("checked",false);if(frz){$("#"+$.jgrid.jqID(n),"#"+$.jgrid.jqID(frz)).removeClass("ui-state-highlight");$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+$.jgrid.jqID(n),"#"+$.jgrid.jqID(frz))[ts.p.useProp?'prop':'attr']("checked",false);}});ts.p.selarrrow=[];$(ts).jqGrid("setSelection",ri,true,e);}}else{$(ts).jqGrid("setSelection",ri,true,e);}}else{if(e[ts.p.multikey]){$(ts).jqGrid("setSelection",ri,true,e);}else if(ts.p.multiselect&&scb){scb=$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+ri).is(":checked");$("#jqg_"+$.jgrid.jqID(ts.p.id)+"_"+ri)[ts.p.useProp?'prop':'attr']("checked",scb);}}}}).bind('reloadGrid',function(e,opts){if(ts.p.treeGrid===true){ts.p.datatype=ts.p.treedatatype;}
if(opts&&opts.current){ts.grid.selectionPreserver(ts);}
if(ts.p.datatype==="local"){$(ts).jqGrid("resetSelection");if(ts.p.data.length){refreshIndex();}}else if(!ts.p.treeGrid){ts.p.selrow=null;if(ts.p.multiselect){ts.p.selarrrow=[];setHeadCheckBox(false);}
ts.p.savedRow=[];}
if(ts.p.scroll){emptyRows.call(ts,true,false);}
if(opts&&opts.page){var page=opts.page;if(page>ts.p.lastpage){page=ts.p.lastpage;}
if(page<1){page=1;}
ts.p.page=page;if(ts.grid.prevRowHeight){ts.grid.bDiv.scrollTop=(page-1)*ts.grid.prevRowHeight*ts.p.rowNum;}else{ts.grid.bDiv.scrollTop=0;}}
if(ts.grid.prevRowHeight&&ts.p.scroll){delete ts.p.lastpage;ts.grid.populateVisible();}else{ts.grid.populate();}
if(ts.p._inlinenav===true){$(ts).jqGrid('showAddEditButtons');}
return false;}).dblclick(function(e){td=e.target;ptr=$(td,ts.rows).closest("tr.jqgrow");if($(ptr).length===0){return;}
ri=ptr[0].rowIndex;ci=$.jgrid.getCellIndex(td);$(ts).triggerHandler("jqGridDblClickRow",[$(ptr).attr("id"),ri,ci,e]);if($.isFunction(ts.p.ondblClickRow)){ts.p.ondblClickRow.call(ts,$(ptr).attr("id"),ri,ci,e);}}).bind('contextmenu',function(e){td=e.target;ptr=$(td,ts.rows).closest("tr.jqgrow");if($(ptr).length===0){return;}
if(!ts.p.multiselect){$(ts).jqGrid("setSelection",ptr[0].id,true,e);}
ri=ptr[0].rowIndex;ci=$.jgrid.getCellIndex(td);$(ts).triggerHandler("jqGridRightClickRow",[$(ptr).attr("id"),ri,ci,e]);if($.isFunction(ts.p.onRightClickRow)){ts.p.onRightClickRow.call(ts,$(ptr).attr("id"),ri,ci,e);}});grid.bDiv=document.createElement("div");if(isMSIE){if(String(ts.p.height).toLowerCase()==="auto"){ts.p.height="100%";}}
$(grid.bDiv).append($('<div style="position:relative;'+(isMSIE&&$.jgrid.msiever()<8?"height:0.01%;":"")+'"></div>').append('<div></div>').append(this)).addClass("ui-jqgrid-bdiv").css({height:ts.p.height+(isNaN(ts.p.height)?"":"px"),width:(grid.width)+"px"}).scroll(grid.scrollGrid);$("table:first",grid.bDiv).css({width:ts.p.tblwidth+"px"});if(!$.support.tbody){if($("tbody",this).length===2){$("tbody:gt(0)",this).remove();}}
if(ts.p.multikey){if($.jgrid.msie){$(grid.bDiv).bind("selectstart",function(){return false;});}else{$(grid.bDiv).bind("mousedown",function(){return false;});}}
if(hg){$(grid.bDiv).hide();}
grid.cDiv=document.createElement("div");var arf=ts.p.hidegrid===true?$("<a role='link' class='ui-jqgrid-titlebar-close HeaderButton' />").hover(function(){arf.addClass('ui-state-hover');},function(){arf.removeClass('ui-state-hover');}).append("<span class='ui-icon ui-icon-circle-triangle-n'></span>").css((dir==="rtl"?"left":"right"),"0px"):"";$(grid.cDiv).append(arf).append("<span class='ui-jqgrid-title"+(dir==="rtl"?"-rtl":"")+"'>"+ts.p.caption+"</span>").addClass("ui-jqgrid-titlebar ui-widget-header ui-corner-top ui-helper-clearfix");$(grid.cDiv).insertBefore(grid.hDiv);if(ts.p.toolbar[0]){grid.uDiv=document.createElement("div");if(ts.p.toolbar[1]==="top"){$(grid.uDiv).insertBefore(grid.hDiv);}else if(ts.p.toolbar[1]==="bottom"){$(grid.uDiv).insertAfter(grid.hDiv);}
if(ts.p.toolbar[1]==="both"){grid.ubDiv=document.createElement("div");$(grid.uDiv).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id).insertBefore(grid.hDiv);$(grid.ubDiv).addClass("ui-userdata ui-state-default").attr("id","tb_"+this.id).insertAfter(grid.hDiv);if(hg){$(grid.ubDiv).hide();}}else{$(grid.uDiv).width(grid.width).addClass("ui-userdata ui-state-default").attr("id","t_"+this.id);}
if(hg){$(grid.uDiv).hide();}}
if(ts.p.toppager){ts.p.toppager=$.jgrid.jqID(ts.p.id)+"_toppager";grid.topDiv=$("<div id='"+ts.p.toppager+"'></div>")[0];ts.p.toppager="#"+ts.p.toppager;$(grid.topDiv).addClass('ui-state-default ui-jqgrid-toppager').width(grid.width).insertBefore(grid.hDiv);setPager(ts.p.toppager,'_t');}
if(ts.p.footerrow){grid.sDiv=$("<div class='ui-jqgrid-sdiv'></div>")[0];hb=$("<div class='ui-jqgrid-hbox"+(dir==="rtl"?"-rtl":"")+"'></div>");$(grid.sDiv).append(hb).width(grid.width).insertAfter(grid.hDiv);$(hb).append(tfoot);grid.footers=$(".ui-jqgrid-ftable",grid.sDiv)[0].rows[0].cells;if(ts.p.rownumbers){grid.footers[0].className='ui-state-default jqgrid-rownum';}
if(hg){$(grid.sDiv).hide();}}
hb=null;if(ts.p.caption){var tdt=ts.p.datatype;if(ts.p.hidegrid===true){$(".ui-jqgrid-titlebar-close",grid.cDiv).click(function(e){var onHdCl=$.isFunction(ts.p.onHeaderClick),elems=".ui-jqgrid-bdiv, .ui-jqgrid-hdiv, .ui-jqgrid-pager, .ui-jqgrid-sdiv",counter,self=this;if(ts.p.toolbar[0]===true){if(ts.p.toolbar[1]==='both'){elems+=', #'+$(grid.ubDiv).attr('id');}
elems+=', #'+$(grid.uDiv).attr('id');}
counter=$(elems,"#gview_"+$.jgrid.jqID(ts.p.id)).length;if(ts.p.gridstate==='visible'){$(elems,"#gbox_"+$.jgrid.jqID(ts.p.id)).slideUp("fast",function(){counter--;if(counter===0){$("span",self).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");ts.p.gridstate='hidden';if($("#gbox_"+$.jgrid.jqID(ts.p.id)).hasClass("ui-resizable")){$(".ui-resizable-handle","#gbox_"+$.jgrid.jqID(ts.p.id)).hide();}
$(ts).triggerHandler("jqGridHeaderClick",[ts.p.gridstate,e]);if(onHdCl){if(!hg){ts.p.onHeaderClick.call(ts,ts.p.gridstate,e);}}}});}else if(ts.p.gridstate==='hidden'){$(elems,"#gbox_"+$.jgrid.jqID(ts.p.id)).slideDown("fast",function(){counter--;if(counter===0){$("span",self).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");if(hg){ts.p.datatype=tdt;populate();hg=false;}
ts.p.gridstate='visible';if($("#gbox_"+$.jgrid.jqID(ts.p.id)).hasClass("ui-resizable")){$(".ui-resizable-handle","#gbox_"+$.jgrid.jqID(ts.p.id)).show();}
$(ts).triggerHandler("jqGridHeaderClick",[ts.p.gridstate,e]);if(onHdCl){if(!hg){ts.p.onHeaderClick.call(ts,ts.p.gridstate,e);}}}});}
return false;});if(hg){ts.p.datatype="local";$(".ui-jqgrid-titlebar-close",grid.cDiv).trigger("click");}}}else{$(grid.cDiv).hide();}
$(grid.hDiv).after(grid.bDiv).mousemove(function(e){if(grid.resizing){grid.dragMove(e);return false;}});$(".ui-jqgrid-labels",grid.hDiv).bind("selectstart",function(){return false;});$(document).bind("mouseup.jqGrid"+ts.p.id,function(){if(grid.resizing){grid.dragEnd();return false;}
return true;});ts.formatCol=formatCol;ts.sortData=sortData;ts.updatepager=updatepager;ts.refreshIndex=refreshIndex;ts.setHeadCheckBox=setHeadCheckBox;ts.constructTr=constructTr;ts.formatter=function(rowId,cellval,colpos,rwdat,act){return formatter(rowId,cellval,colpos,rwdat,act);};$.extend(grid,{populate:populate,emptyRows:emptyRows,beginReq:beginReq,endReq:endReq});this.grid=grid;ts.addXmlData=function(d){addXmlData(d,ts.grid.bDiv);};ts.addJSONData=function(d){addJSONData(d,ts.grid.bDiv);};this.grid.cols=this.rows[0].cells;$(ts).triggerHandler("jqGridInitGrid");if($.isFunction(ts.p.onInitGrid)){ts.p.onInitGrid.call(ts);}
populate();ts.p.hiddengrid=false;});};$.jgrid.extend({getGridParam:function(pName){var $t=this[0];if(!$t||!$t.grid){return;}
if(!pName){return $t.p;}
return $t.p[pName]!==undefined?$t.p[pName]:null;},setGridParam:function(newParams){return this.each(function(){if(this.grid&&typeof newParams==='object'){$.extend(true,this.p,newParams);}});},getGridRowById:function(rowid){var row;this.each(function(){try{row=this.rows.namedItem(rowid);}catch(e){row=$(this.grid.bDiv).find("#"+$.jgrid.jqID(rowid));}});return row;},getDataIDs:function(){var ids=[],i=0,len,j=0;this.each(function(){len=this.rows.length;if(len&&len>0){while(i<len){if($(this.rows[i]).hasClass('jqgrow')){ids[j]=this.rows[i].id;j++;}
i++;}}});return ids;},setSelection:function(selection,onsr,e){return this.each(function(){var $t=this,stat,pt,ner,ia,tpsr,fid;if(selection===undefined){return;}
onsr=onsr===false?false:true;pt=$($t).jqGrid('getGridRowById',selection);if(!pt||!pt.className||pt.className.indexOf('ui-state-disabled')>-1){return;}
function scrGrid(iR){var ch=$($t.grid.bDiv)[0].clientHeight,st=$($t.grid.bDiv)[0].scrollTop,rpos=$($t.rows[iR]).position().top,rh=$t.rows[iR].clientHeight;if(rpos+rh>=ch+st){$($t.grid.bDiv)[0].scrollTop=rpos-(ch+st)+rh+st;}else if(rpos<ch+st){if(rpos<st){$($t.grid.bDiv)[0].scrollTop=rpos;}}}
if($t.p.scrollrows===true){ner=$($t).jqGrid('getGridRowById',selection).rowIndex;if(ner>=0){scrGrid(ner);}}
if($t.p.frozenColumns===true){fid=$t.p.id+"_frozen";}
if(!$t.p.multiselect){if(pt.className!=="ui-subgrid"){if($t.p.selrow!==pt.id&&true==false){$($($t).jqGrid('getGridRowById',$t.p.selrow)).removeClass("ui-state-highlight").attr({"aria-selected":"false","tabindex":"-1"});$(pt).addClass("ui-state-highlight").attr({"aria-selected":"true","tabindex":"0"});if(fid){$("#"+$.jgrid.jqID($t.p.selrow),"#"+$.jgrid.jqID(fid)).removeClass("ui-state-highlight");$("#"+$.jgrid.jqID(selection),"#"+$.jgrid.jqID(fid)).addClass("ui-state-highlight");}
stat=true;}else{stat=false;}
$t.p.selrow=pt.id;if(onsr){$($t).triggerHandler("jqGridSelectRow",[pt.id,stat,e]);if($t.p.onSelectRow){$t.p.onSelectRow.call($t,pt.id,stat,e);}}}}else{$t.setHeadCheckBox(false);$t.p.selrow=pt.id;ia=$.inArray($t.p.selrow,$t.p.selarrrow);if(ia===-1){if(pt.className!=="ui-subgrid"){$(pt).addClass("ui-state-highlight").attr("aria-selected","true");}
stat=true;$t.p.selarrrow.push($t.p.selrow);}else{if(pt.className!=="ui-subgrid"){$(pt).removeClass("ui-state-highlight").attr("aria-selected","false");}
stat=false;$t.p.selarrrow.splice(ia,1);tpsr=$t.p.selarrrow[0];$t.p.selrow=(tpsr===undefined)?null:tpsr;}
$("#jqg_"+$.jgrid.jqID($t.p.id)+"_"+$.jgrid.jqID(pt.id))[$t.p.useProp?'prop':'attr']("checked",stat);if(fid){if(ia===-1){$("#"+$.jgrid.jqID(selection),"#"+$.jgrid.jqID(fid)).addClass("ui-state-highlight");}else{$("#"+$.jgrid.jqID(selection),"#"+$.jgrid.jqID(fid)).removeClass("ui-state-highlight");}
$("#jqg_"+$.jgrid.jqID($t.p.id)+"_"+$.jgrid.jqID(selection),"#"+$.jgrid.jqID(fid))[$t.p.useProp?'prop':'attr']("checked",stat);}
if(onsr){$($t).triggerHandler("jqGridSelectRow",[pt.id,stat,e]);if($t.p.onSelectRow){$t.p.onSelectRow.call($t,pt.id,stat,e);}}}});},resetSelection:function(rowid){return this.each(function(){var t=this,sr,fid;if(t.p.frozenColumns===true){fid=t.p.id+"_frozen";}
if(rowid!==undefined){sr=rowid===t.p.selrow?t.p.selrow:rowid;$("#"+$.jgrid.jqID(t.p.id)+" tbody:first tr#"+$.jgrid.jqID(sr)).removeClass("ui-state-highlight").attr("aria-selected","false");if(fid){$("#"+$.jgrid.jqID(sr),"#"+$.jgrid.jqID(fid)).removeClass("ui-state-highlight");}
if(t.p.multiselect){$("#jqg_"+$.jgrid.jqID(t.p.id)+"_"+$.jgrid.jqID(sr),"#"+$.jgrid.jqID(t.p.id))[t.p.useProp?'prop':'attr']("checked",false);if(fid){$("#jqg_"+$.jgrid.jqID(t.p.id)+"_"+$.jgrid.jqID(sr),"#"+$.jgrid.jqID(fid))[t.p.useProp?'prop':'attr']("checked",false);}
t.setHeadCheckBox(false);}
sr=null;}else if(!t.p.multiselect){if(t.p.selrow){$("#"+$.jgrid.jqID(t.p.id)+" tbody:first tr#"+$.jgrid.jqID(t.p.selrow)).removeClass("ui-state-highlight").attr("aria-selected","false");if(fid){$("#"+$.jgrid.jqID(t.p.selrow),"#"+$.jgrid.jqID(fid)).removeClass("ui-state-highlight");}
t.p.selrow=null;}}else{$(t.p.selarrrow).each(function(i,n){$($(t).jqGrid('getGridRowById',n)).removeClass("ui-state-highlight").attr("aria-selected","false");$("#jqg_"+$.jgrid.jqID(t.p.id)+"_"+$.jgrid.jqID(n))[t.p.useProp?'prop':'attr']("checked",false);if(fid){$("#"+$.jgrid.jqID(n),"#"+$.jgrid.jqID(fid)).removeClass("ui-state-highlight");$("#jqg_"+$.jgrid.jqID(t.p.id)+"_"+$.jgrid.jqID(n),"#"+$.jgrid.jqID(fid))[t.p.useProp?'prop':'attr']("checked",false);}});t.setHeadCheckBox(false);t.p.selarrrow=[];}
if(t.p.cellEdit===true){if(parseInt(t.p.iCol,10)>=0&&parseInt(t.p.iRow,10)>=0){$("td:eq("+t.p.iCol+")",t.rows[t.p.iRow]).removeClass("edit-cell ui-state-highlight");$(t.rows[t.p.iRow]).removeClass("selected-row ui-state-hover");}}
t.p.savedRow=[];});},getRowData:function(rowid){var res={},resall,getall=false,len,j=0;this.each(function(){var $t=this,nm,ind;if(rowid===undefined){getall=true;resall=[];len=$t.rows.length;}else{ind=$($t).jqGrid('getGridRowById',rowid);if(!ind){return res;}
len=2;}
while(j<len){if(getall){ind=$t.rows[j];}
if($(ind).hasClass('jqgrow')){$('td[role="gridcell"]',ind).each(function(i){nm=$t.p.colModel[i].name;if(nm!=='cb'&&nm!=='subgrid'&&nm!=='rn'){if($t.p.treeGrid===true&&nm===$t.p.ExpandColumn){res[nm]=$.jgrid.htmlDecode($("span:first",this).html());}else{try{res[nm]=$.unformat.call($t,this,{rowId:ind.id,colModel:$t.p.colModel[i]},i);}catch(e){res[nm]=$.jgrid.htmlDecode($(this).html());}}}});if(getall){resall.push(res);res={};}}
j++;}});return resall||res;},delRowData:function(rowid){var success=false,rowInd,ia;this.each(function(){var $t=this;rowInd=$($t).jqGrid('getGridRowById',rowid);if(!rowInd){return false;}
$(rowInd).remove();$t.p.records--;$t.p.reccount--;$t.updatepager(true,false);success=true;if($t.p.multiselect){ia=$.inArray(rowid,$t.p.selarrrow);if(ia!==-1){$t.p.selarrrow.splice(ia,1);}}
if($t.p.multiselect&&$t.p.selarrrow.length>0){$t.p.selrow=$t.p.selarrrow[$t.p.selarrrow.length-1];}else{$t.p.selrow=null;}
if($t.p.datatype==='local'){var id=$.jgrid.stripPref($t.p.idPrefix,rowid),pos=$t.p._index[id];if(pos!==undefined){$t.p.data.splice(pos,1);$t.refreshIndex();}}
if($t.p.altRows===true&&success){var cn=$t.p.altclass;$($t.rows).each(function(i){if(i%2===1){$(this).addClass(cn);}else{$(this).removeClass(cn);}});}});return success;},setRowData:function(rowid,data,cssp){var nm,success=true,title;this.each(function(){if(!this.grid){return false;}
var t=this,vl,ind,cp=typeof cssp,lcdata={};ind=$(this).jqGrid('getGridRowById',rowid);if(!ind){return false;}
if(data){try{$(this.p.colModel).each(function(i){nm=this.name;var dval=$.jgrid.getAccessor(data,nm);if(dval!==undefined){lcdata[nm]=this.formatter&&typeof this.formatter==='string'&&this.formatter==='date'?$.unformat.date.call(t,dval,this):dval;vl=t.formatter(rowid,dval,i,data,'set');title=this.title?{"title":$.jgrid.stripHtml(vl)}:{};if(t.p.treeGrid===true&&nm===t.p.ExpandColumn){$("td[role='gridcell']:eq("+i+") > span:first",ind).html(vl).attr(title);}else{var selector=$("td[role='gridcell']:eq("+i+")",ind);var editor=UI.FindEditorInput(selector);if(!editor){selector.html(vl).attr(title);}else{if(vl=="&#160;"||(vl&&vl.indexOf("Mandatory</span>")!=-1))vl="";editor.val(vl);editor.change();if(editor.attr("skipSelect")!="true")
setTimeout(function(){editor.select();},10);}}}});if(t.p.datatype==='local'){var id=$.jgrid.stripPref(t.p.idPrefix,rowid),pos=t.p._index[id],key;if(t.p.treeGrid){for(key in t.p.treeReader){if(t.p.treeReader.hasOwnProperty(key)){delete lcdata[t.p.treeReader[key]];}}}
if(pos!==undefined){t.p.data[pos]=$.extend(true,t.p.data[pos],lcdata);}
lcdata=null;}}catch(e){success=false;}}
if(success){if(cp==='string'){$(ind).addClass(cssp);}else if(cp==='object'){$(ind).css(cssp);}
$(t).triggerHandler("jqGridAfterGridComplete");}});return success;},addRowData:function(rowid,rdata,pos,src){if(!pos){pos="last";}
var success=false,nm,row,gi,si,ni,sind,i,v,prp="",aradd,cnm,cn,data,cm,id;if(rdata){if($.isArray(rdata)){aradd=true;pos="last";cnm=rowid;}else{rdata=[rdata];aradd=false;}
this.each(function(){var t=this,datalen=rdata.length;ni=t.p.rownumbers===true?1:0;gi=t.p.multiselect===true?1:0;si=t.p.subGrid===true?1:0;if(!aradd){if(rowid!==undefined){rowid=String(rowid);}else{rowid=$.jgrid.randId();if(t.p.keyIndex!==false){cnm=t.p.colModel[t.p.keyIndex+gi+si+ni].name;if(rdata[0][cnm]!==undefined){rowid=rdata[0][cnm];}}}}
cn=t.p.altclass;var k=0,cna="",lcdata={},air=$.isFunction(t.p.afterInsertRow)?true:false;while(k<datalen){data=rdata[k];row=[];if(aradd){try{rowid=data[cnm];if(rowid===undefined){rowid=$.jgrid.randId();}}catch(e){rowid=$.jgrid.randId();}
cna=t.p.altRows===true?(t.rows.length-1)%2===0?cn:"":"";}
id=rowid;rowid=t.p.idPrefix+rowid;if(ni){prp=t.formatCol(0,1,'',null,rowid,true);row[row.length]="<td role=\"gridcell\" class=\"ui-state-default jqgrid-rownum\" "+prp+">0</td>";}
if(gi){v="<input role=\"checkbox\" type=\"checkbox\""+" id=\"jqg_"+t.p.id+"_"+rowid+"\" class=\"cbox\"/>";prp=t.formatCol(ni,1,'',null,rowid,true);row[row.length]="<td role=\"gridcell\" "+prp+">"+v+"</td>";}
if(si){row[row.length]=$(t).jqGrid("addSubGridCell",gi+ni,1);}
for(i=gi+si+ni;i<t.p.colModel.length;i++){cm=t.p.colModel[i];nm=cm.name;lcdata[nm]=data[nm];v=t.formatter(rowid,$.jgrid.getAccessor(data,nm),i,data);prp=t.formatCol(i,1,v,data,rowid,lcdata);row[row.length]="<td role=\"gridcell\" "+prp+">"+v+"</td>";}
row.unshift(t.constructTr(rowid,false,cna,lcdata,data,false));row[row.length]="</tr>";if(t.rows.length===0){$("table:first",t.grid.bDiv).append(row.join(''));}else{switch(pos){case'last':$(t.rows[t.rows.length-1]).after(row.join(''));sind=t.rows.length-1;break;case'first':$(t.rows[0]).after(row.join(''));sind=1;break;case'after':sind=$(t).jqGrid('getGridRowById',src);if(sind){if($(t.rows[sind.rowIndex+1]).hasClass("ui-subgrid")){$(t.rows[sind.rowIndex+1]).after(row);}else{$(sind).after(row.join(''));}
sind=sind.rowIndex+1;}
break;case'before':sind=$(t).jqGrid('getGridRowById',src);if(sind){$(sind).before(row.join(''));sind=sind.rowIndex-1;}
break;}}
if(t.p.subGrid===true){$(t).jqGrid("addSubGrid",gi+ni,sind);}
t.p.records++;t.p.reccount++;$(t).triggerHandler("jqGridAfterInsertRow",[rowid,data,data]);if(air){t.p.afterInsertRow.call(t,rowid,data,data);}
k++;if(t.p.datatype==='local'){lcdata[t.p.localReader.id]=id;t.p._index[id]=t.p.data.length;t.p.data.push(lcdata);lcdata={};}}
if(t.p.altRows===true&&!aradd){if(pos==="last"){if((t.rows.length-1)%2===1){$(t.rows[t.rows.length-1]).addClass(cn);}}else{$(t.rows).each(function(i){if(i%2===1){$(this).addClass(cn);}else{$(this).removeClass(cn);}});}}
t.updatepager(true,true);success=true;});}
return success;},footerData:function(action,data,format){var nm,success=false,res={},title;function isEmpty(obj){var i;for(i in obj){if(obj.hasOwnProperty(i)){return false;}}
return true;}
if(action===undefined){action="get";}
if(typeof format!=="boolean"){format=true;}
action=action.toLowerCase();this.each(function(){var t=this,vl;if(!t.grid||!t.p.footerrow){return false;}
if(action==="set"){if(isEmpty(data)){return false;}}
success=true;$(this.p.colModel).each(function(i){nm=this.name;if(action==="set"){if(data[nm]!==undefined){vl=format?t.formatter("",data[nm],i,data,'edit'):data[nm];title=this.title?{"title":$.jgrid.stripHtml(vl)}:{};$("tr.footrow td:eq("+i+")",t.grid.sDiv).html(vl).attr(title);success=true;}}else if(action==="get"){res[nm]=$("tr.footrow td:eq("+i+")",t.grid.sDiv).html();}});});return action==="get"?res:success;},showHideCol:function(colname,show){return this.each(function(){var $t=this,fndh=false,brd=$.jgrid.cell_width?0:$t.p.cellLayout,cw;if(!$t.grid){return;}
if(typeof colname==='string'){colname=[colname];}
show=show!=="none"?"":"none";var sw=show===""?true:false,gh=$t.p.groupHeader&&(typeof $t.p.groupHeader==='object'||$.isFunction($t.p.groupHeader));if(gh){$($t).jqGrid('destroyGroupHeader',false);}
$(this.p.colModel).each(function(i){if($.inArray(this.name,colname)!==-1&&this.hidden===sw){if($t.p.frozenColumns===true&&this.frozen===true){return true;}
$("tr[role=rowheader]",$t.grid.hDiv).each(function(){$(this.cells[i]).css("display",show);});$($t.rows).each(function(){if(!$(this).hasClass("jqgroup")){$(this.cells[i]).css("display",show);}});if($t.p.footerrow){$("tr.footrow td:eq("+i+")",$t.grid.sDiv).css("display",show);}
cw=parseInt(this.width,10);if(show==="none"){$t.p.tblwidth-=cw+brd;}else{$t.p.tblwidth+=cw+brd;}
this.hidden=!sw;fndh=true;$($t).triggerHandler("jqGridShowHideCol",[sw,this.name,i]);}});if(fndh===true){if($t.p.shrinkToFit===true&&!isNaN($t.p.height)){$t.p.tblwidth+=parseInt($t.p.scrollOffset,10);}
$($t).jqGrid("setGridWidth",$t.p.shrinkToFit===true?$t.p.tblwidth:$t.p.width);}
if(gh){$($t).jqGrid('setGroupHeaders',$t.p.groupHeader);}});},hideCol:function(colname){return this.each(function(){$(this).jqGrid("showHideCol",colname,"none");});},showCol:function(colname){return this.each(function(){$(this).jqGrid("showHideCol",colname,"");});},remapColumns:function(permutation,updateCells,keepHeader){function resortArray(a){var ac;if(a.length){ac=$.makeArray(a);}else{ac=$.extend({},a);}
$.each(permutation,function(i){a[i]=ac[this];});}
var ts=this.get(0);function resortRows(parent,clobj){$(">tr"+(clobj||""),parent).each(function(){var row=this;var elems=$.makeArray(row.cells);$.each(permutation,function(){var e=elems[this];if(e){row.appendChild(e);}});});}
resortArray(ts.p.colModel);resortArray(ts.p.colNames);resortArray(ts.grid.headers);resortRows($("thead:first",ts.grid.hDiv),keepHeader&&":not(.ui-jqgrid-labels)");if(updateCells){resortRows($("#"+$.jgrid.jqID(ts.p.id)+" tbody:first"),".jqgfirstrow, tr.jqgrow, tr.jqfoot");}
if(ts.p.footerrow){resortRows($("tbody:first",ts.grid.sDiv));}
if(ts.p.remapColumns){if(!ts.p.remapColumns.length){ts.p.remapColumns=$.makeArray(permutation);}else{resortArray(ts.p.remapColumns);}}
ts.p.lastsort=$.inArray(ts.p.lastsort,permutation);if(ts.p.treeGrid){ts.p.expColInd=$.inArray(ts.p.expColInd,permutation);}
$(ts).triggerHandler("jqGridRemapColumns",[permutation,updateCells,keepHeader]);},setGridWidth:function(nwidth,shrink){return this.each(function(){if(!this.grid){return;}
var $t=this,cw,initwidth=0,brd=$.jgrid.cell_width?0:$t.p.cellLayout,lvc,vc=0,hs=false,scw=$t.p.scrollOffset,aw,gw=0,cr;if(typeof shrink!=='boolean'){shrink=$t.p.shrinkToFit;}
if(isNaN(nwidth)){return;}
nwidth=parseInt(nwidth,10);$t.grid.width=$t.p.width=nwidth;$("#gbox_"+$.jgrid.jqID($t.p.id)).css("width",nwidth+"px");$("#gview_"+$.jgrid.jqID($t.p.id)).css("width",nwidth+"px");$($t.grid.bDiv).css("width",nwidth+"px");$($t.grid.hDiv).css("width",nwidth+"px");if($t.p.pager){$($t.p.pager).css("width",nwidth+"px");}
if($t.p.toppager){$($t.p.toppager).css("width",nwidth+"px");}
if($t.p.toolbar[0]===true){$($t.grid.uDiv).css("width",nwidth+"px");if($t.p.toolbar[1]==="both"){$($t.grid.ubDiv).css("width",nwidth+"px");}}
if($t.p.footerrow){$($t.grid.sDiv).css("width",nwidth+"px");}
if(shrink===false&&$t.p.forceFit===true){$t.p.forceFit=false;}
if(shrink===true){$.each($t.p.colModel,function(){if(this.hidden===false){cw=this.widthOrg;initwidth+=cw+brd;if(this.fixed){gw+=cw+brd;}else{vc++;}}});if(vc===0){return;}
$t.p.tblwidth=initwidth;aw=nwidth-brd*vc-gw;if(!isNaN($t.p.height)){if($($t.grid.bDiv)[0].clientHeight<$($t.grid.bDiv)[0].scrollHeight||$t.rows.length===1){hs=true;aw-=scw;}}
initwidth=0;var cle=$t.grid.cols.length>0;$.each($t.p.colModel,function(i){if(this.hidden===false&&!this.fixed){cw=this.widthOrg;cw=Math.round(aw*cw/($t.p.tblwidth-brd*vc-gw));if(cw<0){return;}
this.width=cw;initwidth+=cw;$t.grid.headers[i].width=cw;$t.grid.headers[i].el.style.width=cw+"px";if($t.p.footerrow){$t.grid.footers[i].style.width=cw+"px";}
if(cle){$t.grid.cols[i].style.width=cw+"px";}
lvc=i;}});if(!lvc){return;}
cr=0;if(hs){if(nwidth-gw-(initwidth+brd*vc)!==scw){cr=nwidth-gw-(initwidth+brd*vc)-scw;}}else if(Math.abs(nwidth-gw-(initwidth+brd*vc))!==1){cr=nwidth-gw-(initwidth+brd*vc);}
$t.p.colModel[lvc].width+=cr;$t.p.tblwidth=initwidth+cr+brd*vc+gw;if($t.p.tblwidth>nwidth){var delta=$t.p.tblwidth-parseInt(nwidth,10);$t.p.tblwidth=nwidth;cw=$t.p.colModel[lvc].width=$t.p.colModel[lvc].width-delta;}else{cw=$t.p.colModel[lvc].width;}
$t.grid.headers[lvc].width=cw;$t.grid.headers[lvc].el.style.width=cw+"px";if(cle){$t.grid.cols[lvc].style.width=cw+"px";}
if($t.p.footerrow){$t.grid.footers[lvc].style.width=cw+"px";}}
if($t.p.tblwidth){$('table:first',$t.grid.bDiv).css("width",$t.p.tblwidth+"px");$('table:first',$t.grid.hDiv).css("width",$t.p.tblwidth+"px");$t.grid.hDiv.scrollLeft=$t.grid.bDiv.scrollLeft;if($t.p.footerrow){$('table:first',$t.grid.sDiv).css("width",$t.p.tblwidth+"px");}}});},setGridHeight:function(nh){return this.each(function(){var $t=this;if(!$t.grid){return;}
var bDiv=$($t.grid.bDiv);bDiv.css({height:nh+(isNaN(nh)?"":"px")});if($t.p.frozenColumns===true){$('#'+$.jgrid.jqID($t.p.id)+"_frozen").parent().height(bDiv.height()-16);}
$t.p.height=nh;if($t.p.scroll){$t.grid.populateVisible();}});},setCaption:function(newcap){return this.each(function(){this.p.caption=newcap;$("span.ui-jqgrid-title, span.ui-jqgrid-title-rtl",this.grid.cDiv).html(newcap);$(this.grid.cDiv).show();});},setLabel:function(colname,nData,prop,attrp){return this.each(function(){var $t=this,pos=-1;if(!$t.grid){return;}
if(colname!==undefined){$($t.p.colModel).each(function(i){if(this.name===colname){pos=i;return false;}});}else{return;}
if(pos>=0){var thecol=$("tr.ui-jqgrid-labels th:eq("+pos+")",$t.grid.hDiv);if(nData){var ico=$(".s-ico",thecol);$("[id^=jqgh_]",thecol).empty().html(nData).append(ico);$t.p.colNames[pos]=nData;}
if(prop){if(typeof prop==='string'){$(thecol).addClass(prop);}else{$(thecol).css(prop);}}
if(typeof attrp==='object'){$(thecol).attr(attrp);}}});},setCell:function(rowid,colname,nData,cssp,attrp,forceupd){return this.each(function(){var $t=this,pos=-1,v,title;if(!$t.grid){return;}
if(isNaN(colname)){$($t.p.colModel).each(function(i){if(this.name===colname){pos=i;return false;}});}else{pos=parseInt(colname,10);}
if(pos>=0){if(!$t.p.colModel[pos].skipsanitize)
nData=Application.SanitizeString(nData);var ind=$($t).jqGrid('getGridRowById',rowid);if(ind){var tcell=$("td:eq("+pos+")",ind);if(nData!==""||forceupd===true){v=$t.formatter(rowid,nData,pos,ind,'edit');title=$t.p.colModel[pos].title?{"title":$.jgrid.stripHtml(v)}:{};if($t.p.treeGrid&&$(".tree-wrap",$(tcell)).length>0){$("span",$(tcell)).html(v).attr(title);}else{$(tcell).html(v).attr(title);}
if($t.p.datatype==="local"){var cm=$t.p.colModel[pos],index;nData=cm.formatter&&typeof cm.formatter==='string'&&cm.formatter==='date'?$.unformat.date.call($t,nData,cm):nData;index=$t.p._index[$.jgrid.stripPref($t.p.idPrefix,rowid)];if(index!==undefined){$t.p.data[index][cm.name]=nData;}}}
if(typeof cssp==='string'){$(tcell).addClass(cssp);}else if(cssp){$(tcell).css(cssp);}
if(typeof attrp==='object'){$(tcell).attr(attrp);}}}});},getCell:function(rowid,col){var ret=false;this.each(function(){var $t=this,pos=-1;if(!$t.grid){return;}
if(isNaN(col)){$($t.p.colModel).each(function(i){if(this.name===col){pos=i;return false;}});}else{pos=parseInt(col,10);}
if(pos>=0){var ind=$($t).jqGrid('getGridRowById',rowid);if(ind){try{ret=$.unformat.call($t,$("td:eq("+pos+")",ind),{rowId:ind.id,colModel:$t.p.colModel[pos]},pos);}catch(e){ret=$.jgrid.htmlDecode($("td:eq("+pos+")",ind).html());}}}});return ret;},getCol:function(col,obj,mathopr){var ret=[],val,sum=0,min,max,v;obj=typeof obj!=='boolean'?false:obj;if(mathopr===undefined){mathopr=false;}
this.each(function(){var $t=this,pos=-1;if(!$t.grid){return;}
if(isNaN(col)){$($t.p.colModel).each(function(i){if(this.name===col){pos=i;return false;}});}else{pos=parseInt(col,10);}
if(pos>=0){var ln=$t.rows.length,i=0,dlen=0;if(ln&&ln>0){while(i<ln){if($($t.rows[i]).hasClass('jqgrow')){try{val=$.unformat.call($t,$($t.rows[i].cells[pos]),{rowId:$t.rows[i].id,colModel:$t.p.colModel[pos]},pos);}catch(e){val=$.jgrid.htmlDecode($t.rows[i].cells[pos].innerHTML);}
var selector=$($t.rows[i].cells[pos]);var editor=UI.FindEditorInput(selector);if(editor){val=editor.val();}
if(mathopr){v=parseFloat(val);if(!isNaN(v)){sum+=v;if(max===undefined){max=min=v;}
min=Math.min(min,v);max=Math.max(max,v);dlen++;}}else if(obj){ret.push({id:$t.rows[i].id,value:val});}else{ret.push(val);}}
i++;}
if(mathopr){switch(mathopr.toLowerCase()){case'sum':ret=sum;break;case'avg':ret=sum/dlen;break;case'count':ret=(ln-1);break;case'min':ret=min;break;case'max':ret=max;break;}}}}});return ret;},clearGridData:function(clearfooter){return this.each(function(){var $t=this;if(!$t.grid){return;}
if(typeof clearfooter!=='boolean'){clearfooter=false;}
if($t.p.deepempty){$("#"+$.jgrid.jqID($t.p.id)+" tbody:first tr:gt(0)").remove();}else{var trf=$("#"+$.jgrid.jqID($t.p.id)+" tbody:first tr:first")[0];$("#"+$.jgrid.jqID($t.p.id)+" tbody:first").empty().append(trf);}
if($t.p.footerrow&&clearfooter){$(".ui-jqgrid-ftable td",$t.grid.sDiv).html("&#160;");}
$t.p.selrow=null;$t.p.selarrrow=[];$t.p.savedRow=[];$t.p.records=0;$t.p.page=1;$t.p.lastpage=0;$t.p.reccount=0;$t.p.data=[];$t.p._index={};$t.updatepager(true,false);});},getInd:function(rowid,rc){var ret=false,rw;this.each(function(){rw=$(this).jqGrid('getGridRowById',rowid);if(rw){ret=rc===true?rw:rw.rowIndex;}});return ret;},bindKeys:function(settings){var o=$.extend({onEnter:null,onSpace:null,onLeftKey:null,onRightKey:null,scrollingRows:true},settings||{});return this.each(function(){var $t=this;if(!$('body').is('[role]')){$('body').attr('role','application');}
$t.p.scrollrows=o.scrollingRows;$($t).keydown(function(event){var target=$($t).find('tr[tabindex=0]')[0],id,r,mind,expanded=$t.p.treeReader.expanded_field;if(target){mind=$t.p._index[$.jgrid.stripPref($t.p.idPrefix,target.id)];if(event.keyCode===37||event.keyCode===38||event.keyCode===39||event.keyCode===40){if(event.keyCode===38){r=target.previousSibling;id="";if(r){if($(r).is(":hidden")){while(r){r=r.previousSibling;if(!$(r).is(":hidden")&&$(r).hasClass('jqgrow')){id=r.id;break;}}}else{id=r.id;}}
$($t).jqGrid('setSelection',id,true,event);event.preventDefault();}
if(event.keyCode===40){r=target.nextSibling;id="";if(r){if($(r).is(":hidden")){while(r){r=r.nextSibling;if(!$(r).is(":hidden")&&$(r).hasClass('jqgrow')){id=r.id;break;}}}else{id=r.id;}}
$($t).jqGrid('setSelection',id,true,event);event.preventDefault();}
if(event.keyCode===37){if($t.p.treeGrid&&$t.p.data[mind][expanded]){$(target).find("div.treeclick").trigger('click');}
$($t).triggerHandler("jqGridKeyLeft",[$t.p.selrow]);if($.isFunction(o.onLeftKey)){o.onLeftKey.call($t,$t.p.selrow);}}
if(event.keyCode===39){if($t.p.treeGrid&&!$t.p.data[mind][expanded]){$(target).find("div.treeclick").trigger('click');}
$($t).triggerHandler("jqGridKeyRight",[$t.p.selrow]);if($.isFunction(o.onRightKey)){o.onRightKey.call($t,$t.p.selrow);}}}
else if(event.keyCode===13){$($t).triggerHandler("jqGridKeyEnter",[$t.p.selrow]);if($.isFunction(o.onEnter)){o.onEnter.call($t,$t.p.selrow);}}else if(event.keyCode===32){$($t).triggerHandler("jqGridKeySpace",[$t.p.selrow]);if($.isFunction(o.onSpace)){o.onSpace.call($t,$t.p.selrow);}}}});});},unbindKeys:function(){return this.each(function(){$(this).unbind('keydown');});},getLocalRow:function(rowid){var ret=false,ind;this.each(function(){if(rowid!==undefined){ind=this.p._index[$.jgrid.stripPref(this.p.idPrefix,rowid)];if(ind>=0){ret=this.p.data[ind];}}});return ret;}});})(jQuery);(function($){"use strict";$.jgrid.extend({getColProp:function(colname){var ret={},$t=this[0];if(!$t.grid){return false;}
var cM=$t.p.colModel,i;for(i=0;i<cM.length;i++){if(cM[i].name===colname){ret=cM[i];break;}}
return ret;},setColProp:function(colname,obj){return this.each(function(){if(this.grid){if(obj){var cM=this.p.colModel,i;for(i=0;i<cM.length;i++){if(cM[i].name===colname){$.extend(true,this.p.colModel[i],obj);break;}}}}});},sortGrid:function(colname,reload,sor){return this.each(function(){var $t=this,idx=-1,i,sobj=false;if(!$t.grid){return;}
if(!colname){colname=$t.p.sortname;}
for(i=0;i<$t.p.colModel.length;i++){if($t.p.colModel[i].index===colname||$t.p.colModel[i].name===colname){idx=i;if($t.p.frozenColumns===true&&$t.p.colModel[i].frozen===true){sobj=$t.grid.fhDiv.find("#"+$t.p.id+"_"+colname);}
break;}}
if(idx!==-1){var sort=$t.p.colModel[idx].sortable;if(typeof sort!=='boolean'){sort=true;}
if(typeof reload!=='boolean'){reload=false;}
if(sort){$t.sortData("jqgh_"+$t.p.id+"_"+colname,idx,reload,sor,sobj);}}});},clearBeforeUnload:function(){return this.each(function(){var grid=this.grid;grid.emptyRows.call(this,true,true);$(document).unbind("mouseup.jqGrid"+this.p.id);$(grid.hDiv).unbind("mousemove");$(this).unbind();grid.dragEnd=null;grid.dragMove=null;grid.dragStart=null;grid.emptyRows=null;grid.populate=null;grid.populateVisible=null;grid.scrollGrid=null;grid.selectionPreserver=null;grid.bDiv=null;grid.cDiv=null;grid.hDiv=null;grid.cols=null;var i,l=grid.headers.length;for(i=0;i<l;i++){grid.headers[i].el=null;}
this.formatCol=null;this.sortData=null;this.updatepager=null;this.refreshIndex=null;this.setHeadCheckBox=null;this.constructTr=null;this.formatter=null;this.addXmlData=null;this.addJSONData=null;});},GridDestroy:function(){return this.each(function(){if(this.grid){if(this.p.pager){$(this.p.pager).remove();}
try{$(this).jqGrid('clearBeforeUnload');$("#gbox_"+$.jgrid.jqID(this.id)).remove();}catch(_){}}});},GridUnload:function(){return this.each(function(){if(!this.grid){return;}
var defgrid={id:$(this).attr('id'),cl:$(this).attr('class')};if(this.p.pager){$(this.p.pager).empty().removeClass("ui-state-default ui-jqgrid-pager corner-bottom");}
var newtable=document.createElement('table');$(newtable).attr({id:defgrid.id});newtable.className=defgrid.cl;var gid=$.jgrid.jqID(this.id);$(newtable).removeClass("ui-jqgrid-btable");if($(this.p.pager).parents("#gbox_"+gid).length===1){$(newtable).insertBefore("#gbox_"+gid).show();$(this.p.pager).insertBefore("#gbox_"+gid);}else{$(newtable).insertBefore("#gbox_"+gid).show();}
$(this).jqGrid('clearBeforeUnload');$("#gbox_"+gid).remove();});},setGridState:function(state){return this.each(function(){if(!this.grid){return;}
var $t=this;if(state==='hidden'){$(".ui-jqgrid-bdiv, .ui-jqgrid-hdiv","#gview_"+$.jgrid.jqID($t.p.id)).slideUp("fast");if($t.p.pager){$($t.p.pager).slideUp("fast");}
if($t.p.toppager){$($t.p.toppager).slideUp("fast");}
if($t.p.toolbar[0]===true){if($t.p.toolbar[1]==='both'){$($t.grid.ubDiv).slideUp("fast");}
$($t.grid.uDiv).slideUp("fast");}
if($t.p.footerrow){$(".ui-jqgrid-sdiv","#gbox_"+$.jgrid.jqID($t.p.id)).slideUp("fast");}
$(".ui-jqgrid-titlebar-close span",$t.grid.cDiv).removeClass("ui-icon-circle-triangle-n").addClass("ui-icon-circle-triangle-s");$t.p.gridstate='hidden';}else if(state==='visible'){$(".ui-jqgrid-hdiv, .ui-jqgrid-bdiv","#gview_"+$.jgrid.jqID($t.p.id)).slideDown("fast");if($t.p.pager){$($t.p.pager).slideDown("fast");}
if($t.p.toppager){$($t.p.toppager).slideDown("fast");}
if($t.p.toolbar[0]===true){if($t.p.toolbar[1]==='both'){$($t.grid.ubDiv).slideDown("fast");}
$($t.grid.uDiv).slideDown("fast");}
if($t.p.footerrow){$(".ui-jqgrid-sdiv","#gbox_"+$.jgrid.jqID($t.p.id)).slideDown("fast");}
$(".ui-jqgrid-titlebar-close span",$t.grid.cDiv).removeClass("ui-icon-circle-triangle-s").addClass("ui-icon-circle-triangle-n");$t.p.gridstate='visible';}});},filterToolbar:function(p){p=$.extend({autosearch:true,searchOnEnter:true,beforeSearch:null,afterSearch:null,beforeClear:null,afterClear:null,searchurl:'',stringResult:false,groupOp:'AND',defaultSearch:"bw",searchOperators:false,operandTitle:"Click to select search operation.",operands:{"eq":"==","ne":"!","lt":"<","le":"<=","gt":">","ge":">=","bw":"^","bn":"!^","in":"=","ni":"!=","ew":"|","en":"!@","cn":"~","nc":"!~","nu":"#","nn":"!#"}},$.jgrid.search,p||{});return this.each(function(){var $t=this;if(this.ftoolbar){return;}
var triggerToolbar=function(){var sdata={},j=0,v,nm,sopt={},so;$.each($t.p.colModel,function(){var $elem=$("#gs_"+$.jgrid.jqID(this.name),(this.frozen===true&&$t.p.frozenColumns===true)?$t.grid.fhDiv:$t.grid.hDiv);nm=this.index||this.name;if(p.searchOperators){so=$elem.parent().prev().children("a").attr("soper")||p.defaultSearch;}else{so=(this.searchoptions&&this.searchoptions.sopt)?this.searchoptions.sopt[0]:this.stype==='select'?'eq':p.defaultSearch;}
v=this.stype==="custom"&&$.isFunction(this.searchoptions.custom_value)&&$elem.length>0&&$elem[0].nodeName.toUpperCase()==="SPAN"?this.searchoptions.custom_value.call($t,$elem.children(".customelement:first"),"get"):$elem.val();if(v||so==="nu"||so==="nn"){sdata[nm]=v;sopt[nm]=so;j++;}else{try{delete $t.p.postData[nm];}catch(z){}}});var sd=j>0?true:false;if(p.stringResult===true||$t.p.datatype==="local"){var ruleGroup="{\"groupOp\":\""+p.groupOp+"\",\"rules\":[";var gi=0;$.each(sdata,function(i,n){if(gi>0){ruleGroup+=",";}
ruleGroup+="{\"field\":\""+i+"\",";ruleGroup+="\"op\":\""+sopt[i]+"\",";n+="";ruleGroup+="\"data\":\""+n.replace(/\\/g,'\\\\').replace(/\"/g,'\\"')+"\"}";gi++;});ruleGroup+="]}";$.extend($t.p.postData,{filters:ruleGroup});$.each(['searchField','searchString','searchOper'],function(i,n){if($t.p.postData.hasOwnProperty(n)){delete $t.p.postData[n];}});}else{$.extend($t.p.postData,sdata);}
var saveurl;if($t.p.searchurl){saveurl=$t.p.url;$($t).jqGrid("setGridParam",{url:$t.p.searchurl});}
var bsr=$($t).triggerHandler("jqGridToolbarBeforeSearch")==='stop'?true:false;if(!bsr&&$.isFunction(p.beforeSearch)){bsr=p.beforeSearch.call($t);}
if(!bsr){$($t).jqGrid("setGridParam",{search:sd}).trigger("reloadGrid",[{page:1}]);}
if(saveurl){$($t).jqGrid("setGridParam",{url:saveurl});}
$($t).triggerHandler("jqGridToolbarAfterSearch");if($.isFunction(p.afterSearch)){p.afterSearch.call($t);}},clearToolbar=function(trigger){var sdata={},j=0,nm;trigger=(typeof trigger!=='boolean')?true:trigger;$.each($t.p.colModel,function(){var v,$elem=$("#gs_"+$.jgrid.jqID(this.name),(this.frozen===true&&$t.p.frozenColumns===true)?$t.grid.fhDiv:$t.grid.hDiv);if(this.searchoptions&&this.searchoptions.defaultValue!==undefined){v=this.searchoptions.defaultValue;}
nm=this.index||this.name;switch(this.stype){case'select':$elem.find("option").each(function(i){if(i===0){this.selected=true;}
if($(this).val()===v){this.selected=true;return false;}});if(v!==undefined){sdata[nm]=v;j++;}else{try{delete $t.p.postData[nm];}catch(e){}}
break;case'text':$elem.val(v);if(v!==undefined){sdata[nm]=v;j++;}else{try{delete $t.p.postData[nm];}catch(y){}}
break;case'custom':if($.isFunction(this.searchoptions.custom_value)&&$elem.length>0&&$elem[0].nodeName.toUpperCase()==="SPAN"){this.searchoptions.custom_value.call($t,$elem.children(".customelement:first"),"set",v);}
break;}});var sd=j>0?true:false;if(p.stringResult===true||$t.p.datatype==="local"){var ruleGroup="{\"groupOp\":\""+p.groupOp+"\",\"rules\":[";var gi=0;$.each(sdata,function(i,n){if(gi>0){ruleGroup+=",";}
ruleGroup+="{\"field\":\""+i+"\",";ruleGroup+="\"op\":\""+"eq"+"\",";n+="";ruleGroup+="\"data\":\""+n.replace(/\\/g,'\\\\').replace(/\"/g,'\\"')+"\"}";gi++;});ruleGroup+="]}";$.extend($t.p.postData,{filters:ruleGroup});$.each(['searchField','searchString','searchOper'],function(i,n){if($t.p.postData.hasOwnProperty(n)){delete $t.p.postData[n];}});}else{$.extend($t.p.postData,sdata);}
var saveurl;if($t.p.searchurl){saveurl=$t.p.url;$($t).jqGrid("setGridParam",{url:$t.p.searchurl});}
var bcv=$($t).triggerHandler("jqGridToolbarBeforeClear")==='stop'?true:false;if(!bcv&&$.isFunction(p.beforeClear)){bcv=p.beforeClear.call($t);}
if(!bcv){if(trigger){$($t).jqGrid("setGridParam",{search:sd}).trigger("reloadGrid",[{page:1}]);}}
if(saveurl){$($t).jqGrid("setGridParam",{url:saveurl});}
$($t).triggerHandler("jqGridToolbarAfterClear");if($.isFunction(p.afterClear)){p.afterClear();}},toggleToolbar=function(){var trow=$("tr.ui-search-toolbar",$t.grid.hDiv),trow2=$t.p.frozenColumns===true?$("tr.ui-search-toolbar",$t.grid.fhDiv):false;if(trow.css("display")==='none'){trow.show();if(trow2){trow2.show();}}else{trow.hide();if(trow2){trow2.hide();}}},buildRuleMenu=function(elem,left,top){$("#sopt_menu").remove();left=parseInt(left,10);top=parseInt(top,10)+18;var fs=$('.ui-jqgrid-view').css('font-size')||'11px';var str='<ul id="sopt_menu" class="ui-search-menu" role="menu" tabindex="0" style="font-size:'+fs+';left:'+left+'px;top:'+top+'px;">',selected=$(elem).attr("soper"),selclass,aoprs=[],ina;var i=0,nm=$(elem).attr("colname"),len=$t.p.colModel.length;while(i<len){if($t.p.colModel[i].name===nm){break;}
i++;}
var cm=$t.p.colModel[i],options=$.extend({},cm.searchoptions);if(!options.sopt){options.sopt=[];options.sopt[0]=cm.stype==='select'?'eq':p.defaultSearch;}
$.each(p.odata,function(){aoprs.push(this.oper);});for(i=0;i<options.sopt.length;i++){ina=$.inArray(options.sopt[i],aoprs);if(ina!==-1){selclass=selected===p.odata[ina].oper?"ui-state-highlight":"";str+='<li class="ui-menu-item '+selclass+'" role="presentation"><a class="ui-corner-all g-menu-item" tabindex="0" role="menuitem" value="'+p.odata[ina].oper+'" oper="'+p.operands[p.odata[ina].oper]+'"><table cellspacing="0" cellpadding="0" border="0"><tr><td width="25px">'+p.operands[p.odata[ina].oper]+'</td><td>'+p.odata[ina].text+'</td></tr></table></a></li>';}}
str+="</ul>";$('body').append(str);$("#sopt_menu").addClass("ui-menu ui-widget ui-widget-content ui-corner-all");$("#sopt_menu > li > a").hover(function(){$(this).addClass("ui-state-hover");},function(){$(this).removeClass("ui-state-hover");}).click(function(e){var v=$(this).attr("value"),oper=$(this).attr("oper");$($t).triggerHandler("jqGridToolbarSelectOper",[v,oper,elem]);$("#sopt_menu").hide();$(elem).text(oper).attr("soper",v);if(p.autosearch===true){var inpelm=$(elem).parent().next().children()[0];if($(inpelm).val()||v==="nu"||v==="nn"){triggerToolbar();}}});};var tr=$("<tr class='ui-search-toolbar' role='rowheader'></tr>");var timeoutHnd;$.each($t.p.colModel,function(ci){var cm=this,soptions,surl,self,select="",sot="=",so,i,th=$("<th role='columnheader' class='ui-state-default ui-th-column ui-th-"+$t.p.direction+"'></th>"),thd=$("<div style='position:relative;height:100%;padding-right:0.3em;padding-left:0.3em;'></div>"),stbl=$("<table class='ui-search-table' cellspacing='0'><tr><td class='ui-search-oper'></td><td class='ui-search-input'></td><td class='ui-search-clear'></td></tr></table>");if(this.hidden===true){$(th).css("display","none");}
this.search=this.search===false?false:true;if(this.stype===undefined){this.stype='text';}
soptions=$.extend({},this.searchoptions||{});if(this.search){if(p.searchOperators){so=(soptions.sopt)?soptions.sopt[0]:cm.stype==='select'?'eq':p.defaultSearch;for(i=0;i<p.odata.length;i++){if(p.odata[i].oper===so){sot=p.operands[so]||"";break;}}
var st=soptions.searchtitle!=null?soptions.searchtitle:p.operandTitle;select="<a title='"+st+"' style='padding-right: 0.5em;' soper='"+so+"' class='soptclass' colname='"+this.name+"'>"+sot+"</a>";}
$("td:eq(0)",stbl).attr("colindex",ci).append(select);if(soptions.clearSearch===undefined){soptions.clearSearch=true;}
if(soptions.clearSearch){$("td:eq(2)",stbl).append("<a title='Clear Search Value' style='padding-right: 0.3em;padding-left: 0.3em;' class='clearsearchclass'>x</a>");}
switch(this.stype){case"select":surl=this.surl||soptions.dataUrl;if(surl){self=thd;$(self).append(stbl);$.ajax($.extend({url:surl,dataType:"html",success:function(res){if(soptions.buildSelect!==undefined){var d=soptions.buildSelect(res);if(d){$("td:eq(1)",stbl).append(d);}}else{$("td:eq(1)",stbl).append(res);}
if(soptions.defaultValue!==undefined){$("select",self).val(soptions.defaultValue);}
$("select",self).attr({name:cm.index||cm.name,id:"gs_"+cm.name});if(soptions.attr){$("select",self).attr(soptions.attr);}
$("select",self).css({width:"100%"});$.jgrid.bindEv.call($t,$("select",self)[0],soptions);if(p.autosearch===true){$("select",self).change(function(){triggerToolbar();return false;});}
res=null;}},$.jgrid.ajaxOptions,$t.p.ajaxSelectOptions||{}));}else{var oSv,sep,delim;if(cm.searchoptions){oSv=cm.searchoptions.value===undefined?"":cm.searchoptions.value;sep=cm.searchoptions.separator===undefined?":":cm.searchoptions.separator;delim=cm.searchoptions.delimiter===undefined?";":cm.searchoptions.delimiter;}else if(cm.editoptions){oSv=cm.editoptions.value===undefined?"":cm.editoptions.value;sep=cm.editoptions.separator===undefined?":":cm.editoptions.separator;delim=cm.editoptions.delimiter===undefined?";":cm.editoptions.delimiter;}
if(oSv){var elem=document.createElement("select");elem.style.width="100%";$(elem).attr({name:cm.index||cm.name,id:"gs_"+cm.name});var sv,ov,key,k;if(typeof oSv==="string"){so=oSv.split(delim);for(k=0;k<so.length;k++){sv=so[k].split(sep);ov=document.createElement("option");ov.value=sv[0];ov.innerHTML=sv[1];elem.appendChild(ov);}}else if(typeof oSv==="object"){for(key in oSv){if(oSv.hasOwnProperty(key)){ov=document.createElement("option");ov.value=key;ov.innerHTML=oSv[key];elem.appendChild(ov);}}}
if(soptions.defaultValue!==undefined){$(elem).val(soptions.defaultValue);}
if(soptions.attr){$(elem).attr(soptions.attr);}
$(thd).append(stbl);$.jgrid.bindEv.call($t,elem,soptions);$("td:eq(1)",stbl).append(elem);if(p.autosearch===true){$(elem).change(function(){triggerToolbar();return false;});}}}
break;case"text":var df=soptions.defaultValue!==undefined?soptions.defaultValue:"";$("td:eq(1)",stbl).append("<input type='text' style='width:100%;padding:0px;' name='"+(cm.index||cm.name)+"' id='gs_"+cm.name+"' value='"+df+"'/>");$(thd).append(stbl);if(soptions.attr){$("input",thd).attr(soptions.attr);}
$.jgrid.bindEv.call($t,$("input",thd)[0],soptions);if(p.autosearch===true){if(p.searchOnEnter){$("input",thd).keypress(function(e){var key=e.charCode||e.keyCode||0;if(key===13){triggerToolbar();return false;}
return this;});}else{$("input",thd).keydown(function(e){var key=e.which;switch(key){case 13:return false;case 9:case 16:case 37:case 38:case 39:case 40:case 27:break;default:if(timeoutHnd){clearTimeout(timeoutHnd);}
timeoutHnd=setTimeout(function(){triggerToolbar();},500);}});}}
break;case"custom":$("td:eq(1)",stbl).append("<span style='width:95%;padding:0px;' name='"+(cm.index||cm.name)+"' id='gs_"+cm.name+"'/>");$(thd).append(stbl);try{if($.isFunction(soptions.custom_element)){var celm=soptions.custom_element.call($t,soptions.defaultValue!==undefined?soptions.defaultValue:"",soptions);if(celm){celm=$(celm).addClass("customelement");$(thd).find(">span").append(celm);}else{throw"e2";}}else{throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_element' "+$.jgrid.edit.msg.nodefined,$.jgrid.edit.bClose);}
if(e==="e2"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_element' "+$.jgrid.edit.msg.novalue,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,typeof e==="string"?e:e.message,$.jgrid.edit.bClose);}}
break;}}
$(th).append(thd);$(tr).append(th);if(!p.searchOperators){$("td:eq(0)",stbl).hide();}});$("table thead",$t.grid.hDiv).append(tr);if(p.searchOperators){$(".soptclass",tr).click(function(e){var offset=$(this).offset(),left=(offset.left),top=(offset.top);buildRuleMenu(this,left,top);e.stopPropagation();});$("body").on('click',function(e){if(e.target.className!=="soptclass"){$("#sopt_menu").hide();}});}
$(".clearsearchclass",tr).click(function(e){var ptr=$(this).parents("tr:first"),coli=parseInt($("td.ui-search-oper",ptr).attr('colindex'),10),sval=$.extend({},$t.p.colModel[coli].searchoptions||{}),dval=sval.defaultValue?sval.defaultValue:"";if($t.p.colModel[coli].stype==="select"){if(dval){$("td.ui-search-input select",ptr).val(dval);}else{$("td.ui-search-input select",ptr)[0].selectedIndex=0;}}else{$("td.ui-search-input input",ptr).val(dval);}
if(p.autosearch===true){triggerToolbar();}});this.ftoolbar=true;this.triggerToolbar=triggerToolbar;this.clearToolbar=clearToolbar;this.toggleToolbar=toggleToolbar;});},destroyFilterToolbar:function(){return this.each(function(){if(!this.ftoolbar){return;}
this.triggerToolbar=null;this.clearToolbar=null;this.toggleToolbar=null;this.ftoolbar=false;$(this.grid.hDiv).find("table thead tr.ui-search-toolbar").remove();});},destroyGroupHeader:function(nullHeader){if(nullHeader===undefined){nullHeader=true;}
return this.each(function(){var $t=this,$tr,i,l,headers,$th,$resizing,grid=$t.grid,thead=$("table.ui-jqgrid-htable thead",grid.hDiv),cm=$t.p.colModel,hc;if(!grid){return;}
$(this).unbind('.setGroupHeaders');$tr=$("<tr>",{role:"rowheader"}).addClass("ui-jqgrid-labels");headers=grid.headers;for(i=0,l=headers.length;i<l;i++){hc=cm[i].hidden?"none":"";$th=$(headers[i].el).width(headers[i].width).css('display',hc);try{$th.removeAttr("rowSpan");}catch(rs){$th.attr("rowSpan",1);}
$tr.append($th);$resizing=$th.children("span.ui-jqgrid-resize");if($resizing.length>0){$resizing[0].style.height="";}
$th.children("div")[0].style.top="";}
$(thead).children('tr.ui-jqgrid-labels').remove();$(thead).prepend($tr);if(nullHeader===true){$($t).jqGrid('setGridParam',{'groupHeader':null});}});},setGroupHeaders:function(o){o=$.extend({useColSpanStyle:false,groupHeaders:[]},o||{});return this.each(function(){this.p.groupHeader=o;var ts=this,i,cmi,skip=0,$tr,$colHeader,th,$th,thStyle,iCol,cghi,numberOfColumns,titleText,cVisibleColumns,colModel=ts.p.colModel,cml=colModel.length,ths=ts.grid.headers,$htable=$("table.ui-jqgrid-htable",ts.grid.hDiv),$trLabels=$htable.children("thead").children("tr.ui-jqgrid-labels:last").addClass("jqg-second-row-header"),$thead=$htable.children("thead"),$theadInTable,$firstHeaderRow=$htable.find(".jqg-first-row-header");if($firstHeaderRow[0]===undefined){$firstHeaderRow=$('<tr>',{role:"row","aria-hidden":"true"}).addClass("jqg-first-row-header").css("height","auto");}else{$firstHeaderRow.empty();}
var $firstRow,inColumnHeader=function(text,columnHeaders){var length=columnHeaders.length,i;for(i=0;i<length;i++){if(columnHeaders[i].startColumnName===text){return i;}}
return-1;};$(ts).prepend($thead);$tr=$('<tr>',{role:"rowheader"}).addClass("ui-jqgrid-labels jqg-third-row-header");for(i=0;i<cml;i++){th=ths[i].el;$th=$(th);cmi=colModel[i];thStyle={height:'0px',width:ths[i].width+'px',display:(cmi.hidden?'none':'')};$("<th>",{role:'gridcell'}).css(thStyle).addClass("ui-first-th-"+ts.p.direction).appendTo($firstHeaderRow);th.style.width="";iCol=inColumnHeader(cmi.name,o.groupHeaders);if(iCol>=0){cghi=o.groupHeaders[iCol];numberOfColumns=cghi.numberOfColumns;titleText=cghi.titleText;for(cVisibleColumns=0,iCol=0;iCol<numberOfColumns&&(i+iCol<cml);iCol++){if(!colModel[i+iCol].hidden){cVisibleColumns++;}}
$colHeader=$('<th>').attr({role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+ts.p.direction).css({'height':'22px','border-top':'0px none'}).html(titleText);if(cVisibleColumns>0){$colHeader.attr("colspan",String(cVisibleColumns));}
if(ts.p.headertitles){$colHeader.attr("title",$colHeader.text());}
if(cVisibleColumns===0){$colHeader.hide();}
$th.before($colHeader);$tr.append(th);skip=numberOfColumns-1;}else{if(skip===0){if(o.useColSpanStyle){$th.attr("rowspan","2");}else{$('<th>',{role:"columnheader"}).addClass("ui-state-default ui-th-column-header ui-th-"+ts.p.direction).css({"display":cmi.hidden?'none':'','border-top':'0px none'}).insertBefore($th);$tr.append(th);}}else{$tr.append(th);skip--;}}}
$theadInTable=$(ts).children("thead");$theadInTable.prepend($firstHeaderRow);$tr.insertAfter($trLabels);$htable.append($theadInTable);if(o.useColSpanStyle){$htable.find("span.ui-jqgrid-resize").each(function(){var $parent=$(this).parent();if($parent.is(":visible")){this.style.cssText='height: '+$parent.height()+'px !important; cursor: col-resize;';}});$htable.find("div.ui-jqgrid-sortable").each(function(){var $ts=$(this),$parent=$ts.parent();if($parent.is(":visible")&&$parent.is(":has(span.ui-jqgrid-resize)")){$ts.css('top',($parent.height()-$ts.outerHeight())/2+'px');}});}
$firstRow=$theadInTable.find("tr.jqg-first-row-header");$(ts).bind('jqGridResizeStop.setGroupHeaders',function(e,nw,idx){$firstRow.find('th').eq(idx).width(nw);});});},setFrozenColumns:function(){return this.each(function(){if(!this.grid){return;}
var $t=this,cm=$t.p.colModel,i=0,len=cm.length,maxfrozen=-1,frozen=false;if($t.p.subGrid===true||$t.p.treeGrid===true||$t.p.cellEdit===true||$t.p.sortable||$t.p.scroll||$t.p.grouping){return;}
if($t.p.rownumbers){i++;}
if($t.p.multiselect){i++;}
while(i<len){if(cm[i].frozen===true){frozen=true;maxfrozen=i;}else{break;}
i++;}
if(maxfrozen>=0&&frozen){var top=$t.p.caption?$($t.grid.cDiv).outerHeight():0,hth=$(".ui-jqgrid-htable","#gview_"+$.jgrid.jqID($t.p.id)).height();if($t.p.toppager){top=top+$($t.grid.topDiv).outerHeight();}
if($t.p.toolbar[0]===true){if($t.p.toolbar[1]!=="bottom"){top=top+$($t.grid.uDiv).outerHeight();}}
$t.grid.fhDiv=$('<div style="position:absolute;left:0px;top:'+top+'px;height:'+hth+'px;" class="frozen-div ui-state-default ui-jqgrid-hdiv"></div>');$t.grid.fbDiv=$('<div style="position:absolute;left:0px;top:'+(parseInt(top,10)+parseInt(hth,10)+1)+'px;overflow-y:hidden" class="frozen-bdiv ui-jqgrid-bdiv"></div>');$("#gview_"+$.jgrid.jqID($t.p.id)).append($t.grid.fhDiv);var htbl=$(".ui-jqgrid-htable","#gview_"+$.jgrid.jqID($t.p.id)).clone(true);if($t.p.groupHeader){$("tr.jqg-first-row-header, tr.jqg-third-row-header",htbl).each(function(){$("th:gt("+maxfrozen+")",this).remove();});var swapfroz=-1,fdel=-1,cs,rs;$("tr.jqg-second-row-header th",htbl).each(function(){cs=parseInt($(this).attr("colspan"),10);rs=parseInt($(this).attr("rowspan"),10);if(rs){swapfroz++;fdel++;}
if(cs){swapfroz=swapfroz+cs;fdel++;}
if(swapfroz===maxfrozen){return false;}});if(swapfroz!==maxfrozen){fdel=maxfrozen;}
$("tr.jqg-second-row-header",htbl).each(function(){$("th:gt("+fdel+")",this).remove();});}else{$("tr",htbl).each(function(){$("th:gt("+maxfrozen+")",this).remove();});}
$(htbl).width(1);$($t.grid.fhDiv).append(htbl).mousemove(function(e){if($t.grid.resizing){$t.grid.dragMove(e);return false;}});$($t).bind('jqGridResizeStop.setFrozenColumns',function(e,w,index){var rhth=$(".ui-jqgrid-htable",$t.grid.fhDiv);$("th:eq("+index+")",rhth).width(w);var btd=$(".ui-jqgrid-btable",$t.grid.fbDiv);$("tr:first td:eq("+index+")",btd).width(w);});$($t).bind('jqGridSortCol.setFrozenColumns',function(e,index,idxcol){var previousSelectedTh=$("tr.ui-jqgrid-labels:last th:eq("+$t.p.lastsort+")",$t.grid.fhDiv),newSelectedTh=$("tr.ui-jqgrid-labels:last th:eq("+idxcol+")",$t.grid.fhDiv);$("span.ui-grid-ico-sort",previousSelectedTh).addClass('ui-state-disabled');$(previousSelectedTh).attr("aria-selected","false");$("span.ui-icon-"+$t.p.sortorder,newSelectedTh).removeClass('ui-state-disabled');$(newSelectedTh).attr("aria-selected","true");if(!$t.p.viewsortcols[0]){if($t.p.lastsort!==idxcol){$("span.s-ico",previousSelectedTh).hide();$("span.s-ico",newSelectedTh).show();}}});$("#gview_"+$.jgrid.jqID($t.p.id)).append($t.grid.fbDiv);$($t.grid.bDiv).scroll(function(){$($t.grid.fbDiv).scrollTop($(this).scrollTop());});if($t.p.hoverrows===true){$("#"+$.jgrid.jqID($t.p.id)).unbind('mouseover').unbind('mouseout');}
$($t).bind('jqGridAfterGridComplete.setFrozenColumns',function(){$("#"+$.jgrid.jqID($t.p.id)+"_frozen").remove();$($t.grid.fbDiv).height($($t.grid.bDiv).height()-16);var btbl=$("#"+$.jgrid.jqID($t.p.id)).clone(true);$("tr[role=row]",btbl).each(function(){$("td[role=gridcell]:gt("+maxfrozen+")",this).remove();});$(btbl).width(1).attr("id",$t.p.id+"_frozen");$($t.grid.fbDiv).append(btbl);if($t.p.hoverrows===true){$("tr.jqgrow",btbl).hover(function(){$(this).addClass("ui-state-hover");$("#"+$.jgrid.jqID(this.id),"#"+$.jgrid.jqID($t.p.id)).addClass("ui-state-hover");},function(){$(this).removeClass("ui-state-hover");$("#"+$.jgrid.jqID(this.id),"#"+$.jgrid.jqID($t.p.id)).removeClass("ui-state-hover");});$("tr.jqgrow","#"+$.jgrid.jqID($t.p.id)).hover(function(){$(this).addClass("ui-state-hover");$("#"+$.jgrid.jqID(this.id),"#"+$.jgrid.jqID($t.p.id)+"_frozen").addClass("ui-state-hover");},function(){$(this).removeClass("ui-state-hover");$("#"+$.jgrid.jqID(this.id),"#"+$.jgrid.jqID($t.p.id)+"_frozen").removeClass("ui-state-hover");});}
btbl=null;});if(!$t.grid.hDiv.loading){$($t).triggerHandler("jqGridAfterGridComplete");}
$t.p.frozenColumns=true;}});},destroyFrozenColumns:function(){return this.each(function(){if(!this.grid){return;}
if(this.p.frozenColumns===true){var $t=this;$($t.grid.fhDiv).remove();$($t.grid.fbDiv).remove();$t.grid.fhDiv=null;$t.grid.fbDiv=null;$(this).unbind('.setFrozenColumns');if($t.p.hoverrows===true){var ptr;$("#"+$.jgrid.jqID($t.p.id)).bind('mouseover',function(e){ptr=$(e.target).closest("tr.jqgrow");if($(ptr).attr("class")!=="ui-subgrid"){$(ptr).addClass("ui-state-hover");}}).bind('mouseout',function(e){ptr=$(e.target).closest("tr.jqgrow");$(ptr).removeClass("ui-state-hover");});}
this.p.frozenColumns=false;}});}});})(jQuery);(function($){$.fn.jqm=function(o){var p={overlay:50,closeoverlay:true,overlayClass:'jqmOverlay',closeClass:'jqmClose',trigger:'.jqModal',ajax:F,ajaxText:'',target:F,modal:F,toTop:F,onShow:F,onHide:F,onLoad:F};return this.each(function(){if(this._jqm)return H[this._jqm].c=$.extend({},H[this._jqm].c,o);s++;this._jqm=s;H[s]={c:$.extend(p,$.jqm.params,o),a:F,w:$(this).addClass('jqmID'+s),s:s};if(p.trigger)$(this).jqmAddTrigger(p.trigger);});};$.fn.jqmAddClose=function(e){return hs(this,e,'jqmHide');};$.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};$.fn.jqmShow=function(t){return this.each(function(){$.jqm.open(this._jqm,t);});};$.fn.jqmHide=function(t){return this.each(function(){$.jqm.close(this._jqm,t)});};$.jqm={hash:{},open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=(parseInt(h.w.css('z-index')));z=(z>0)?z:3000;var o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});if(h.a)return F;h.t=t;h.a=true;h.w.css('z-index',z);if(c.modal){if(!A[0])setTimeout(function(){L('bind');},1);A.push(s);}else if(c.overlay>0){if(c.closeoverlay)h.w.jqmAddClose(o);}else o=F;h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):F;if(c.ajax){var r=c.target||h.w,u=c.ajax;r=(typeof r=='string')?$(r,h.w):$(r);u=(u.substr(0,1)=='@')?$(t).attr(u.substring(1)):u;r.html(c.ajaxText).load(u,function(){if(c.onLoad)c.onLoad.call(this,h);if(cc)h.w.jqmAddClose($(cc,h.w));e(h);});}else if(cc)h.w.jqmAddClose($(cc,h.w));if(c.toTop&&h.o)h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);(c.onShow)?c.onShow(h):h.w.show();e(h);return F;},close:function(s){var h=H[s];if(!h.a)return F;h.a=F;if(A[0]){A.pop();if(!A[0])L('unbind');}
if(h.c.toTop&&h.o)$('#jqmP'+h.w[0]._jqm).after(h.w).remove();if(h.c.onHide)h.c.onHide(h);else{h.w.hide();if(h.o)h.o.remove();}
return F;},params:{}};var s=0,H=$.jqm.hash,A=[],F=false,e=function(h){f(h);},f=function(h){try{$(':input:visible',h.w)[0].focus();}catch(_){}},L=function(t){$(document)[t]("keypress",m)[t]("keydown",m)[t]("mousedown",m);},m=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);if(r){$('.jqmID'+h.s).each(function(){var $self=$(this),offset=$self.offset();if(offset.top<=e.pageY&&e.pageY<=offset.top+$self.height()&&offset.left<=e.pageX&&e.pageX<=offset.left+$self.width()){r=false;return false;}});f(h);}
return!r;},hs=function(w,t,c){return w.each(function(){var s=this._jqm;$(t).each(function(){if(!this[c]){this[c]=[];$(this).click(function(){for(var i in{jqmShow:1,jqmHide:1})
for(var s in this[i])
if(H[this[i][s]])H[this[i][s]].w[i](this);return F;});}
this[c].push(s);});});};})(jQuery);(function($){$.fn.jqDrag=function(h){return i(this,h,'d');};$.fn.jqResize=function(h,ar){return i(this,h,'r',ar);};$.jqDnR={dnr:{},e:0,drag:function(v){if(M.k=='d'){E.css({left:M.X+v.pageX-M.pX,top:M.Y+v.pageY-M.pY});}else{E.css({width:Math.max(v.pageX-M.pX+M.W,0),height:Math.max(v.pageY-M.pY+M.H,0)});if(M1){E1.css({width:Math.max(v.pageX-M1.pX+M1.W,0),height:Math.max(v.pageY-M1.pY+M1.H,0)});}}
return false;},stop:function(){$(document).unbind('mousemove',J.drag).unbind('mouseup',J.stop);}};var J=$.jqDnR,M=J.dnr,E=J.e,E1,M1,i=function(e,h,k,aR){return e.each(function(){h=(h)?$(h,e):e;h.bind('mousedown',{e:e,k:k},function(v){var d=v.data,p={};E=d.e;E1=aR?$(aR):false;if(E.css('position')!='relative'){try{E.position(p);}catch(e){}}
M={X:p.left||f('left')||0,Y:p.top||f('top')||0,W:f('width')||E[0].scrollWidth||0,H:f('height')||E[0].scrollHeight||0,pX:v.pageX,pY:v.pageY,k:d.k};if(E1&&d.k!='d'){M1={X:p.left||f1('left')||0,Y:p.top||f1('top')||0,W:E1[0].offsetWidth||f1('width')||0,H:E1[0].offsetHeight||f1('height')||0,pX:v.pageX,pY:v.pageY,k:d.k};}else{M1=false;}
if($("input.hasDatepicker",E[0])[0]){try{$("input.hasDatepicker",E[0]).datepicker('hide');}catch(dpe){}}
$(document).mousemove($.jqDnR.drag).mouseup($.jqDnR.stop);return false;});});},f=function(k){return parseInt(E.css(k),10)||false;},f1=function(k){return parseInt(E1.css(k),10)||false;};})(jQuery);var xmlJsonClass={xml2json:function(xml,tab){if(xml.nodeType===9){xml=xml.documentElement;}
var nws=this.removeWhite(xml);var obj=this.toObj(nws);var json=this.toJson(obj,xml.nodeName,"\t");return"{\n"+tab+(tab?json.replace(/\t/g,tab):json.replace(/\t|\n/g,""))+"\n}";},json2xml:function(o,tab){var toXml=function(v,name,ind){var xml="";var i,n;if(v instanceof Array){if(v.length===0){xml+=ind+"<"+name+">__EMPTY_ARRAY_</"+name+">\n";}else{for(i=0,n=v.length;i<n;i+=1){var sXml=ind+toXml(v[i],name,ind+"\t")+"\n";xml+=sXml;}}}else if(typeof(v)==="object"){var hasChild=false;xml+=ind+"<"+name;var m;for(m in v)
if(v.hasOwnProperty(m)){if(m.charAt(0)==="@"){xml+=" "+m.substr(1)+"=\""+v[m].toString()+"\"";}else{hasChild=true;}}
xml+=hasChild?">":"/>";if(hasChild){for(m in v)
if(v.hasOwnProperty(m)){if(m==="#text"){xml+=v[m];}else if(m==="#cdata"){xml+="<![CDATA["+v[m]+"]]>";}else if(m.charAt(0)!=="@"){xml+=toXml(v[m],m,ind+"\t");}}
xml+=(xml.charAt(xml.length-1)==="\n"?ind:"")+"</"+name+">";}}else if(typeof(v)==="function"){xml+=ind+"<"+name+">"+"<![CDATA["+v+"]]>"+"</"+name+">";}else{if(v===undefined){v="";}
if(v.toString()==="\"\""||v.toString().length===0){xml+=ind+"<"+name+">__EMPTY_STRING_</"+name+">";}else{xml+=ind+"<"+name+">"+v.toString()+"</"+name+">";}}
return xml;};var xml="";var m;for(m in o)
if(o.hasOwnProperty(m)){xml+=toXml(o[m],m,"");}
return tab?xml.replace(/\t/g,tab):xml.replace(/\t|\n/g,"");},toObj:function(xml){var o={};var FuncTest=/function/i;if(xml.nodeType===1){if(xml.attributes.length){var i;for(i=0;i<xml.attributes.length;i+=1){o["@"+xml.attributes[i].nodeName]=(xml.attributes[i].nodeValue||"").toString();}}
if(xml.firstChild){var textChild=0,cdataChild=0,hasElementChild=false;var n;for(n=xml.firstChild;n;n=n.nextSibling){if(n.nodeType===1){hasElementChild=true;}else if(n.nodeType===3&&n.nodeValue.match(/[^ \f\n\r\t\v]/)){textChild+=1;}else if(n.nodeType===4){cdataChild+=1;}}
if(hasElementChild){if(textChild<2&&cdataChild<2){this.removeWhite(xml);for(n=xml.firstChild;n;n=n.nextSibling){if(n.nodeType===3){o["#text"]=this.escape(n.nodeValue);}else if(n.nodeType===4){if(FuncTest.test(n.nodeValue)){o[n.nodeName]=[o[n.nodeName],n.nodeValue];}else{o["#cdata"]=this.escape(n.nodeValue);}}else if(o[n.nodeName]){if(o[n.nodeName]instanceof Array){o[n.nodeName][o[n.nodeName].length]=this.toObj(n);}else{o[n.nodeName]=[o[n.nodeName],this.toObj(n)];}}else{o[n.nodeName]=this.toObj(n);}}}else{if(!xml.attributes.length){o=this.escape(this.innerXml(xml));}else{o["#text"]=this.escape(this.innerXml(xml));}}}else if(textChild){if(!xml.attributes.length){o=this.escape(this.innerXml(xml));if(o==="__EMPTY_ARRAY_"){o="[]";}else if(o==="__EMPTY_STRING_"){o="";}}else{o["#text"]=this.escape(this.innerXml(xml));}}else if(cdataChild){if(cdataChild>1){o=this.escape(this.innerXml(xml));}else{for(n=xml.firstChild;n;n=n.nextSibling){if(FuncTest.test(xml.firstChild.nodeValue)){o=xml.firstChild.nodeValue;break;}else{o["#cdata"]=this.escape(n.nodeValue);}}}}}
if(!xml.attributes.length&&!xml.firstChild){o=null;}}else if(xml.nodeType===9){o=this.toObj(xml.documentElement);}else{alert("unhandled node type: "+xml.nodeType);}
return o;},toJson:function(o,name,ind,wellform){if(wellform===undefined)wellform=true;var json=name?("\""+name+"\""):"",tab="\t",newline="\n";if(!wellform){tab="";newline="";}
if(o==="[]"){json+=(name?":[]":"[]");}else if(o instanceof Array){var n,i,ar=[];for(i=0,n=o.length;i<n;i+=1){ar[i]=this.toJson(o[i],"",ind+tab,wellform);}
json+=(name?":[":"[")+(ar.length>1?(newline+ind+tab+ar.join(","+newline+ind+tab)+newline+ind):ar.join(""))+"]";}else if(o===null){json+=(name&&":")+"null";}else if(typeof(o)==="object"){var arr=[],m;for(m in o){if(o.hasOwnProperty(m)){arr[arr.length]=this.toJson(o[m],m,ind+tab,wellform);}}
json+=(name?":{":"{")+(arr.length>1?(newline+ind+tab+arr.join(","+newline+ind+tab)+newline+ind):arr.join(""))+"}";}else if(typeof(o)==="string"){json+=(name&&":")+"\""+o.replace(/\\/g,'\\\\').replace(/\"/g,'\\"')+"\"";}else{json+=(name&&":")+o.toString();}
return json;},innerXml:function(node){var s="";if("innerHTML"in node){s=node.innerHTML;}else{var asXml=function(n){var s="",i;if(n.nodeType===1){s+="<"+n.nodeName;for(i=0;i<n.attributes.length;i+=1){s+=" "+n.attributes[i].nodeName+"=\""+(n.attributes[i].nodeValue||"").toString()+"\"";}
if(n.firstChild){s+=">";for(var c=n.firstChild;c;c=c.nextSibling){s+=asXml(c);}
s+="</"+n.nodeName+">";}else{s+="/>";}}else if(n.nodeType===3){s+=n.nodeValue;}else if(n.nodeType===4){s+="<![CDATA["+n.nodeValue+"]]>";}
return s;};for(var c=node.firstChild;c;c=c.nextSibling){s+=asXml(c);}}
return s;},escape:function(txt){return txt.replace(/[\\]/g,"\\\\").replace(/[\"]/g,'\\"').replace(/[\n]/g,'\\n').replace(/[\r]/g,'\\r');},removeWhite:function(e){e.normalize();var n;for(n=e.firstChild;n;){if(n.nodeType===3){if(!n.nodeValue.match(/[^ \f\n\r\t\v]/)){var nxt=n.nextSibling;e.removeChild(n);n=nxt;}else{n=n.nextSibling;}}else if(n.nodeType===1){this.removeWhite(n);n=n.nextSibling;}else{n=n.nextSibling;}}
return e;}};(function($){"use strict";$.fmatter={};$.extend($.fmatter,{isBoolean:function(o){return typeof o==='boolean';},isObject:function(o){return(o&&(typeof o==='object'||$.isFunction(o)))||false;},isString:function(o){return typeof o==='string';},isNumber:function(o){return typeof o==='number'&&isFinite(o);},isValue:function(o){return(this.isObject(o)||this.isString(o)||this.isNumber(o)||this.isBoolean(o));},isEmpty:function(o){if(!this.isString(o)&&this.isValue(o)){return false;}
if(!this.isValue(o)){return true;}
o=$.trim(o).replace(/\&nbsp\;/ig,'').replace(/\&#160\;/ig,'');return o==="";}});$.fn.fmatter=function(formatType,cellval,opts,rwd,act){var v=cellval;opts=$.extend({},$.jgrid.formatter,opts);try{v=$.fn.fmatter[formatType].call(this,cellval,opts,rwd,act);}catch(fe){}
return v;};$.fmatter.util={NumberFormat:function(nData,opts){if(!$.fmatter.isNumber(nData)){nData*=1;}
if($.fmatter.isNumber(nData)){var bNegative=(nData<0);var sOutput=String(nData);var sDecimalSeparator=opts.decimalSeparator||".";var nDotIndex;if($.fmatter.isNumber(opts.decimalPlaces)){var nDecimalPlaces=opts.decimalPlaces;var nDecimal=Math.pow(10,nDecimalPlaces);sOutput=String(Math.round(nData*nDecimal)/nDecimal);nDotIndex=sOutput.lastIndexOf(".");if(nDecimalPlaces>0){if(nDotIndex<0){sOutput+=sDecimalSeparator;nDotIndex=sOutput.length-1;}
else if(sDecimalSeparator!=="."){sOutput=sOutput.replace(".",sDecimalSeparator);}
while((sOutput.length-1-nDotIndex)<nDecimalPlaces){sOutput+="0";}}}
if(opts.thousandsSeparator){var sThousandsSeparator=opts.thousandsSeparator;nDotIndex=sOutput.lastIndexOf(sDecimalSeparator);nDotIndex=(nDotIndex>-1)?nDotIndex:sOutput.length;var sNewOutput=sOutput.substring(nDotIndex);var nCount=-1,i;for(i=nDotIndex;i>0;i--){nCount++;if((nCount%3===0)&&(i!==nDotIndex)&&(!bNegative||(i>1))){sNewOutput=sThousandsSeparator+sNewOutput;}
sNewOutput=sOutput.charAt(i-1)+sNewOutput;}
sOutput=sNewOutput;}
sOutput=(opts.prefix)?opts.prefix+sOutput:sOutput;sOutput=(opts.suffix)?sOutput+opts.suffix:sOutput;return sOutput;}
return nData;}};$.fn.fmatter.defaultFormat=function(cellval,opts){return($.fmatter.isValue(cellval)&&cellval!=="")?cellval:opts.defaultValue||"&#160;";};$.fn.fmatter.email=function(cellval,opts){if(!$.fmatter.isEmpty(cellval)){return"<a href=\"mailto:"+cellval+"\">"+cellval+"</a>";}
return $.fn.fmatter.defaultFormat(cellval,opts);};$.fn.fmatter.checkbox=function(cval,opts){var op=$.extend({},opts.checkbox),ds;if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if(op.disabled===true){ds="disabled=\"disabled\"";}else{ds="";}
if($.fmatter.isEmpty(cval)||cval===undefined){cval=$.fn.fmatter.defaultFormat(cval,op);}
cval=String(cval);cval=(cval+"").toLowerCase();var bchk=cval.search(/(false|f|0|no|n|off|undefined)/i)<0?" checked='checked' ":"";return"<input type=\"checkbox\" "+bchk+" value=\""+cval+"\" offval=\"no\" "+ds+"/>";};$.fn.fmatter.link=function(cellval,opts){var op={target:opts.target};var target="";if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if(op.target){target='target='+op.target;}
if(!$.fmatter.isEmpty(cellval)){return"<a "+target+" href=\""+cellval+"\">"+cellval+"</a>";}
return $.fn.fmatter.defaultFormat(cellval,opts);};$.fn.fmatter.showlink=function(cellval,opts){var op={baseLinkUrl:opts.baseLinkUrl,showAction:opts.showAction,addParam:opts.addParam||"",target:opts.target,idName:opts.idName},target="",idUrl;if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if(op.target){target='target='+op.target;}
idUrl=op.baseLinkUrl+op.showAction+'?'+op.idName+'='+opts.rowId+op.addParam;if($.fmatter.isString(cellval)||$.fmatter.isNumber(cellval)){return"<a "+target+" href=\""+idUrl+"\">"+cellval+"</a>";}
return $.fn.fmatter.defaultFormat(cellval,opts);};$.fn.fmatter.integer=function(cellval,opts){var op=$.extend({},opts.integer);if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if($.fmatter.isEmpty(cellval)){return op.defaultValue;}
return $.fmatter.util.NumberFormat(cellval,op);};$.fn.fmatter.number=function(cellval,opts){var op=$.extend({},opts.number);if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if($.fmatter.isEmpty(cellval)){return op.defaultValue;}
return $.fmatter.util.NumberFormat(cellval,op);};$.fn.fmatter.currency=function(cellval,opts){var op=$.extend({},opts.currency);if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if($.fmatter.isEmpty(cellval)){return op.defaultValue;}
return $.fmatter.util.NumberFormat(cellval,op);};$.fn.fmatter.date=function(cellval,opts,rwd,act){var op=$.extend({},opts.date);if(opts.colModel!==undefined&&opts.colModel.formatoptions!==undefined){op=$.extend({},op,opts.colModel.formatoptions);}
if(!op.reformatAfterEdit&&act==='edit'){return $.fn.fmatter.defaultFormat(cellval,opts);}
if(!$.fmatter.isEmpty(cellval)){return $.jgrid.parseDate(op.srcformat,cellval,op.newformat,op);}
return $.fn.fmatter.defaultFormat(cellval,opts);};$.fn.fmatter.select=function(cellval,opts){cellval=String(cellval);var oSelect=false,ret=[],sep,delim;if(opts.colModel.formatoptions!==undefined){oSelect=opts.colModel.formatoptions.value;sep=opts.colModel.formatoptions.separator===undefined?":":opts.colModel.formatoptions.separator;delim=opts.colModel.formatoptions.delimiter===undefined?";":opts.colModel.formatoptions.delimiter;}else if(opts.colModel.editoptions!==undefined){oSelect=opts.colModel.editoptions.value;sep=opts.colModel.editoptions.separator===undefined?":":opts.colModel.editoptions.separator;delim=opts.colModel.editoptions.delimiter===undefined?";":opts.colModel.editoptions.delimiter;}
if(oSelect){var msl=opts.colModel.editoptions.multiple===true?true:false,scell=[],sv;if(msl){scell=cellval.split(",");scell=$.map(scell,function(n){return $.trim(n);});}
if($.fmatter.isString(oSelect)){var so=oSelect.split(delim),j=0,i;for(i=0;i<so.length;i++){sv=so[i].split(sep);if(sv.length>2){sv[1]=$.map(sv,function(n,i){if(i>0){return n;}}).join(sep);}
if(msl){if($.inArray(sv[0],scell)>-1){ret[j]=sv[1];j++;}}else if($.trim(sv[0])===$.trim(cellval)){ret[0]=sv[1];break;}}}else if($.fmatter.isObject(oSelect)){if(msl){ret=$.map(scell,function(n){return oSelect[n];});}else{ret[0]=oSelect[cellval]||"";}}}
cellval=ret.join(", ");return cellval===""?$.fn.fmatter.defaultFormat(cellval,opts):cellval;};$.fn.fmatter.rowactions=function(act){var $tr=$(this).closest("tr.jqgrow"),rid=$tr.attr("id"),$id=$(this).closest("table.ui-jqgrid-btable").attr('id').replace(/_frozen([^_]*)$/,'$1'),$grid=$("#"+$id),$t=$grid[0],p=$t.p,cm=p.colModel[$.jgrid.getCellIndex(this)],$actionsDiv=cm.frozen?$("tr#"+rid+" td:eq("+$.jgrid.getCellIndex(this)+") > div",$grid):$(this).parent(),op={keys:false,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null,restoreAfterError:true,mtype:"POST",delOptions:{},editOptions:{}},saverow=function(rowid,res){if($.isFunction(op.afterSave)){op.afterSave.call($t,rowid,res);}
$actionsDiv.find("div.ui-inline-edit,div.ui-inline-del").show();$actionsDiv.find("div.ui-inline-save,div.ui-inline-cancel").hide();},restorerow=function(rowid){if($.isFunction(op.afterRestore)){op.afterRestore.call($t,rowid);}
$actionsDiv.find("div.ui-inline-edit,div.ui-inline-del").show();$actionsDiv.find("div.ui-inline-save,div.ui-inline-cancel").hide();};if(cm.formatoptions!==undefined){op=$.extend(op,cm.formatoptions);}
if(p.editOptions!==undefined){op.editOptions=p.editOptions;}
if(p.delOptions!==undefined){op.delOptions=p.delOptions;}
if($tr.hasClass("jqgrid-new-row")){op.extraparam[p.prmNames.oper]=p.prmNames.addoper;}
var actop={keys:op.keys,oneditfunc:op.onEdit,successfunc:op.onSuccess,url:op.url,extraparam:op.extraparam,aftersavefunc:saverow,errorfunc:op.onError,afterrestorefunc:restorerow,restoreAfterError:op.restoreAfterError,mtype:op.mtype};switch(act){case'edit':$grid.jqGrid('editRow',rid,actop);$actionsDiv.find("div.ui-inline-edit,div.ui-inline-del").hide();$actionsDiv.find("div.ui-inline-save,div.ui-inline-cancel").show();$grid.triggerHandler("jqGridAfterGridComplete");break;case'save':if($grid.jqGrid('saveRow',rid,actop)){$actionsDiv.find("div.ui-inline-edit,div.ui-inline-del").show();$actionsDiv.find("div.ui-inline-save,div.ui-inline-cancel").hide();$grid.triggerHandler("jqGridAfterGridComplete");}
break;case'cancel':$grid.jqGrid('restoreRow',rid,restorerow);$actionsDiv.find("div.ui-inline-edit,div.ui-inline-del").show();$actionsDiv.find("div.ui-inline-save,div.ui-inline-cancel").hide();$grid.triggerHandler("jqGridAfterGridComplete");break;case'del':$grid.jqGrid('delGridRow',rid,op.delOptions);break;case'formedit':$grid.jqGrid('setSelection',rid);$grid.jqGrid('editGridRow',rid,op.editOptions);break;}};$.fn.fmatter.actions=function(cellval,opts){var op={keys:false,editbutton:true,delbutton:true,editformbutton:false},rowid=opts.rowId,str="",ocl;if(opts.colModel.formatoptions!==undefined){op=$.extend(op,opts.colModel.formatoptions);}
if(rowid===undefined||$.fmatter.isEmpty(rowid)){return"";}
if(op.editformbutton){ocl="id='jEditButton_"+rowid+"' onclick=jQuery.fn.fmatter.rowactions.call(this,'formedit'); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";str+="<div title='"+$.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+ocl+"><span class='ui-icon ui-icon-pencil'></span></div>";}else if(op.editbutton){ocl="id='jEditButton_"+rowid+"' onclick=jQuery.fn.fmatter.rowactions.call(this,'edit'); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover') ";str+="<div title='"+$.jgrid.nav.edittitle+"' style='float:left;cursor:pointer;' class='ui-pg-div ui-inline-edit' "+ocl+"><span class='ui-icon ui-icon-pencil'></span></div>";}
if(op.delbutton){ocl="id='jDeleteButton_"+rowid+"' onclick=jQuery.fn.fmatter.rowactions.call(this,'del'); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";str+="<div title='"+$.jgrid.nav.deltitle+"' style='float:left;margin-left:5px;' class='ui-pg-div ui-inline-del' "+ocl+"><span class='ui-icon ui-icon-trash'></span></div>";}
ocl="id='jSaveButton_"+rowid+"' onclick=jQuery.fn.fmatter.rowactions.call(this,'save'); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";str+="<div title='"+$.jgrid.edit.bSubmit+"' style='float:left;display:none' class='ui-pg-div ui-inline-save' "+ocl+"><span class='ui-icon ui-icon-disk'></span></div>";ocl="id='jCancelButton_"+rowid+"' onclick=jQuery.fn.fmatter.rowactions.call(this,'cancel'); onmouseover=jQuery(this).addClass('ui-state-hover'); onmouseout=jQuery(this).removeClass('ui-state-hover'); ";str+="<div title='"+$.jgrid.edit.bCancel+"' style='float:left;display:none;margin-left:5px;' class='ui-pg-div ui-inline-cancel' "+ocl+"><span class='ui-icon ui-icon-cancel'></span></div>";return"<div style='margin-left:8px;'>"+str+"</div>";};$.unformat=function(cellval,options,pos,cnt){var ret,formatType=options.colModel.formatter,op=options.colModel.formatoptions||{},sep,re=/([\.\*\_\'\(\)\{\}\+\?\\])/g,unformatFunc=options.colModel.unformat||($.fn.fmatter[formatType]&&$.fn.fmatter[formatType].unformat);if(unformatFunc!==undefined&&$.isFunction(unformatFunc)){ret=unformatFunc.call(this,$(cellval).text(),options,cellval);}else if(formatType!==undefined&&$.fmatter.isString(formatType)){var opts=$.jgrid.formatter||{},stripTag;switch(formatType){case'integer':op=$.extend({},opts.integer,op);sep=op.thousandsSeparator.replace(re,"\\$1");stripTag=new RegExp(sep,"g");ret=$(cellval).text().replace(stripTag,'');break;case'number':op=$.extend({},opts.number,op);sep=op.thousandsSeparator.replace(re,"\\$1");stripTag=new RegExp(sep,"g");ret=$(cellval).text().replace(stripTag,"").replace(op.decimalSeparator,'.');break;case'currency':op=$.extend({},opts.currency,op);sep=op.thousandsSeparator.replace(re,"\\$1");stripTag=new RegExp(sep,"g");ret=$(cellval).text();if(op.prefix&&op.prefix.length){ret=ret.substr(op.prefix.length);}
if(op.suffix&&op.suffix.length){ret=ret.substr(0,ret.length-op.suffix.length);}
ret=ret.replace(stripTag,'').replace(op.decimalSeparator,'.');break;case'checkbox':var cbv=(options.colModel.editoptions)?options.colModel.editoptions.value.split(":"):["Yes","No"];ret=$('input',cellval).is(":checked")?cbv[0]:cbv[1];break;case'select':ret=$.unformat.select(cellval,options,pos,cnt);break;case'actions':return"";default:ret=$(cellval).text();}}
return ret!==undefined?ret:cnt===true?$(cellval).text():$.jgrid.htmlDecode($(cellval).html());};$.unformat.select=function(cellval,options,pos,cnt){var ret=[];var cell=$(cellval).text();if(cnt===true){return cell;}
var op=$.extend({},options.colModel.formatoptions!==undefined?options.colModel.formatoptions:options.colModel.editoptions),sep=op.separator===undefined?":":op.separator,delim=op.delimiter===undefined?";":op.delimiter;if(op.value){var oSelect=op.value,msl=op.multiple===true?true:false,scell=[],sv;if(msl){scell=cell.split(",");scell=$.map(scell,function(n){return $.trim(n);});}
if($.fmatter.isString(oSelect)){var so=oSelect.split(delim),j=0,i;for(i=0;i<so.length;i++){sv=so[i].split(sep);if(sv.length>2){sv[1]=$.map(sv,function(n,i){if(i>0){return n;}}).join(sep);}
if(msl){if($.inArray(sv[1],scell)>-1){ret[j]=sv[0];j++;}}else if($.trim(sv[1])===$.trim(cell)){ret[0]=sv[0];break;}}}else if($.fmatter.isObject(oSelect)||$.isArray(oSelect)){if(!msl){scell[0]=cell;}
ret=$.map(scell,function(n){var rv;$.each(oSelect,function(i,val){if(val===n){rv=i;return false;}});if(rv!==undefined){return rv;}});}
return ret.join(", ");}
return cell||"";};$.unformat.date=function(cellval,opts){var op=$.jgrid.formatter.date||{};if(opts.formatoptions!==undefined){op=$.extend({},op,opts.formatoptions);}
if(!$.fmatter.isEmpty(cellval)){return $.jgrid.parseDate(op.newformat,cellval,op.srcformat,op);}
return $.fn.fmatter.defaultFormat(cellval,opts);};})(jQuery);(function($){"use strict";$.extend($.jgrid,{showModal:function(h){h.w.show();},closeModal:function(h){h.w.hide().attr("aria-hidden","true");if(h.o){h.o.remove();}},hideModal:function(selector,o){o=$.extend({jqm:true,gb:''},o||{});if(o.onClose){var oncret=o.gb&&typeof o.gb==="string"&&o.gb.substr(0,6)==="#gbox_"?o.onClose.call($("#"+o.gb.substr(6))[0],selector):o.onClose(selector);if(typeof oncret==='boolean'&&!oncret){return;}}
if($.fn.jqm&&o.jqm===true){$(selector).attr("aria-hidden","true").jqmHide();}else{if(o.gb!==''){try{$(".jqgrid-overlay:first",o.gb).hide();}catch(e){}}
$(selector).hide().attr("aria-hidden","true");}},findPos:function(obj){var curleft=0,curtop=0;if(obj.offsetParent){do{curleft+=obj.offsetLeft;curtop+=obj.offsetTop;}while(obj=obj.offsetParent);}
return[curleft,curtop];},createModal:function(aIDs,content,p,insertSelector,posSelector,appendsel,css){p=$.extend(true,{},$.jgrid.jqModal||{},p);var mw=document.createElement('div'),rtlsup,self=this;css=$.extend({},css||{});rtlsup=$(p.gbox).attr("dir")==="rtl"?true:false;mw.className="ui-widget ui-widget-content ui-corner-all ui-jqdialog";mw.id=aIDs.themodal;var mh=document.createElement('div');mh.className="ui-jqdialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix";mh.id=aIDs.modalhead;$(mh).append("<span class='ui-jqdialog-title'>"+p.caption+"</span>");var ahr=$("<a class='ui-jqdialog-titlebar-close ui-corner-all'></a>").hover(function(){ahr.addClass('ui-state-hover');},function(){ahr.removeClass('ui-state-hover');}).append("<span class='ui-icon ui-icon-closethick'></span>");$(mh).append(ahr);if(rtlsup){mw.dir="rtl";$(".ui-jqdialog-title",mh).css("float","right");$(".ui-jqdialog-titlebar-close",mh).css("left",0.3+"em");}else{mw.dir="ltr";$(".ui-jqdialog-title",mh).css("float","left");$(".ui-jqdialog-titlebar-close",mh).css("right",0.3+"em");}
var mc=document.createElement('div');$(mc).addClass("ui-jqdialog-content ui-widget-content").attr("id",aIDs.modalcontent);$(mc).append(content);mw.appendChild(mc);$(mw).prepend(mh);if(appendsel===true){$('body').append(mw);}
else if(typeof appendsel==="string"){$(appendsel).append(mw);}else{$(mw).insertBefore(insertSelector);}
$(mw).css(css);if(p.jqModal===undefined){p.jqModal=true;}
var coord={};if($.fn.jqm&&p.jqModal===true){if(p.left===0&&p.top===0&&p.overlay){var pos=[];pos=$.jgrid.findPos(posSelector);p.left=pos[0]+4;p.top=pos[1]+4;}
coord.top=p.top+"px";coord.left=p.left;}else if(p.left!==0||p.top!==0){coord.left=p.left;coord.top=p.top+"px";}
$("a.ui-jqdialog-titlebar-close",mh).click(function(){var oncm=$("#"+$.jgrid.jqID(aIDs.themodal)).data("onClose")||p.onClose;var gboxclose=$("#"+$.jgrid.jqID(aIDs.themodal)).data("gbox")||p.gbox;self.hideModal("#"+$.jgrid.jqID(aIDs.themodal),{gb:gboxclose,jqm:p.jqModal,onClose:oncm});return false;});if(p.width===0||!p.width){p.width=300;}
if(p.height===0||!p.height){p.height=200;}
if(!p.zIndex){var parentZ=$(insertSelector).parents("*[role=dialog]").filter(':first').css("z-index");if(parentZ){p.zIndex=parseInt(parentZ,10)+2;}else{p.zIndex=950;}}
var rtlt=0;if(rtlsup&&coord.left&&!appendsel){rtlt=$(p.gbox).width()-(!isNaN(p.width)?parseInt(p.width,10):0)-8;coord.left=parseInt(coord.left,10)+parseInt(rtlt,10);}
if(coord.left){coord.left+="px";}
$(mw).css($.extend({width:isNaN(p.width)?"auto":p.width+"px",height:isNaN(p.height)?"auto":p.height+"px",zIndex:p.zIndex,overflow:'hidden'},coord)).attr({tabIndex:"-1","role":"dialog","aria-labelledby":aIDs.modalhead,"aria-hidden":"true"});if(p.drag===undefined){p.drag=true;}
if(p.resize===undefined){p.resize=true;}
if(p.drag){$(mh).css('cursor','move');if($.fn.jqDrag){$(mw).jqDrag(mh);}else{try{$(mw).draggable({handle:$("#"+$.jgrid.jqID(mh.id))});}catch(e){}}}
if(p.resize){if($.fn.jqResize){$(mw).append("<div class='jqResize ui-resizable-handle ui-resizable-se ui-icon ui-icon-gripsmall-diagonal-se'></div>");$("#"+$.jgrid.jqID(aIDs.themodal)).jqResize(".jqResize",aIDs.scrollelm?"#"+$.jgrid.jqID(aIDs.scrollelm):false);}else{try{$(mw).resizable({handles:'se, sw',alsoResize:aIDs.scrollelm?"#"+$.jgrid.jqID(aIDs.scrollelm):false});}catch(r){}}}
if(p.closeOnEscape===true){$(mw).keydown(function(e){if(e.which==27){var cone=$("#"+$.jgrid.jqID(aIDs.themodal)).data("onClose")||p.onClose;self.hideModal("#"+$.jgrid.jqID(aIDs.themodal),{gb:p.gbox,jqm:p.jqModal,onClose:cone});}});}},viewModal:function(selector,o){o=$.extend({toTop:true,overlay:10,modal:false,overlayClass:'ui-widget-overlay',onShow:$.jgrid.showModal,onHide:$.jgrid.closeModal,gbox:'',jqm:true,jqM:true},o||{});if($.fn.jqm&&o.jqm===true){if(o.jqM){$(selector).attr("aria-hidden","false").jqm(o).jqmShow();}else{$(selector).attr("aria-hidden","false").jqmShow();}}else{if(o.gbox!==''){$(".jqgrid-overlay:first",o.gbox).show();$(selector).data("gbox",o.gbox);}
$(selector).show().attr("aria-hidden","false");try{$(':input:visible',selector)[0].focus();}catch(_){}}},info_dialog:function(caption,content,c_b,modalopt){var mopt={width:290,height:'auto',dataheight:'auto',drag:true,resize:false,left:250,top:170,zIndex:1000,jqModal:true,modal:false,closeOnEscape:true,align:'center',buttonalign:'center',buttons:[]};$.extend(true,mopt,$.jgrid.jqModal||{},{caption:"<b>"+caption+"</b>"},modalopt||{});var jm=mopt.jqModal,self=this;if($.fn.jqm&&!jm){jm=false;}
var buttstr="",i;if(mopt.buttons.length>0){for(i=0;i<mopt.buttons.length;i++){if(mopt.buttons[i].id===undefined){mopt.buttons[i].id="info_button_"+i;}
buttstr+="<a id='"+mopt.buttons[i].id+"' class='fm-button ui-state-default ui-corner-all'>"+mopt.buttons[i].text+"</a>";}}
var dh=isNaN(mopt.dataheight)?mopt.dataheight:mopt.dataheight+"px",cn="text-align:"+mopt.align+";";var cnt="<div id='info_id'>";cnt+="<div id='infocnt' style='margin:0px;padding-bottom:1em;width:100%;overflow:auto;position:relative;height:"+dh+";"+cn+"'>"+content+"</div>";cnt+=c_b?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+mopt.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'><a id='closedialog' class='fm-button ui-state-default ui-corner-all'>"+c_b+"</a>"+buttstr+"</div>":buttstr!==""?"<div class='ui-widget-content ui-helper-clearfix' style='text-align:"+mopt.buttonalign+";padding-bottom:0.8em;padding-top:0.5em;background-image: none;border-width: 1px 0 0 0;'>"+buttstr+"</div>":"";cnt+="</div>";try{if($("#info_dialog").attr("aria-hidden")==="false"){$.jgrid.hideModal("#info_dialog",{jqm:jm});}
$("#info_dialog").remove();}catch(e){}
$.jgrid.createModal({themodal:'info_dialog',modalhead:'info_head',modalcontent:'info_content',scrollelm:'infocnt'},cnt,mopt,'','',true);if(buttstr){$.each(mopt.buttons,function(i){$("#"+$.jgrid.jqID(this.id),"#info_id").bind('click',function(){mopt.buttons[i].onClick.call($("#info_dialog"));return false;});});}
$("#closedialog","#info_id").click(function(){self.hideModal("#info_dialog",{jqm:jm,onClose:$("#info_dialog").data("onClose")||mopt.onClose,gb:$("#info_dialog").data("gbox")||mopt.gbox});return false;});$(".fm-button","#info_dialog").hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});if($.isFunction(mopt.beforeOpen)){mopt.beforeOpen();}
$.jgrid.viewModal("#info_dialog",{onHide:function(h){h.w.hide().remove();if(h.o){h.o.remove();}},modal:mopt.modal,jqm:jm});if($.isFunction(mopt.afterOpen)){mopt.afterOpen();}
try{$("#info_dialog").focus();}catch(m){}},bindEv:function(el,opt){var $t=this;if($.isFunction(opt.dataInit)){opt.dataInit.call($t,el,opt);}
if(opt.dataEvents){$.each(opt.dataEvents,function(){if(this.data!==undefined){$(el).bind(this.type,this.data,this.fn);}else{$(el).bind(this.type,this.fn);}});}},createEl:function(eltype,options,vl,autowidth,ajaxso){var elem="",$t=this;function setAttributes(elm,atr,exl){var exclude=['dataInit','dataEvents','dataUrl','buildSelect','sopt','searchhidden','defaultValue','attr','custom_element','custom_value'];if(exl!==undefined&&$.isArray(exl)){$.merge(exclude,exl);}
$.each(atr,function(key,value){if($.inArray(key,exclude)===-1){$(elm).attr(key,value);}});if(!atr.hasOwnProperty('id')){$(elm).attr('id',$.jgrid.randId());}}
switch(eltype){case"textarea":elem=document.createElement("textarea");if(autowidth){if(!options.cols){$(elem).css({width:"98%"});}}else if(!options.cols){options.cols=20;}
if(!options.rows){options.rows=2;}
if(vl==='&nbsp;'||vl==='&#160;'||(vl.length===1&&vl.charCodeAt(0)===160)){vl="";}
elem.value=vl;setAttributes(elem,options);$(elem).attr({"role":"textbox","multiline":"true"});break;case"checkbox":elem=document.createElement("input");elem.type="checkbox";if(!options.value){var vl1=(vl+"").toLowerCase();if(vl1.search(/(false|f|0|no|n|off|undefined)/i)<0&&vl1!==""){elem.checked=true;elem.defaultChecked=true;elem.value=vl;}else{elem.value="on";}
$(elem).attr("offval","off");}else{var cbval=options.value.split(":");if(vl===cbval[0]){elem.checked=true;elem.defaultChecked=true;}
elem.value=cbval[0];$(elem).attr("offval",cbval[1]);}
setAttributes(elem,options,['value']);$(elem).attr("role","checkbox");break;case"select":elem=document.createElement("select");elem.setAttribute("role","select");var msl,ovm=[];if(options.multiple===true){msl=true;elem.multiple="multiple";$(elem).attr("aria-multiselectable","true");}else{msl=false;}
if(options.dataUrl!==undefined){var rowid=options.name?String(options.id).substring(0,String(options.id).length-String(options.name).length-1):String(options.id),postData=options.postData||ajaxso.postData;if($t.p&&$t.p.idPrefix){rowid=$.jgrid.stripPref($t.p.idPrefix,rowid);}
$.ajax($.extend({url:$.isFunction(options.dataUrl)?options.dataUrl.call($t,rowid,vl,String(options.name)):options.dataUrl,type:"GET",dataType:"html",data:$.isFunction(postData)?postData.call($t,rowid,vl,String(options.name)):postData,context:{elem:elem,options:options,vl:vl},success:function(data){var ovm=[],elem=this.elem,vl=this.vl,options=$.extend({},this.options),msl=options.multiple===true,a=$.isFunction(options.buildSelect)?options.buildSelect.call($t,data):data;if(typeof a==='string'){a=$($.trim(a)).html();}
if(a){$(elem).append(a);setAttributes(elem,options,postData?['postData']:undefined);if(options.size===undefined){options.size=msl?3:1;}
if(msl){ovm=vl.split(",");ovm=$.map(ovm,function(n){return $.trim(n);});}else{ovm[0]=$.trim(vl);}
setTimeout(function(){$("option",elem).each(function(i){if(i===0&&elem.multiple){this.selected=false;}
$(this).attr("role","option");if($.inArray($.trim($(this).text()),ovm)>-1||$.inArray($.trim($(this).val()),ovm)>-1){this.selected="selected";}});},0);}}},ajaxso||{}));}else if(options.value){var i;if(options.size===undefined){options.size=msl?3:1;}
if(msl){ovm=vl.split(",");ovm=$.map(ovm,function(n){return $.trim(n);});}
if(typeof options.value==='function'){options.value=options.value();}
var so,sv,ov,sep=options.separator===undefined?":":options.separator,delim=options.delimiter===undefined?";":options.delimiter;if(typeof options.value==='string'){so=options.value.split(delim);for(i=0;i<so.length;i++){sv=so[i].split(sep);if(sv.length>2){sv[1]=$.map(sv,function(n,ii){if(ii>0){return n;}}).join(sep);}
ov=document.createElement("option");ov.setAttribute("role","option");ov.value=sv[0];ov.innerHTML=sv[1];elem.appendChild(ov);if(!msl&&($.trim(sv[0])===$.trim(vl)||$.trim(sv[1])===$.trim(vl))){ov.selected="selected";}
if(msl&&($.inArray($.trim(sv[1]),ovm)>-1||$.inArray($.trim(sv[0]),ovm)>-1)){ov.selected="selected";}}}else if(typeof options.value==='object'){var oSv=options.value,key;for(key in oSv){if(oSv.hasOwnProperty(key)){ov=document.createElement("option");ov.setAttribute("role","option");ov.value=key;ov.innerHTML=oSv[key];elem.appendChild(ov);if(!msl&&($.trim(key)===$.trim(vl)||$.trim(oSv[key])===$.trim(vl))){ov.selected="selected";}
if(msl&&($.inArray($.trim(oSv[key]),ovm)>-1||$.inArray($.trim(key),ovm)>-1)){ov.selected="selected";}}}}
setAttributes(elem,options,['value']);}
break;case"text":case"password":case"button":var role;if(eltype==="button"){role="button";}else{role="textbox";}
elem=document.createElement("input");elem.type=eltype;elem.value=vl;setAttributes(elem,options);if(eltype!=="button"){if(autowidth){if(!options.size){$(elem).css({width:"98%"});}}else if(!options.size){options.size=20;}}
$(elem).attr("role",role);break;case"image":case"file":elem=document.createElement("input");elem.type=eltype;setAttributes(elem,options);break;case"custom":elem=document.createElement("span");try{if($.isFunction(options.custom_element)){var celm=options.custom_element.call($t,vl,options);if(celm){celm=$(celm).addClass("customelement").attr({id:options.id,name:options.name});$(elem).empty().append(celm);}else{throw"e2";}}else{throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_element' "+$.jgrid.edit.msg.nodefined,$.jgrid.edit.bClose);}
if(e==="e2"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_element' "+$.jgrid.edit.msg.novalue,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,typeof e==="string"?e:e.message,$.jgrid.edit.bClose);}}
break;}
return elem;},checkDate:function(format,date){var daysInFebruary=function(year){return(((year%4===0)&&(year%100!==0||(year%400===0)))?29:28);},tsp={},sep;format=format.toLowerCase();if(format.indexOf("/")!==-1){sep="/";}else if(format.indexOf("-")!==-1){sep="-";}else if(format.indexOf(".")!==-1){sep=".";}else{sep="/";}
format=format.split(sep);date=date.split(sep);if(date.length!==3){return false;}
var j=-1,yln,dln=-1,mln=-1,i;for(i=0;i<format.length;i++){var dv=isNaN(date[i])?0:parseInt(date[i],10);tsp[format[i]]=dv;yln=format[i];if(yln.indexOf("y")!==-1){j=i;}
if(yln.indexOf("m")!==-1){mln=i;}
if(yln.indexOf("d")!==-1){dln=i;}}
if(format[j]==="y"||format[j]==="yyyy"){yln=4;}else if(format[j]==="yy"){yln=2;}else{yln=-1;}
var daysInMonth=[0,31,29,31,30,31,30,31,31,30,31,30,31],strDate;if(j===-1){return false;}
strDate=tsp[format[j]].toString();if(yln===2&&strDate.length===1){yln=1;}
if(strDate.length!==yln||(tsp[format[j]]===0&&date[j]!=="00")){return false;}
if(mln===-1){return false;}
strDate=tsp[format[mln]].toString();if(strDate.length<1||tsp[format[mln]]<1||tsp[format[mln]]>12){return false;}
if(dln===-1){return false;}
strDate=tsp[format[dln]].toString();if(strDate.length<1||tsp[format[dln]]<1||tsp[format[dln]]>31||(tsp[format[mln]]===2&&tsp[format[dln]]>daysInFebruary(tsp[format[j]]))||tsp[format[dln]]>daysInMonth[tsp[format[mln]]]){return false;}
return true;},isEmpty:function(val){if(val.match(/^\s+$/)||val===""){return true;}
return false;},checkTime:function(time){var re=/^(\d{1,2}):(\d{2})([apAP][Mm])?$/,regs;if(!$.jgrid.isEmpty(time)){regs=time.match(re);if(regs){if(regs[3]){if(regs[1]<1||regs[1]>12){return false;}}else{if(regs[1]>23){return false;}}
if(regs[2]>59){return false;}}else{return false;}}
return true;},checkValues:function(val,valref,customobject,nam){var edtrul,i,nm,dft,len,g=this,cm=g.p.colModel;if(customobject===undefined){if(typeof valref==='string'){for(i=0,len=cm.length;i<len;i++){if(cm[i].name===valref){edtrul=cm[i].editrules;valref=i;if(cm[i].formoptions!=null){nm=cm[i].formoptions.label;}
break;}}}else if(valref>=0){edtrul=cm[valref].editrules;}}else{edtrul=customobject;nm=nam===undefined?"_":nam;}
if(edtrul){if(!nm){nm=g.p.colNames!=null?g.p.colNames[valref]:cm[valref].label;}
if(edtrul.required===true){if($.jgrid.isEmpty(val)){return[false,nm+": "+$.jgrid.edit.msg.required,""];}}
var rqfield=edtrul.required===false?false:true;if(edtrul.number===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){if(isNaN(val)){return[false,nm+": "+$.jgrid.edit.msg.number,""];}}}
if(edtrul.minValue!==undefined&&!isNaN(edtrul.minValue)){if(parseFloat(val)<parseFloat(edtrul.minValue)){return[false,nm+": "+$.jgrid.edit.msg.minValue+" "+edtrul.minValue,""];}}
if(edtrul.maxValue!==undefined&&!isNaN(edtrul.maxValue)){if(parseFloat(val)>parseFloat(edtrul.maxValue)){return[false,nm+": "+$.jgrid.edit.msg.maxValue+" "+edtrul.maxValue,""];}}
var filter;if(edtrul.email===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){filter=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;if(!filter.test(val)){return[false,nm+": "+$.jgrid.edit.msg.email,""];}}}
if(edtrul.integer===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){if(isNaN(val)){return[false,nm+": "+$.jgrid.edit.msg.integer,""];}
if((val%1!==0)||(val.indexOf('.')!==-1)){return[false,nm+": "+$.jgrid.edit.msg.integer,""];}}}
if(edtrul.date===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){if(cm[valref].formatoptions&&cm[valref].formatoptions.newformat){dft=cm[valref].formatoptions.newformat;if($.jgrid.formatter.date.masks.hasOwnProperty(dft)){dft=$.jgrid.formatter.date.masks[dft];}}else{dft=cm[valref].datefmt||"Y-m-d";}
if(!$.jgrid.checkDate(dft,val)){return[false,nm+": "+$.jgrid.edit.msg.date+" - "+dft,""];}}}
if(edtrul.time===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){if(!$.jgrid.checkTime(val)){return[false,nm+": "+$.jgrid.edit.msg.date+" - hh:mm (am/pm)",""];}}}
if(edtrul.url===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){filter=/^(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;if(!filter.test(val)){return[false,nm+": "+$.jgrid.edit.msg.url,""];}}}
if(edtrul.custom===true){if(!(rqfield===false&&$.jgrid.isEmpty(val))){if($.isFunction(edtrul.custom_func)){var ret=edtrul.custom_func.call(g,val,nm,valref);return $.isArray(ret)?ret:[false,$.jgrid.edit.msg.customarray,""];}
return[false,$.jgrid.edit.msg.customfcheck,""];}}}
return[true,"",""];}});})(jQuery);(function($){"use strict";$.fn.jqFilter=function(arg){if(typeof arg==='string'){var fn=$.fn.jqFilter[arg];if(!fn){throw("jqFilter - No such method: "+arg);}
var args=$.makeArray(arguments).slice(1);return fn.apply(this,args);}
var p=$.extend(true,{filter:null,columns:[],onChange:null,afterRedraw:null,checkValues:null,error:false,errmsg:"",errorcheck:true,showQuery:true,sopt:null,ops:[],operands:null,numopts:['eq','ne','lt','le','gt','ge','nu','nn','in','ni'],stropts:['eq','ne','bw','bn','ew','en','cn','nc','nu','nn','in','ni'],strarr:['text','string','blob'],groupOps:[{op:"AND",text:"AND"},{op:"OR",text:"OR"}],groupButton:true,ruleButtons:true,direction:"ltr"},$.jgrid.filter,arg||{});return this.each(function(){if(this.filter){return;}
this.p=p;if(this.p.filter===null||this.p.filter===undefined){this.p.filter={groupOp:this.p.groupOps[0].op,rules:[],groups:[]};}
var i,len=this.p.columns.length,cl,isIE=/msie/i.test(navigator.userAgent)&&!window.opera;this.p.initFilter=$.extend(true,{},this.p.filter);if(!len){return;}
for(i=0;i<len;i++){cl=this.p.columns[i];if(cl.stype){cl.inputtype=cl.stype;}else if(!cl.inputtype){cl.inputtype='text';}
if(cl.sorttype){cl.searchtype=cl.sorttype;}else if(!cl.searchtype){cl.searchtype='string';}
if(cl.hidden===undefined){cl.hidden=false;}
if(!cl.label){cl.label=cl.name;}
if(cl.index){cl.name=cl.index;}
if(!cl.hasOwnProperty('searchoptions')){cl.searchoptions={};}
if(!cl.hasOwnProperty('searchrules')){cl.searchrules={};}}
if(this.p.showQuery){$(this).append("<table class='queryresult ui-widget ui-widget-content' style='display:block;max-width:440px;border:0px none;' dir='"+this.p.direction+"'><tbody><tr><td class='query'></td></tr></tbody></table>");}
var getGrid=function(){return $("#"+$.jgrid.jqID(p.id))[0]||null;};var checkData=function(val,colModelItem){var ret=[true,""],$t=getGrid();if($.isFunction(colModelItem.searchrules)){ret=colModelItem.searchrules.call($t,val,colModelItem);}else if($.jgrid&&$.jgrid.checkValues){try{ret=$.jgrid.checkValues.call($t,val,-1,colModelItem.searchrules,colModelItem.label);}catch(e){}}
if(ret&&ret.length&&ret[0]===false){p.error=!ret[0];p.errmsg=ret[1];}};this.onchange=function(){this.p.error=false;this.p.errmsg="";return $.isFunction(this.p.onChange)?this.p.onChange.call(this,this.p):false;};this.reDraw=function(){$("table.group:first",this).remove();var t=this.createTableForGroup(p.filter,null);$(this).append(t);if($.isFunction(this.p.afterRedraw)){this.p.afterRedraw.call(this,this.p);}};this.createTableForGroup=function(group,parentgroup){var that=this,i;var table=$("<table class='group ui-widget ui-widget-content' style='border:0px none;'><tbody></tbody></table>"),align="left";if(this.p.direction==="rtl"){align="right";table.attr("dir","rtl");}
if(parentgroup===null){table.append("<tr class='error' style='display:none;'><th colspan='5' class='ui-state-error' align='"+align+"'></th></tr>");}
var tr=$("<tr></tr>");table.append(tr);var th=$("<th colspan='5' align='"+align+"'></th>");tr.append(th);if(this.p.ruleButtons===true){var groupOpSelect=$("<select class='opsel'></select>");th.append(groupOpSelect);var str="",selected;for(i=0;i<p.groupOps.length;i++){selected=group.groupOp===that.p.groupOps[i].op?" selected='selected'":"";str+="<option value='"+that.p.groupOps[i].op+"'"+selected+">"+that.p.groupOps[i].text+"</option>";}
groupOpSelect.append(str).bind('change',function(){group.groupOp=$(groupOpSelect).val();that.onchange();});}
var inputAddSubgroup="<span></span>";if(this.p.groupButton){inputAddSubgroup=$("<input type='button' value='+ {}' title='Add subgroup' class='add-group'/>");inputAddSubgroup.bind('click',function(){if(group.groups===undefined){group.groups=[];}
group.groups.push({groupOp:p.groupOps[0].op,rules:[],groups:[]});that.reDraw();that.onchange();return false;});}
th.append(inputAddSubgroup);if(this.p.ruleButtons===true){var inputAddRule=$("<input type='button' value='+' title='Add rule' class='add-rule ui-add'/>"),cm;inputAddRule.bind('click',function(){if(group.rules===undefined){group.rules=[];}
for(i=0;i<that.p.columns.length;i++){var searchable=(that.p.columns[i].search===undefined)?true:that.p.columns[i].search,hidden=(that.p.columns[i].hidden===true),ignoreHiding=(that.p.columns[i].searchoptions.searchhidden===true);if((ignoreHiding&&searchable)||(searchable&&!hidden)){cm=that.p.columns[i];break;}}
var opr;if(cm.searchoptions.sopt){opr=cm.searchoptions.sopt;}else if(that.p.sopt){opr=that.p.sopt;}else if($.inArray(cm.searchtype,that.p.strarr)!==-1){opr=that.p.stropts;}else{opr=that.p.numopts;}
group.rules.push({field:cm.name,op:opr[0],data:""});that.reDraw();return false;});th.append(inputAddRule);}
if(parentgroup!==null){var inputDeleteGroup=$("<input type='button' value='-' title='Delete group' class='delete-group'/>");th.append(inputDeleteGroup);inputDeleteGroup.bind('click',function(){for(i=0;i<parentgroup.groups.length;i++){if(parentgroup.groups[i]===group){parentgroup.groups.splice(i,1);break;}}
that.reDraw();that.onchange();return false;});}
if(group.groups!==undefined){for(i=0;i<group.groups.length;i++){var trHolderForSubgroup=$("<tr></tr>");table.append(trHolderForSubgroup);var tdFirstHolderForSubgroup=$("<td class='first'></td>");trHolderForSubgroup.append(tdFirstHolderForSubgroup);var tdMainHolderForSubgroup=$("<td colspan='4'></td>");tdMainHolderForSubgroup.append(this.createTableForGroup(group.groups[i],group));trHolderForSubgroup.append(tdMainHolderForSubgroup);}}
if(group.groupOp===undefined){group.groupOp=that.p.groupOps[0].op;}
if(group.rules!==undefined){for(i=0;i<group.rules.length;i++){table.append(this.createTableRowForRule(group.rules[i],group));}}
return table;};this.createTableRowForRule=function(rule,group){var that=this,$t=getGrid(),tr=$("<tr></tr>"),i,op,trpar,cm,str="",selected;tr.append("<td class='first'></td>");var ruleFieldTd=$("<td class='columns'></td>");tr.append(ruleFieldTd);var ruleFieldSelect=$("<select></select>"),ina,aoprs=[];ruleFieldTd.append(ruleFieldSelect);ruleFieldSelect.bind('change',function(){rule.field=$(ruleFieldSelect).val();trpar=$(this).parents("tr:first");for(i=0;i<that.p.columns.length;i++){if(that.p.columns[i].name===rule.field){cm=that.p.columns[i];break;}}
if(!cm){return;}
cm.searchoptions.id=$.jgrid.randId();if(isIE&&cm.inputtype==="text"){if(!cm.searchoptions.size){cm.searchoptions.size=10;}}
var elm=$.jgrid.createEl.call($t,cm.inputtype,cm.searchoptions,"",true,that.p.ajaxSelectOptions||{},true);$(elm).addClass("input-elm");if(cm.searchoptions.sopt){op=cm.searchoptions.sopt;}else if(that.p.sopt){op=that.p.sopt;}else if($.inArray(cm.searchtype,that.p.strarr)!==-1){op=that.p.stropts;}else{op=that.p.numopts;}
var s="",so=0;aoprs=[];$.each(that.p.ops,function(){aoprs.push(this.oper);});for(i=0;i<op.length;i++){ina=$.inArray(op[i],aoprs);if(ina!==-1){if(so===0){rule.op=that.p.ops[ina].oper;}
s+="<option value='"+that.p.ops[ina].oper+"'>"+that.p.ops[ina].text+"</option>";so++;}}
$(".selectopts",trpar).empty().append(s);$(".selectopts",trpar)[0].selectedIndex=0;if($.jgrid.msie&&$.jgrid.msiever()<9){var sw=parseInt($("select.selectopts",trpar)[0].offsetWidth,10)+1;$(".selectopts",trpar).width(sw);$(".selectopts",trpar).css("width","auto");}
$(".data",trpar).empty().append(elm);$.jgrid.bindEv.call($t,elm,cm.searchoptions);$(".input-elm",trpar).bind('change',function(e){var tmo=$(this).hasClass("ui-autocomplete-input")?200:0;setTimeout(function(){var elem=e.target;rule.data=elem.nodeName.toUpperCase()==="SPAN"&&cm.searchoptions&&$.isFunction(cm.searchoptions.custom_value)?cm.searchoptions.custom_value.call($t,$(elem).children(".customelement:first"),'get'):elem.value;that.onchange();},tmo);});setTimeout(function(){rule.data=$(elm).val();that.onchange();},0);});var j=0;for(i=0;i<that.p.columns.length;i++){var searchable=(that.p.columns[i].search===undefined)?true:that.p.columns[i].search,hidden=(that.p.columns[i].hidden===true),ignoreHiding=(that.p.columns[i].searchoptions.searchhidden===true);if((ignoreHiding&&searchable)||(searchable&&!hidden)){selected="";if(rule.field===that.p.columns[i].name){selected=" selected='selected'";j=i;}
str+="<option value='"+that.p.columns[i].name+"'"+selected+">"+that.p.columns[i].label+"</option>";}}
ruleFieldSelect.append(str);var ruleOperatorTd=$("<td class='operators'></td>");tr.append(ruleOperatorTd);cm=p.columns[j];cm.searchoptions.id=$.jgrid.randId();if(isIE&&cm.inputtype==="text"){if(!cm.searchoptions.size){cm.searchoptions.size=10;}}
var ruleDataInput=$.jgrid.createEl.call($t,cm.inputtype,cm.searchoptions,rule.data,true,that.p.ajaxSelectOptions||{},true);if(rule.op==='nu'||rule.op==='nn'){$(ruleDataInput).attr('readonly','true');$(ruleDataInput).attr('disabled','true');}
var ruleOperatorSelect=$("<select class='selectopts'></select>");ruleOperatorTd.append(ruleOperatorSelect);ruleOperatorSelect.bind('change',function(){rule.op=$(ruleOperatorSelect).val();trpar=$(this).parents("tr:first");var rd=$(".input-elm",trpar)[0];if(rule.op==="nu"||rule.op==="nn"){rule.data="";if(rd.tagName.toUpperCase()!=='SELECT')rd.value="";rd.setAttribute("readonly","true");rd.setAttribute("disabled","true");}else{if(rd.tagName.toUpperCase()==='SELECT')rule.data=rd.value;rd.removeAttribute("readonly");rd.removeAttribute("disabled");}
that.onchange();});if(cm.searchoptions.sopt){op=cm.searchoptions.sopt;}else if(that.p.sopt){op=that.p.sopt;}else if($.inArray(cm.searchtype,that.p.strarr)!==-1){op=that.p.stropts;}else{op=that.p.numopts;}
str="";$.each(that.p.ops,function(){aoprs.push(this.oper);});for(i=0;i<op.length;i++){ina=$.inArray(op[i],aoprs);if(ina!==-1){selected=rule.op===that.p.ops[ina].oper?" selected='selected'":"";str+="<option value='"+that.p.ops[ina].oper+"'"+selected+">"+that.p.ops[ina].text+"</option>";}}
ruleOperatorSelect.append(str);var ruleDataTd=$("<td class='data'></td>");tr.append(ruleDataTd);ruleDataTd.append(ruleDataInput);$.jgrid.bindEv.call($t,ruleDataInput,cm.searchoptions);$(ruleDataInput).addClass("input-elm").bind('change',function(){rule.data=cm.inputtype==='custom'?cm.searchoptions.custom_value.call($t,$(this).children(".customelement:first"),'get'):$(this).val();that.onchange();});var ruleDeleteTd=$("<td></td>");tr.append(ruleDeleteTd);if(this.p.ruleButtons===true){var ruleDeleteInput=$("<input type='button' value='-' title='Delete rule' class='delete-rule ui-del'/>");ruleDeleteTd.append(ruleDeleteInput);ruleDeleteInput.bind('click',function(){for(i=0;i<group.rules.length;i++){if(group.rules[i]===rule){group.rules.splice(i,1);break;}}
that.reDraw();that.onchange();return false;});}
return tr;};this.getStringForGroup=function(group){var s="(",index;if(group.groups!==undefined){for(index=0;index<group.groups.length;index++){if(s.length>1){s+=" "+group.groupOp+" ";}
try{s+=this.getStringForGroup(group.groups[index]);}catch(eg){alert(eg);}}}
if(group.rules!==undefined){try{for(index=0;index<group.rules.length;index++){if(s.length>1){s+=" "+group.groupOp+" ";}
s+=this.getStringForRule(group.rules[index]);}}catch(e){alert(e);}}
s+=")";if(s==="()"){return"";}
return s;};this.getStringForRule=function(rule){var opUF="",opC="",i,cm,ret,val,numtypes=['int','integer','float','number','currency'];for(i=0;i<this.p.ops.length;i++){if(this.p.ops[i].oper===rule.op){opUF=this.p.operands.hasOwnProperty(rule.op)?this.p.operands[rule.op]:"";opC=this.p.ops[i].oper;break;}}
for(i=0;i<this.p.columns.length;i++){if(this.p.columns[i].name===rule.field){cm=this.p.columns[i];break;}}
if(cm===undefined){return"";}
val=rule.data;if(opC==='bw'||opC==='bn'){val=val+"%";}
if(opC==='ew'||opC==='en'){val="%"+val;}
if(opC==='cn'||opC==='nc'){val="%"+val+"%";}
if(opC==='in'||opC==='ni'){val=" ("+val+")";}
if(p.errorcheck){checkData(rule.data,cm);}
if($.inArray(cm.searchtype,numtypes)!==-1||opC==='nn'||opC==='nu'){ret=rule.field+" "+opUF+" "+val;}else{ret=rule.field+" "+opUF+" \""+val+"\"";}
return ret;};this.resetFilter=function(){this.p.filter=$.extend(true,{},this.p.initFilter);this.reDraw();this.onchange();};this.hideError=function(){$("th.ui-state-error",this).html("");$("tr.error",this).hide();};this.showError=function(){$("th.ui-state-error",this).html(this.p.errmsg);$("tr.error",this).show();};this.toUserFriendlyString=function(){return this.getStringForGroup(p.filter);};this.toString=function(){var that=this;function getStringRule(rule){if(that.p.errorcheck){var i,cm;for(i=0;i<that.p.columns.length;i++){if(that.p.columns[i].name===rule.field){cm=that.p.columns[i];break;}}
if(cm){checkData(rule.data,cm);}}
return rule.op+"(item."+rule.field+",'"+rule.data+"')";}
function getStringForGroup(group){var s="(",index;if(group.groups!==undefined){for(index=0;index<group.groups.length;index++){if(s.length>1){if(group.groupOp==="OR"){s+=" || ";}else{s+=" && ";}}
s+=getStringForGroup(group.groups[index]);}}
if(group.rules!==undefined){for(index=0;index<group.rules.length;index++){if(s.length>1){if(group.groupOp==="OR"){s+=" || ";}else{s+=" && ";}}
s+=getStringRule(group.rules[index]);}}
s+=")";if(s==="()"){return"";}
return s;}
return getStringForGroup(this.p.filter);};this.reDraw();if(this.p.showQuery){this.onchange();}
this.filter=true;});};$.extend($.fn.jqFilter,{toSQLString:function(){var s="";this.each(function(){s=this.toUserFriendlyString();});return s;},filterData:function(){var s;this.each(function(){s=this.p.filter;});return s;},getParameter:function(param){if(param!==undefined){if(this.p.hasOwnProperty(param)){return this.p[param];}}
return this.p;},resetFilter:function(){return this.each(function(){this.resetFilter();});},addFilter:function(pfilter){if(typeof pfilter==="string"){pfilter=$.jgrid.parse(pfilter);}
this.each(function(){this.p.filter=pfilter;this.reDraw();this.onchange();});}});})(jQuery);(function($){"use strict";var rp_ge={};$.jgrid.extend({searchGrid:function(p){p=$.extend(true,{recreateFilter:false,drag:true,sField:'searchField',sValue:'searchString',sOper:'searchOper',sFilter:'filters',loadDefaults:true,beforeShowSearch:null,afterShowSearch:null,onInitializeSearch:null,afterRedraw:null,afterChange:null,closeAfterSearch:false,closeAfterReset:false,closeOnEscape:false,searchOnEnter:false,multipleSearch:false,multipleGroup:false,top:0,left:0,jqModal:true,modal:false,resize:true,width:450,height:'auto',dataheight:'auto',showQuery:false,errorcheck:true,sopt:null,stringResult:undefined,onClose:null,onSearch:null,onReset:null,toTop:true,overlay:30,columns:[],tmplNames:null,tmplFilters:null,tmplLabel:' Template: ',showOnLoad:false,layer:null,operands:{"eq":"=","ne":"<>","lt":"<","le":"<=","gt":">","ge":">=","bw":"LIKE","bn":"NOT LIKE","in":"IN","ni":"NOT IN","ew":"LIKE","en":"NOT LIKE","cn":"LIKE","nc":"NOT LIKE","nu":"IS NULL","nn":"ISNOT NULL"}},$.jgrid.search,p||{});return this.each(function(){var $t=this;if(!$t.grid){return;}
var fid="fbox_"+$t.p.id,showFrm=true,mustReload=true,IDs={themodal:'searchmod'+fid,modalhead:'searchhd'+fid,modalcontent:'searchcnt'+fid,scrollelm:fid},defaultFilters=$t.p.postData[p.sFilter];if(typeof defaultFilters==="string"){defaultFilters=$.jgrid.parse(defaultFilters);}
if(p.recreateFilter===true){$("#"+$.jgrid.jqID(IDs.themodal)).remove();}
function showFilter(_filter){showFrm=$($t).triggerHandler("jqGridFilterBeforeShow",[_filter]);if(showFrm===undefined){showFrm=true;}
if(showFrm&&$.isFunction(p.beforeShowSearch)){showFrm=p.beforeShowSearch.call($t,_filter);}
if(showFrm){$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(fid),jqm:p.jqModal,modal:p.modal,overlay:p.overlay,toTop:p.toTop});$($t).triggerHandler("jqGridFilterAfterShow",[_filter]);if($.isFunction(p.afterShowSearch)){p.afterShowSearch.call($t,_filter);}}}
if($("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){showFilter($("#fbox_"+$.jgrid.jqID(+$t.p.id)));}else{var fil=$("<div><div id='"+fid+"' class='searchFilter' style='overflow:auto'></div></div>").insertBefore("#gview_"+$.jgrid.jqID($t.p.id)),align="left",butleft="";if($t.p.direction==="rtl"){align="right";butleft=" style='text-align:left'";fil.attr("dir","rtl");}
var columns=$.extend([],$t.p.colModel),bS="<a id='"+fid+"_search' class='fm-button ui-state-default ui-corner-all fm-button-icon-right ui-reset'><span class='ui-icon ui-icon-search'></span>"+p.Find+"</a>",bC="<a id='"+fid+"_reset' class='fm-button ui-state-default ui-corner-all fm-button-icon-left ui-search'><span class='ui-icon ui-icon-arrowreturnthick-1-w'></span>"+p.Reset+"</a>",bQ="",tmpl="",colnm,found=false,bt,cmi=-1;if(p.showQuery){bQ="<a id='"+fid+"_query' class='fm-button ui-state-default ui-corner-all fm-button-icon-left'><span class='ui-icon ui-icon-comment'></span>Query</a>";}
if(!p.columns.length){$.each(columns,function(i,n){if(!n.label){n.label=$t.p.colNames[i];}
if(!found){var searchable=(n.search===undefined)?true:n.search,hidden=(n.hidden===true),ignoreHiding=(n.searchoptions&&n.searchoptions.searchhidden===true);if((ignoreHiding&&searchable)||(searchable&&!hidden)){found=true;colnm=n.index||n.name;cmi=i;}}});}else{columns=p.columns;cmi=0;colnm=columns[0].index||columns[0].name;}
if((!defaultFilters&&colnm)||p.multipleSearch===false){var cmop="eq";if(cmi>=0&&columns[cmi].searchoptions&&columns[cmi].searchoptions.sopt){cmop=columns[cmi].searchoptions.sopt[0];}else if(p.sopt&&p.sopt.length){cmop=p.sopt[0];}
defaultFilters={groupOp:"AND",rules:[{field:colnm,op:cmop,data:""}]};}
found=false;if(p.tmplNames&&p.tmplNames.length){found=true;tmpl=p.tmplLabel;tmpl+="<select class='ui-template'>";tmpl+="<option value='default'>Default</option>";$.each(p.tmplNames,function(i,n){tmpl+="<option value='"+i+"'>"+n+"</option>";});tmpl+="</select>";}
bt="<table class='EditTable' style='border:0px none;margin-top:5px' id='"+fid+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='EditButton' style='text-align:"+align+"'>"+bC+tmpl+"</td><td class='EditButton' "+butleft+">"+bQ+bS+"</td></tr></tbody></table>";fid=$.jgrid.jqID(fid);$("#"+fid).jqFilter({columns:columns,filter:p.loadDefaults?defaultFilters:null,showQuery:p.showQuery,errorcheck:p.errorcheck,sopt:p.sopt,groupButton:p.multipleGroup,ruleButtons:p.multipleSearch,afterRedraw:p.afterRedraw,ops:p.odata,operands:p.operands,ajaxSelectOptions:$t.p.ajaxSelectOptions,groupOps:p.groupOps,onChange:function(){if(this.p.showQuery){$('.query',this).html(this.toUserFriendlyString());}
if($.isFunction(p.afterChange)){p.afterChange.call($t,$("#"+fid),p);}},direction:$t.p.direction,id:$t.p.id});fil.append(bt);if(found&&p.tmplFilters&&p.tmplFilters.length){$(".ui-template",fil).bind('change',function(){var curtempl=$(this).val();if(curtempl==="default"){$("#"+fid).jqFilter('addFilter',defaultFilters);}else{$("#"+fid).jqFilter('addFilter',p.tmplFilters[parseInt(curtempl,10)]);}
return false;});}
if(p.multipleGroup===true){p.multipleSearch=true;}
$($t).triggerHandler("jqGridFilterInitialize",[$("#"+fid)]);if($.isFunction(p.onInitializeSearch)){p.onInitializeSearch.call($t,$("#"+fid));}
p.gbox="#gbox_"+fid;if(p.layer){$.jgrid.createModal(IDs,fil,p,"#gview_"+$.jgrid.jqID($t.p.id),$("#gbox_"+$.jgrid.jqID($t.p.id))[0],"#"+$.jgrid.jqID(p.layer),{position:"relative"});}else{$.jgrid.createModal(IDs,fil,p,"#gview_"+$.jgrid.jqID($t.p.id),$("#gbox_"+$.jgrid.jqID($t.p.id))[0]);}
if(p.searchOnEnter||p.closeOnEscape){$("#"+$.jgrid.jqID(IDs.themodal)).keydown(function(e){var $target=$(e.target);if(p.searchOnEnter&&e.which===13&&!$target.hasClass('add-group')&&!$target.hasClass('add-rule')&&!$target.hasClass('delete-group')&&!$target.hasClass('delete-rule')&&(!$target.hasClass("fm-button")||!$target.is("[id$=_query]"))){$("#"+fid+"_search").focus().click();return false;}
if(p.closeOnEscape&&e.which===27){$("#"+$.jgrid.jqID(IDs.modalhead)).find(".ui-jqdialog-titlebar-close").focus().click();return false;}});}
if(bQ){$("#"+fid+"_query").bind('click',function(){$(".queryresult",fil).toggle();return false;});}
if(p.stringResult===undefined){p.stringResult=p.multipleSearch;}
$("#"+fid+"_search").bind('click',function(){var fl=$("#"+fid),sdata={},res,filters=fl.jqFilter('filterData');if(p.errorcheck){fl[0].hideError();if(!p.showQuery){fl.jqFilter('toSQLString');}
if(fl[0].p.error){fl[0].showError();return false;}}
if(p.stringResult){try{res=xmlJsonClass.toJson(filters,'','',false);}catch(e){try{res=JSON.stringify(filters);}catch(e2){}}
if(typeof res==="string"){sdata[p.sFilter]=res;$.each([p.sField,p.sValue,p.sOper],function(){sdata[this]="";});}}else{if(p.multipleSearch){sdata[p.sFilter]=filters;$.each([p.sField,p.sValue,p.sOper],function(){sdata[this]="";});}else{sdata[p.sField]=filters.rules[0].field;sdata[p.sValue]=filters.rules[0].data;sdata[p.sOper]=filters.rules[0].op;sdata[p.sFilter]="";}}
$t.p.search=true;$.extend($t.p.postData,sdata);mustReload=$($t).triggerHandler("jqGridFilterSearch");if(mustReload===undefined){mustReload=true;}
if(mustReload&&$.isFunction(p.onSearch)){mustReload=p.onSearch.call($t,$t.p.filters);}
if(mustReload!==false){$($t).trigger("reloadGrid",[{page:1}]);}
if(p.closeAfterSearch){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID($t.p.id),jqm:p.jqModal,onClose:p.onClose});}
return false;});$("#"+fid+"_reset").bind('click',function(){var sdata={},fl=$("#"+fid);$t.p.search=false;if(p.multipleSearch===false){sdata[p.sField]=sdata[p.sValue]=sdata[p.sOper]="";}else{sdata[p.sFilter]="";}
fl[0].resetFilter();if(found){$(".ui-template",fil).val("default");}
$.extend($t.p.postData,sdata);mustReload=$($t).triggerHandler("jqGridFilterReset");if(mustReload===undefined){mustReload=true;}
if(mustReload&&$.isFunction(p.onReset)){mustReload=p.onReset.call($t);}
if(mustReload!==false){$($t).trigger("reloadGrid",[{page:1}]);}
if(p.closeAfterReset){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID($t.p.id),jqm:p.jqModal,onClose:p.onClose});}
return false;});showFilter($("#"+fid));$(".fm-button:not(.ui-state-disabled)",fil).hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});}});},editGridRow:function(rowid,p){p=$.extend(true,{top:0,left:0,width:300,datawidth:'auto',height:'auto',dataheight:'auto',modal:false,overlay:30,drag:true,resize:true,url:null,mtype:"POST",clearAfterAdd:true,closeAfterEdit:false,reloadAfterSubmit:true,onInitializeForm:null,beforeInitData:null,beforeShowForm:null,afterShowForm:null,beforeSubmit:null,afterSubmit:null,onclickSubmit:null,afterComplete:null,onclickPgButtons:null,afterclickPgButtons:null,editData:{},recreateForm:false,jqModal:true,closeOnEscape:false,addedrow:"first",topinfo:'',bottominfo:'',saveicon:[],closeicon:[],savekey:[false,13],navkeys:[false,38,40],checkOnSubmit:false,checkOnUpdate:false,_savedData:{},processing:false,onClose:null,ajaxEditOptions:{},serializeEditData:null,viewPagerButtons:true,overlayClass:'ui-widget-overlay'},$.jgrid.edit,p||{});rp_ge[$(this)[0].p.id]=p;return this.each(function(){var $t=this;if(!$t.grid||!rowid){return;}
var gID=$t.p.id,frmgr="FrmGrid_"+gID,frmtborg="TblGrid_"+gID,frmtb="#"+$.jgrid.jqID(frmtborg),IDs={themodal:'editmod'+gID,modalhead:'edithd'+gID,modalcontent:'editcnt'+gID,scrollelm:frmgr},onBeforeShow=$.isFunction(rp_ge[$t.p.id].beforeShowForm)?rp_ge[$t.p.id].beforeShowForm:false,onAfterShow=$.isFunction(rp_ge[$t.p.id].afterShowForm)?rp_ge[$t.p.id].afterShowForm:false,onBeforeInit=$.isFunction(rp_ge[$t.p.id].beforeInitData)?rp_ge[$t.p.id].beforeInitData:false,onInitializeForm=$.isFunction(rp_ge[$t.p.id].onInitializeForm)?rp_ge[$t.p.id].onInitializeForm:false,showFrm=true,maxCols=1,maxRows=0,postdata,diff,frmoper;frmgr=$.jgrid.jqID(frmgr);if(rowid==="new"){rowid="_empty";frmoper="add";p.caption=rp_ge[$t.p.id].addCaption;}else{p.caption=rp_ge[$t.p.id].editCaption;frmoper="edit";}
if(p.recreateForm===true&&$("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){$("#"+$.jgrid.jqID(IDs.themodal)).remove();}
var closeovrl=true;if(p.checkOnUpdate&&p.jqModal&&!p.modal){closeovrl=false;}
function getFormData(){$(frmtb+" > tbody > tr > td > .FormElement").each(function(){var celm=$(".customelement",this);if(celm.length){var elem=celm[0],nm=$(elem).attr('name');$.each($t.p.colModel,function(){if(this.name===nm&&this.editoptions&&$.isFunction(this.editoptions.custom_value)){try{postdata[nm]=this.editoptions.custom_value.call($t,$("#"+$.jgrid.jqID(nm),frmtb),'get');if(postdata[nm]===undefined){throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.novalue,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,e.message,$.jgrid.edit.bClose);}}
return true;}});}else{switch($(this).get(0).type){case"checkbox":if($(this).is(":checked")){postdata[this.name]=$(this).val();}else{var ofv=$(this).attr("offval");postdata[this.name]=ofv;}
break;case"select-one":postdata[this.name]=$("option:selected",this).val();break;case"select-multiple":postdata[this.name]=$(this).val();if(postdata[this.name]){postdata[this.name]=postdata[this.name].join(",");}else{postdata[this.name]="";}
var selectedText=[];$("option:selected",this).each(function(i,selected){selectedText[i]=$(selected).text();});break;case"password":case"text":case"textarea":case"button":postdata[this.name]=$(this).val();break;}
if($t.p.autoencode){postdata[this.name]=$.jgrid.htmlEncode(postdata[this.name]);}}});return true;}
function createData(rowid,obj,tb,maxcols){var nm,hc,trdata,cnt=0,tmp,dc,elc,retpos=[],ind=false,tdtmpl="<td class='CaptionTD'>&#160;</td><td class='DataTD'>&#160;</td>",tmpl="",i;for(i=1;i<=maxcols;i++){tmpl+=tdtmpl;}
if(rowid!=='_empty'){ind=$(obj).jqGrid("getInd",rowid);}
$(obj.p.colModel).each(function(i){nm=this.name;if(this.editrules&&this.editrules.edithidden===true){hc=false;}else{hc=this.hidden===true?true:false;}
dc=hc?"style='display:none'":"";if(nm!=='cb'&&nm!=='subgrid'&&this.editable===true&&nm!=='rn'){if(ind===false){tmp="";}else{if(nm===obj.p.ExpandColumn&&obj.p.treeGrid===true){tmp=$("td[role='gridcell']:eq("+i+")",obj.rows[ind]).text();}else{try{tmp=$.unformat.call(obj,$("td[role='gridcell']:eq("+i+")",obj.rows[ind]),{rowId:rowid,colModel:this},i);}catch(_){tmp=(this.edittype&&this.edittype==="textarea")?$("td[role='gridcell']:eq("+i+")",obj.rows[ind]).text():$("td[role='gridcell']:eq("+i+")",obj.rows[ind]).html();}
if(!tmp||tmp==="&nbsp;"||tmp==="&#160;"||(tmp.length===1&&tmp.charCodeAt(0)===160)){tmp='';}}}
var opt=$.extend({},this.editoptions||{},{id:nm,name:nm}),frmopt=$.extend({},{elmprefix:'',elmsuffix:'',rowabove:false,rowcontent:''},this.formoptions||{}),rp=parseInt(frmopt.rowpos,10)||cnt+1,cp=parseInt((parseInt(frmopt.colpos,10)||1)*2,10);if(rowid==="_empty"&&opt.defaultValue){tmp=$.isFunction(opt.defaultValue)?opt.defaultValue.call($t):opt.defaultValue;}
if(!this.edittype){this.edittype="text";}
if($t.p.autoencode){tmp=$.jgrid.htmlDecode(tmp);}
elc=$.jgrid.createEl.call($t,this.edittype,opt,tmp,false,$.extend({},$.jgrid.ajaxOptions,obj.p.ajaxSelectOptions||{}));if(rp_ge[$t.p.id].checkOnSubmit||rp_ge[$t.p.id].checkOnUpdate){rp_ge[$t.p.id]._savedData[nm]=tmp;}
$(elc).addClass("FormElement");if($.inArray(this.edittype,['text','textarea','password','select'])>-1){$(elc).addClass("ui-widget-content ui-corner-all");}
trdata=$(tb).find("tr[rowpos="+rp+"]");if(frmopt.rowabove){var newdata=$("<tr><td class='contentinfo' colspan='"+(maxcols*2)+"'>"+frmopt.rowcontent+"</td></tr>");$(tb).append(newdata);newdata[0].rp=rp;}
if(trdata.length===0){trdata=$("<tr "+dc+" rowpos='"+rp+"'></tr>").addClass("FormData").attr("id","tr_"+nm);$(trdata).append(tmpl);$(tb).append(trdata);trdata[0].rp=rp;}
$("td:eq("+(cp-2)+")",trdata[0]).html(frmopt.label===undefined?obj.p.colNames[i]:frmopt.label);$("td:eq("+(cp-1)+")",trdata[0]).append(frmopt.elmprefix).append(elc).append(frmopt.elmsuffix);if(this.edittype==='custom'&&$.isFunction(opt.custom_value)){opt.custom_value.call($t,$("#"+nm,"#"+frmgr),'set',tmp);}
$.jgrid.bindEv.call($t,elc,opt);retpos[cnt]=i;cnt++;}});if(cnt>0){var idrow=$("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+(maxcols*2-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='"+obj.p.id+"_id' value='"+rowid+"'/></td></tr>");idrow[0].rp=cnt+999;$(tb).append(idrow);if(rp_ge[$t.p.id].checkOnSubmit||rp_ge[$t.p.id].checkOnUpdate){rp_ge[$t.p.id]._savedData[obj.p.id+"_id"]=rowid;}}
return retpos;}
function fillData(rowid,obj,fmid){var nm,cnt=0,tmp,fld,opt,vl,vlc;if(rp_ge[$t.p.id].checkOnSubmit||rp_ge[$t.p.id].checkOnUpdate){rp_ge[$t.p.id]._savedData={};rp_ge[$t.p.id]._savedData[obj.p.id+"_id"]=rowid;}
var cm=obj.p.colModel;if(rowid==='_empty'){$(cm).each(function(){nm=this.name;opt=$.extend({},this.editoptions||{});fld=$("#"+$.jgrid.jqID(nm),"#"+fmid);if(fld&&fld.length&&fld[0]!==null){vl="";if(this.edittype==='custom'&&$.isFunction(opt.custom_value)){opt.custom_value.call($t,$("#"+nm,"#"+fmid),'set',vl);}else if(opt.defaultValue){vl=$.isFunction(opt.defaultValue)?opt.defaultValue.call($t):opt.defaultValue;if(fld[0].type==='checkbox'){vlc=vl.toLowerCase();if(vlc.search(/(false|f|0|no|n|off|undefined)/i)<0&&vlc!==""){fld[0].checked=true;fld[0].defaultChecked=true;fld[0].value=vl;}else{fld[0].checked=false;fld[0].defaultChecked=false;}}else{fld.val(vl);}}else{if(fld[0].type==='checkbox'){fld[0].checked=false;fld[0].defaultChecked=false;vl=$(fld).attr("offval");}else if(fld[0].type&&fld[0].type.substr(0,6)==='select'){fld[0].selectedIndex=0;}else{fld.val(vl);}}
if(rp_ge[$t.p.id].checkOnSubmit===true||rp_ge[$t.p.id].checkOnUpdate){rp_ge[$t.p.id]._savedData[nm]=vl;}}});$("#id_g","#"+fmid).val(rowid);return;}
var tre=$(obj).jqGrid("getInd",rowid,true);if(!tre){return;}
$('td[role="gridcell"]',tre).each(function(i){nm=cm[i].name;if(nm!=='cb'&&nm!=='subgrid'&&nm!=='rn'&&cm[i].editable===true){if(nm===obj.p.ExpandColumn&&obj.p.treeGrid===true){tmp=$(this).text();}else{try{tmp=$.unformat.call(obj,$(this),{rowId:rowid,colModel:cm[i]},i);}catch(_){tmp=cm[i].edittype==="textarea"?$(this).text():$(this).html();}}
if($t.p.autoencode){tmp=$.jgrid.htmlDecode(tmp);}
if(rp_ge[$t.p.id].checkOnSubmit===true||rp_ge[$t.p.id].checkOnUpdate){rp_ge[$t.p.id]._savedData[nm]=tmp;}
nm=$.jgrid.jqID(nm);switch(cm[i].edittype){case"password":case"text":case"button":case"image":case"textarea":if(tmp==="&nbsp;"||tmp==="&#160;"||(tmp.length===1&&tmp.charCodeAt(0)===160)){tmp='';}
$("#"+nm,"#"+fmid).val(tmp);break;case"select":var opv=tmp.split(",");opv=$.map(opv,function(n){return $.trim(n);});$("#"+nm+" option","#"+fmid).each(function(){if(!cm[i].editoptions.multiple&&($.trim(tmp)===$.trim($(this).text())||opv[0]===$.trim($(this).text())||opv[0]===$.trim($(this).val()))){this.selected=true;}else if(cm[i].editoptions.multiple){if($.inArray($.trim($(this).text()),opv)>-1||$.inArray($.trim($(this).val()),opv)>-1){this.selected=true;}else{this.selected=false;}}else{this.selected=false;}});break;case"checkbox":tmp=String(tmp);if(cm[i].editoptions&&cm[i].editoptions.value){var cb=cm[i].editoptions.value.split(":");if(cb[0]===tmp){$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']({"checked":true,"defaultChecked":true});}else{$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']({"checked":false,"defaultChecked":false});}}else{tmp=tmp.toLowerCase();if(tmp.search(/(false|f|0|no|n|off|undefined)/i)<0&&tmp!==""){$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']("checked",true);$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']("defaultChecked",true);}else{$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']("checked",false);$("#"+nm,"#"+fmid)[$t.p.useProp?'prop':'attr']("defaultChecked",false);}}
break;case'custom':try{if(cm[i].editoptions&&$.isFunction(cm[i].editoptions.custom_value)){cm[i].editoptions.custom_value.call($t,$("#"+nm,"#"+fmid),'set',tmp);}else{throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.nodefined,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,e.message,$.jgrid.edit.bClose);}}
break;}
cnt++;}});if(cnt>0){$("#id_g",frmtb).val(rowid);}}
function setNulls(){$.each($t.p.colModel,function(i,n){if(n.editoptions&&n.editoptions.NullIfEmpty===true){if(postdata.hasOwnProperty(n.name)&&postdata[n.name]===""){postdata[n.name]='null';}}});}
function postIt(){var copydata,ret=[true,"",""],onCS={},opers=$t.p.prmNames,idname,oper,key,selr,i;var retvals=$($t).triggerHandler("jqGridAddEditBeforeCheckValues",[$("#"+frmgr),frmoper]);if(retvals&&typeof retvals==='object'){postdata=retvals;}
if($.isFunction(rp_ge[$t.p.id].beforeCheckValues)){retvals=rp_ge[$t.p.id].beforeCheckValues.call($t,postdata,$("#"+frmgr),frmoper);if(retvals&&typeof retvals==='object'){postdata=retvals;}}
for(key in postdata){if(postdata.hasOwnProperty(key)){ret=$.jgrid.checkValues.call($t,postdata[key],key);if(ret[0]===false){break;}}}
setNulls();if(ret[0]){onCS=$($t).triggerHandler("jqGridAddEditClickSubmit",[rp_ge[$t.p.id],postdata,frmoper]);if(onCS===undefined&&$.isFunction(rp_ge[$t.p.id].onclickSubmit)){onCS=rp_ge[$t.p.id].onclickSubmit.call($t,rp_ge[$t.p.id],postdata,frmoper)||{};}
ret=$($t).triggerHandler("jqGridAddEditBeforeSubmit",[postdata,$("#"+frmgr),frmoper]);if(ret===undefined){ret=[true,"",""];}
if(ret[0]&&$.isFunction(rp_ge[$t.p.id].beforeSubmit)){ret=rp_ge[$t.p.id].beforeSubmit.call($t,postdata,$("#"+frmgr),frmoper);}}
if(ret[0]&&!rp_ge[$t.p.id].processing){rp_ge[$t.p.id].processing=true;$("#sData",frmtb+"_2").addClass('ui-state-active');oper=opers.oper;idname=opers.id;postdata[oper]=($.trim(postdata[$t.p.id+"_id"])==="_empty")?opers.addoper:opers.editoper;if(postdata[oper]!==opers.addoper){postdata[idname]=postdata[$t.p.id+"_id"];}else{if(postdata[idname]===undefined){postdata[idname]=postdata[$t.p.id+"_id"];}}
delete postdata[$t.p.id+"_id"];postdata=$.extend(postdata,rp_ge[$t.p.id].editData,onCS);if($t.p.treeGrid===true){if(postdata[oper]===opers.addoper){selr=$($t).jqGrid("getGridParam",'selrow');var tr_par_id=$t.p.treeGridModel==='adjacency'?$t.p.treeReader.parent_id_field:'parent_id';postdata[tr_par_id]=selr;}
for(i in $t.p.treeReader){if($t.p.treeReader.hasOwnProperty(i)){var itm=$t.p.treeReader[i];if(postdata.hasOwnProperty(itm)){if(postdata[oper]===opers.addoper&&i==='parent_id_field'){continue;}
delete postdata[itm];}}}}
postdata[idname]=$.jgrid.stripPref($t.p.idPrefix,postdata[idname]);var ajaxOptions=$.extend({url:rp_ge[$t.p.id].url||$($t).jqGrid('getGridParam','editurl'),type:rp_ge[$t.p.id].mtype,data:$.isFunction(rp_ge[$t.p.id].serializeEditData)?rp_ge[$t.p.id].serializeEditData.call($t,postdata):postdata,complete:function(data,status){var key;postdata[idname]=$t.p.idPrefix+postdata[idname];if(data.status>=300&&data.status!==304){ret[0]=false;ret[1]=$($t).triggerHandler("jqGridAddEditErrorTextFormat",[data,frmoper]);if($.isFunction(rp_ge[$t.p.id].errorTextFormat)){ret[1]=rp_ge[$t.p.id].errorTextFormat.call($t,data,frmoper);}else{ret[1]=status+" Status: '"+data.statusText+"'. Error code: "+data.status;}}else{ret=$($t).triggerHandler("jqGridAddEditAfterSubmit",[data,postdata,frmoper]);if(ret===undefined){ret=[true,"",""];}
if(ret[0]&&$.isFunction(rp_ge[$t.p.id].afterSubmit)){ret=rp_ge[$t.p.id].afterSubmit.call($t,data,postdata,frmoper);}}
if(ret[0]===false){$("#FormError>td",frmtb).html(ret[1]);$("#FormError",frmtb).show();}else{if($t.p.autoencode){$.each(postdata,function(n,v){postdata[n]=$.jgrid.htmlDecode(v);});}
if(postdata[oper]===opers.addoper){if(!ret[2]){ret[2]=$.jgrid.randId();}
postdata[idname]=ret[2];if(rp_ge[$t.p.id].reloadAfterSubmit){$($t).trigger("reloadGrid");}else{if($t.p.treeGrid===true){$($t).jqGrid("addChildNode",ret[2],selr,postdata);}else{$($t).jqGrid("addRowData",ret[2],postdata,p.addedrow);}}
if(rp_ge[$t.p.id].closeAfterAdd){if($t.p.treeGrid!==true){$($t).jqGrid("setSelection",ret[2]);}
$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}else if(rp_ge[$t.p.id].clearAfterAdd){fillData("_empty",$t,frmgr);}}else{if(rp_ge[$t.p.id].reloadAfterSubmit){$($t).trigger("reloadGrid");if(!rp_ge[$t.p.id].closeAfterEdit){setTimeout(function(){$($t).jqGrid("setSelection",postdata[idname]);},1000);}}else{if($t.p.treeGrid===true){$($t).jqGrid("setTreeRow",postdata[idname],postdata);}else{$($t).jqGrid("setRowData",postdata[idname],postdata);}}
if(rp_ge[$t.p.id].closeAfterEdit){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}}
if($.isFunction(rp_ge[$t.p.id].afterComplete)){copydata=data;setTimeout(function(){$($t).triggerHandler("jqGridAddEditAfterComplete",[copydata,postdata,$("#"+frmgr),frmoper]);rp_ge[$t.p.id].afterComplete.call($t,copydata,postdata,$("#"+frmgr),frmoper);copydata=null;},500);}
if(rp_ge[$t.p.id].checkOnSubmit||rp_ge[$t.p.id].checkOnUpdate){$("#"+frmgr).data("disabled",false);if(rp_ge[$t.p.id]._savedData[$t.p.id+"_id"]!=="_empty"){for(key in rp_ge[$t.p.id]._savedData){if(rp_ge[$t.p.id]._savedData.hasOwnProperty(key)&&postdata[key]){rp_ge[$t.p.id]._savedData[key]=postdata[key];}}}}}
rp_ge[$t.p.id].processing=false;$("#sData",frmtb+"_2").removeClass('ui-state-active');try{$(':input:visible',"#"+frmgr)[0].focus();}catch(e){}}},$.jgrid.ajaxOptions,rp_ge[$t.p.id].ajaxEditOptions);if(!ajaxOptions.url&&!rp_ge[$t.p.id].useDataProxy){if($.isFunction($t.p.dataProxy)){rp_ge[$t.p.id].useDataProxy=true;}else{ret[0]=false;ret[1]+=" "+$.jgrid.errors.nourl;}}
if(ret[0]){if(rp_ge[$t.p.id].useDataProxy){var dpret=$t.p.dataProxy.call($t,ajaxOptions,"set_"+$t.p.id);if(dpret===undefined){dpret=[true,""];}
if(dpret[0]===false){ret[0]=false;ret[1]=dpret[1]||"Error deleting the selected row!";}else{if(ajaxOptions.data.oper===opers.addoper&&rp_ge[$t.p.id].closeAfterAdd){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}
if(ajaxOptions.data.oper===opers.editoper&&rp_ge[$t.p.id].closeAfterEdit){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}}}else{$.ajax(ajaxOptions);}}}
if(ret[0]===false){$("#FormError>td",frmtb).html(ret[1]);$("#FormError",frmtb).show();}}
function compareData(nObj,oObj){var ret=false,key;for(key in nObj){if(nObj.hasOwnProperty(key)&&nObj[key]!=oObj[key]){ret=true;break;}}
return ret;}
function checkUpdates(){var stat=true;$("#FormError",frmtb).hide();if(rp_ge[$t.p.id].checkOnUpdate){postdata={};getFormData();diff=compareData(postdata,rp_ge[$t.p.id]._savedData);if(diff){$("#"+frmgr).data("disabled",true);$(".confirm","#"+IDs.themodal).show();stat=false;}}
return stat;}
function restoreInline(){var i;if(rowid!=="_empty"&&$t.p.savedRow!==undefined&&$t.p.savedRow.length>0&&$.isFunction($.fn.jqGrid.restoreRow)){for(i=0;i<$t.p.savedRow.length;i++){if($t.p.savedRow[i].id==rowid){$($t).jqGrid('restoreRow',rowid);break;}}}}
function updateNav(cr,posarr){var totr=posarr[1].length-1;if(cr===0){$("#pData",frmtb+"_2").addClass('ui-state-disabled');}else if(posarr[1][cr-1]!==undefined&&$("#"+$.jgrid.jqID(posarr[1][cr-1])).hasClass('ui-state-disabled')){$("#pData",frmtb+"_2").addClass('ui-state-disabled');}else{$("#pData",frmtb+"_2").removeClass('ui-state-disabled');}
if(cr===totr){$("#nData",frmtb+"_2").addClass('ui-state-disabled');}else if(posarr[1][cr+1]!==undefined&&$("#"+$.jgrid.jqID(posarr[1][cr+1])).hasClass('ui-state-disabled')){$("#nData",frmtb+"_2").addClass('ui-state-disabled');}else{$("#nData",frmtb+"_2").removeClass('ui-state-disabled');}}
function getCurrPos(){var rowsInGrid=$($t).jqGrid("getDataIDs"),selrow=$("#id_g",frmtb).val(),pos=$.inArray(selrow,rowsInGrid);return[pos,rowsInGrid];}
if($("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){showFrm=$($t).triggerHandler("jqGridAddEditBeforeInitData",[$("#"+$.jgrid.jqID(frmgr)),frmoper]);if(showFrm===undefined){showFrm=true;}
if(showFrm&&onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+frmgr),frmoper);}
if(showFrm===false){return;}
restoreInline();$(".ui-jqdialog-title","#"+$.jgrid.jqID(IDs.modalhead)).html(p.caption);$("#FormError",frmtb).hide();if(rp_ge[$t.p.id].topinfo){$(".topinfo",frmtb).html(rp_ge[$t.p.id].topinfo);$(".tinfo",frmtb).show();}else{$(".tinfo",frmtb).hide();}
if(rp_ge[$t.p.id].bottominfo){$(".bottominfo",frmtb+"_2").html(rp_ge[$t.p.id].bottominfo);$(".binfo",frmtb+"_2").show();}else{$(".binfo",frmtb+"_2").hide();}
fillData(rowid,$t,frmgr);if(rowid==="_empty"||!rp_ge[$t.p.id].viewPagerButtons){$("#pData, #nData",frmtb+"_2").hide();}else{$("#pData, #nData",frmtb+"_2").show();}
if(rp_ge[$t.p.id].processing===true){rp_ge[$t.p.id].processing=false;$("#sData",frmtb+"_2").removeClass('ui-state-active');}
if($("#"+frmgr).data("disabled")===true){$(".confirm","#"+$.jgrid.jqID(IDs.themodal)).hide();$("#"+frmgr).data("disabled",false);}
$($t).triggerHandler("jqGridAddEditBeforeShowForm",[$("#"+frmgr),frmoper]);if(onBeforeShow){onBeforeShow.call($t,$("#"+frmgr),frmoper);}
$("#"+$.jgrid.jqID(IDs.themodal)).data("onClose",rp_ge[$t.p.id].onClose);$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,jqM:false,overlay:p.overlay,modal:p.modal,overlayClass:p.overlayClass});if(!closeovrl){$("."+$.jgrid.jqID(p.overlayClass)).click(function(){if(!checkUpdates()){return false;}
$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});}
$($t).triggerHandler("jqGridAddEditAfterShowForm",[$("#"+frmgr),frmoper]);if(onAfterShow){onAfterShow.call($t,$("#"+frmgr),frmoper);}}else{var dh=isNaN(p.dataheight)?p.dataheight:p.dataheight+"px",dw=isNaN(p.datawidth)?p.datawidth:p.datawidth+"px",frm=$("<form name='FormPost' id='"+frmgr+"' class='FormGrid' onSubmit='return false;' style='width:"+dw+";overflow:auto;position:relative;height:"+dh+";'></form>").data("disabled",false),tbl=$("<table id='"+frmtborg+"' class='EditTable' cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>");showFrm=$($t).triggerHandler("jqGridAddEditBeforeInitData",[$("#"+frmgr),frmoper]);if(showFrm===undefined){showFrm=true;}
if(showFrm&&onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+frmgr),frmoper);}
if(showFrm===false){return;}
restoreInline();$($t.p.colModel).each(function(){var fmto=this.formoptions;maxCols=Math.max(maxCols,fmto?fmto.colpos||0:0);maxRows=Math.max(maxRows,fmto?fmto.rowpos||0:0);});$(frm).append(tbl);var flr=$("<tr id='FormError' style='display:none'><td class='ui-state-error' colspan='"+(maxCols*2)+"'></td></tr>");flr[0].rp=0;$(tbl).append(flr);flr=$("<tr style='display:none' class='tinfo'><td class='topinfo' colspan='"+(maxCols*2)+"'>"+rp_ge[$t.p.id].topinfo+"</td></tr>");flr[0].rp=0;$(tbl).append(flr);var rtlb=$t.p.direction==="rtl"?true:false,bp=rtlb?"nData":"pData",bn=rtlb?"pData":"nData";createData(rowid,$t,tbl,maxCols);var bP="<a id='"+bp+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>",bN="<a id='"+bn+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>",bS="<a id='sData' class='fm-button ui-state-default ui-corner-all'>"+p.bSubmit+"</a>",bC="<a id='cData' class='fm-button ui-state-default ui-corner-all'>"+p.bCancel+"</a>";var bt="<table border='0' cellspacing='0' cellpadding='0' class='EditTable' id='"+frmtborg+"_2'><tbody><tr><td colspan='2'><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr id='Act_Buttons'><td class='navButton'>"+(rtlb?bN+bP:bP+bN)+"</td><td class='EditButton'>"+bS+bC+"</td></tr>";bt+="<tr style='display:none' class='binfo'><td class='bottominfo' colspan='2'>"+rp_ge[$t.p.id].bottominfo+"</td></tr>";bt+="</tbody></table>";if(maxRows>0){var sd=[];$.each($(tbl)[0].rows,function(i,r){sd[i]=r;});sd.sort(function(a,b){if(a.rp>b.rp){return 1;}
if(a.rp<b.rp){return-1;}
return 0;});$.each(sd,function(index,row){$('tbody',tbl).append(row);});}
p.gbox="#gbox_"+$.jgrid.jqID(gID);var cle=false;if(p.closeOnEscape===true){p.closeOnEscape=false;cle=true;}
var tms=$("<div></div>").append(frm).append(bt);$.jgrid.createModal(IDs,tms,p,"#gview_"+$.jgrid.jqID($t.p.id),$("#gbox_"+$.jgrid.jqID($t.p.id))[0]);if(rtlb){$("#pData, #nData",frmtb+"_2").css("float","right");$(".EditButton",frmtb+"_2").css("text-align","left");}
if(rp_ge[$t.p.id].topinfo){$(".tinfo",frmtb).show();}
if(rp_ge[$t.p.id].bottominfo){$(".binfo",frmtb+"_2").show();}
tms=null;bt=null;$("#"+$.jgrid.jqID(IDs.themodal)).keydown(function(e){var wkey=e.target;if($("#"+frmgr).data("disabled")===true){return false;}
if(rp_ge[$t.p.id].savekey[0]===true&&e.which===rp_ge[$t.p.id].savekey[1]){if(wkey.tagName!=="TEXTAREA"){$("#sData",frmtb+"_2").trigger("click");return false;}}
if(e.which===27){if(!checkUpdates()){return false;}
if(cle){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:p.gbox,jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}
return false;}
if(rp_ge[$t.p.id].navkeys[0]===true){if($("#id_g",frmtb).val()==="_empty"){return true;}
if(e.which===rp_ge[$t.p.id].navkeys[1]){$("#pData",frmtb+"_2").trigger("click");return false;}
if(e.which===rp_ge[$t.p.id].navkeys[2]){$("#nData",frmtb+"_2").trigger("click");return false;}}});if(p.checkOnUpdate){$("a.ui-jqdialog-titlebar-close span","#"+$.jgrid.jqID(IDs.themodal)).removeClass("jqmClose");$("a.ui-jqdialog-titlebar-close","#"+$.jgrid.jqID(IDs.themodal)).unbind("click").click(function(){if(!checkUpdates()){return false;}
$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});}
p.saveicon=$.extend([true,"left","ui-icon-disk"],p.saveicon);p.closeicon=$.extend([true,"left","ui-icon-close"],p.closeicon);if(p.saveicon[0]===true){$("#sData",frmtb+"_2").addClass(p.saveicon[1]==="right"?'fm-button-icon-right':'fm-button-icon-left').append("<span class='ui-icon "+p.saveicon[2]+"'></span>");}
if(p.closeicon[0]===true){$("#cData",frmtb+"_2").addClass(p.closeicon[1]==="right"?'fm-button-icon-right':'fm-button-icon-left').append("<span class='ui-icon "+p.closeicon[2]+"'></span>");}
if(rp_ge[$t.p.id].checkOnSubmit||rp_ge[$t.p.id].checkOnUpdate){bS="<a id='sNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+p.bYes+"</a>";bN="<a id='nNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+p.bNo+"</a>";bC="<a id='cNew' class='fm-button ui-state-default ui-corner-all' style='z-index:1002'>"+p.bExit+"</a>";var zI=p.zIndex||999;zI++;$("<div class='"+p.overlayClass+" jqgrid-overlay confirm' style='z-index:"+zI+";display:none;'>&#160;"+"</div><div class='confirm ui-widget-content ui-jqconfirm' style='z-index:"+(zI+1)+"'>"+p.saveData+"<br/><br/>"+bS+bN+bC+"</div>").insertAfter("#"+frmgr);$("#sNew","#"+$.jgrid.jqID(IDs.themodal)).click(function(){postIt();$("#"+frmgr).data("disabled",false);$(".confirm","#"+$.jgrid.jqID(IDs.themodal)).hide();return false;});$("#nNew","#"+$.jgrid.jqID(IDs.themodal)).click(function(){$(".confirm","#"+$.jgrid.jqID(IDs.themodal)).hide();$("#"+frmgr).data("disabled",false);setTimeout(function(){$(":input:visible","#"+frmgr)[0].focus();},0);return false;});$("#cNew","#"+$.jgrid.jqID(IDs.themodal)).click(function(){$(".confirm","#"+$.jgrid.jqID(IDs.themodal)).hide();$("#"+frmgr).data("disabled",false);$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});}
$($t).triggerHandler("jqGridAddEditInitializeForm",[$("#"+frmgr),frmoper]);if(onInitializeForm){onInitializeForm.call($t,$("#"+frmgr),frmoper);}
if(rowid==="_empty"||!rp_ge[$t.p.id].viewPagerButtons){$("#pData,#nData",frmtb+"_2").hide();}else{$("#pData,#nData",frmtb+"_2").show();}
$($t).triggerHandler("jqGridAddEditBeforeShowForm",[$("#"+frmgr),frmoper]);if(onBeforeShow){onBeforeShow.call($t,$("#"+frmgr),frmoper);}
$("#"+$.jgrid.jqID(IDs.themodal)).data("onClose",rp_ge[$t.p.id].onClose);$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,overlay:p.overlay,modal:p.modal,overlayClass:p.overlayClass});if(!closeovrl){$("."+$.jgrid.jqID(p.overlayClass)).click(function(){if(!checkUpdates()){return false;}
$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});}
$($t).triggerHandler("jqGridAddEditAfterShowForm",[$("#"+frmgr),frmoper]);if(onAfterShow){onAfterShow.call($t,$("#"+frmgr),frmoper);}
$(".fm-button","#"+$.jgrid.jqID(IDs.themodal)).hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});$("#sData",frmtb+"_2").click(function(){postdata={};$("#FormError",frmtb).hide();getFormData();if(postdata[$t.p.id+"_id"]==="_empty"){postIt();}else if(p.checkOnSubmit===true){diff=compareData(postdata,rp_ge[$t.p.id]._savedData);if(diff){$("#"+frmgr).data("disabled",true);$(".confirm","#"+$.jgrid.jqID(IDs.themodal)).show();}else{postIt();}}else{postIt();}
return false;});$("#cData",frmtb+"_2").click(function(){if(!checkUpdates()){return false;}
$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});$("#nData",frmtb+"_2").click(function(){if(!checkUpdates()){return false;}
$("#FormError",frmtb).hide();var npos=getCurrPos();npos[0]=parseInt(npos[0],10);if(npos[0]!==-1&&npos[1][npos[0]+1]){$($t).triggerHandler("jqGridAddEditClickPgButtons",['next',$("#"+frmgr),npos[1][npos[0]]]);var nposret;if($.isFunction(p.onclickPgButtons)){nposret=p.onclickPgButtons.call($t,'next',$("#"+frmgr),npos[1][npos[0]]);if(nposret!==undefined&&nposret===false){return false;}}
if($("#"+$.jgrid.jqID(npos[1][npos[0]+1])).hasClass('ui-state-disabled')){return false;}
fillData(npos[1][npos[0]+1],$t,frmgr);$($t).jqGrid("setSelection",npos[1][npos[0]+1]);$($t).triggerHandler("jqGridAddEditAfterClickPgButtons",['next',$("#"+frmgr),npos[1][npos[0]]]);if($.isFunction(p.afterclickPgButtons)){p.afterclickPgButtons.call($t,'next',$("#"+frmgr),npos[1][npos[0]+1]);}
updateNav(npos[0]+1,npos);}
return false;});$("#pData",frmtb+"_2").click(function(){if(!checkUpdates()){return false;}
$("#FormError",frmtb).hide();var ppos=getCurrPos();if(ppos[0]!==-1&&ppos[1][ppos[0]-1]){$($t).triggerHandler("jqGridAddEditClickPgButtons",['prev',$("#"+frmgr),ppos[1][ppos[0]]]);var pposret;if($.isFunction(p.onclickPgButtons)){pposret=p.onclickPgButtons.call($t,'prev',$("#"+frmgr),ppos[1][ppos[0]]);if(pposret!==undefined&&pposret===false){return false;}}
if($("#"+$.jgrid.jqID(ppos[1][ppos[0]-1])).hasClass('ui-state-disabled')){return false;}
fillData(ppos[1][ppos[0]-1],$t,frmgr);$($t).jqGrid("setSelection",ppos[1][ppos[0]-1]);$($t).triggerHandler("jqGridAddEditAfterClickPgButtons",['prev',$("#"+frmgr),ppos[1][ppos[0]]]);if($.isFunction(p.afterclickPgButtons)){p.afterclickPgButtons.call($t,'prev',$("#"+frmgr),ppos[1][ppos[0]-1]);}
updateNav(ppos[0]-1,ppos);}
return false;});}
var posInit=getCurrPos();updateNav(posInit[0],posInit);});},viewGridRow:function(rowid,p){p=$.extend(true,{top:0,left:0,width:0,datawidth:'auto',height:'auto',dataheight:'auto',modal:false,overlay:30,drag:true,resize:true,jqModal:true,closeOnEscape:false,labelswidth:'30%',closeicon:[],navkeys:[false,38,40],onClose:null,beforeShowForm:null,beforeInitData:null,viewPagerButtons:true,recreateForm:false},$.jgrid.view,p||{});rp_ge[$(this)[0].p.id]=p;return this.each(function(){var $t=this;if(!$t.grid||!rowid){return;}
var gID=$t.p.id,frmgr="ViewGrid_"+$.jgrid.jqID(gID),frmtb="ViewTbl_"+$.jgrid.jqID(gID),frmgr_id="ViewGrid_"+gID,frmtb_id="ViewTbl_"+gID,IDs={themodal:'viewmod'+gID,modalhead:'viewhd'+gID,modalcontent:'viewcnt'+gID,scrollelm:frmgr},onBeforeInit=$.isFunction(rp_ge[$t.p.id].beforeInitData)?rp_ge[$t.p.id].beforeInitData:false,showFrm=true,maxCols=1,maxRows=0;if(p.recreateForm===true&&$("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){$("#"+$.jgrid.jqID(IDs.themodal)).remove();}
function focusaref(){if(rp_ge[$t.p.id].closeOnEscape===true||rp_ge[$t.p.id].navkeys[0]===true){setTimeout(function(){$(".ui-jqdialog-titlebar-close","#"+$.jgrid.jqID(IDs.modalhead)).focus();},0);}}
function createData(rowid,obj,tb,maxcols){var nm,hc,trdata,cnt=0,tmp,dc,retpos=[],ind=false,i,tdtmpl="<td class='CaptionTD form-view-label ui-widget-content' width='"+p.labelswidth+"'>&#160;</td><td class='DataTD form-view-data ui-helper-reset ui-widget-content'>&#160;</td>",tmpl="",tdtmpl2="<td class='CaptionTD form-view-label ui-widget-content'>&#160;</td><td class='DataTD form-view-data ui-widget-content'>&#160;</td>",fmtnum=['integer','number','currency'],max1=0,max2=0,maxw,setme,viewfld;for(i=1;i<=maxcols;i++){tmpl+=i===1?tdtmpl:tdtmpl2;}
$(obj.p.colModel).each(function(){if(this.editrules&&this.editrules.edithidden===true){hc=false;}else{hc=this.hidden===true?true:false;}
if(!hc&&this.align==='right'){if(this.formatter&&$.inArray(this.formatter,fmtnum)!==-1){max1=Math.max(max1,parseInt(this.width,10));}else{max2=Math.max(max2,parseInt(this.width,10));}}});maxw=max1!==0?max1:max2!==0?max2:0;ind=$(obj).jqGrid("getInd",rowid);$(obj.p.colModel).each(function(i){nm=this.name;setme=false;if(this.editrules&&this.editrules.edithidden===true){hc=false;}else{hc=this.hidden===true?true:false;}
dc=hc?"style='display:none'":"";viewfld=(typeof this.viewable!=='boolean')?true:this.viewable;if(nm!=='cb'&&nm!=='subgrid'&&nm!=='rn'&&viewfld){if(ind===false){tmp="";}else{if(nm===obj.p.ExpandColumn&&obj.p.treeGrid===true){tmp=$("td:eq("+i+")",obj.rows[ind]).text();}else{tmp=$("td:eq("+i+")",obj.rows[ind]).html();}}
setme=this.align==='right'&&maxw!==0?true:false;var frmopt=$.extend({},{rowabove:false,rowcontent:''},this.formoptions||{}),rp=parseInt(frmopt.rowpos,10)||cnt+1,cp=parseInt((parseInt(frmopt.colpos,10)||1)*2,10);if(frmopt.rowabove){var newdata=$("<tr><td class='contentinfo' colspan='"+(maxcols*2)+"'>"+frmopt.rowcontent+"</td></tr>");$(tb).append(newdata);newdata[0].rp=rp;}
trdata=$(tb).find("tr[rowpos="+rp+"]");if(trdata.length===0){trdata=$("<tr "+dc+" rowpos='"+rp+"'></tr>").addClass("FormData").attr("id","trv_"+nm);$(trdata).append(tmpl);$(tb).append(trdata);trdata[0].rp=rp;}
$("td:eq("+(cp-2)+")",trdata[0]).html('<b>'+(frmopt.label===undefined?obj.p.colNames[i]:frmopt.label)+'</b>');$("td:eq("+(cp-1)+")",trdata[0]).append("<span>"+tmp+"</span>").attr("id","v_"+nm);if(setme){$("td:eq("+(cp-1)+") span",trdata[0]).css({'text-align':'right',width:maxw+"px"});}
retpos[cnt]=i;cnt++;}});if(cnt>0){var idrow=$("<tr class='FormData' style='display:none'><td class='CaptionTD'></td><td colspan='"+(maxcols*2-1)+"' class='DataTD'><input class='FormElement' id='id_g' type='text' name='id' value='"+rowid+"'/></td></tr>");idrow[0].rp=cnt+99;$(tb).append(idrow);}
return retpos;}
function fillData(rowid,obj){var nm,hc,cnt=0,tmp,trv;trv=$(obj).jqGrid("getInd",rowid,true);if(!trv){return;}
$('td',trv).each(function(i){nm=obj.p.colModel[i].name;if(obj.p.colModel[i].editrules&&obj.p.colModel[i].editrules.edithidden===true){hc=false;}else{hc=obj.p.colModel[i].hidden===true?true:false;}
if(nm!=='cb'&&nm!=='subgrid'&&nm!=='rn'){if(nm===obj.p.ExpandColumn&&obj.p.treeGrid===true){tmp=$(this).text();}else{tmp=$(this).html();}
nm=$.jgrid.jqID("v_"+nm);$("#"+nm+" span","#"+frmtb).html(tmp);if(hc){$("#"+nm,"#"+frmtb).parents("tr:first").hide();}
cnt++;}});if(cnt>0){$("#id_g","#"+frmtb).val(rowid);}}
function updateNav(cr,posarr){var totr=posarr[1].length-1;if(cr===0){$("#pData","#"+frmtb+"_2").addClass('ui-state-disabled');}else if(posarr[1][cr-1]!==undefined&&$("#"+$.jgrid.jqID(posarr[1][cr-1])).hasClass('ui-state-disabled')){$("#pData",frmtb+"_2").addClass('ui-state-disabled');}else{$("#pData","#"+frmtb+"_2").removeClass('ui-state-disabled');}
if(cr===totr){$("#nData","#"+frmtb+"_2").addClass('ui-state-disabled');}else if(posarr[1][cr+1]!==undefined&&$("#"+$.jgrid.jqID(posarr[1][cr+1])).hasClass('ui-state-disabled')){$("#nData",frmtb+"_2").addClass('ui-state-disabled');}else{$("#nData","#"+frmtb+"_2").removeClass('ui-state-disabled');}}
function getCurrPos(){var rowsInGrid=$($t).jqGrid("getDataIDs"),selrow=$("#id_g","#"+frmtb).val(),pos=$.inArray(selrow,rowsInGrid);return[pos,rowsInGrid];}
if($("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){if(onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+frmgr));if(showFrm===undefined){showFrm=true;}}
if(showFrm===false){return;}
$(".ui-jqdialog-title","#"+$.jgrid.jqID(IDs.modalhead)).html(p.caption);$("#FormError","#"+frmtb).hide();fillData(rowid,$t);if($.isFunction(rp_ge[$t.p.id].beforeShowForm)){rp_ge[$t.p.id].beforeShowForm.call($t,$("#"+frmgr));}
$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,jqM:false,overlay:p.overlay,modal:p.modal});focusaref();}else{var dh=isNaN(p.dataheight)?p.dataheight:p.dataheight+"px",dw=isNaN(p.datawidth)?p.datawidth:p.datawidth+"px",frm=$("<form name='FormPost' id='"+frmgr_id+"' class='FormGrid' style='width:"+dw+";overflow:auto;position:relative;height:"+dh+";'></form>"),tbl=$("<table id='"+frmtb_id+"' class='EditTable' cellspacing='1' cellpadding='2' border='0' style='table-layout:fixed'><tbody></tbody></table>");if(onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+frmgr));if(showFrm===undefined){showFrm=true;}}
if(showFrm===false){return;}
$($t.p.colModel).each(function(){var fmto=this.formoptions;maxCols=Math.max(maxCols,fmto?fmto.colpos||0:0);maxRows=Math.max(maxRows,fmto?fmto.rowpos||0:0);});$(frm).append(tbl);createData(rowid,$t,tbl,maxCols);var rtlb=$t.p.direction==="rtl"?true:false,bp=rtlb?"nData":"pData",bn=rtlb?"pData":"nData",bP="<a id='"+bp+"' class='fm-button ui-state-default ui-corner-left'><span class='ui-icon ui-icon-triangle-1-w'></span></a>",bN="<a id='"+bn+"' class='fm-button ui-state-default ui-corner-right'><span class='ui-icon ui-icon-triangle-1-e'></span></a>",bC="<a id='cData' class='fm-button ui-state-default ui-corner-all'>"+p.bClose+"</a>";if(maxRows>0){var sd=[];$.each($(tbl)[0].rows,function(i,r){sd[i]=r;});sd.sort(function(a,b){if(a.rp>b.rp){return 1;}
if(a.rp<b.rp){return-1;}
return 0;});$.each(sd,function(index,row){$('tbody',tbl).append(row);});}
p.gbox="#gbox_"+$.jgrid.jqID(gID);var bt=$("<div></div>").append(frm).append("<table border='0' class='EditTable' id='"+frmtb+"_2'><tbody><tr id='Act_Buttons'><td class='navButton' width='"+p.labelswidth+"'>"+(rtlb?bN+bP:bP+bN)+"</td><td class='EditButton'>"+bC+"</td></tr></tbody></table>");$.jgrid.createModal(IDs,bt,p,"#gview_"+$.jgrid.jqID($t.p.id),$("#gview_"+$.jgrid.jqID($t.p.id))[0]);if(rtlb){$("#pData, #nData","#"+frmtb+"_2").css("float","right");$(".EditButton","#"+frmtb+"_2").css("text-align","left");}
if(!p.viewPagerButtons){$("#pData, #nData","#"+frmtb+"_2").hide();}
bt=null;$("#"+IDs.themodal).keydown(function(e){if(e.which===27){if(rp_ge[$t.p.id].closeOnEscape){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:p.gbox,jqm:p.jqModal,onClose:p.onClose});}
return false;}
if(p.navkeys[0]===true){if(e.which===p.navkeys[1]){$("#pData","#"+frmtb+"_2").trigger("click");return false;}
if(e.which===p.navkeys[2]){$("#nData","#"+frmtb+"_2").trigger("click");return false;}}});p.closeicon=$.extend([true,"left","ui-icon-close"],p.closeicon);if(p.closeicon[0]===true){$("#cData","#"+frmtb+"_2").addClass(p.closeicon[1]==="right"?'fm-button-icon-right':'fm-button-icon-left').append("<span class='ui-icon "+p.closeicon[2]+"'></span>");}
if($.isFunction(p.beforeShowForm)){p.beforeShowForm.call($t,$("#"+frmgr));}
$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,overlay:p.overlay,modal:p.modal});$(".fm-button:not(.ui-state-disabled)","#"+frmtb+"_2").hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});focusaref();$("#cData","#"+frmtb+"_2").click(function(){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:p.onClose});return false;});$("#nData","#"+frmtb+"_2").click(function(){$("#FormError","#"+frmtb).hide();var npos=getCurrPos();npos[0]=parseInt(npos[0],10);if(npos[0]!==-1&&npos[1][npos[0]+1]){if($.isFunction(p.onclickPgButtons)){p.onclickPgButtons.call($t,'next',$("#"+frmgr),npos[1][npos[0]]);}
fillData(npos[1][npos[0]+1],$t);$($t).jqGrid("setSelection",npos[1][npos[0]+1]);if($.isFunction(p.afterclickPgButtons)){p.afterclickPgButtons.call($t,'next',$("#"+frmgr),npos[1][npos[0]+1]);}
updateNav(npos[0]+1,npos);}
focusaref();return false;});$("#pData","#"+frmtb+"_2").click(function(){$("#FormError","#"+frmtb).hide();var ppos=getCurrPos();if(ppos[0]!==-1&&ppos[1][ppos[0]-1]){if($.isFunction(p.onclickPgButtons)){p.onclickPgButtons.call($t,'prev',$("#"+frmgr),ppos[1][ppos[0]]);}
fillData(ppos[1][ppos[0]-1],$t);$($t).jqGrid("setSelection",ppos[1][ppos[0]-1]);if($.isFunction(p.afterclickPgButtons)){p.afterclickPgButtons.call($t,'prev',$("#"+frmgr),ppos[1][ppos[0]-1]);}
updateNav(ppos[0]-1,ppos);}
focusaref();return false;});}
var posInit=getCurrPos();updateNav(posInit[0],posInit);});},delGridRow:function(rowids,p){p=$.extend(true,{top:0,left:0,width:240,height:'auto',dataheight:'auto',modal:false,overlay:30,drag:true,resize:true,url:'',mtype:"POST",reloadAfterSubmit:true,beforeShowForm:null,beforeInitData:null,afterShowForm:null,beforeSubmit:null,onclickSubmit:null,afterSubmit:null,jqModal:true,closeOnEscape:false,delData:{},delicon:[],cancelicon:[],onClose:null,ajaxDelOptions:{},processing:false,serializeDelData:null,useDataProxy:false},$.jgrid.del,p||{});rp_ge[$(this)[0].p.id]=p;return this.each(function(){var $t=this;if(!$t.grid){return;}
if(!rowids){return;}
var onBeforeShow=$.isFunction(rp_ge[$t.p.id].beforeShowForm),onAfterShow=$.isFunction(rp_ge[$t.p.id].afterShowForm),onBeforeInit=$.isFunction(rp_ge[$t.p.id].beforeInitData)?rp_ge[$t.p.id].beforeInitData:false,gID=$t.p.id,onCS={},showFrm=true,dtbl="DelTbl_"+$.jgrid.jqID(gID),postd,idname,opers,oper,dtbl_id="DelTbl_"+gID,IDs={themodal:'delmod'+gID,modalhead:'delhd'+gID,modalcontent:'delcnt'+gID,scrollelm:dtbl};if($.isArray(rowids)){rowids=rowids.join();}
if($("#"+$.jgrid.jqID(IDs.themodal))[0]!==undefined){if(onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+dtbl));if(showFrm===undefined){showFrm=true;}}
if(showFrm===false){return;}
$("#DelData>td","#"+dtbl).text(rowids);$("#DelError","#"+dtbl).hide();if(rp_ge[$t.p.id].processing===true){rp_ge[$t.p.id].processing=false;$("#dData","#"+dtbl).removeClass('ui-state-active');}
if(onBeforeShow){rp_ge[$t.p.id].beforeShowForm.call($t,$("#"+dtbl));}
$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:rp_ge[$t.p.id].jqModal,jqM:false,overlay:rp_ge[$t.p.id].overlay,modal:rp_ge[$t.p.id].modal});if(onAfterShow){rp_ge[$t.p.id].afterShowForm.call($t,$("#"+dtbl));}}else{var dh=isNaN(rp_ge[$t.p.id].dataheight)?rp_ge[$t.p.id].dataheight:rp_ge[$t.p.id].dataheight+"px",dw=isNaN(p.datawidth)?p.datawidth:p.datawidth+"px",tbl="<div id='"+dtbl_id+"' class='formdata' style='width:"+dw+";overflow:auto;position:relative;height:"+dh+";'>";tbl+="<table class='DelTable'><tbody>";tbl+="<tr id='DelError' style='display:none'><td class='ui-state-error'></td></tr>";tbl+="<tr id='DelData' style='display:none'><td >"+rowids+"</td></tr>";tbl+="<tr><td class=\"delmsg\" style=\"white-space:pre;\">"+rp_ge[$t.p.id].msg+"</td></tr><tr><td >&#160;</td></tr>";tbl+="</tbody></table></div>";var bS="<a id='dData' class='fm-button ui-state-default ui-corner-all'>"+p.bSubmit+"</a>",bC="<a id='eData' class='fm-button ui-state-default ui-corner-all'>"+p.bCancel+"</a>";tbl+="<table cellspacing='0' cellpadding='0' border='0' class='EditTable' id='"+dtbl+"_2'><tbody><tr><td><hr class='ui-widget-content' style='margin:1px'/></td></tr><tr><td class='DelButton EditButton'>"+bS+"&#160;"+bC+"</td></tr></tbody></table>";p.gbox="#gbox_"+$.jgrid.jqID(gID);$.jgrid.createModal(IDs,tbl,p,"#gview_"+$.jgrid.jqID($t.p.id),$("#gview_"+$.jgrid.jqID($t.p.id))[0]);if(onBeforeInit){showFrm=onBeforeInit.call($t,$("#"+dtbl));if(showFrm===undefined){showFrm=true;}}
if(showFrm===false){return;}
$(".fm-button","#"+dtbl+"_2").hover(function(){$(this).addClass('ui-state-hover');},function(){$(this).removeClass('ui-state-hover');});p.delicon=$.extend([true,"left","ui-icon-scissors"],rp_ge[$t.p.id].delicon);p.cancelicon=$.extend([true,"left","ui-icon-cancel"],rp_ge[$t.p.id].cancelicon);if(p.delicon[0]===true){$("#dData","#"+dtbl+"_2").addClass(p.delicon[1]==="right"?'fm-button-icon-right':'fm-button-icon-left').append("<span class='ui-icon "+p.delicon[2]+"'></span>");}
if(p.cancelicon[0]===true){$("#eData","#"+dtbl+"_2").addClass(p.cancelicon[1]==="right"?'fm-button-icon-right':'fm-button-icon-left').append("<span class='ui-icon "+p.cancelicon[2]+"'></span>");}
$("#dData","#"+dtbl+"_2").click(function(){var ret=[true,""],pk,postdata=$("#DelData>td","#"+dtbl).text();onCS={};if($.isFunction(rp_ge[$t.p.id].onclickSubmit)){onCS=rp_ge[$t.p.id].onclickSubmit.call($t,rp_ge[$t.p.id],postdata)||{};}
if($.isFunction(rp_ge[$t.p.id].beforeSubmit)){ret=rp_ge[$t.p.id].beforeSubmit.call($t,postdata);}
if(ret[0]&&!rp_ge[$t.p.id].processing){rp_ge[$t.p.id].processing=true;opers=$t.p.prmNames;postd=$.extend({},rp_ge[$t.p.id].delData,onCS);oper=opers.oper;postd[oper]=opers.deloper;idname=opers.id;postdata=String(postdata).split(",");if(!postdata.length){return false;}
for(pk in postdata){if(postdata.hasOwnProperty(pk)){postdata[pk]=$.jgrid.stripPref($t.p.idPrefix,postdata[pk]);}}
postd[idname]=postdata.join();$(this).addClass('ui-state-active');var ajaxOptions=$.extend({url:rp_ge[$t.p.id].url||$($t).jqGrid('getGridParam','editurl'),type:rp_ge[$t.p.id].mtype,data:$.isFunction(rp_ge[$t.p.id].serializeDelData)?rp_ge[$t.p.id].serializeDelData.call($t,postd):postd,complete:function(data,status){var i;if(data.status>=300&&data.status!==304){ret[0]=false;if($.isFunction(rp_ge[$t.p.id].errorTextFormat)){ret[1]=rp_ge[$t.p.id].errorTextFormat.call($t,data);}else{ret[1]=status+" Status: '"+data.statusText+"'. Error code: "+data.status;}}else{if($.isFunction(rp_ge[$t.p.id].afterSubmit)){ret=rp_ge[$t.p.id].afterSubmit.call($t,data,postd);}}
if(ret[0]===false){$("#DelError>td","#"+dtbl).html(ret[1]);$("#DelError","#"+dtbl).show();}else{if(rp_ge[$t.p.id].reloadAfterSubmit&&$t.p.datatype!=="local"){$($t).trigger("reloadGrid");}else{if($t.p.treeGrid===true){try{$($t).jqGrid("delTreeNode",$t.p.idPrefix+postdata[0]);}catch(e){}}else{for(i=0;i<postdata.length;i++){$($t).jqGrid("delRowData",$t.p.idPrefix+postdata[i]);}}
$t.p.selrow=null;$t.p.selarrrow=[];}
if($.isFunction(rp_ge[$t.p.id].afterComplete)){setTimeout(function(){rp_ge[$t.p.id].afterComplete.call($t,data,postdata);},500);}}
rp_ge[$t.p.id].processing=false;$("#dData","#"+dtbl+"_2").removeClass('ui-state-active');if(ret[0]){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}}},$.jgrid.ajaxOptions,rp_ge[$t.p.id].ajaxDelOptions);if(!ajaxOptions.url&&!rp_ge[$t.p.id].useDataProxy){if($.isFunction($t.p.dataProxy)){rp_ge[$t.p.id].useDataProxy=true;}else{ret[0]=false;ret[1]+=" "+$.jgrid.errors.nourl;}}
if(ret[0]){if(rp_ge[$t.p.id].useDataProxy){var dpret=$t.p.dataProxy.call($t,ajaxOptions,"del_"+$t.p.id);if(dpret===undefined){dpret=[true,""];}
if(dpret[0]===false){ret[0]=false;ret[1]=dpret[1]||"Error deleting the selected row!";}else{$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:p.jqModal,onClose:rp_ge[$t.p.id].onClose});}}else{$.ajax(ajaxOptions);}}}
if(ret[0]===false){$("#DelError>td","#"+dtbl).html(ret[1]);$("#DelError","#"+dtbl).show();}
return false;});$("#eData","#"+dtbl+"_2").click(function(){$.jgrid.hideModal("#"+$.jgrid.jqID(IDs.themodal),{gb:"#gbox_"+$.jgrid.jqID(gID),jqm:rp_ge[$t.p.id].jqModal,onClose:rp_ge[$t.p.id].onClose});return false;});if(onBeforeShow){rp_ge[$t.p.id].beforeShowForm.call($t,$("#"+dtbl));}
$.jgrid.viewModal("#"+$.jgrid.jqID(IDs.themodal),{gbox:"#gbox_"+$.jgrid.jqID(gID),jqm:rp_ge[$t.p.id].jqModal,overlay:rp_ge[$t.p.id].overlay,modal:rp_ge[$t.p.id].modal});if(onAfterShow){rp_ge[$t.p.id].afterShowForm.call($t,$("#"+dtbl));}}
if(rp_ge[$t.p.id].closeOnEscape===true){setTimeout(function(){$(".ui-jqdialog-titlebar-close","#"+$.jgrid.jqID(IDs.modalhead)).focus();},0);}});},navGrid:function(elem,o,pEdit,pAdd,pDel,pSearch,pView){o=$.extend({edit:true,editicon:"ui-icon-pencil",add:true,addicon:"ui-icon-plus",del:true,delicon:"ui-icon-trash",search:true,searchicon:"ui-icon-search",refresh:true,refreshicon:"ui-icon-refresh",refreshstate:'firstpage',view:false,viewicon:"ui-icon-document",position:"left",closeOnEscape:true,beforeRefresh:null,afterRefresh:null,cloneToTop:false,alertwidth:200,alertheight:'auto',alerttop:null,alertleft:null,alertzIndex:null},$.jgrid.nav,o||{});return this.each(function(){if(this.nav){return;}
var alertIDs={themodal:'alertmod_'+this.p.id,modalhead:'alerthd_'+this.p.id,modalcontent:'alertcnt_'+this.p.id},$t=this,twd,tdw;if(!$t.grid||typeof elem!=='string'){return;}
if($("#"+alertIDs.themodal)[0]===undefined){if(!o.alerttop&&!o.alertleft){if(window.innerWidth!==undefined){o.alertleft=window.innerWidth;o.alerttop=window.innerHeight;}else if(document.documentElement!==undefined&&document.documentElement.clientWidth!==undefined&&document.documentElement.clientWidth!==0){o.alertleft=document.documentElement.clientWidth;o.alerttop=document.documentElement.clientHeight;}else{o.alertleft=1024;o.alerttop=768;}
o.alertleft=o.alertleft/2-parseInt(o.alertwidth,10)/2;o.alerttop=o.alerttop/2-25;}
$.jgrid.createModal(alertIDs,"<div>"+o.alerttext+"</div><span tabindex='0'><span tabindex='-1' id='jqg_alrt'></span></span>",{gbox:"#gbox_"+$.jgrid.jqID($t.p.id),jqModal:true,drag:true,resize:true,caption:o.alertcap,top:o.alerttop,left:o.alertleft,width:o.alertwidth,height:o.alertheight,closeOnEscape:o.closeOnEscape,zIndex:o.alertzIndex},"#gview_"+$.jgrid.jqID($t.p.id),$("#gbox_"+$.jgrid.jqID($t.p.id))[0],true);}
var clone=1,i,onHoverIn=function(){if(!$(this).hasClass('ui-state-disabled')){$(this).addClass("ui-state-hover");}},onHoverOut=function(){$(this).removeClass("ui-state-hover");};if(o.cloneToTop&&$t.p.toppager){clone=2;}
for(i=0;i<clone;i++){var tbd,navtbl=$("<table cellspacing='0' cellpadding='0' border='0' class='ui-pg-table navtable' style='float:left;table-layout:auto;'><tbody><tr></tr></tbody></table>"),sep="<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='ui-separator'></span></td>",pgid,elemids;if(i===0){pgid=elem;elemids=$t.p.id;if(pgid===$t.p.toppager){elemids+="_top";clone=1;}}else{pgid=$t.p.toppager;elemids=$t.p.id+"_top";}
if($t.p.direction==="rtl"){$(navtbl).attr("dir","rtl").css("float","right");}
if(o.add){pAdd=pAdd||{};tbd=$("<td class='ui-pg-button ui-corner-all'></td>");$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.addicon+"'></span>"+o.addtext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.addtitle||"",id:pAdd.id||"add_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){if($.isFunction(o.addfunc)){o.addfunc.call($t);}else{$($t).jqGrid("editGridRow","new",pAdd);}}
return false;}).hover(onHoverIn,onHoverOut);tbd=null;}
if(o.edit){tbd=$("<td class='ui-pg-button ui-corner-all'></td>");pEdit=pEdit||{};$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.editicon+"'></span>"+o.edittext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.edittitle||"",id:pEdit.id||"edit_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){var sr=$t.p.selrow;if(sr){if($.isFunction(o.editfunc)){o.editfunc.call($t,sr);}else{$($t).jqGrid("editGridRow",sr,pEdit);}}else{$.jgrid.viewModal("#"+alertIDs.themodal,{gbox:"#gbox_"+$.jgrid.jqID($t.p.id),jqm:true});$("#jqg_alrt").focus();}}
return false;}).hover(onHoverIn,onHoverOut);tbd=null;}
if(o.view){tbd=$("<td class='ui-pg-button ui-corner-all'></td>");pView=pView||{};$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.viewicon+"'></span>"+o.viewtext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.viewtitle||"",id:pView.id||"view_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){var sr=$t.p.selrow;if(sr){if($.isFunction(o.viewfunc)){o.viewfunc.call($t,sr);}else{$($t).jqGrid("viewGridRow",sr,pView);}}else{$.jgrid.viewModal("#"+alertIDs.themodal,{gbox:"#gbox_"+$.jgrid.jqID($t.p.id),jqm:true});$("#jqg_alrt").focus();}}
return false;}).hover(onHoverIn,onHoverOut);tbd=null;}
if(o.del){tbd=$("<td class='ui-pg-button ui-corner-all'></td>");pDel=pDel||{};$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.delicon+"'></span>"+o.deltext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.deltitle||"",id:pDel.id||"del_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){var dr;if($t.p.multiselect){dr=$t.p.selarrrow;if(dr.length===0){dr=null;}}else{dr=$t.p.selrow;}
if(dr){if($.isFunction(o.delfunc)){o.delfunc.call($t,dr);}else{$($t).jqGrid("delGridRow",dr,pDel);}}else{$.jgrid.viewModal("#"+alertIDs.themodal,{gbox:"#gbox_"+$.jgrid.jqID($t.p.id),jqm:true});$("#jqg_alrt").focus();}}
return false;}).hover(onHoverIn,onHoverOut);tbd=null;}
if(o.add||o.edit||o.del||o.view){$("tr",navtbl).append(sep);}
if(o.search){tbd=$("<td class='ui-pg-button ui-corner-all'></td>");pSearch=pSearch||{};$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.searchicon+"'></span>"+o.searchtext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.searchtitle||"",id:pSearch.id||"search_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){if($.isFunction(o.searchfunc)){o.searchfunc.call($t,pSearch);}else{$($t).jqGrid("searchGrid",pSearch);}}
return false;}).hover(onHoverIn,onHoverOut);if(pSearch.showOnLoad&&pSearch.showOnLoad===true){$(tbd,navtbl).click();}
tbd=null;}
if(o.refresh){tbd=$("<td class='ui-pg-button ui-corner-all'></td>");$(tbd).append("<div class='ui-pg-div'><span class='ui-icon "+o.refreshicon+"'></span>"+o.refreshtext+"</div>");$("tr",navtbl).append(tbd);$(tbd,navtbl).attr({"title":o.refreshtitle||"",id:"refresh_"+elemids}).click(function(){if(!$(this).hasClass('ui-state-disabled')){if($.isFunction(o.beforeRefresh)){o.beforeRefresh.call($t);}
$t.p.search=false;try{var gID=$t.p.id;$t.p.postData.filters="";try{$("#fbox_"+$.jgrid.jqID(gID)).jqFilter('resetFilter');}catch(ef){}
if($.isFunction($t.clearToolbar)){$t.clearToolbar.call($t,false);}}catch(e){}
switch(o.refreshstate){case'firstpage':$($t).trigger("reloadGrid",[{page:1}]);break;case'current':$($t).trigger("reloadGrid",[{current:true}]);break;}
if($.isFunction(o.afterRefresh)){o.afterRefresh.call($t);}}
return false;}).hover(onHoverIn,onHoverOut);tbd=null;}
tdw=$(".ui-jqgrid").css("font-size")||"11px";$('body').append("<div id='testpg2' class='ui-jqgrid ui-widget ui-widget-content' style='font-size:"+tdw+";visibility:hidden;' ></div>");twd=$(navtbl).clone().appendTo("#testpg2").width();$("#testpg2").remove();$(pgid+"_"+o.position,pgid).append(navtbl);if($t.p._nvtd){if(twd>$t.p._nvtd[0]){$(pgid+"_"+o.position,pgid).width(twd);$t.p._nvtd[0]=twd;}
$t.p._nvtd[1]=twd;}
tdw=null;twd=null;navtbl=null;this.nav=true;}});},navButtonAdd:function(elem,p){p=$.extend({caption:"newButton",title:'',buttonicon:'ui-icon-newwin',onClickButton:null,position:"last",cursor:'pointer'},p||{});return this.each(function(){if(!this.grid){return;}
if(typeof elem==="string"&&elem.indexOf("#")!==0){elem="#"+$.jgrid.jqID(elem);}
var findnav=$(".navtable",elem)[0],$t=this;if(findnav){if(p.id&&$("#"+$.jgrid.jqID(p.id),findnav)[0]!==undefined){return;}
var tbd=$("<td></td>");if(p.buttonicon.toString().toUpperCase()==="NONE"){$(tbd).addClass('ui-pg-button ui-corner-all').append("<div class='ui-pg-div'>"+p.caption+"</div>");}else{$(tbd).addClass('ui-pg-button ui-corner-all').append("<div class='ui-pg-div'><span class='ui-icon "+p.buttonicon+"'></span>"+p.caption+"</div>");}
if(p.id){$(tbd).attr("id",p.id);}
if(p.position==='first'){if(findnav.rows[0].cells.length===0){$("tr",findnav).append(tbd);}else{$("tr td:eq(0)",findnav).before(tbd);}}else{$("tr",findnav).append(tbd);}
$(tbd,findnav).attr("title",p.title||"").click(function(e){if(!$(this).hasClass('ui-state-disabled')){if($.isFunction(p.onClickButton)){p.onClickButton.call($t,e);}}
return false;}).hover(function(){if(!$(this).hasClass('ui-state-disabled')){$(this).addClass('ui-state-hover');}},function(){$(this).removeClass("ui-state-hover");});}});},navSeparatorAdd:function(elem,p){p=$.extend({sepclass:"ui-separator",sepcontent:'',position:"last"},p||{});return this.each(function(){if(!this.grid){return;}
if(typeof elem==="string"&&elem.indexOf("#")!==0){elem="#"+$.jgrid.jqID(elem);}
var findnav=$(".navtable",elem)[0];if(findnav){var sep="<td class='ui-pg-button ui-state-disabled' style='width:4px;'><span class='"+p.sepclass+"'></span>"+p.sepcontent+"</td>";if(p.position==='first'){if(findnav.rows[0].cells.length===0){$("tr",findnav).append(sep);}else{$("tr td:eq(0)",findnav).before(sep);}}else{$("tr",findnav).append(sep);}}});},GridToForm:function(rowid,formid){return this.each(function(){var $t=this,i;if(!$t.grid){return;}
var rowdata=$($t).jqGrid("getRowData",rowid);if(rowdata){for(i in rowdata){if(rowdata.hasOwnProperty(i)){if($("[name="+$.jgrid.jqID(i)+"]",formid).is("input:radio")||$("[name="+$.jgrid.jqID(i)+"]",formid).is("input:checkbox")){$("[name="+$.jgrid.jqID(i)+"]",formid).each(function(){if($(this).val()==rowdata[i]){$(this)[$t.p.useProp?'prop':'attr']("checked",true);}else{$(this)[$t.p.useProp?'prop':'attr']("checked",false);}});}else{$("[name="+$.jgrid.jqID(i)+"]",formid).val(rowdata[i]);}}}}});},FormToGrid:function(rowid,formid,mode,position){return this.each(function(){var $t=this;if(!$t.grid){return;}
if(!mode){mode='set';}
if(!position){position='first';}
var fields=$(formid).serializeArray();var griddata={};$.each(fields,function(i,field){griddata[field.name]=field.value;});if(mode==='add'){$($t).jqGrid("addRowData",rowid,griddata,position);}else if(mode==='set'){$($t).jqGrid("setRowData",rowid,griddata);}});}});})(jQuery);(function($){"use strict";$.jgrid.inlineEdit=$.jgrid.inlineEdit||{};$.jgrid.extend({editRow:function(rowid,keys,oneditfunc,successfunc,url,extraparam,aftersavefunc,errorfunc,afterrestorefunc){var o={},args=$.makeArray(arguments).slice(1);if($.type(args[0])==="object"){o=args[0];}else{if(keys!==undefined){o.keys=keys;}
if($.isFunction(oneditfunc)){o.oneditfunc=oneditfunc;}
if($.isFunction(successfunc)){o.successfunc=successfunc;}
if(url!==undefined){o.url=url;}
if(extraparam!==undefined){o.extraparam=extraparam;}
if($.isFunction(aftersavefunc)){o.aftersavefunc=aftersavefunc;}
if($.isFunction(errorfunc)){o.errorfunc=errorfunc;}
if($.isFunction(afterrestorefunc)){o.afterrestorefunc=afterrestorefunc;}}
o=$.extend(true,{keys:false,oneditfunc:null,successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:true,mtype:"POST"},$.jgrid.inlineEdit,o);return this.each(function(){var $t=this,nm,tmp,editable,cnt=0,focus=null,svr={},ind,cm,bfer;if(!$t.grid){return;}
ind=$($t).jqGrid("getInd",rowid,true);if(ind===false){return;}
bfer=$.isFunction(o.beforeEditRow)?o.beforeEditRow.call($t,o,rowid):undefined;if(bfer===undefined){bfer=true;}
if(!bfer){return;}
editable=$(ind).attr("editable")||"0";if(editable==="0"&&!$(ind).hasClass("not-editable-row")){cm=$t.p.colModel;$('td[role="gridcell"]',ind).each(function(i){nm=cm[i].name;var treeg=$t.p.treeGrid===true&&nm===$t.p.ExpandColumn;if(treeg){tmp=$("span:first",this).html();}else{try{tmp=$.unformat.call($t,this,{rowId:rowid,colModel:cm[i]},i);}catch(_){tmp=(cm[i].edittype&&cm[i].edittype==='textarea')?$(this).text():$(this).html();}}
if(nm!=='cb'&&nm!=='subgrid'&&nm!=='rn'){if($t.p.autoencode){tmp=$.jgrid.htmlDecode(tmp);}
svr[nm]=tmp;if(cm[i].editable===true){if(focus===null){focus=i;}
if(treeg){$("span:first",this).html("");}else{$(this).html("");}
var opt=$.extend({},cm[i].editoptions||{},{id:rowid+"_"+nm,name:nm});if(!cm[i].edittype){cm[i].edittype="text";}
if(tmp==="&nbsp;"||tmp==="&#160;"||(tmp.length===1&&tmp.charCodeAt(0)===160)){tmp='';}
var elc=$.jgrid.createEl.call($t,cm[i].edittype,opt,tmp,true,$.extend({},$.jgrid.ajaxOptions,$t.p.ajaxSelectOptions||{}));$(elc).addClass("editable");if(treeg){$("span:first",this).append(elc);}else{$(this).append(elc);}
$.jgrid.bindEv.call($t,elc,opt);if(cm[i].edittype==="select"&&cm[i].editoptions!==undefined&&cm[i].editoptions.multiple===true&&cm[i].editoptions.dataUrl===undefined&&$.jgrid.msie){$(elc).width($(elc).width());}
cnt++;}}});if(cnt>0){svr.id=rowid;$t.p.savedRow.push(svr);$(ind).attr("editable","1");$("td:eq("+focus+") input",ind).focus();if(o.keys===true){$(ind).bind("keydown",function(e){if(e.keyCode===27){$($t).jqGrid("restoreRow",rowid,o.afterrestorefunc);if($t.p._inlinenav){try{$($t).jqGrid('showAddEditButtons');}catch(eer1){}}
return false;}
if(e.keyCode===13){var ta=e.target;if(ta.tagName==='TEXTAREA'){return true;}
if($($t).jqGrid("saveRow",rowid,o)){if($t.p._inlinenav){try{$($t).jqGrid('showAddEditButtons');}catch(eer2){}}}
return false;}});}
$($t).triggerHandler("jqGridInlineEditRow",[rowid,o]);if($.isFunction(o.oneditfunc)){o.oneditfunc.call($t,rowid);}}}});},saveRow:function(rowid,successfunc,url,extraparam,aftersavefunc,errorfunc,afterrestorefunc){var args=$.makeArray(arguments).slice(1),o={};if($.type(args[0])==="object"){o=args[0];}else{if($.isFunction(successfunc)){o.successfunc=successfunc;}
if(url!==undefined){o.url=url;}
if(extraparam!==undefined){o.extraparam=extraparam;}
if($.isFunction(aftersavefunc)){o.aftersavefunc=aftersavefunc;}
if($.isFunction(errorfunc)){o.errorfunc=errorfunc;}
if($.isFunction(afterrestorefunc)){o.afterrestorefunc=afterrestorefunc;}}
o=$.extend(true,{successfunc:null,url:null,extraparam:{},aftersavefunc:null,errorfunc:null,afterrestorefunc:null,restoreAfterError:true,mtype:"POST"},$.jgrid.inlineEdit,o);var success=false;var $t=this[0],nm,tmp={},tmp2={},tmp3={},editable,fr,cv,ind;if(!$t.grid){return success;}
ind=$($t).jqGrid("getInd",rowid,true);if(ind===false){return success;}
var bfsr=$.isFunction(o.beforeSaveRow)?o.beforeSaveRow.call($t,o,rowid):undefined;if(bfsr===undefined){bfsr=true;}
if(!bfsr){return;}
editable=$(ind).attr("editable");o.url=o.url||$t.p.editurl;if(editable==="1"){var cm;$('td[role="gridcell"]',ind).each(function(i){cm=$t.p.colModel[i];nm=cm.name;if(nm!=='cb'&&nm!=='subgrid'&&cm.editable===true&&nm!=='rn'&&!$(this).hasClass('not-editable-cell')){switch(cm.edittype){case"checkbox":var cbv=["Yes","No"];if(cm.editoptions){cbv=cm.editoptions.value.split(":");}
tmp[nm]=$("input",this).is(":checked")?cbv[0]:cbv[1];break;case'text':case'password':case'textarea':case"button":tmp[nm]=$("input, textarea",this).val();break;case'select':if(!cm.editoptions.multiple){tmp[nm]=$("select option:selected",this).val();tmp2[nm]=$("select option:selected",this).text();}else{var sel=$("select",this),selectedText=[];tmp[nm]=$(sel).val();if(tmp[nm]){tmp[nm]=tmp[nm].join(",");}else{tmp[nm]="";}
$("select option:selected",this).each(function(i,selected){selectedText[i]=$(selected).text();});tmp2[nm]=selectedText.join(",");}
if(cm.formatter&&cm.formatter==='select'){tmp2={};}
break;case'custom':try{if(cm.editoptions&&$.isFunction(cm.editoptions.custom_value)){tmp[nm]=cm.editoptions.custom_value.call($t,$(".customelement",this),'get');if(tmp[nm]===undefined){throw"e2";}}else{throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.nodefined,$.jgrid.edit.bClose);}
if(e==="e2"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.novalue,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,e.message,$.jgrid.edit.bClose);}}
break;}
cv=$.jgrid.checkValues.call($t,tmp[nm],i);if(cv[0]===false){return false;}
if($t.p.autoencode){tmp[nm]=$.jgrid.htmlEncode(tmp[nm]);}
if(o.url!=='clientArray'&&cm.editoptions&&cm.editoptions.NullIfEmpty===true){if(tmp[nm]===""){tmp3[nm]='null';}}}});if(cv[0]===false){try{var tr=$($t).jqGrid('getGridRowById',rowid),positions=$.jgrid.findPos(tr);$.jgrid.info_dialog($.jgrid.errors.errcap,cv[1],$.jgrid.edit.bClose,{left:positions[0],top:positions[1]+$(tr).outerHeight()});}catch(e){alert(cv[1]);}
return success;}
var idname,opers=$t.p.prmNames,oldRowId=rowid;if($t.p.keyIndex===false){idname=opers.id;}else{idname=$t.p.colModel[$t.p.keyIndex+
($t.p.rownumbers===true?1:0)+
($t.p.multiselect===true?1:0)+
($t.p.subGrid===true?1:0)].name;}
if(tmp){tmp[opers.oper]=opers.editoper;if(tmp[idname]===undefined||tmp[idname]===""){tmp[idname]=rowid;}else if(ind.id!==$t.p.idPrefix+tmp[idname]){var oldid=$.jgrid.stripPref($t.p.idPrefix,rowid);if($t.p._index[oldid]!==undefined){$t.p._index[tmp[idname]]=$t.p._index[oldid];delete $t.p._index[oldid];}
rowid=$t.p.idPrefix+tmp[idname];$(ind).attr("id",rowid);if($t.p.selrow===oldRowId){$t.p.selrow=rowid;}
if($.isArray($t.p.selarrrow)){var i=$.inArray(oldRowId,$t.p.selarrrow);if(i>=0){$t.p.selarrrow[i]=rowid;}}
if($t.p.multiselect){var newCboxId="jqg_"+$t.p.id+"_"+rowid;$("input.cbox",ind).attr("id",newCboxId).attr("name",newCboxId);}}
if($t.p.inlineData===undefined){$t.p.inlineData={};}
tmp=$.extend({},tmp,$t.p.inlineData,o.extraparam);}
if(o.url==='clientArray'){tmp=$.extend({},tmp,tmp2);if($t.p.autoencode){$.each(tmp,function(n,v){tmp[n]=$.jgrid.htmlDecode(v);});}
var k,resp=$($t).jqGrid("setRowData",rowid,tmp);$(ind).attr("editable","0");for(k=0;k<$t.p.savedRow.length;k++){if(String($t.p.savedRow[k].id)===String(oldRowId)){fr=k;break;}}
if(fr>=0){$t.p.savedRow.splice(fr,1);}
$($t).triggerHandler("jqGridInlineAfterSaveRow",[rowid,resp,tmp,o]);if($.isFunction(o.aftersavefunc)){o.aftersavefunc.call($t,rowid,resp,o);}
success=true;$(ind).removeClass("jqgrid-new-row").unbind("keydown");}else{$("#lui_"+$.jgrid.jqID($t.p.id)).show();tmp3=$.extend({},tmp,tmp3);tmp3[idname]=$.jgrid.stripPref($t.p.idPrefix,tmp3[idname]);$.ajax($.extend({url:o.url,data:$.isFunction($t.p.serializeRowData)?$t.p.serializeRowData.call($t,tmp3):tmp3,type:o.mtype,async:false,complete:function(res,stat){$("#lui_"+$.jgrid.jqID($t.p.id)).hide();if(stat==="success"){var ret=true,sucret,k;sucret=$($t).triggerHandler("jqGridInlineSuccessSaveRow",[res,rowid,o]);if(!$.isArray(sucret)){sucret=[true,tmp];}
if(sucret[0]&&$.isFunction(o.successfunc)){sucret=o.successfunc.call($t,res);}
if($.isArray(sucret)){ret=sucret[0];tmp=sucret[1]||tmp;}else{ret=sucret;}
if(ret===true){if($t.p.autoencode){$.each(tmp,function(n,v){tmp[n]=$.jgrid.htmlDecode(v);});}
tmp=$.extend({},tmp,tmp2);$($t).jqGrid("setRowData",rowid,tmp);$(ind).attr("editable","0");for(k=0;k<$t.p.savedRow.length;k++){if(String($t.p.savedRow[k].id)===String(rowid)){fr=k;break;}}
if(fr>=0){$t.p.savedRow.splice(fr,1);}
$($t).triggerHandler("jqGridInlineAfterSaveRow",[rowid,res,tmp,o]);if($.isFunction(o.aftersavefunc)){o.aftersavefunc.call($t,rowid,res);}
success=true;$(ind).removeClass("jqgrid-new-row").unbind("keydown");}else{$($t).triggerHandler("jqGridInlineErrorSaveRow",[rowid,res,stat,null,o]);if($.isFunction(o.errorfunc)){o.errorfunc.call($t,rowid,res,stat,null);}
if(o.restoreAfterError===true){$($t).jqGrid("restoreRow",rowid,o.afterrestorefunc);}}}},error:function(res,stat,err){$("#lui_"+$.jgrid.jqID($t.p.id)).hide();$($t).triggerHandler("jqGridInlineErrorSaveRow",[rowid,res,stat,err,o]);if($.isFunction(o.errorfunc)){o.errorfunc.call($t,rowid,res,stat,err);}else{var rT=res.responseText||res.statusText;try{$.jgrid.info_dialog($.jgrid.errors.errcap,'<div class="ui-state-error">'+rT+'</div>',$.jgrid.edit.bClose,{buttonalign:'right'});}catch(e){alert(rT);}}
if(o.restoreAfterError===true){$($t).jqGrid("restoreRow",rowid,o.afterrestorefunc);}}},$.jgrid.ajaxOptions,$t.p.ajaxRowOptions||{}));}}
return success;},restoreRow:function(rowid,afterrestorefunc){var args=$.makeArray(arguments).slice(1),o={};if($.type(args[0])==="object"){o=args[0];}else{if($.isFunction(afterrestorefunc)){o.afterrestorefunc=afterrestorefunc;}}
o=$.extend(true,{},$.jgrid.inlineEdit,o);return this.each(function(){var $t=this,fr,ind,ares={},k;if(!$t.grid){return;}
ind=$($t).jqGrid("getInd",rowid,true);if(ind===false){return;}
var bfcr=$.isFunction(o.beforeCancelRow)?o.beforeCancelRow.call($t,cancelPrm,sr):undefined;if(bfcr===undefined){bfcr=true;}
if(!bfcr){return;}
for(k=0;k<$t.p.savedRow.length;k++){if(String($t.p.savedRow[k].id)===String(rowid)){fr=k;break;}}
if(fr>=0){if($.isFunction($.fn.datepicker)){try{$("input.hasDatepicker","#"+$.jgrid.jqID(ind.id)).datepicker('hide');}catch(e){}}
$.each($t.p.colModel,function(){if(this.editable===true&&$t.p.savedRow[fr].hasOwnProperty(this.name)){ares[this.name]=$t.p.savedRow[fr][this.name];}});$($t).jqGrid("setRowData",rowid,ares);$(ind).attr("editable","0").unbind("keydown");$t.p.savedRow.splice(fr,1);if($("#"+$.jgrid.jqID(rowid),"#"+$.jgrid.jqID($t.p.id)).hasClass("jqgrid-new-row")){setTimeout(function(){$($t).jqGrid("delRowData",rowid);$($t).jqGrid('showAddEditButtons');},0);}}
$($t).triggerHandler("jqGridInlineAfterRestoreRow",[rowid]);if($.isFunction(o.afterrestorefunc)){o.afterrestorefunc.call($t,rowid);}});},addRow:function(p){p=$.extend(true,{rowID:null,initdata:{},position:"first",useDefValues:true,useFormatter:false,addRowParams:{extraparam:{}}},p||{});return this.each(function(){if(!this.grid){return;}
var $t=this;var bfar=$.isFunction(p.beforeAddRow)?p.beforeAddRow.call($t,p.addRowParams):undefined;if(bfar===undefined){bfar=true;}
if(!bfar){return;}
p.rowID=$.isFunction(p.rowID)?p.rowID.call($t,p):((p.rowID!=null)?p.rowID:$.jgrid.randId());if(p.useDefValues===true){$($t.p.colModel).each(function(){if(this.editoptions&&this.editoptions.defaultValue){var opt=this.editoptions.defaultValue,tmp=$.isFunction(opt)?opt.call($t):opt;p.initdata[this.name]=tmp;}});}
$($t).jqGrid('addRowData',p.rowID,p.initdata,p.position);p.rowID=$t.p.idPrefix+p.rowID;$("#"+$.jgrid.jqID(p.rowID),"#"+$.jgrid.jqID($t.p.id)).addClass("jqgrid-new-row");if(p.useFormatter){$("#"+$.jgrid.jqID(p.rowID)+" .ui-inline-edit","#"+$.jgrid.jqID($t.p.id)).click();}else{var opers=$t.p.prmNames,oper=opers.oper;p.addRowParams.extraparam[oper]=opers.addoper;$($t).jqGrid('editRow',p.rowID,p.addRowParams);$($t).jqGrid('setSelection',p.rowID);}});},inlineNav:function(elem,o){o=$.extend(true,{edit:true,editicon:"ui-icon-pencil",add:true,addicon:"ui-icon-plus",save:true,saveicon:"ui-icon-disk",cancel:true,cancelicon:"ui-icon-cancel",addParams:{addRowParams:{extraparam:{}}},editParams:{},restoreAfterSelect:true},$.jgrid.nav,o||{});return this.each(function(){if(!this.grid){return;}
var $t=this,onSelect,gID=$.jgrid.jqID($t.p.id);$t.p._inlinenav=true;if(o.addParams.useFormatter===true){var cm=$t.p.colModel,i;for(i=0;i<cm.length;i++){if(cm[i].formatter&&cm[i].formatter==="actions"){if(cm[i].formatoptions){var defaults={keys:false,onEdit:null,onSuccess:null,afterSave:null,onError:null,afterRestore:null,extraparam:{},url:null},ap=$.extend(defaults,cm[i].formatoptions);o.addParams.addRowParams={"keys":ap.keys,"oneditfunc":ap.onEdit,"successfunc":ap.onSuccess,"url":ap.url,"extraparam":ap.extraparam,"aftersavefunc":ap.afterSave,"errorfunc":ap.onError,"afterrestorefunc":ap.afterRestore};}
break;}}}
if(o.add){$($t).jqGrid('navButtonAdd',elem,{caption:o.addtext,title:o.addtitle,buttonicon:o.addicon,id:$t.p.id+"_iladd",onClickButton:function(){$($t).jqGrid('addRow',o.addParams);if(!o.addParams.useFormatter){$("#"+gID+"_ilsave").removeClass('ui-state-disabled');$("#"+gID+"_ilcancel").removeClass('ui-state-disabled');$("#"+gID+"_iladd").addClass('ui-state-disabled');$("#"+gID+"_iledit").addClass('ui-state-disabled');}}});}
if(o.edit){$($t).jqGrid('navButtonAdd',elem,{caption:o.edittext,title:o.edittitle,buttonicon:o.editicon,id:$t.p.id+"_iledit",onClickButton:function(){var sr=$($t).jqGrid('getGridParam','selrow');if(sr){$($t).jqGrid('editRow',sr,o.editParams);$("#"+gID+"_ilsave").removeClass('ui-state-disabled');$("#"+gID+"_ilcancel").removeClass('ui-state-disabled');$("#"+gID+"_iladd").addClass('ui-state-disabled');$("#"+gID+"_iledit").addClass('ui-state-disabled');}else{$.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+gID,jqm:true});$("#jqg_alrt").focus();}}});}
if(o.save){$($t).jqGrid('navButtonAdd',elem,{caption:o.savetext||'',title:o.savetitle||'Save row',buttonicon:o.saveicon,id:$t.p.id+"_ilsave",onClickButton:function(){var sr=$t.p.savedRow[0].id;if(sr){var opers=$t.p.prmNames,oper=opers.oper,tmpParams={};if($("#"+$.jgrid.jqID(sr),"#"+gID).hasClass("jqgrid-new-row")){o.addParams.addRowParams.extraparam[oper]=opers.addoper;tmpParams=o.addParams.addRowParams;}else{if(!o.editParams.extraparam){o.editParams.extraparam={};}
o.editParams.extraparam[oper]=opers.editoper;tmpParams=o.editParams;}
if($($t).jqGrid('saveRow',sr,tmpParams)){$($t).jqGrid('showAddEditButtons');}}else{$.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+gID,jqm:true});$("#jqg_alrt").focus();}}});$("#"+gID+"_ilsave").addClass('ui-state-disabled');}
if(o.cancel){$($t).jqGrid('navButtonAdd',elem,{caption:o.canceltext||'',title:o.canceltitle||'Cancel row editing',buttonicon:o.cancelicon,id:$t.p.id+"_ilcancel",onClickButton:function(){var sr=$t.p.savedRow[0].id,cancelPrm={};if(sr){if($("#"+$.jgrid.jqID(sr),"#"+gID).hasClass("jqgrid-new-row")){cancelPrm=o.addParams.addRowParams;}else{cancelPrm=o.editParams;}
$($t).jqGrid('restoreRow',sr,cancelPrm);$($t).jqGrid('showAddEditButtons');}else{$.jgrid.viewModal("#alertmod",{gbox:"#gbox_"+gID,jqm:true});$("#jqg_alrt").focus();}}});$("#"+gID+"_ilcancel").addClass('ui-state-disabled');}
if(o.restoreAfterSelect===true){if($.isFunction($t.p.beforeSelectRow)){onSelect=$t.p.beforeSelectRow;}else{onSelect=false;}
$t.p.beforeSelectRow=function(id,stat){var ret=true;if($t.p.savedRow.length>0&&$t.p._inlinenav===true&&(id!==$t.p.selrow&&$t.p.selrow!==null)){if($t.p.selrow===o.addParams.rowID){$($t).jqGrid('delRowData',$t.p.selrow);}else{$($t).jqGrid('restoreRow',$t.p.selrow,o.editParams);}
$($t).jqGrid('showAddEditButtons');}
if(onSelect){ret=onSelect.call($t,id,stat);}
return ret;};}});},showAddEditButtons:function(){return this.each(function(){if(!this.grid){return;}
var gID=$.jgrid.jqID(this.p.id);$("#"+gID+"_ilsave").addClass('ui-state-disabled');$("#"+gID+"_ilcancel").addClass('ui-state-disabled');$("#"+gID+"_iladd").removeClass('ui-state-disabled');$("#"+gID+"_iledit").removeClass('ui-state-disabled');});}});})(jQuery);(function($){"use strict";$.jgrid.extend({editCell:function(iRow,iCol,ed){return this.each(function(){var $t=this,nm,tmp,cc,cm;if(!$t.grid||$t.p.cellEdit!==true){return;}
iCol=parseInt(iCol,10);$t.p.selrow=$t.rows[iRow].id;if(!$t.p.knv){$($t).jqGrid("GridNav");}
if($t.p.savedRow.length>0){if(ed===true){if(iRow==$t.p.iRow&&iCol==$t.p.iCol){return;}}
$($t).jqGrid("saveCell",$t.p.savedRow[0].id,$t.p.savedRow[0].ic);}else{window.setTimeout(function(){$("#"+$.jgrid.jqID($t.p.knv)).attr("tabindex","-1").focus();},0);}
cm=$t.p.colModel[iCol];nm=cm.name;if(nm==='subgrid'||nm==='cb'||nm==='rn'){return;}
cc=$("td:eq("+iCol+")",$t.rows[iRow]);if(cm.editable===true&&ed===true&&!cc.hasClass("not-editable-cell")){if(parseInt($t.p.iCol,10)>=0&&parseInt($t.p.iRow,10)>=0){$("td:eq("+$t.p.iCol+")",$t.rows[$t.p.iRow]).removeClass("edit-cell ui-state-highlight");$($t.rows[$t.p.iRow]).removeClass("selected-row ui-state-hover");}
$(cc).addClass("edit-cell ui-state-highlight");$($t.rows[iRow]).addClass("selected-row ui-state-hover");try{tmp=$.unformat.call($t,cc,{rowId:$t.rows[iRow].id,colModel:cm},iCol);}catch(_){tmp=(cm.edittype&&cm.edittype==='textarea')?$(cc).text():$(cc).html();}
if($t.p.autoencode){tmp=$.jgrid.htmlDecode(tmp);}
if(!cm.edittype){cm.edittype="text";}
$t.p.savedRow.push({id:iRow,ic:iCol,name:nm,v:tmp});if(tmp==="&nbsp;"||tmp==="&#160;"||(tmp.length===1&&tmp.charCodeAt(0)===160)){tmp='';}
if($.isFunction($t.p.formatCell)){var tmp2=$t.p.formatCell.call($t,$t.rows[iRow].id,nm,tmp,iRow,iCol);if(tmp2!==undefined){tmp=tmp2;}}
$($t).triggerHandler("jqGridBeforeEditCell",[$t.rows[iRow].id,nm,tmp,iRow,iCol]);if($.isFunction($t.p.beforeEditCell)){$t.p.beforeEditCell.call($t,$t.rows[iRow].id,nm,tmp,iRow,iCol);}
var opt=$.extend({},cm.editoptions||{},{id:iRow+"_"+nm,name:nm});var elc=$.jgrid.createEl.call($t,cm.edittype,opt,tmp,true,$.extend({},$.jgrid.ajaxOptions,$t.p.ajaxSelectOptions||{}));$(cc).html("").append(elc).attr("tabindex","0");$.jgrid.bindEv.call($t,elc,opt);window.setTimeout(function(){$(elc).focus();},0);$("input, select, textarea",cc).bind("keydown",function(e){if(e.keyCode===27){if($("input.hasDatepicker",cc).length>0){if($(".ui-datepicker").is(":hidden")){$($t).jqGrid("restoreCell",iRow,iCol);}else{$("input.hasDatepicker",cc).datepicker('hide');}}else{$($t).jqGrid("restoreCell",iRow,iCol);}}
if(e.keyCode===13){if(!$t.grid.hDiv.loading){if(e.shiftKey){$($t).jqGrid("prevCell",iRow,iCol);}
else{$($t).jqGrid("nextCell",iRow,iCol);}}else{return false;}}
if(e.keyCode===9){if(!$t.grid.hDiv.loading){if(e.shiftKey){$($t).jqGrid("prevCell",iRow,iCol);e.stopPropagation();return false;}
else{$($t).jqGrid("nextCell",iRow,iCol);e.stopPropagation();return false;}}else{return false;}}
e.stopPropagation();});$($t).triggerHandler("jqGridAfterEditCell",[$t.rows[iRow].id,nm,tmp,iRow,iCol]);if($.isFunction($t.p.afterEditCell)){$t.p.afterEditCell.call($t,$t.rows[iRow].id,nm,tmp,iRow,iCol);}}else{if(parseInt($t.p.iCol,10)>=0&&parseInt($t.p.iRow,10)>=0){$("td:eq("+$t.p.iCol+")",$t.rows[$t.p.iRow]).removeClass("edit-cell ui-state-highlight");$($t.rows[$t.p.iRow]).removeClass("selected-row ui-state-hover");}
cc.addClass("edit-cell ui-state-highlight");$($t.rows[iRow]).addClass("selected-row ui-state-hover");tmp=cc.html().replace(/\&#160\;/ig,'');$($t).triggerHandler("jqGridSelectCell",[$t.rows[iRow].id,nm,tmp,iRow,iCol]);if($.isFunction($t.p.onSelectCell)){$t.p.onSelectCell.call($t,$t.rows[iRow].id,nm,tmp,iRow,iCol);}}
$t.p.iCol=iCol;$t.p.iRow=iRow;});},saveCell:function(iRow,iCol){return this.each(function(){var $t=this,fr;if(!$t.grid||$t.p.cellEdit!==true){return;}
if($t.p.savedRow.length>=1){fr=0;}else{fr=null;}
if(fr!==null){var cc=$("td:eq("+iCol+")",$t.rows[iRow]),v,v2,cm=$t.p.colModel[iCol],nm=cm.name,nmjq=$.jgrid.jqID(nm);switch(cm.edittype){case"select":if(!cm.editoptions.multiple){v=$("#"+iRow+"_"+nmjq+" option:selected",$t.rows[iRow]).val();v2=$("#"+iRow+"_"+nmjq+" option:selected",$t.rows[iRow]).text();}else{var sel=$("#"+iRow+"_"+nmjq,$t.rows[iRow]),selectedText=[];v=$(sel).val();if(v){v.join(",");}else{v="";}
$("option:selected",sel).each(function(i,selected){selectedText[i]=$(selected).text();});v2=selectedText.join(",");}
if(cm.formatter){v2=v;}
break;case"checkbox":var cbv=["Yes","No"];if(cm.editoptions){cbv=cm.editoptions.value.split(":");}
v=$("#"+iRow+"_"+nmjq,$t.rows[iRow]).is(":checked")?cbv[0]:cbv[1];v2=v;break;case"password":case"text":case"textarea":case"button":v=$("#"+iRow+"_"+nmjq,$t.rows[iRow]).val();v2=v;break;case'custom':try{if(cm.editoptions&&$.isFunction(cm.editoptions.custom_value)){v=cm.editoptions.custom_value.call($t,$(".customelement",cc),'get');if(v===undefined){throw"e2";}else{v2=v;}}else{throw"e1";}}catch(e){if(e==="e1"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.nodefined,$.jgrid.edit.bClose);}
if(e==="e2"){$.jgrid.info_dialog($.jgrid.errors.errcap,"function 'custom_value' "+$.jgrid.edit.msg.novalue,$.jgrid.edit.bClose);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,e.message,$.jgrid.edit.bClose);}}
break;}
if(v2!==$t.p.savedRow[fr].v){var vvv=$($t).triggerHandler("jqGridBeforeSaveCell",[$t.rows[iRow].id,nm,v,iRow,iCol]);if(vvv){v=vvv;v2=vvv;}
if($.isFunction($t.p.beforeSaveCell)){var vv=$t.p.beforeSaveCell.call($t,$t.rows[iRow].id,nm,v,iRow,iCol);if(vv){v=vv;v2=vv;}}
var cv=$.jgrid.checkValues.call($t,v,iCol);if(cv[0]===true){var addpost=$($t).triggerHandler("jqGridBeforeSubmitCell",[$t.rows[iRow].id,nm,v,iRow,iCol])||{};if($.isFunction($t.p.beforeSubmitCell)){addpost=$t.p.beforeSubmitCell.call($t,$t.rows[iRow].id,nm,v,iRow,iCol);if(!addpost){addpost={};}}
if($("input.hasDatepicker",cc).length>0){$("input.hasDatepicker",cc).datepicker('hide');}
if($t.p.cellsubmit==='remote'){if($t.p.cellurl){var postdata={};if($t.p.autoencode){v=$.jgrid.htmlEncode(v);}
postdata[nm]=v;var idname,oper,opers;opers=$t.p.prmNames;idname=opers.id;oper=opers.oper;postdata[idname]=$.jgrid.stripPref($t.p.idPrefix,$t.rows[iRow].id);postdata[oper]=opers.editoper;postdata=$.extend(addpost,postdata);$("#lui_"+$.jgrid.jqID($t.p.id)).show();$t.grid.hDiv.loading=true;$.ajax($.extend({url:$t.p.cellurl,data:$.isFunction($t.p.serializeCellData)?$t.p.serializeCellData.call($t,postdata):postdata,type:"POST",complete:function(result,stat){$("#lui_"+$t.p.id).hide();$t.grid.hDiv.loading=false;if(stat==='success'){var ret=$($t).triggerHandler("jqGridAfterSubmitCell",[$t,result,postdata.id,nm,v,iRow,iCol])||[true,''];if(ret[0]===true&&$.isFunction($t.p.afterSubmitCell)){ret=$t.p.afterSubmitCell.call($t,result,postdata.id,nm,v,iRow,iCol);}
if(ret[0]===true){$(cc).empty();$($t).jqGrid("setCell",$t.rows[iRow].id,iCol,v2,false,false,true);$(cc).addClass("dirty-cell");$($t.rows[iRow]).addClass("edited");$($t).triggerHandler("jqGridAfterSaveCell",[$t.rows[iRow].id,nm,v,iRow,iCol]);if($.isFunction($t.p.afterSaveCell)){$t.p.afterSaveCell.call($t,$t.rows[iRow].id,nm,v,iRow,iCol);}
$t.p.savedRow.splice(0,1);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,ret[1],$.jgrid.edit.bClose);$($t).jqGrid("restoreCell",iRow,iCol);}}},error:function(res,stat,err){$("#lui_"+$.jgrid.jqID($t.p.id)).hide();$t.grid.hDiv.loading=false;$($t).triggerHandler("jqGridErrorCell",[res,stat,err]);if($.isFunction($t.p.errorCell)){$t.p.errorCell.call($t,res,stat,err);$($t).jqGrid("restoreCell",iRow,iCol);}else{$.jgrid.info_dialog($.jgrid.errors.errcap,res.status+" : "+res.statusText+"<br/>"+stat,$.jgrid.edit.bClose);$($t).jqGrid("restoreCell",iRow,iCol);}}},$.jgrid.ajaxOptions,$t.p.ajaxCellOptions||{}));}else{try{$.jgrid.info_dialog($.jgrid.errors.errcap,$.jgrid.errors.nourl,$.jgrid.edit.bClose);$($t).jqGrid("restoreCell",iRow,iCol);}catch(e){}}}
if($t.p.cellsubmit==='clientArray'){$(cc).empty();$($t).jqGrid("setCell",$t.rows[iRow].id,iCol,v2,false,false,true);$(cc).addClass("dirty-cell");$($t.rows[iRow]).addClass("edited");$($t).triggerHandler("jqGridAfterSaveCell",[$t.rows[iRow].id,nm,v,iRow,iCol]);if($.isFunction($t.p.afterSaveCell)){$t.p.afterSaveCell.call($t,$t.rows[iRow].id,nm,v,iRow,iCol);}
$t.p.savedRow.splice(0,1);}}else{try{window.setTimeout(function(){$.jgrid.info_dialog($.jgrid.errors.errcap,v+" "+cv[1],$.jgrid.edit.bClose);},100);$($t).jqGrid("restoreCell",iRow,iCol);}catch(e){}}}else{$($t).jqGrid("restoreCell",iRow,iCol);}}
window.setTimeout(function(){$("#"+$.jgrid.jqID($t.p.knv)).attr("tabindex","-1").focus();},0);});},restoreCell:function(iRow,iCol){return this.each(function(){var $t=this,fr;if(!$t.grid||$t.p.cellEdit!==true){return;}
if($t.p.savedRow.length>=1){fr=0;}else{fr=null;}
if(fr!==null){var cc=$("td:eq("+iCol+")",$t.rows[iRow]);if($.isFunction($.fn.datepicker)){try{$("input.hasDatepicker",cc).datepicker('hide');}catch(e){}}
$(cc).empty().attr("tabindex","-1");$($t).jqGrid("setCell",$t.rows[iRow].id,iCol,$t.p.savedRow[fr].v,false,false,true);$($t).triggerHandler("jqGridAfterRestoreCell",[$t.rows[iRow].id,$t.p.savedRow[fr].v,iRow,iCol]);if($.isFunction($t.p.afterRestoreCell)){$t.p.afterRestoreCell.call($t,$t.rows[iRow].id,$t.p.savedRow[fr].v,iRow,iCol);}
$t.p.savedRow.splice(0,1);}
window.setTimeout(function(){$("#"+$t.p.knv).attr("tabindex","-1").focus();},0);});},nextCell:function(iRow,iCol){return this.each(function(){var $t=this,nCol=false,i;if(!$t.grid||$t.p.cellEdit!==true){return;}
for(i=iCol+1;i<$t.p.colModel.length;i++){if($t.p.colModel[i].editable===true&&$t.p.colModel[i].hidden!=true){nCol=i;break;}}
if(nCol!==false){$($t).jqGrid("editCell",iRow,nCol,true);}else{if($t.p.savedRow.length>0){$($t).jqGrid("saveCell",iRow,iCol);}}});},prevCell:function(iRow,iCol){return this.each(function(){var $t=this,nCol=false,i;if(!$t.grid||$t.p.cellEdit!==true){return;}
for(i=iCol-1;i>=0;i--){if($t.p.colModel[i].editable===true){nCol=i;break;}}
if(nCol!==false){$($t).jqGrid("editCell",iRow,nCol,true);}else{if($t.p.savedRow.length>0){$($t).jqGrid("saveCell",iRow,iCol);}}});},GridNav:function(){return this.each(function(){var $t=this;if(!$t.grid||$t.p.cellEdit!==true){return;}
$t.p.knv=$t.p.id+"_kn";var selection=$("<div style='position:fixed;top:0px;width:1px;height:1px;' tabindex='0'><div tabindex='-1' style='width:1px;height:1px;' id='"+$t.p.knv+"'></div></div>"),i,kdir;function scrollGrid(iR,iC,tp){if(tp.substr(0,1)==='v'){var ch=$($t.grid.bDiv)[0].clientHeight,st=$($t.grid.bDiv)[0].scrollTop,nROT=$t.rows[iR].offsetTop+$t.rows[iR].clientHeight,pROT=$t.rows[iR].offsetTop;if(tp==='vd'){if(nROT>=ch){$($t.grid.bDiv)[0].scrollTop=$($t.grid.bDiv)[0].scrollTop+$t.rows[iR].clientHeight;}}
if(tp==='vu'){if(pROT<st){$($t.grid.bDiv)[0].scrollTop=$($t.grid.bDiv)[0].scrollTop-$t.rows[iR].clientHeight;}}}
if(tp==='h'){var cw=$($t.grid.bDiv)[0].clientWidth,sl=$($t.grid.bDiv)[0].scrollLeft,nCOL=$t.rows[iR].cells[iC].offsetLeft+$t.rows[iR].cells[iC].clientWidth,pCOL=$t.rows[iR].cells[iC].offsetLeft;if(nCOL>=cw+parseInt(sl,10)){$($t.grid.bDiv)[0].scrollLeft=$($t.grid.bDiv)[0].scrollLeft+$t.rows[iR].cells[iC].clientWidth;}else if(pCOL<sl){$($t.grid.bDiv)[0].scrollLeft=$($t.grid.bDiv)[0].scrollLeft-$t.rows[iR].cells[iC].clientWidth;}}}
function findNextVisible(iC,act){var ind,i;if(act==='lft'){ind=iC+1;for(i=iC;i>=0;i--){if($t.p.colModel[i].hidden!==true){ind=i;break;}}}
if(act==='rgt'){ind=iC-1;for(i=iC;i<$t.p.colModel.length;i++){if($t.p.colModel[i].hidden!==true){ind=i;break;}}}
return ind;}
$(selection).insertBefore($t.grid.cDiv);$("#"+$t.p.knv).focus().keydown(function(e){kdir=e.keyCode;if($t.p.direction==="rtl"){if(kdir===37){kdir=39;}else if(kdir===39){kdir=37;}}
switch(kdir){case 38:if($t.p.iRow-1>0){scrollGrid($t.p.iRow-1,$t.p.iCol,'vu');$($t).jqGrid("editCell",$t.p.iRow-1,$t.p.iCol,false);}
break;case 40:if($t.p.iRow+1<=$t.rows.length-1){scrollGrid($t.p.iRow+1,$t.p.iCol,'vd');$($t).jqGrid("editCell",$t.p.iRow+1,$t.p.iCol,false);}
break;case 37:if($t.p.iCol-1>=0){i=findNextVisible($t.p.iCol-1,'lft');scrollGrid($t.p.iRow,i,'h');$($t).jqGrid("editCell",$t.p.iRow,i,false);}
break;case 39:if($t.p.iCol+1<=$t.p.colModel.length-1){i=findNextVisible($t.p.iCol+1,'rgt');scrollGrid($t.p.iRow,i,'h');$($t).jqGrid("editCell",$t.p.iRow,i,false);}
break;case 13:if(parseInt($t.p.iCol,10)>=0&&parseInt($t.p.iRow,10)>=0){$($t).jqGrid("editCell",$t.p.iRow,$t.p.iCol,true);}
break;case 9:if(e.shiftKey){if($t.p.iCol-1>=0){i=findNextVisible($t.p.iCol-1,'lft');scrollGrid($t.p.iRow,i,'h');$($t).jqGrid("editCell",$t.p.iRow,i,false);}}else{if($t.p.iCol+1<=$t.p.colModel.length-1){i=findNextVisible($t.p.iCol+1,'rgt');scrollGrid($t.p.iRow,i,'h');$($t).jqGrid("editCell",$t.p.iRow,i,false);}}
break;default:return true;}
return false;});});},getChangedCells:function(mthd){var ret=[];if(!mthd){mthd='all';}
this.each(function(){var $t=this,nm;if(!$t.grid||$t.p.cellEdit!==true){return;}
$($t.rows).each(function(j){var res={};if($(this).hasClass("edited")){$('td',this).each(function(i){nm=$t.p.colModel[i].name;if(nm!=='cb'&&nm!=='subgrid'){if(mthd==='dirty'){if($(this).hasClass('dirty-cell')){try{res[nm]=$.unformat.call($t,this,{rowId:$t.rows[j].id,colModel:$t.p.colModel[i]},i);}catch(e){res[nm]=$.jgrid.htmlDecode($(this).html());}}}else{try{res[nm]=$.unformat.call($t,this,{rowId:$t.rows[j].id,colModel:$t.p.colModel[i]},i);}catch(e){res[nm]=$.jgrid.htmlDecode($(this).html());}}}});res.id=this.id;ret.push(res);}});});return ret;}});})(jQuery);(function($){"use strict";$.jgrid.extend({setSubGrid:function(){return this.each(function(){var $t=this,cm,i,suboptions={plusicon:"ui-icon-plus",minusicon:"ui-icon-minus",openicon:"ui-icon-carat-1-sw",expandOnLoad:false,delayOnLoad:50,selectOnExpand:false,selectOnCollapse:false,reloadOnExpand:true};$t.p.subGridOptions=$.extend(suboptions,$t.p.subGridOptions||{});$t.p.colNames.unshift("");$t.p.colModel.unshift({name:'subgrid',width:$.jgrid.cell_width?$t.p.subGridWidth+$t.p.cellLayout:$t.p.subGridWidth,sortable:false,resizable:false,hidedlg:true,search:false,fixed:true});cm=$t.p.subGridModel;if(cm[0]){cm[0].align=$.extend([],cm[0].align||[]);for(i=0;i<cm[0].name.length;i++){cm[0].align[i]=cm[0].align[i]||'left';}}});},addSubGridCell:function(pos,iRow){var prp='',ic,sid;this.each(function(){prp=this.formatCol(pos,iRow);sid=this.p.id;ic=this.p.subGridOptions.plusicon;});return"<td role=\"gridcell\" aria-describedby=\""+sid+"_subgrid\" class=\"ui-sgcollapsed sgcollapsed\" "+prp+"><a style='cursor:pointer;'><span class='ui-icon "+ic+"'></span></a></td>";},addSubGrid:function(pos,sind){return this.each(function(){var ts=this;if(!ts.grid){return;}
var subGridCell=function(trdiv,cell,pos){var tddiv=$("<td align='"+ts.p.subGridModel[0].align[pos]+"'></td>").html(cell);$(trdiv).append(tddiv);};var subGridXml=function(sjxml,sbid){var tddiv,i,sgmap,dummy=$("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),trdiv=$("<tr></tr>");for(i=0;i<ts.p.subGridModel[0].name.length;i++){tddiv=$("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+ts.p.direction+"'></th>");$(tddiv).html(ts.p.subGridModel[0].name[i]);$(tddiv).width(ts.p.subGridModel[0].width[i]);$(trdiv).append(tddiv);}
$(dummy).append(trdiv);if(sjxml){sgmap=ts.p.xmlReader.subgrid;$(sgmap.root+" "+sgmap.row,sjxml).each(function(){trdiv=$("<tr class='ui-widget-content ui-subtblcell'></tr>");if(sgmap.repeatitems===true){$(sgmap.cell,this).each(function(i){subGridCell(trdiv,$(this).text()||'&#160;',i);});}else{var f=ts.p.subGridModel[0].mapping||ts.p.subGridModel[0].name;if(f){for(i=0;i<f.length;i++){subGridCell(trdiv,$(f[i],this).text()||'&#160;',i);}}}
$(dummy).append(trdiv);});}
var pID=$("table:first",ts.grid.bDiv).attr("id")+"_";$("#"+$.jgrid.jqID(pID+sbid)).append(dummy);ts.grid.hDiv.loading=false;$("#load_"+$.jgrid.jqID(ts.p.id)).hide();return false;};var subGridJson=function(sjxml,sbid){var tddiv,result,i,cur,sgmap,j,dummy=$("<table cellspacing='0' cellpadding='0' border='0'><tbody></tbody></table>"),trdiv=$("<tr></tr>");for(i=0;i<ts.p.subGridModel[0].name.length;i++){tddiv=$("<th class='ui-state-default ui-th-subgrid ui-th-column ui-th-"+ts.p.direction+"'></th>");$(tddiv).html(ts.p.subGridModel[0].name[i]);$(tddiv).width(ts.p.subGridModel[0].width[i]);$(trdiv).append(tddiv);}
$(dummy).append(trdiv);if(sjxml){sgmap=ts.p.jsonReader.subgrid;result=$.jgrid.getAccessor(sjxml,sgmap.root);if(result!==undefined){for(i=0;i<result.length;i++){cur=result[i];trdiv=$("<tr class='ui-widget-content ui-subtblcell'></tr>");if(sgmap.repeatitems===true){if(sgmap.cell){cur=cur[sgmap.cell];}
for(j=0;j<cur.length;j++){subGridCell(trdiv,cur[j]||'&#160;',j);}}else{var f=ts.p.subGridModel[0].mapping||ts.p.subGridModel[0].name;if(f.length){for(j=0;j<f.length;j++){subGridCell(trdiv,cur[f[j]]||'&#160;',j);}}}
$(dummy).append(trdiv);}}}
var pID=$("table:first",ts.grid.bDiv).attr("id")+"_";$("#"+$.jgrid.jqID(pID+sbid)).append(dummy);ts.grid.hDiv.loading=false;$("#load_"+$.jgrid.jqID(ts.p.id)).hide();return false;};var populatesubgrid=function(rd){var sid,dp,i,j;sid=$(rd).attr("id");dp={nd_:(new Date().getTime())};dp[ts.p.prmNames.subgridid]=sid;if(!ts.p.subGridModel[0]){return false;}
if(ts.p.subGridModel[0].params){for(j=0;j<ts.p.subGridModel[0].params.length;j++){for(i=0;i<ts.p.colModel.length;i++){if(ts.p.colModel[i].name===ts.p.subGridModel[0].params[j]){dp[ts.p.colModel[i].name]=$("td:eq("+i+")",rd).text().replace(/\&#160\;/ig,'');}}}}
if(!ts.grid.hDiv.loading){ts.grid.hDiv.loading=true;$("#load_"+$.jgrid.jqID(ts.p.id)).show();if(!ts.p.subgridtype){ts.p.subgridtype=ts.p.datatype;}
if($.isFunction(ts.p.subgridtype)){ts.p.subgridtype.call(ts,dp);}else{ts.p.subgridtype=ts.p.subgridtype.toLowerCase();}
switch(ts.p.subgridtype){case"xml":case"json":$.ajax($.extend({type:ts.p.mtype,url:ts.p.subGridUrl,dataType:ts.p.subgridtype,data:$.isFunction(ts.p.serializeSubGridData)?ts.p.serializeSubGridData.call(ts,dp):dp,complete:function(sxml){if(ts.p.subgridtype==="xml"){subGridXml(sxml.responseXML,sid);}else{subGridJson($.jgrid.parse(sxml.responseText),sid);}
sxml=null;}},$.jgrid.ajaxOptions,ts.p.ajaxSubgridOptions||{}));break;}}
return false;};var _id,pID,atd,nhc=0,bfsc,r;$.each(ts.p.colModel,function(){if(this.hidden===true||this.name==='rn'||this.name==='cb'){nhc++;}});var len=ts.rows.length,i=1;if(sind!==undefined&&sind>0){i=sind;len=sind+1;}
while(i<len){if($(ts.rows[i]).hasClass('jqgrow')){$(ts.rows[i].cells[pos]).bind('click',function(){var tr=$(this).parent("tr")[0];r=tr.nextSibling;if($(this).hasClass("sgcollapsed")){pID=ts.p.id;_id=tr.id;if(ts.p.subGridOptions.reloadOnExpand===true||(ts.p.subGridOptions.reloadOnExpand===false&&!$(r).hasClass('ui-subgrid'))){atd=pos>=1?"<td colspan='"+pos+"'>&#160;</td>":"";bfsc=$(ts).triggerHandler("jqGridSubGridBeforeExpand",[pID+"_"+_id,_id]);bfsc=(bfsc===false||bfsc==='stop')?false:true;if(bfsc&&$.isFunction(ts.p.subGridBeforeExpand)){bfsc=ts.p.subGridBeforeExpand.call(ts,pID+"_"+_id,_id);}
if(bfsc===false){return false;}
$(tr).after("<tr role='row' class='ui-subgrid'>"+atd+"<td class='ui-widget-content subgrid-cell'><span class='ui-icon "+ts.p.subGridOptions.openicon+"'></span></td><td colspan='"+parseInt(ts.p.colNames.length-1-nhc,10)+"' class='ui-widget-content subgrid-data'><div id="+pID+"_"+_id+" class='tablediv'></div></td></tr>");$(ts).triggerHandler("jqGridSubGridRowExpanded",[pID+"_"+_id,_id]);if($.isFunction(ts.p.subGridRowExpanded)){ts.p.subGridRowExpanded.call(ts,pID+"_"+_id,_id);}else{populatesubgrid(tr);}}else{$(r).show();}
$(this).html("<a style='cursor:pointer;'><span class='ui-icon "+ts.p.subGridOptions.minusicon+"'></span></a>").removeClass("sgcollapsed").addClass("sgexpanded");if(ts.p.subGridOptions.selectOnExpand){$(ts).jqGrid('setSelection',_id);}}else if($(this).hasClass("sgexpanded")){bfsc=$(ts).triggerHandler("jqGridSubGridRowColapsed",[pID+"_"+_id,_id]);bfsc=(bfsc===false||bfsc==='stop')?false:true;_id=tr.id;if(bfsc&&$.isFunction(ts.p.subGridRowColapsed)){bfsc=ts.p.subGridRowColapsed.call(ts,pID+"_"+_id,_id);}
if(bfsc===false){return false;}
if(ts.p.subGridOptions.reloadOnExpand===true){$(r).remove(".ui-subgrid");}else if($(r).hasClass('ui-subgrid')){$(r).hide();}
$(this).html("<a style='cursor:pointer;'><span class='ui-icon "+ts.p.subGridOptions.plusicon+"'></span></a>").removeClass("sgexpanded").addClass("sgcollapsed");if(ts.p.subGridOptions.selectOnCollapse){$(ts).jqGrid('setSelection',_id);}}
return false;});}
i++;}
if(ts.p.subGridOptions.expandOnLoad===true){$(ts.rows).filter('.jqgrow').each(function(index,row){$(row.cells[0]).click();});}
ts.subGridXml=function(xml,sid){subGridXml(xml,sid);};ts.subGridJson=function(json,sid){subGridJson(json,sid);};});},expandSubGridRow:function(rowid){return this.each(function(){var $t=this;if(!$t.grid&&!rowid){return;}
if($t.p.subGrid===true){var rc=$(this).jqGrid("getInd",rowid,true);if(rc){var sgc=$("td.sgcollapsed",rc)[0];if(sgc){$(sgc).trigger("click");}}}});},collapseSubGridRow:function(rowid){return this.each(function(){var $t=this;if(!$t.grid&&!rowid){return;}
if($t.p.subGrid===true){var rc=$(this).jqGrid("getInd",rowid,true);if(rc){var sgc=$("td.sgexpanded",rc)[0];if(sgc){$(sgc).trigger("click");}}}});},toggleSubGridRow:function(rowid){return this.each(function(){var $t=this;if(!$t.grid&&!rowid){return;}
if($t.p.subGrid===true){var rc=$(this).jqGrid("getInd",rowid,true);if(rc){var sgc=$("td.sgcollapsed",rc)[0];if(sgc){$(sgc).trigger("click");}else{sgc=$("td.sgexpanded",rc)[0];if(sgc){$(sgc).trigger("click");}}}}});}});})(jQuery);(function($){"use strict";$.jgrid.extend({setTreeNode:function(i,len){return this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
var expCol=$t.p.expColInd,expanded=$t.p.treeReader.expanded_field,isLeaf=$t.p.treeReader.leaf_field,level=$t.p.treeReader.level_field,icon=$t.p.treeReader.icon_field,loaded=$t.p.treeReader.loaded,lft,rgt,curLevel,ident,lftpos,twrap,ldat,lf;while(i<len){var ind=$.jgrid.stripPref($t.p.idPrefix,$t.rows[i].id),dind=$t.p._index[ind],expan;ldat=$t.p.data[dind];if($t.p.treeGridModel==='nested'){if(!ldat[isLeaf]){lft=parseInt(ldat[$t.p.treeReader.left_field],10);rgt=parseInt(ldat[$t.p.treeReader.right_field],10);ldat[isLeaf]=(rgt===lft+1)?'true':'false';$t.rows[i].cells[$t.p._treeleafpos].innerHTML=ldat[isLeaf];}}
curLevel=parseInt(ldat[level],10);if($t.p.tree_root_level===0){ident=curLevel+1;lftpos=curLevel;}else{ident=curLevel;lftpos=curLevel-1;}
twrap="<div class='tree-wrap tree-wrap-"+$t.p.direction+"' style='width:"+(ident*18)+"px;'>";twrap+="<div style='"+($t.p.direction==="rtl"?"right:":"left:")+(lftpos*18)+"px;' class='ui-icon ";if(ldat[loaded]!==undefined){if(ldat[loaded]==="true"||ldat[loaded]===true){ldat[loaded]=true;}else{ldat[loaded]=false;}}
if(ldat[isLeaf]==="true"||ldat[isLeaf]===true){twrap+=((ldat[icon]!==undefined&&ldat[icon]!=="")?ldat[icon]:$t.p.treeIcons.leaf)+" tree-leaf treeclick";ldat[isLeaf]=true;lf="leaf";}else{ldat[isLeaf]=false;lf="";}
ldat[expanded]=((ldat[expanded]==="true"||ldat[expanded]===true)?true:false)&&(ldat[loaded]||ldat[loaded]===undefined);if(ldat[expanded]===false){twrap+=((ldat[isLeaf]===true)?"'":$t.p.treeIcons.plus+" tree-plus treeclick'");}else{twrap+=((ldat[isLeaf]===true)?"'":$t.p.treeIcons.minus+" tree-minus treeclick'");}
twrap+="></div></div>";$($t.rows[i].cells[expCol]).wrapInner("<span class='cell-wrapper"+lf+"'></span>").prepend(twrap);if(curLevel!==parseInt($t.p.tree_root_level,10)){var pn=$($t).jqGrid('getNodeParent',ldat);expan=pn&&pn.hasOwnProperty(expanded)?pn[expanded]:true;if(!expan){$($t.rows[i]).css("display","none");}}
$($t.rows[i].cells[expCol]).find("div.treeclick").bind("click",function(e){var target=e.target||e.srcElement,ind2=$.jgrid.stripPref($t.p.idPrefix,$(target,$t.rows).closest("tr.jqgrow")[0].id),pos=$t.p._index[ind2];if(!$t.p.data[pos][isLeaf]){if($t.p.data[pos][expanded]){$($t).jqGrid("collapseRow",$t.p.data[pos]);$($t).jqGrid("collapseNode",$t.p.data[pos]);}else{$($t).jqGrid("expandRow",$t.p.data[pos]);$($t).jqGrid("expandNode",$t.p.data[pos]);}}
return false;});if($t.p.ExpandColClick===true){$($t.rows[i].cells[expCol]).find("span.cell-wrapper").css("cursor","pointer").bind("click",function(e){var target=e.target||e.srcElement,ind2=$.jgrid.stripPref($t.p.idPrefix,$(target,$t.rows).closest("tr.jqgrow")[0].id),pos=$t.p._index[ind2];if(!$t.p.data[pos][isLeaf]){if($t.p.data[pos][expanded]){$($t).jqGrid("collapseRow",$t.p.data[pos]);$($t).jqGrid("collapseNode",$t.p.data[pos]);}else{$($t).jqGrid("expandRow",$t.p.data[pos]);$($t).jqGrid("expandNode",$t.p.data[pos]);}}
$($t).jqGrid("setSelection",ind2);return false;});}
i++;}});},setTreeGrid:function(){return this.each(function(){var $t=this,i=0,pico,ecol=false,nm,key,tkey,dupcols=[];if(!$t.p.treeGrid){return;}
if(!$t.p.treedatatype){$.extend($t.p,{treedatatype:$t.p.datatype});}
$t.p.subGrid=false;$t.p.altRows=false;$t.p.pgbuttons=false;$t.p.pginput=false;$t.p.gridview=true;if($t.p.rowTotal===null){$t.p.rowNum=10000;}
$t.p.multiselect=false;$t.p.rowList=[];$t.p.expColInd=0;pico='ui-icon-triangle-1-'+($t.p.direction==="rtl"?'w':'e');$t.p.treeIcons=$.extend({plus:pico,minus:'ui-icon-triangle-1-s',leaf:'ui-icon-radio-off'},$t.p.treeIcons||{});if($t.p.treeGridModel==='nested'){$t.p.treeReader=$.extend({level_field:"level",left_field:"lft",right_field:"rgt",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},$t.p.treeReader);}else if($t.p.treeGridModel==='adjacency'){$t.p.treeReader=$.extend({level_field:"level",parent_id_field:"parent",leaf_field:"isLeaf",expanded_field:"expanded",loaded:"loaded",icon_field:"icon"},$t.p.treeReader);}
for(key in $t.p.colModel){if($t.p.colModel.hasOwnProperty(key)){nm=$t.p.colModel[key].name;if(nm===$t.p.ExpandColumn&&!ecol){ecol=true;$t.p.expColInd=i;}
i++;for(tkey in $t.p.treeReader){if($t.p.treeReader.hasOwnProperty(tkey)&&$t.p.treeReader[tkey]===nm){dupcols.push(nm);}}}}
$.each($t.p.treeReader,function(j,n){if(n&&$.inArray(n,dupcols)===-1){if(j==='leaf_field'){$t.p._treeleafpos=i;}
i++;$t.p.colNames.push(n);$t.p.colModel.push({name:n,width:1,hidden:true,sortable:false,resizable:false,hidedlg:true,editable:true,search:false});}});});},expandRow:function(record){this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
var childern=$($t).jqGrid("getNodeChildren",record),expanded=$t.p.treeReader.expanded_field;$(childern).each(function(){var id=$t.p.idPrefix+$.jgrid.getAccessor(this,$t.p.localReader.id);$($($t).jqGrid('getGridRowById',id)).css("display","");if(this[expanded]){$($t).jqGrid("expandRow",this);}});});},collapseRow:function(record){this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
var childern=$($t).jqGrid("getNodeChildren",record),expanded=$t.p.treeReader.expanded_field;$(childern).each(function(){var id=$t.p.idPrefix+$.jgrid.getAccessor(this,$t.p.localReader.id);$($($t).jqGrid('getGridRowById',id)).css("display","none");if(this[expanded]){$($t).jqGrid("collapseRow",this);}});});},getRootNodes:function(){var result=[];this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
switch($t.p.treeGridModel){case'nested':var level=$t.p.treeReader.level_field;$($t.p.data).each(function(){if(parseInt(this[level],10)===parseInt($t.p.tree_root_level,10)){result.push(this);}});break;case'adjacency':var parent_id=$t.p.treeReader.parent_id_field;$($t.p.data).each(function(){if(this[parent_id]===null||String(this[parent_id]).toLowerCase()==="null"){result.push(this);}});break;}});return result;},getNodeDepth:function(rc){var ret=null;this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var $t=this;switch($t.p.treeGridModel){case'nested':var level=$t.p.treeReader.level_field;ret=parseInt(rc[level],10)-parseInt($t.p.tree_root_level,10);break;case'adjacency':ret=$($t).jqGrid("getNodeAncestors",rc).length;break;}});return ret;},getNodeParent:function(rc){var result=null;this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
switch($t.p.treeGridModel){case'nested':var lftc=$t.p.treeReader.left_field,rgtc=$t.p.treeReader.right_field,levelc=$t.p.treeReader.level_field,lft=parseInt(rc[lftc],10),rgt=parseInt(rc[rgtc],10),level=parseInt(rc[levelc],10);$(this.p.data).each(function(){if(parseInt(this[levelc],10)===level-1&&parseInt(this[lftc],10)<lft&&parseInt(this[rgtc],10)>rgt){result=this;return false;}});break;case'adjacency':var parent_id=$t.p.treeReader.parent_id_field,dtid=$t.p.localReader.id;$(this.p.data).each(function(){if(this[dtid]===$.jgrid.stripPref($t.p.idPrefix,rc[parent_id])){result=this;return false;}});break;}});return result;},getNodeChildren:function(rc){var result=[];this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
switch($t.p.treeGridModel){case'nested':var lftc=$t.p.treeReader.left_field,rgtc=$t.p.treeReader.right_field,levelc=$t.p.treeReader.level_field,lft=parseInt(rc[lftc],10),rgt=parseInt(rc[rgtc],10),level=parseInt(rc[levelc],10);$(this.p.data).each(function(){if(parseInt(this[levelc],10)===level+1&&parseInt(this[lftc],10)>lft&&parseInt(this[rgtc],10)<rgt){result.push(this);}});break;case'adjacency':var parent_id=$t.p.treeReader.parent_id_field,dtid=$t.p.localReader.id;$(this.p.data).each(function(){if(this[parent_id]==$.jgrid.stripPref($t.p.idPrefix,rc[dtid])){result.push(this);}});break;}});return result;},getFullTreeNode:function(rc){var result=[];this.each(function(){var $t=this,len;if(!$t.grid||!$t.p.treeGrid){return;}
switch($t.p.treeGridModel){case'nested':var lftc=$t.p.treeReader.left_field,rgtc=$t.p.treeReader.right_field,levelc=$t.p.treeReader.level_field,lft=parseInt(rc[lftc],10),rgt=parseInt(rc[rgtc],10),level=parseInt(rc[levelc],10);$(this.p.data).each(function(){if(parseInt(this[levelc],10)>=level&&parseInt(this[lftc],10)>=lft&&parseInt(this[lftc],10)<=rgt){result.push(this);}});break;case'adjacency':if(rc){result.push(rc);var parent_id=$t.p.treeReader.parent_id_field,dtid=$t.p.localReader.id;$(this.p.data).each(function(i){len=result.length;for(i=0;i<len;i++){if($.jgrid.stripPref($t.p.idPrefix,result[i][dtid])===this[parent_id]){result.push(this);break;}}});}
break;}});return result;},getNodeAncestors:function(rc){var ancestors=[];this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var parent=$(this).jqGrid("getNodeParent",rc);while(parent){ancestors.push(parent);parent=$(this).jqGrid("getNodeParent",parent);}});return ancestors;},isVisibleNode:function(rc){var result=true;this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
var ancestors=$($t).jqGrid("getNodeAncestors",rc),expanded=$t.p.treeReader.expanded_field;$(ancestors).each(function(){result=result&&this[expanded];if(!result){return false;}});});return result;},isNodeLoaded:function(rc){var result;this.each(function(){var $t=this;if(!$t.grid||!$t.p.treeGrid){return;}
var isLeaf=$t.p.treeReader.leaf_field,loaded=$t.p.treeReader.loaded;if(rc!==undefined){if(rc[loaded]!==undefined){result=rc[loaded];}else if(rc[isLeaf]||$($t).jqGrid("getNodeChildren",rc).length>0){result=true;}else{result=false;}}else{result=false;}});return result;},expandNode:function(rc){return this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var expanded=this.p.treeReader.expanded_field,parent=this.p.treeReader.parent_id_field,loaded=this.p.treeReader.loaded,level=this.p.treeReader.level_field,lft=this.p.treeReader.left_field,rgt=this.p.treeReader.right_field;if(!rc[expanded]){var id=$.jgrid.getAccessor(rc,this.p.localReader.id);var rc1=$("#"+this.p.idPrefix+$.jgrid.jqID(id),this.grid.bDiv)[0];var position=this.p._index[id];if($(this).jqGrid("isNodeLoaded",this.p.data[position])){rc[expanded]=true;$("div.treeclick",rc1).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus");}else if(!this.grid.hDiv.loading){rc[expanded]=true;$("div.treeclick",rc1).removeClass(this.p.treeIcons.plus+" tree-plus").addClass(this.p.treeIcons.minus+" tree-minus");this.p.treeANode=rc1.rowIndex;this.p.datatype=this.p.treedatatype;if(this.p.treeGridModel==='nested'){$(this).jqGrid("setGridParam",{postData:{nodeid:id,n_left:rc[lft],n_right:rc[rgt],n_level:rc[level]}});}else{$(this).jqGrid("setGridParam",{postData:{nodeid:id,parentid:rc[parent],n_level:rc[level]}});}
$(this).trigger("reloadGrid");rc[loaded]=true;if(this.p.treeGridModel==='nested'){$(this).jqGrid("setGridParam",{postData:{nodeid:'',n_left:'',n_right:'',n_level:''}});}else{$(this).jqGrid("setGridParam",{postData:{nodeid:'',parentid:'',n_level:''}});}}}});},collapseNode:function(rc){return this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var expanded=this.p.treeReader.expanded_field;if(rc[expanded]){rc[expanded]=false;var id=$.jgrid.getAccessor(rc,this.p.localReader.id);var rc1=$("#"+this.p.idPrefix+$.jgrid.jqID(id),this.grid.bDiv)[0];$("div.treeclick",rc1).removeClass(this.p.treeIcons.minus+" tree-minus").addClass(this.p.treeIcons.plus+" tree-plus");}});},SortTree:function(sortname,newDir,st,datefmt){return this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var i,len,rec,records=[],$t=this,query,roots,rt=$(this).jqGrid("getRootNodes");query=$.jgrid.from(rt);query.orderBy(sortname,newDir,st,datefmt);roots=query.select();for(i=0,len=roots.length;i<len;i++){rec=roots[i];records.push(rec);$(this).jqGrid("collectChildrenSortTree",records,rec,sortname,newDir,st,datefmt);}
$.each(records,function(index){var id=$.jgrid.getAccessor(this,$t.p.localReader.id);$('#'+$.jgrid.jqID($t.p.id)+' tbody tr:eq('+index+')').after($('tr#'+$.jgrid.jqID(id),$t.grid.bDiv));});query=null;roots=null;records=null;});},collectChildrenSortTree:function(records,rec,sortname,newDir,st,datefmt){return this.each(function(){if(!this.grid||!this.p.treeGrid){return;}
var i,len,child,ch,query,children;ch=$(this).jqGrid("getNodeChildren",rec);query=$.jgrid.from(ch);query.orderBy(sortname,newDir,st,datefmt);children=query.select();for(i=0,len=children.length;i<len;i++){child=children[i];records.push(child);$(this).jqGrid("collectChildrenSortTree",records,child,sortname,newDir,st,datefmt);}});},setTreeRow:function(rowid,data){var success=false;this.each(function(){var t=this;if(!t.grid||!t.p.treeGrid){return;}
success=$(t).jqGrid("setRowData",rowid,data);});return success;},delTreeNode:function(rowid){return this.each(function(){var $t=this,rid=$t.p.localReader.id,i,left=$t.p.treeReader.left_field,right=$t.p.treeReader.right_field,myright,width,res,key;if(!$t.grid||!$t.p.treeGrid){return;}
var rc=$t.p._index[rowid];if(rc!==undefined){myright=parseInt($t.p.data[rc][right],10);width=myright-parseInt($t.p.data[rc][left],10)+1;var dr=$($t).jqGrid("getFullTreeNode",$t.p.data[rc]);if(dr.length>0){for(i=0;i<dr.length;i++){$($t).jqGrid("delRowData",dr[i][rid]);}}
if($t.p.treeGridModel==="nested"){res=$.jgrid.from($t.p.data).greater(left,myright,{stype:'integer'}).select();if(res.length){for(key in res){if(res.hasOwnProperty(key)){res[key][left]=parseInt(res[key][left],10)-width;}}}
res=$.jgrid.from($t.p.data).greater(right,myright,{stype:'integer'}).select();if(res.length){for(key in res){if(res.hasOwnProperty(key)){res[key][right]=parseInt(res[key][right],10)-width;}}}}}});},addChildNode:function(nodeid,parentid,data,expandData){var $t=this[0];if(data){var expanded=$t.p.treeReader.expanded_field,isLeaf=$t.p.treeReader.leaf_field,level=$t.p.treeReader.level_field,parent=$t.p.treeReader.parent_id_field,left=$t.p.treeReader.left_field,right=$t.p.treeReader.right_field,loaded=$t.p.treeReader.loaded,method,parentindex,parentdata,parentlevel,i,len,max=0,rowind=parentid,leaf,maxright;if(expandData===undefined){expandData=false;}
if(nodeid===undefined||nodeid===null){i=$t.p.data.length-1;if(i>=0){while(i>=0){max=Math.max(max,parseInt($t.p.data[i][$t.p.localReader.id],10));i--;}}
nodeid=max+1;}
var prow=$($t).jqGrid('getInd',parentid);leaf=false;if(parentid===undefined||parentid===null||parentid===""){parentid=null;rowind=null;method='last';parentlevel=$t.p.tree_root_level;i=$t.p.data.length+1;}else{method='after';parentindex=$t.p._index[parentid];parentdata=$t.p.data[parentindex];parentid=parentdata[$t.p.localReader.id];parentlevel=parseInt(parentdata[level],10)+1;var childs=$($t).jqGrid('getFullTreeNode',parentdata);if(childs.length){i=childs[childs.length-1][$t.p.localReader.id];rowind=i;i=$($t).jqGrid('getInd',rowind)+1;}else{i=$($t).jqGrid('getInd',parentid)+1;}
if(parentdata[isLeaf]){leaf=true;parentdata[expanded]=true;$($t.rows[prow]).find("span.cell-wrapperleaf").removeClass("cell-wrapperleaf").addClass("cell-wrapper").end().find("div.tree-leaf").removeClass($t.p.treeIcons.leaf+" tree-leaf").addClass($t.p.treeIcons.minus+" tree-minus");$t.p.data[parentindex][isLeaf]=false;parentdata[loaded]=true;}}
len=i+1;if(data[expanded]===undefined){data[expanded]=false;}
if(data[loaded]===undefined){data[loaded]=false;}
data[level]=parentlevel;if(data[isLeaf]===undefined){data[isLeaf]=true;}
if($t.p.treeGridModel==="adjacency"){data[parent]=parentid;}
if($t.p.treeGridModel==="nested"){var query,res,key;if(parentid!==null){maxright=parseInt(parentdata[right],10);query=$.jgrid.from($t.p.data);query=query.greaterOrEquals(right,maxright,{stype:'integer'});res=query.select();if(res.length){for(key in res){if(res.hasOwnProperty(key)){res[key][left]=res[key][left]>maxright?parseInt(res[key][left],10)+2:res[key][left];res[key][right]=res[key][right]>=maxright?parseInt(res[key][right],10)+2:res[key][right];}}}
data[left]=maxright;data[right]=maxright+1;}else{maxright=parseInt($($t).jqGrid('getCol',right,false,'max'),10);res=$.jgrid.from($t.p.data).greater(left,maxright,{stype:'integer'}).select();if(res.length){for(key in res){if(res.hasOwnProperty(key)){res[key][left]=parseInt(res[key][left],10)+2;}}}
res=$.jgrid.from($t.p.data).greater(right,maxright,{stype:'integer'}).select();if(res.length){for(key in res){if(res.hasOwnProperty(key)){res[key][right]=parseInt(res[key][right],10)+2;}}}
data[left]=maxright+1;data[right]=maxright+2;}}
if(parentid===null||$($t).jqGrid("isNodeLoaded",parentdata)||leaf){$($t).jqGrid('addRowData',nodeid,data,method,rowind);$($t).jqGrid('setTreeNode',i,len);}
if(parentdata&&!parentdata[expanded]&&expandData){$($t.rows[prow]).find("div.treeclick").click();}}}});})(jQuery);(function($){"use strict";$.extend($.jgrid,{template:function(format){var args=$.makeArray(arguments).slice(1),j,al=args.length;if(format==null){format="";}
return format.replace(/\{([\w\-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,function(m,i){if(!isNaN(parseInt(i,10))){return args[parseInt(i,10)];}
for(j=0;j<al;j++){if($.isArray(args[j])){var nmarr=args[j],k=nmarr.length;while(k--){if(i===nmarr[k].nm){return nmarr[k].v;}}}}});}});$.jgrid.extend({groupingSetup:function(){return this.each(function(){var $t=this,i,j,cml,cm=$t.p.colModel,grp=$t.p.groupingView;if(grp!==null&&((typeof grp==='object')||$.isFunction(grp))){if(!grp.groupField.length){$t.p.grouping=false;}else{if(grp.visibiltyOnNextGrouping===undefined){grp.visibiltyOnNextGrouping=[];}
grp.lastvalues=[];grp.groups=[];grp.counters=[];for(i=0;i<grp.groupField.length;i++){if(!grp.groupOrder[i]){grp.groupOrder[i]='asc';}
if(!grp.groupText[i]){grp.groupText[i]='{0}';}
if(typeof grp.groupColumnShow[i]!=='boolean'){grp.groupColumnShow[i]=true;}
if(typeof grp.groupSummary[i]!=='boolean'){grp.groupSummary[i]=false;}
if(grp.groupColumnShow[i]===true){grp.visibiltyOnNextGrouping[i]=true;$($t).jqGrid('showCol',grp.groupField[i]);}else{grp.visibiltyOnNextGrouping[i]=$("#"+$.jgrid.jqID($t.p.id+"_"+grp.groupField[i])).is(":visible");$($t).jqGrid('hideCol',grp.groupField[i]);}}
grp.summary=[];for(j=0,cml=cm.length;j<cml;j++){if(cm[j].summaryType){if(cm[j].summaryDivider){grp.summary.push({nm:cm[j].name,st:cm[j].summaryType,v:'',sd:cm[j].summaryDivider,vd:'',sr:cm[j].summaryRound,srt:cm[j].summaryRoundType||'round'});}else{grp.summary.push({nm:cm[j].name,st:cm[j].summaryType,v:'',sr:cm[j].summaryRound,srt:cm[j].summaryRoundType||'round'});}}}}}else{$t.p.grouping=false;}});},groupingPrepare:function(rData,gdata,record,irow){this.each(function(){var grp=this.p.groupingView,$t=this,i,grlen=grp.groupField.length,fieldName,v,displayName,displayValue,fieldCaption,changed=0;for(i=0;i<grlen;i++){fieldName=grp.groupField[i];displayName=grp.displayField[i];fieldCaption=grp.groupFieldCaption[i];v=record[fieldName];displayValue=displayName==null?null:record[displayName];if(displayValue==null){displayValue=v;}
if(v!==undefined){if(irow===0){grp.groups.push({idx:i,dataIndex:fieldName,value:v,displayValue:displayValue,startRow:irow,cnt:1,summary:[],fieldCaption:fieldCaption});grp.lastvalues[i]=v;grp.counters[i]={cnt:1,pos:grp.groups.length-1,summary:$.extend(true,[],grp.summary)};$.each(grp.counters[i].summary,function(){if($.isFunction(this.st)){this.v=this.st.call($t,this.v,this.nm,record);}else{this.v=$($t).jqGrid('groupingCalculations.handler',this.st,this.v,this.nm,this.sr,this.srt,record);if(this.st.toLowerCase()==='avg'&&this.sd){this.vd=$($t).jqGrid('groupingCalculations.handler',this.st,this.vd,this.sd,this.sr,this.srt,record);}}});grp.groups[grp.counters[i].pos].summary=grp.counters[i].summary;}else{if(typeof v!=="object"&&($.isArray(grp.isInTheSameGroup)&&$.isFunction(grp.isInTheSameGroup[i])?!grp.isInTheSameGroup[i].call($t,grp.lastvalues[i],v,i,grp):grp.lastvalues[i]!==v)){grp.groups.push({idx:i,dataIndex:fieldName,value:v,displayValue:displayValue,startRow:irow,cnt:1,summary:[],fieldCaption:fieldCaption});grp.lastvalues[i]=v;changed=1;grp.counters[i]={cnt:1,pos:grp.groups.length-1,summary:$.extend(true,[],grp.summary)};$.each(grp.counters[i].summary,function(){if($.isFunction(this.st)){this.v=this.st.call($t,this.v,this.nm,record);}else{this.v=$($t).jqGrid('groupingCalculations.handler',this.st,this.v,this.nm,this.sr,this.srt,record);if(this.st.toLowerCase()==='avg'&&this.sd){this.vd=$($t).jqGrid('groupingCalculations.handler',this.st,this.vd,this.sd,this.sr,this.srt,record);}}});grp.groups[grp.counters[i].pos].summary=grp.counters[i].summary;}else{if(changed===1){grp.groups.push({idx:i,dataIndex:fieldName,value:v,displayValue:displayValue,startRow:irow,cnt:1,summary:[],fieldCaption:fieldCaption});grp.lastvalues[i]=v;grp.counters[i]={cnt:1,pos:grp.groups.length-1,summary:$.extend(true,[],grp.summary)};$.each(grp.counters[i].summary,function(){if($.isFunction(this.st)){this.v=this.st.call($t,this.v,this.nm,record);}else{this.v=$($t).jqGrid('groupingCalculations.handler',this.st,this.v,this.nm,this.sr,this.srt,record);if(this.st.toLowerCase()==='avg'&&this.sd){this.vd=$($t).jqGrid('groupingCalculations.handler',this.st,this.vd,this.sd,this.sr,this.srt,record);}}});grp.groups[grp.counters[i].pos].summary=grp.counters[i].summary;}else{grp.counters[i].cnt+=1;grp.groups[grp.counters[i].pos].cnt=grp.counters[i].cnt;$.each(grp.counters[i].summary,function(){if($.isFunction(this.st)){this.v=this.st.call($t,this.v,this.nm,record);}else{this.v=$($t).jqGrid('groupingCalculations.handler',this.st,this.v,this.nm,this.sr,this.srt,record);if(this.st.toLowerCase()==='avg'&&this.sd){this.vd=$($t).jqGrid('groupingCalculations.handler',this.st,this.vd,this.sd,this.sr,this.srt,record);}}});grp.groups[grp.counters[i].pos].summary=grp.counters[i].summary;}}}}}
gdata.push(rData);});return gdata;},groupingToggle:function(hid){this.each(function(){var $t=this,grp=$t.p.groupingView,strpos=hid.split('_'),num=parseInt(strpos[strpos.length-2],10);strpos.splice(strpos.length-2,2);var uid=strpos.join("_"),minus=grp.minusicon,plus=grp.plusicon,tar=$("#"+$.jgrid.jqID(hid)),r=tar.length?tar[0].nextSibling:null,tarspan=$("#"+$.jgrid.jqID(hid)+" span."+"tree-wrap-"+$t.p.direction),getGroupingLevelFromClass=function(className){var nums=$.map(className.split(" "),function(item){if(item.substring(0,uid.length+1)===uid+"_"){return parseInt(item.substring(uid.length+1),10);}});return nums.length>0?nums[0]:undefined;},itemGroupingLevel,showData,collapsed=false;if(tarspan.hasClass(minus)){if(grp.showSummaryOnHide){if(r){while(r){if($(r).hasClass('jqfoot')){var lv=parseInt($(r).attr("jqfootlevel"),10);if(lv<=num){break;}}
$(r).hide();r=r.nextSibling;}}}else{if(r){while(r){itemGroupingLevel=getGroupingLevelFromClass(r.className);if(itemGroupingLevel!==undefined&&itemGroupingLevel<=num){break;}
$(r).hide();r=r.nextSibling;}}}
tarspan.removeClass(minus).addClass(plus);collapsed=true;}else{if(r){showData=undefined;while(r){itemGroupingLevel=getGroupingLevelFromClass(r.className);if(showData===undefined){showData=itemGroupingLevel===undefined;}
if(itemGroupingLevel!==undefined){if(itemGroupingLevel<=num){break;}
if(itemGroupingLevel===num+1){$(r).show().find(">td>span."+"tree-wrap-"+$t.p.direction).removeClass(minus).addClass(plus);}}else if(showData){$(r).show();}
r=r.nextSibling;}}
tarspan.removeClass(plus).addClass(minus);}
$($t).triggerHandler("jqGridGroupingClickGroup",[hid,collapsed]);if($.isFunction($t.p.onClickGroup)){$t.p.onClickGroup.call($t,hid,collapsed);}});return false;},groupingRender:function(grdata,colspans){return this.each(function(){var $t=this,grp=$t.p.groupingView,str="",icon="",hid,clid,pmrtl=grp.groupCollapse?grp.plusicon:grp.minusicon,gv,cp=[],len=grp.groupField.length;pmrtl+=" tree-wrap-"+$t.p.direction;$.each($t.p.colModel,function(i,n){var ii;for(ii=0;ii<len;ii++){if(grp.groupField[ii]===n.name){cp[ii]=i;break;}}});var toEnd=0;function findGroupIdx(ind,offset,grp){var ret=false,i;if(offset===0){ret=grp[ind];}else{var id=grp[ind].idx;if(id===0){ret=grp[ind];}else{for(i=ind;i>=0;i--){if(grp[i].idx===id-offset){ret=grp[i];break;}}}}
return ret;}
var sumreverse=$.makeArray(grp.groupSummary);sumreverse.reverse();$.each(grp.groups,function(i,n){toEnd++;clid=$t.p.id+"ghead_"+n.idx;hid=clid+"_"+i;icon="<span style='cursor:pointer;' class='ui-icon "+pmrtl+"' onclick=\"jQuery('#"+$.jgrid.jqID($t.p.id)+"').jqGrid('groupingToggle','"+hid+"');return false;\"></span>";try{if($.isArray(grp.formatDisplayField)&&$.isFunction(grp.formatDisplayField[n.idx])){n.displayValue=grp.formatDisplayField[n.idx].call($t,n.displayValue,n.value,$t.p.colModel[cp[n.idx]],n.idx,grp);gv=n.displayValue;}else{gv=$t.formatter(hid,n.displayValue,cp[n.idx],n.value);}}catch(egv){gv=n.displayValue;}
str+="<tr id=\""+hid+"\""+(grp.groupCollapse&&n.idx>0?" style=\"display:none;\" ":" ")+"role=\"row\" class= \"ui-widget-content jqgroup ui-row-"+$t.p.direction+" "+clid+"\"><td style=\"padding-left:"+(n.idx*12)+"px;"+"\" colspan=\""+colspans+"\">"+icon+$.jgrid.template(grp.groupText[n.idx],(gv==null?'blank':gv),n.cnt,n.summary,n.fieldCaption)+"</td></tr>";var leaf=len-1===n.idx;if(leaf){var gg=grp.groups[i+1],k,kk,ik;var end=gg!==undefined?grp.groups[i+1].startRow:grdata.length;for(kk=n.startRow;kk<end;kk++){str+=grdata[kk].join('');}
var jj;if(gg!==undefined){for(jj=0;jj<grp.groupField.length;jj++){if(gg.dataIndex===grp.groupField[jj]){break;}}
toEnd=grp.groupField.length-jj;}
for(ik=0;ik<toEnd;ik++){if(!sumreverse[ik]){continue;}
var hhdr="";if(grp.groupCollapse&&!grp.showSummaryOnHide){hhdr=" style=\"display:none;\"";}
str+="<tr"+hhdr+" jqfootlevel=\""+(n.idx-ik)+"\" role=\"row\" class=\"ui-widget-content jqfoot ui-row-"+$t.p.direction+"\">";var fdata=findGroupIdx(i,ik,grp.groups),cm=$t.p.colModel,vv,grlen=fdata.cnt;var gv2=null;try{if($.isArray(grp.formatDisplayField)&&$.isFunction(grp.formatDisplayField[fdata.idx])){fdata.displayValue=grp.formatDisplayField[fdata.idx].call($t,fdata.displayValue,fdata.value,$t.p.colModel[cp[fdata.idx]],fdata.idx,grp);}
gv2=$t.formatter(hid,fdata.displayValue,cp[fdata.idx],fdata.value);}catch(eee){gv2=fdata.displayValue;}
str+="<td style=\"padding-left:"+(fdata.idx*12)+"px;"+"\" colspan=\""+$t.p.groupingView.colspan+"\">Total "+$.jgrid.template(grp.groupText[fdata.idx],(gv2==null?'blank':gv2),fdata.cnt,fdata.summary,fdata.fieldCaption)+"</td>";for(k=parseInt($t.p.groupingView.colspan);k<colspans;k++){var tmpdata="<td "+$t.formatCol(k,1,'')+">&#160;</td>",tplfld="{0}";$.each(fdata.summary,function(){if(this.nm===cm[k].name){if(cm[k].summaryTpl){tplfld=cm[k].summaryTpl;}
if(typeof this.st==='string'&&this.st.toLowerCase()==='avg'){if(this.sd&&this.vd){this.v=(this.v/this.vd);}else if(this.v&&grlen>0){this.v=(this.v/grlen);}}
try{vv=$t.formatter('',this.v,k,this);}catch(ef){vv=this.v;}
tmpdata="<td "+$t.formatCol(k,1,'')+">"+$.jgrid.format(tplfld,vv)+"</td>";return false;}});str+=tmpdata;}
str+="</tr>";}
toEnd=jj;}});$("#"+$.jgrid.jqID($t.p.id)+" tbody:first").append(str);str=null;});},groupingGroupBy:function(name,options){return this.each(function(){var $t=this;if(typeof name==="string"){name=[name];}
var grp=$t.p.groupingView;$t.p.grouping=true;if(grp.visibiltyOnNextGrouping===undefined){grp.visibiltyOnNextGrouping=[];}
var i;for(i=0;i<grp.groupField.length;i++){if(!grp.groupColumnShow[i]&&grp.visibiltyOnNextGrouping[i]){$($t).jqGrid('showCol',grp.groupField[i]);}}
for(i=0;i<name.length;i++){grp.visibiltyOnNextGrouping[i]=$("#"+$.jgrid.jqID($t.p.id)+"_"+$.jgrid.jqID(name[i])).is(":visible");}
$t.p.groupingView=$.extend($t.p.groupingView,options||{});grp.groupField=name;$($t).trigger("reloadGrid");});},groupingRemove:function(current){return this.each(function(){var $t=this;if(current===undefined){current=true;}
$t.p.grouping=false;if(current===true){var grp=$t.p.groupingView,i;for(i=0;i<grp.groupField.length;i++){if(!grp.groupColumnShow[i]&&grp.visibiltyOnNextGrouping[i]){$($t).jqGrid('showCol',grp.groupField);}}
$("tr.jqgroup, tr.jqfoot","#"+$.jgrid.jqID($t.p.id)+" tbody:first").remove();$("tr.jqgrow:hidden","#"+$.jgrid.jqID($t.p.id)+" tbody:first").show();}else{$($t).trigger("reloadGrid");}});},groupingCalculations:{handler:function(fn,v,field,round,roundType,rc){var funcs={sum:function(){return parseFloat(v||0)+parseFloat((rc[field]||0));},min:function(){if(v===""){return parseFloat(rc[field]||0);}
return Math.min(parseFloat(v),parseFloat(rc[field]||0));},max:function(){if(v===""){return parseFloat(rc[field]||0);}
return Math.max(parseFloat(v),parseFloat(rc[field]||0));},count:function(){if(v===""){v=0;}
if(rc.hasOwnProperty(field)){return v+1;}
return 0;},avg:function(){return funcs.sum();}};if(!funcs[fn]){throw("jqGrid Grouping No such method: "+fn);}
var res=funcs[fn]();if(round!=null){if(roundType==='fixed'){res=res.toFixed(round);}else{var mul=Math.pow(10,round);res=Math.round(res*mul)/mul;}}
return res;}}});})(jQuery);(function($){"use strict";$.jgrid.extend({jqGridImport:function(o){o=$.extend({imptype:"xml",impstring:"",impurl:"",mtype:"GET",impData:{},xmlGrid:{config:"roots>grid",data:"roots>rows"},jsonGrid:{config:"grid",data:"data"},ajaxOptions:{}},o||{});return this.each(function(){var $t=this;var xmlConvert=function(xml,o){var cnfg=$(o.xmlGrid.config,xml)[0];var xmldata=$(o.xmlGrid.data,xml)[0],jstr,jstr1,key;if(xmlJsonClass.xml2json&&$.jgrid.parse){jstr=xmlJsonClass.xml2json(cnfg," ");jstr=$.jgrid.parse(jstr);for(key in jstr){if(jstr.hasOwnProperty(key)){jstr1=jstr[key];}}
if(xmldata){var svdatatype=jstr.grid.datatype;jstr.grid.datatype='xmlstring';jstr.grid.datastr=xml;$($t).jqGrid(jstr1).jqGrid("setGridParam",{datatype:svdatatype});}else{$($t).jqGrid(jstr1);}
jstr=null;jstr1=null;}else{alert("xml2json or parse are not present");}};var jsonConvert=function(jsonstr,o){if(jsonstr&&typeof jsonstr==='string'){var _jsonparse=false;if($.jgrid.useJSON){$.jgrid.useJSON=false;_jsonparse=true;}
var json=$.jgrid.parse(jsonstr);if(_jsonparse){$.jgrid.useJSON=true;}
var gprm=json[o.jsonGrid.config];var jdata=json[o.jsonGrid.data];if(jdata){var svdatatype=gprm.datatype;gprm.datatype='jsonstring';gprm.datastr=jdata;$($t).jqGrid(gprm).jqGrid("setGridParam",{datatype:svdatatype});}else{$($t).jqGrid(gprm);}}};switch(o.imptype){case'xml':$.ajax($.extend({url:o.impurl,type:o.mtype,data:o.impData,dataType:"xml",complete:function(xml,stat){if(stat==='success'){xmlConvert(xml.responseXML,o);$($t).triggerHandler("jqGridImportComplete",[xml,o]);if($.isFunction(o.importComplete)){o.importComplete(xml);}}
xml=null;}},o.ajaxOptions));break;case'xmlstring':if(o.impstring&&typeof o.impstring==='string'){var xmld=$.parseXML(o.impstring);if(xmld){xmlConvert(xmld,o);$($t).triggerHandler("jqGridImportComplete",[xmld,o]);if($.isFunction(o.importComplete)){o.importComplete(xmld);}
o.impstring=null;}
xmld=null;}
break;case'json':$.ajax($.extend({url:o.impurl,type:o.mtype,data:o.impData,dataType:"json",complete:function(json){try{jsonConvert(json.responseText,o);$($t).triggerHandler("jqGridImportComplete",[json,o]);if($.isFunction(o.importComplete)){o.importComplete(json);}}catch(ee){}
json=null;}},o.ajaxOptions));break;case'jsonstring':if(o.impstring&&typeof o.impstring==='string'){jsonConvert(o.impstring,o);$($t).triggerHandler("jqGridImportComplete",[o.impstring,o]);if($.isFunction(o.importComplete)){o.importComplete(o.impstring);}
o.impstring=null;}
break;}});},jqGridExport:function(o){o=$.extend({exptype:"xmlstring",root:"grid",ident:"\t"},o||{});var ret=null;this.each(function(){if(!this.grid){return;}
var key,gprm=$.extend(true,{},$(this).jqGrid("getGridParam"));if(gprm.rownumbers){gprm.colNames.splice(0,1);gprm.colModel.splice(0,1);}
if(gprm.multiselect){gprm.colNames.splice(0,1);gprm.colModel.splice(0,1);}
if(gprm.subGrid){gprm.colNames.splice(0,1);gprm.colModel.splice(0,1);}
gprm.knv=null;if(gprm.treeGrid){for(key in gprm.treeReader){if(gprm.treeReader.hasOwnProperty(key)){gprm.colNames.splice(gprm.colNames.length-1);gprm.colModel.splice(gprm.colModel.length-1);}}}
switch(o.exptype){case'xmlstring':ret="<"+o.root+">"+xmlJsonClass.json2xml(gprm,o.ident)+"</"+o.root+">";break;case'jsonstring':ret="{"+xmlJsonClass.toJson(gprm,o.root,o.ident,false)+"}";if(gprm.postData.filters!==undefined){ret=ret.replace(/filters":"/,'filters":');ret=ret.replace(/}]}"/,'}]}');}
break;}});return ret;},excelExport:function(o){o=$.extend({exptype:"remote",url:null,oper:"oper",tag:"excel",exportOptions:{}},o||{});return this.each(function(){if(!this.grid){return;}
var url;if(o.exptype==="remote"){var pdata=$.extend({},this.p.postData);pdata[o.oper]=o.tag;var params=jQuery.param(pdata);if(o.url.indexOf("?")!==-1){url=o.url+"&"+params;}else{url=o.url+"?"+params;}
window.location=url;}});}});})(jQuery);(function($){"use strict";if($.jgrid.msie&&$.jgrid.msiever()===8){$.expr[":"].hidden=function(elem){return elem.offsetWidth===0||elem.offsetHeight===0||elem.style.display==="none";};}
$.jgrid._multiselect=false;if($.ui){if($.ui.multiselect){if($.ui.multiselect.prototype._setSelected){var setSelected=$.ui.multiselect.prototype._setSelected;$.ui.multiselect.prototype._setSelected=function(item,selected){var ret=setSelected.call(this,item,selected);if(selected&&this.selectedList){var elt=this.element;this.selectedList.find('li').each(function(){if($(this).data('optionLink')){$(this).data('optionLink').remove().appendTo(elt);}});}
return ret;};}
if($.ui.multiselect.prototype.destroy){$.ui.multiselect.prototype.destroy=function(){this.element.show();this.container.remove();if($.Widget===undefined){$.widget.prototype.destroy.apply(this,arguments);}else{$.Widget.prototype.destroy.apply(this,arguments);}};}
$.jgrid._multiselect=true;}}
$.jgrid.extend({sortableColumns:function(tblrow){return this.each(function(){var ts=this,tid=$.jgrid.jqID(ts.p.id);function start(){ts.p.disableClick=true;}
var sortable_opts={"tolerance":"pointer","axis":"x","scrollSensitivity":"1","items":'>th:not(:has(#jqgh_'+tid+'_cb'+',#jqgh_'+tid+'_rn'+',#jqgh_'+tid+'_subgrid),:hidden)',"placeholder":{element:function(item){var el=$(document.createElement(item[0].nodeName)).addClass(item[0].className+" ui-sortable-placeholder ui-state-highlight").removeClass("ui-sortable-helper")[0];return el;},update:function(self,p){p.height(self.currentItem.innerHeight()-parseInt(self.currentItem.css('paddingTop')||0,10)-parseInt(self.currentItem.css('paddingBottom')||0,10));p.width(self.currentItem.innerWidth()-parseInt(self.currentItem.css('paddingLeft')||0,10)-parseInt(self.currentItem.css('paddingRight')||0,10));}},"update":function(event,ui){var p=$(ui.item).parent(),th=$(">th",p),colModel=ts.p.colModel,cmMap={},tid=ts.p.id+"_";$.each(colModel,function(i){cmMap[this.name]=i;});var permutation=[];th.each(function(){var id=$(">div",this).get(0).id.replace(/^jqgh_/,"").replace(tid,"");if(cmMap.hasOwnProperty(id)){permutation.push(cmMap[id]);}});$(ts).jqGrid("remapColumns",permutation,true,true);if($.isFunction(ts.p.sortable.update)){ts.p.sortable.update(permutation);}
setTimeout(function(){ts.p.disableClick=false;},50);}};if(ts.p.sortable.options){$.extend(sortable_opts,ts.p.sortable.options);}else if($.isFunction(ts.p.sortable)){ts.p.sortable={"update":ts.p.sortable};}
if(sortable_opts.start){var s=sortable_opts.start;sortable_opts.start=function(e,ui){start();s.call(this,e,ui);};}else{sortable_opts.start=start;}
if(ts.p.sortable.exclude){sortable_opts.items+=":not("+ts.p.sortable.exclude+")";}
tblrow.sortable(sortable_opts).data("sortable").floating=true;});},columnChooser:function(opts){var self=this;if($("#colchooser_"+$.jgrid.jqID(self[0].p.id)).length){return;}
var selector=$('<div id="colchooser_'+self[0].p.id+'" style="position:relative;overflow:hidden"><div><select multiple="multiple"></select></div></div>');var select=$('select',selector);function insert(perm,i,v){if(i>=0){var a=perm.slice();var b=a.splice(i,Math.max(perm.length-i,i));if(i>perm.length){i=perm.length;}
a[i]=v;return a.concat(b);}}
opts=$.extend({"width":420,"height":240,"classname":null,"done":function(perm){if(perm){self.jqGrid("remapColumns",perm,true);}},"msel":"multiselect","dlog":"dialog","dialog_opts":{"minWidth":470},"dlog_opts":function(opts){var buttons={};buttons[opts.bSubmit]=function(){opts.apply_perm();opts.cleanup(false);};buttons[opts.bCancel]=function(){opts.cleanup(true);};return $.extend(true,{"buttons":buttons,"close":function(){opts.cleanup(true);},"modal":opts.modal||false,"resizable":opts.resizable||true,"width":opts.width+20},opts.dialog_opts||{});},"apply_perm":function(){$('option',select).each(function(){if(this.selected){self.jqGrid("showCol",colModel[this.value].name);}else{self.jqGrid("hideCol",colModel[this.value].name);}});var perm=[];$('option:selected',select).each(function(){perm.push(parseInt(this.value,10));});$.each(perm,function(){delete colMap[colModel[parseInt(this,10)].name];});$.each(colMap,function(){var ti=parseInt(this,10);perm=insert(perm,ti,ti);});if(opts.done){opts.done.call(self,perm);}},"cleanup":function(calldone){call(opts.dlog,selector,'destroy');call(opts.msel,select,'destroy');selector.remove();if(calldone&&opts.done){opts.done.call(self);}},"msel_opts":{}},$.jgrid.col,opts||{});if($.ui){if($.ui.multiselect){if(opts.msel==="multiselect"){if(!$.jgrid._multiselect){alert("Multiselect plugin loaded after jqGrid. Please load the plugin before the jqGrid!");return;}
opts.msel_opts=$.extend($.ui.multiselect.defaults,opts.msel_opts);}}}
if(opts.caption){selector.attr("title",opts.caption);}
if(opts.classname){selector.addClass(opts.classname);select.addClass(opts.classname);}
if(opts.width){$(">div",selector).css({"width":opts.width,"margin":"0 auto"});select.css("width",opts.width);}
if(opts.height){$(">div",selector).css("height",opts.height);select.css("height",opts.height-10);}
var colModel=self.jqGrid("getGridParam","colModel");var colNames=self.jqGrid("getGridParam","colNames");var colMap={},fixedCols=[];select.empty();$.each(colModel,function(i){colMap[this.name]=i;if(this.hidedlg){if(!this.hidden){fixedCols.push(i);}
return;}
select.append("<option value='"+i+"' "+
(this.hidden?"":"selected='selected'")+">"+$.jgrid.stripHtml(colNames[i])+"</option>");});function call(fn,obj){if(!fn){return;}
if(typeof fn==='string'){if($.fn[fn]){$.fn[fn].apply(obj,$.makeArray(arguments).slice(2));}}else if($.isFunction(fn)){fn.apply(obj,$.makeArray(arguments).slice(2));}}
var dopts=$.isFunction(opts.dlog_opts)?opts.dlog_opts.call(self,opts):opts.dlog_opts;call(opts.dlog,selector,dopts);var mopts=$.isFunction(opts.msel_opts)?opts.msel_opts.call(self,opts):opts.msel_opts;call(opts.msel,select,mopts);},sortableRows:function(opts){return this.each(function(){var $t=this;if(!$t.grid){return;}
if($t.p.treeGrid){return;}
if($.fn.sortable){opts=$.extend({"cursor":"move","axis":"y","items":".jqgrow"},opts||{});if(opts.start&&$.isFunction(opts.start)){opts._start_=opts.start;delete opts.start;}else{opts._start_=false;}
if(opts.update&&$.isFunction(opts.update)){opts._update_=opts.update;delete opts.update;}else{opts._update_=false;}
opts.start=function(ev,ui){$(ui.item).css("border-width","0px");$("td",ui.item).each(function(i){this.style.width=$t.grid.cols[i].style.width;});if($t.p.subGrid){var subgid=$(ui.item).attr("id");try{$($t).jqGrid('collapseSubGridRow',subgid);}catch(e){}}
if(opts._start_){opts._start_.apply(this,[ev,ui]);}};opts.update=function(ev,ui){$(ui.item).css("border-width","");if($t.p.rownumbers===true){$("td.jqgrid-rownum",$t.rows).each(function(i){$(this).html(i+1+(parseInt($t.p.page,10)-1)*parseInt($t.p.rowNum,10));});}
if(opts._update_){opts._update_.apply(this,[ev,ui]);}};$("tbody:first",$t).sortable(opts);$("tbody:first",$t).disableSelection();}});},gridDnD:function(opts){return this.each(function(){var $t=this,i,cn;if(!$t.grid){return;}
if($t.p.treeGrid){return;}
if(!$.fn.draggable||!$.fn.droppable){return;}
function updateDnD(){var datadnd=$.data($t,"dnd");$("tr.jqgrow:not(.ui-draggable)",$t).draggable($.isFunction(datadnd.drag)?datadnd.drag.call($($t),datadnd):datadnd.drag);}
var appender="<table id='jqgrid_dnd' class='ui-jqgrid-dnd'></table>";if($("#jqgrid_dnd")[0]===undefined){$('body').append(appender);}
if(typeof opts==='string'&&opts==='updateDnD'&&$t.p.jqgdnd===true){updateDnD();return;}
opts=$.extend({"drag":function(opts){return $.extend({start:function(ev,ui){var i,subgid;if($t.p.subGrid){subgid=$(ui.helper).attr("id");try{$($t).jqGrid('collapseSubGridRow',subgid);}catch(e){}}
for(i=0;i<$.data($t,"dnd").connectWith.length;i++){if($($.data($t,"dnd").connectWith[i]).jqGrid('getGridParam','reccount')===0){$($.data($t,"dnd").connectWith[i]).jqGrid('addRowData','jqg_empty_row',{});}}
ui.helper.addClass("ui-state-highlight");$("td",ui.helper).each(function(i){this.style.width=$t.grid.headers[i].width+"px";});if(opts.onstart&&$.isFunction(opts.onstart)){opts.onstart.call($($t),ev,ui);}},stop:function(ev,ui){var i,ids;if(ui.helper.dropped&&!opts.dragcopy){ids=$(ui.helper).attr("id");if(ids===undefined){ids=$(this).attr("id");}
$($t).jqGrid('delRowData',ids);}
for(i=0;i<$.data($t,"dnd").connectWith.length;i++){$($.data($t,"dnd").connectWith[i]).jqGrid('delRowData','jqg_empty_row');}
if(opts.onstop&&$.isFunction(opts.onstop)){opts.onstop.call($($t),ev,ui);}}},opts.drag_opts||{});},"drop":function(opts){return $.extend({accept:function(d){if(!$(d).hasClass('jqgrow')){return d;}
var tid=$(d).closest("table.ui-jqgrid-btable");if(tid.length>0&&$.data(tid[0],"dnd")!==undefined){var cn=$.data(tid[0],"dnd").connectWith;return $.inArray('#'+$.jgrid.jqID(this.id),cn)!==-1?true:false;}
return false;},drop:function(ev,ui){if(!$(ui.draggable).hasClass('jqgrow')){return;}
var accept=$(ui.draggable).attr("id");var getdata=ui.draggable.parent().parent().jqGrid('getRowData',accept);if(!opts.dropbyname){var j=0,tmpdata={},nm,key;var dropmodel=$("#"+$.jgrid.jqID(this.id)).jqGrid('getGridParam','colModel');try{for(key in getdata){if(getdata.hasOwnProperty(key)){nm=dropmodel[j].name;if(!(nm==='cb'||nm==='rn'||nm==='subgrid')){if(getdata.hasOwnProperty(key)&&dropmodel[j]){tmpdata[nm]=getdata[key];}}
j++;}}
getdata=tmpdata;}catch(e){}}
ui.helper.dropped=true;if(opts.beforedrop&&$.isFunction(opts.beforedrop)){var datatoinsert=opts.beforedrop.call(this,ev,ui,getdata,$('#'+$.jgrid.jqID($t.p.id)),$(this));if(datatoinsert!==undefined&&datatoinsert!==null&&typeof datatoinsert==="object"){getdata=datatoinsert;}}
if(ui.helper.dropped){var grid;if(opts.autoid){if($.isFunction(opts.autoid)){grid=opts.autoid.call(this,getdata);}else{grid=Math.ceil(Math.random()*1000);grid=opts.autoidprefix+grid;}}
$("#"+$.jgrid.jqID(this.id)).jqGrid('addRowData',grid,getdata,opts.droppos);}
if(opts.ondrop&&$.isFunction(opts.ondrop)){opts.ondrop.call(this,ev,ui,getdata);}}},opts.drop_opts||{});},"onstart":null,"onstop":null,"beforedrop":null,"ondrop":null,"drop_opts":{"activeClass":"ui-state-active","hoverClass":"ui-state-hover"},"drag_opts":{"revert":"invalid","helper":"clone","cursor":"move","appendTo":"#jqgrid_dnd","zIndex":5000},"dragcopy":false,"dropbyname":false,"droppos":"first","autoid":true,"autoidprefix":"dnd_"},opts||{});if(!opts.connectWith){return;}
opts.connectWith=opts.connectWith.split(",");opts.connectWith=$.map(opts.connectWith,function(n){return $.trim(n);});$.data($t,"dnd",opts);if($t.p.reccount!==0&&!$t.p.jqgdnd){updateDnD();}
$t.p.jqgdnd=true;for(i=0;i<opts.connectWith.length;i++){cn=opts.connectWith[i];$(cn).droppable($.isFunction(opts.drop)?opts.drop.call($($t),opts):opts.drop);}});},gridResize:function(opts){return this.each(function(){var $t=this,gID=$.jgrid.jqID($t.p.id);if(!$t.grid||!$.fn.resizable){return;}
opts=$.extend({},opts||{});if(opts.alsoResize){opts._alsoResize_=opts.alsoResize;delete opts.alsoResize;}else{opts._alsoResize_=false;}
if(opts.stop&&$.isFunction(opts.stop)){opts._stop_=opts.stop;delete opts.stop;}else{opts._stop_=false;}
opts.stop=function(ev,ui){$($t).jqGrid('setGridParam',{height:$("#gview_"+gID+" .ui-jqgrid-bdiv").height()});$($t).jqGrid('setGridWidth',ui.size.width,opts.shrinkToFit);if(opts._stop_){opts._stop_.call($t,ev,ui);}};if(opts._alsoResize_){var optstest="{\'#gview_"+gID+" .ui-jqgrid-bdiv\':true,'"+opts._alsoResize_+"':true}";opts.alsoResize=eval('('+optstest+')');}else{opts.alsoResize=$(".ui-jqgrid-bdiv","#gview_"+gID);}
delete opts._alsoResize_;$("#gbox_"+gID).resizable(opts);});}});})(jQuery);function tableToGrid(selector,options){jQuery(selector).each(function(){if(this.grid){return;}
jQuery(this).width("99%");var w=jQuery(this).width();var inputCheckbox=jQuery('tr td:first-child input[type=checkbox]:first',jQuery(this));var inputRadio=jQuery('tr td:first-child input[type=radio]:first',jQuery(this));var selectMultiple=inputCheckbox.length>0;var selectSingle=!selectMultiple&&inputRadio.length>0;var selectable=selectMultiple||selectSingle;var colModel=[];var colNames=[];jQuery('th',jQuery(this)).each(function(){if(colModel.length===0&&selectable){colModel.push({name:'__selection__',index:'__selection__',width:0,hidden:true});colNames.push('__selection__');}else{colModel.push({name:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(' ').join('_'),index:jQuery(this).attr("id")||jQuery.trim(jQuery.jgrid.stripHtml(jQuery(this).html())).split(' ').join('_'),width:jQuery(this).width()||150});colNames.push(jQuery(this).html());}});var data=[];var rowIds=[];var rowChecked=[];jQuery('tbody > tr',jQuery(this)).each(function(){var row={};var rowPos=0;jQuery('td',jQuery(this)).each(function(){if(rowPos===0&&selectable){var input=jQuery('input',jQuery(this));var rowId=input.attr("value");rowIds.push(rowId||data.length);if(input.is(":checked")){rowChecked.push(rowId);}
row[colModel[rowPos].name]=input.attr("value");}else{row[colModel[rowPos].name]=jQuery(this).html();}
rowPos++;});if(rowPos>0){data.push(row);}});jQuery(this).empty();jQuery(this).addClass("scroll");jQuery(this).jqGrid(jQuery.extend({datatype:"local",width:w,colNames:colNames,colModel:colModel,multiselect:selectMultiple},options||{}));var a;for(a=0;a<data.length;a++){var id=null;if(rowIds.length>0){id=rowIds[a];if(id&&id.replace){id=encodeURIComponent(id).replace(/[.\-%]/g,"_");}}
if(id===null){id=a+1;}
jQuery(this).jqGrid("addRowData",id,data[a]);}
for(a=0;a<rowChecked.length;a++){jQuery(this).jqGrid("setSelection",rowChecked[a]);}});};

//Application Namespace.
if (typeof Application == 'undefined')
    var Application = new Object();

function Default(value_, default_) {
    if (value_ == null)
        return default_;
    return typeof (value_) != 'undefined' ? value_ : default_;
};

function Extend(obj, objExt){

    obj = Default(obj, new Object());
    for(var i in objExt){
        obj[i] = Default(obj[i],objExt[i]);
    }
    return obj;
};

//Global variables.
Application.name = "Liveapp Framework";
Application.version = '5.0.1-build.2';
Application.copyright = "Copyright © Scrubit Pty Ltd 2017";
Application.url = "https://go.scrubit.com.au/";

//All objects should use this or inherit this.
AppObject = function (type_) {

    //Members
    var m_type = null;    

    //Methods        
    this.Constructor = function (type_) {                
        m_type = type_;
    };

    //Properties        
    this.ObjectType = function () {         
        return m_type;
    };
              
    //Constructor
    this.Constructor(type_);
};

window.onpopstate = function(event) {
	if(event.state==null)
	    return;
	if(!event.state.windowid || typeof event.state.hash != "undefined") 
	    return;

	var homepage = false;
	if(ThisViewer().Options && ThisViewer().Options() && ThisViewer().Options()["homepage"])
		homepage = true;
	
	if(ThisViewer() && !homepage)
		Application.RunNext(function(){
			return UI.WindowManager.Close(ThisViewer().ID());
		});
};

//#region Speed Fixes

Application.timeouts = [];
(function () {

    var messageName = "ztm";

    // Like setTimeout, but only takes a function argument.  There's
    // no time argument (always zero) and no arguments (you have to
    // use a closure).
    function setZeroTimeout(fn) {
        Application.timeouts.push(fn);
        window.postMessage(messageName, "*");
    }

    function handleMessage(event) {
		
		if (event.origin == "https://www.liveapp.com.au:444"){
			Application.Log.HandleMessage(event);
			return;
		}
		
        if (event.source == window && event.data == messageName) {
            event.stopPropagation();
            if (Application.timeouts.length > 0) {
                var fn = Application.timeouts.shift();
                fn();
            }
        }
    }

    window.addEventListener("message", handleMessage, true);

    // Add the one thing we want added to the window object.
    window.setZeroTimeout = setZeroTimeout;
})();

function memoize(fn, resolver) {

  var memoized = function() {

    resolver  = resolver || JSON.stringify;

    var cache = memoized.cache;
    var args  = Array.prototype.slice.call(arguments);
    var key   = "";
	if(args.length > 0)
		key = resolver.apply(this, args);

    return (key in cache) ? cache[key] : (cache[key] = fn.apply(this, arguments));

  };

  memoized.cache = {};

  return memoized;
};

//#endregion

//#region Base Prototypes

String.prototype.endsWith = function (suffix) {
    return this.indexOf(suffix, this.length - suffix.length) !== -1;
};

String.prototype.within = function (arr) {
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == this)
            return true;
    }
    return false;
};

String.prototype.trim = String.prototype.trim ||
function () {
    return this.replace(/^\s*|\s*$/g, '');
};

String.prototype.replaceall = function (str,rep) {
    var s = this;
	while(s.indexOf(str) != -1)
		s = s.replace(str,rep);
	return s;
};

if (!Array.indexOf) {
    Array.prototype.indexOf = function (obj) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == obj) {
                return i;
            }
        }
        return -1;
    }
}

Array.prototype.firstObject = function () {
    for (var i = 0; i < this.length; i++) {
        if (this[i] != null && this[i] != "") {
            return i;
        }
    }
    return -1;
}

Array.prototype.list = function (seperator) {
    seperator = Default(seperator,",");
    var str = "";
    for (var i = 0; i < this.length; i++) {
        if (i == 0) {
            str = this[i].toString();
        } else {
            str += seperator + this[i].toString();
        }
    }
    return str;
};

Date.prototype.stdTimezoneOffset = function() {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

Date.prototype.toJSON = function(){
	if(!this)
		return "null";
    return moment(this).format("YYYY/MM/DD HH:mm:00");
}

if($.datepicker && $.datepicker._gotoToday){
	var old_goToToday = $.datepicker._gotoToday
	$.datepicker._gotoToday = function(id) {
	  old_goToToday.call(this,id)
	  this._selectDate(id)
	}
}

//#endregion

Application.coreFunctions = new Object();

Define = function (name, base, def) {    
    if (base == null)
        base = function () {
            return new AppObject(name);
        }
    var obj = window;
    var params = name.split(".");
    while (params.length > 1) {
        obj = obj[params[0]];
        if (obj == null) 
            obj = new Object();
        params.splice(0, 1);
    }
    Application.coreFunctions[params[0]] = def;
    obj[params[0]] = function (arg1, arg2, arg3, arg4, arg5) {
        Application.coreFunctions[params[0]].prototype = base(arg1, arg2, arg3, arg4, arg5);
        return new Application.coreFunctions[params[0]](arg1, arg2, arg3, arg4, arg5);
    };
    return obj[params[0]];
};

Base = function (name) {
    return Application.coreFunctions[name].prototype
};

//#region Application Objects

Application.Objects = new Object();

Application.Objects.ArrayList = function () {
    return [];
};

Application.Objects.AuthInfo = function () {
    return {"Username":"","Password":"","SessionID":"","Remember":false,"Type":0,"LoginTime":"","Instance":"","Role":"","UserData":"","Layout":"","OfflineAuth":"","AppSecret":""};
};

Application.Objects.RecordSetInfo = function () {
    return {"Table":"","View":"","Position":0,"Record":{"NewRecord":true,"Fields":[],"UnAssigned":false},"xRecord":{"NewRecord":true,"Fields":[],"UnAssigned":false},"Blank":true,"Count":0,"Temp":false,"Functions":[],"CalculatedFields":[],"GroupFilters":[]};
};

Application.Objects.RecordInfo = function () {
    return {"NewRecord":true,"Fields":[],"UnAssigned":false};
};

Application.Objects.RecordFieldInfo = function () {
    return {"Name":"","Caption":"","Value":null,"Type":""};
};

Application.Objects.ColumnInfo = function () {
    return {"Name":"","Type":0,"Size":0,"DecimalPlaces":"","PrimaryKey":false,"Modified":true,"XName":"","Caption":"","CodeField":"","OptionString":"","OptionCaption":"","OnValidate":"","OnLookup":"","LookupTable":"","LookupField":"","LookupFilters":"","LookupColumns":"","LookupCategoryField":"","LookupDisplayField":""};
};

Application.Objects.TableInfo = function () {
    return {"Name":"","LicensePart":"","Columns":[],"Keys":[]};
};

Application.Objects.PageInfo = function () {
    return {"Name":"","Caption":"","LicensePart":"","Type":"","Fields":[],"Actions":[],"View":"","DeleteAllowed":false,"InsertAllowed":false,"CloseFunction":null,"OpenFunction":null,"TabList":[],"ShowFilters":false,"RunFunctionOnCancel":false,"RunDblClickOnNew":false,"SkipRecordLoad":false,"SourceID":"","AllowExternal":false,"NoCache":false,"GlobalCache":false,"Icon":""};
};

Application.Objects.PageFieldInfo = function () {
    return {"Name":"","Caption":"","Editable":false,"Validate":false,"Type":"","Width":0,"TabName":"","FieldMask":"","Tooltip":"","Hidden":false,"IncrementDelta":0,"Totals":false,"CustomControl":"","Sort":0,"OptionString":"","OptionCaption":"","OnValidate":"","OnLookup":"","LookupTable":"","LookupField":"","LookupFilters":"","LookupColumns":"","LookupCategoryField":"","LookupDisplayField":""};
};

Application.Objects.PageActionInfo = function () {
    return {"Name":"","Type":"","ActionCode":"","Image":"","RecordRequired":false,"FormID":"","FormView":"","Reload":false,"ReloadParent":false,"OnDoubleClick":false};
};

Application.Objects.CodeModuleInfo = function () {
    return {"Name":"","LicensePart":"","Code":""};
};

Application.Objects.LicenseInfo = function () {
    return {"No":"","LicenseDate":"","Program":"","ProgramVersion":"","ClientName":"","ResellName":"","AuthCode":"","Address1":"","Address2":"","Address3":"","Address4":"","Address5":"","Address6":"","Address7":"","Address8":"","Developer":"","Password":"","UserCount":"","AvailableParts":{"AvailableParts":null}};
};


//#endregion

//#region Globals

//Application Structs
Application.windowType = {
    Normal: 1,
    Frame: 2,
    Mobile: 4
};
Application.position = {
    normal: 0,
    right: 1,
    block: 2,
    rolehalf: 3,    
    rolequarter: 4,
    rolefull: 5
};
Application.authType = {
    Login: 1,
    Cookie: 2,
    Token: 3
};
Application.pages = {
    ErrorBrowser: 8911
};
Application.remoteStatus = {
    Disconnected: 1,
    Connecting: 2,
    Connected: 3
};

Application.supressError = false;
Application.supressServiceErrors = false;
Application.noGUI = false;
Application.auth = Application.Objects.AuthInfo();
Application.scripts = Array();
Application.executionPath = "https://go.scrubit.com.au/";
Application.event = {};
Application.maxRecords = 10000; 
Application.connected = false;
Application.debugMode = false;
Application.developerMode = false;
Application.timezone = -660;  
Application.testMode = false;
Application.transactionStarted = 0;
Application.restrictedMode = false;
Application.type = Application.windowType.Normal;
Application.license = null;
Application.Virtual = new Object(); //#35 Virtual Tables 
Application.lastExecute = {};

//Caching.
Application.cacheValues = ['uncached','idle','checking','downloading','updateready','obsolete'];

//Global functions.
ThisViewer = function () { 
 if (ThisWindow()) 
    if(ThisWindow().LineEditor && ThisWindow().LineEditor() != null){
        return ThisWindow().LineEditor().pv;
    }else{
        return ThisWindow();
    }
};
ThisPage = function () { 
    if (ThisWindow()) 
        return ThisViewer().Page() 
};
ThisWindow = function () { 
    if ($moduleloaded("WindowManager")) 
        return UI.WindowManager.SelectedWindow(); 
};

//Error Handling.
Application.OnError = null;

Application.MessageBox = null;
Application.ConfirmBox = null;
Application.ProgressBox = null;

//Offline.
Application.IsOffline = function () {
    if ($moduleloaded("OfflineManager"))
        return Application.Offline.IsOffline();
    return false;
};

Application.CheckOfflineObject = function(type, id){
	if($moduleloaded("OfflineManager"))
		return Application.Offline.CheckOfflineObject(type, id);
	return true;
};

//Logging.
Application.LogInfo = function (msg) {
    if ($moduleloaded("Logging"))
        Application.Log.Info(msg);
};
Application.LogError = function (msg) {
    if ($moduleloaded("Logging"))
        Application.Log.Error(msg);
};
Application.LogDebug = function (msg) {
    if ($moduleloaded("Logging"))
        Application.Log.Debug(msg);
};
Application.LogWarn = function (msg) {
    if ($moduleloaded("Logging"))
        Application.Log.Warn(msg);
};

//Application Events.

Application.On = function (name, handler) {
    if (Application.event[name] == null)
        Application.event[name] = [];
    Application.event[name].push(handler);
};

Application.FireWait = function () {

    __slice = [].slice;

    var args, handler, name;
    name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    if (Application.event[name] != null) {

        var ref = Application.event[name];

        if (ref.length > 0)
            return $loop(function (i) {

                return $codeblock(

                    function () {
                        handler = ref[i];
                        return handler.apply(null, args);
                    },

                    function () {
                        if (i < ref.length - 1)
                            return $next;
                    }
                );

            });
    }
};

Application.Fire = function () { 

    __slice = [].slice;

    var args, handler, name;
    name = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    if (Application.event[name] != null) {

        var ref = Application.event[name];
        for (var i = 0; i < ref.length; i++) {
            handler = ref[i];
            if(ref.length==1 || (i == ref.length - 1 && name=="ProcessCaption")){
                return handler.apply(null, args);
            }else{
				if(name=="ProcessCaption"){
					args[0] = handler.apply(null, args);
				}else{
					handler.apply(null, args);	
				}
            }
        }
    }
};

//#endregion

//#region Web Service Functions

(function ($, window, undefined) {
    //is onprogress supported by browser?
    var hasOnProgress = ("onprogress" in $.ajaxSettings.xhr());

    //If not supported, do nothing
    if (!hasOnProgress) {
        return;
    }

    //patch ajax settings to call a progress callback
    var oldXHR = $.ajaxSettings.xhr;
    $.ajaxSettings.xhr = function () {
        var xhr = oldXHR();
        if (xhr instanceof window.XMLHttpRequest) {
            xhr.addEventListener('progress', this.progress, false);
        }

        if (xhr && xhr.upload) {
            xhr.upload.addEventListener('progress', this.progress, false);
        }

        return xhr;
    };
})(jQuery, window);

Application.GenerateWebService = function (method, args){
        
    var url = "https://go.scrubit.com.au/q/?m=" + method;
    var ret = new Object();
	ret.url = url;
	ret.data = args;
	return ret;
};

Application.ExecuteWebService = function (method, args, callback_, async_, progress_, ignoreConnection_, overrideCallbacks_, timeout_) {

	//Retry last service call
	if(!method){		
	
		method = Application.lastExecute.method;
		args = Application.lastExecute.args;
		callback_ = Application.lastExecute.callback_;
		async_ = Application.lastExecute.async_;
		progress_ = Application.lastExecute.progress_;
		ignoreConnection_ = Application.lastExecute.ignoreConnection_;
		overrideCallbacks_ = Application.lastExecute.overrideCallbacks_;
		timeout_ = Application.lastExecute.timeout_;
		
	}else{
		
		if (method != "GetServerInfo" && method != "GetNotifications" && method != "GetMessage")
			Application.lastExecute = {
				method:method, 
				args:args, 
				callback_:callback_, 
				async_:async_, 
				progress_:progress_, 
				ignoreConnection_:ignoreConnection_, 
				overrideCallbacks_:overrideCallbacks_, 
				timeout_:timeout_
			};
	
	}

    //#35 Virtual Tables
    if(method == "RecordSet" && Application.Virtual[args.table_]){
        if(Application.Virtual[args.table_].RecordSet(args, callback_))
            return;
    }

    if (Application.IsOffline() && $moduleloaded("OfflineManager")) {
        Application.LogInfo("Executing Offline Action: " + method + ", Session ID: " + Application.auth.SessionID);
        if (Application.Offline.Process(method, args, callback_))
            return;
        Application.Error("Offline action not found: " + method);
    }

    if (async_ == null) async_ = true;

    //Set the server URL and q extention.
    var url = "https://go.scrubit.com.au/q/";

	if (method != "GetServerInfo" && method != "GetNotifications" && method != "GetMessage"){
		
		Application.LogInfo("Executing Webservice: " + method + ", Session ID: " + Application.auth.SessionID);
	
		Application.LogDebug("Method: "+method+", Args: "+$.toJSON(args));
	
		if(Application.Log.RemoteStatus() == Application.remoteStatus.Connected)
			Application.LogInfo("Method: "+method+", Args: "+$.toJSON(args));
	}      
	
    var xhr = $.ajax({
        beforeSend: function (xhrObj) {
            xhrObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
            xhrObj.setRequestHeader("Accept", "application/json");
        },
        async: async_,
        type: "POST",
        url: url + '?m=' + method,
        dataType: 'json',
        data: encodeURIComponent($.toJSON(args)), //Encode the arguments.
		timeout: timeout_,
        error: (function (e) {
			
			Application.Fire("ExecutedWebservice", method, false);
			
			if (e.statusText)
                e = e.statusText;
			
			if ((method == "GetServerInfo" || method == "GetNotifications" || method == "GetMessage") && !Application.HasDisconnected(e))
				return;            		
            
            if (overrideCallbacks_ && overrideCallbacks_.onerror) {
                overrideCallbacks_.onerror(e);
                return;
            }
            if (!Application.supressServiceErrors)
                Application.Error(e);
            if (method != "GetServerInfo" && method != "GetNotifications")
                Application.supressServiceErrors = false;
			if (callback_) callback_(false);
        }),
        success: (function (result) {
			
            Application.Fire("ExecutedWebservice", method, true);            

            if (!Application.connected) {
                Application.Fire("Connected");
                Application.connected = true;
            }
            
            if (result != null) {
                if (result.Message) {
                    if (result.Message != "FALSE") {
						if ((method == "GetServerInfo" || method == "GetNotifications" || method == "GetMessage") && !Application.HasDisconnected(result.Message))
							return;
						 if (overrideCallbacks_ && overrideCallbacks_.onerror) {
							overrideCallbacks_.onerror(result.Message);
							return;
						}
                        if (!Application.supressServiceErrors)
                            Application.Error(result.Message);                                             
                    }
                }
            }
			
			if (overrideCallbacks_ && overrideCallbacks_.onsuccess) {
                overrideCallbacks_.onsuccess(result);
                return;
            }
			
            if (method != "GetServerInfo" && method != "GetNotifications")
                Application.supressServiceErrors = false;
            if (callback_) callback_(result);
        }),
        progress: function (e) {
            if (progress_)
                progress_(e.loaded);
        }
    });
    if (overrideCallbacks_ && overrideCallbacks_.onsend)
        overrideCallbacks_.onsend(xhr);
};

Application.WebServiceWait = function (func, params, async_, progress_, ignoreConnection_) {

    var w = $wait();

    Application.ExecuteWebService(func, params, function (r) {        
        w.resolve(r);
    }, async_, progress_, ignoreConnection_);

    return w.promise();

};

Application.Authorize = function () {

    var w = $wait();

    Application.ExecuteWebService("Authorize", { auth: Application.auth }, function (r) {
        
        //Save timezone and license.
        Application.timezone = r.TZ; 
        var license = new Object();
        app_transferObjectProperties.call(license, r.License);
        Application.license = license;
        r.License = null;

        if (r) r.LoginTime = Application.ConvertDate(r.LoginTime,true) //Bug fix	
                		        
        w.resolve(r);

    }, true, null, true);

    return w.promise();
};

Application.LoginCookieExists = function(instance_){
    return Application.WebServiceWait("LoginCookieExists", {instance: instance_});
};

Application.Disconnect = function (async_, clearcookie_) {
    Application.connected = false;    
    async_ = Default(async_, false);
    clearcookie_ = Default(clearcookie_, false);
    return Application.WebServiceWait("Disconnect", { auth: Application.auth, clearcookie_: clearcookie_}, async_, null, true);
};

Application.LoadMainMenu = function () {
    return Application.WebServiceWait("LoadMainMenu", { auth: Application.auth });
};

Application.GetUserLicense = function () {
    return Application.WebServiceWait("GetUserLicense", { auth: Application.auth });
};

Application.ClearCache = function (id) {
    return Application.WebServiceWait("ClearCache", { auth: Application.auth, id_: id });
};

Application.CheckUpdates = function () {    
    return Application.WebServiceWait("CheckUpdates", { auth: Application.auth });
};

Application.CheckUpdatesSkipVersion = function () {    
    return Application.WebServiceWait("CheckUpdatesSkipVersion", { auth: Application.auth });
};

Application.GetUpdates = function () {
    return Application.WebServiceWait("GetUpdates", { auth: Application.auth });
};

Application.ClearRecordCache = function () {
    return Application.WebServiceWait("ClearRecordCache", { auth: Application.auth });
};

Application.SyncSecurity = function (user_) {
    //#39 Not needed in new security model.
    return;
};

Application.AuthCode = function (instance_) {
    instance_ = Default(instance_,"");
    var w = $wait();
    Application.ExecuteWebService("AuthCode", { auth: Application.auth, instance_: instance_ }, function (r) {
        Application.Message(r, null, "Auth Code");
        w.resolve();
    });
    return w.promise();
};

Application.SaveSource = function (type, id, code) {
    return Application.WebServiceWait("SaveSource", { auth: Application.auth, type_: type, id_: id, code_: code });
};

Application.UpdateProfileImage = function (type, img) {
    return Application.WebServiceWait("UpdateProfileImage", { auth: Application.auth, type_: type, img_: img });
};

Application.ExecutePlugin = function (plugin, method, args) {
    args.auth = Application.auth;
    return Application.WebServiceWait("ExecutePlugin&pluginname="+plugin+"&pluginmethod="+method, args);
};

Application.DownloadDataPack = function (progress_) {
    return Application.WebServiceWait("DownloadDataPack", { auth: Application.auth }, true, progress_);
};

Application.UploadDataPack = function (name_) {
    return Application.WebServiceWait("UploadDataPack", { auth: Application.auth, name_: name_ });
};

Application.BeginTransaction = function () {
    
    if(Application.transactionStarted > 0){    
        Application.transactionStarted += 1;    
        Application.LogWarn("A transaction was already started. Ignored BeginTransaction");
        return;
    }

    var w = $wait();

    Application.ExecuteWebService("BeginTransaction", { auth: Application.auth }, function (r) {
        Application.transactionStarted += 1;      
        w.resolve(r);
    });

    return w.promise();    
};

Application.CommitTransaction = function () {   

    if(Application.transactionStarted > 1){
        Application.transactionStarted -= 1;
        Application.LogWarn("A transaction was already started. Ignored CommitTransaction");
		return;
    }else if(Application.transactionStarted <= 0){
        Application.transactionStarted = 0;
        Application.LogWarn("A transaction has not started. Ignored CommitTransaction");
		if(Application.developerMode){
			Application.Message("Tried to commit too many transactions!");
		}
        return;
    }

    var w = $wait();

    Application.ExecuteWebService("CommitTransaction", { auth: Application.auth }, function (r) {   
        Application.transactionStarted -= 1;       		        
		w.resolve(r);
    });

    return w.promise();         
};

Application.RollbackTransaction = function () {    
    
    if(Application.transactionStarted <= 0){
        Application.transactionStarted = 0;
        Application.LogWarn("A transaction has not started. Ignored RollbackTransaction");
		if(Application.developerMode){
			Application.Message("Tried to rollback too many transactions!");
		}
        return;
    }

    var w = $wait();

    Application.ExecuteWebService("RollbackTransaction", { auth: Application.auth }, function (r) {   
        Application.transactionStarted = 0;       		        
		w.resolve(r);
    });

    return w.promise();    
};

Application.CreateFileForUpload = function (name_, length_, chunkSize_, mime_) {
    return Application.WebServiceWait("CreateFileForUpload", { auth: Application.auth, name_: name_, length_: length_, chunkSize_: chunkSize_, mime_: mime_ });
};

Application.CreateUser = function (username_, password_) {
    return Application.WebServiceWait("CreateUser", { auth: Application.auth, username_: username_, password_: password_ });
};

Application.LicensePassword = function (pass_) {
    return Application.WebServiceWait("LicensePassword", { auth: Application.auth, pass_: pass_ });
};

Application.ExportObjects = function (view_,src_) {
    return Application.WebServiceWait("ExportObjects", { auth: Application.auth, view_: view_, src_: src_ });
};

Application.ExportIndividualObjects = function (view_,src_) {
    return Application.WebServiceWait("ExportIndividualObjects", { auth: Application.auth, view_: view_, src_: src_ });
};

Application.ExportObjectBackup = function (view_,src_) {
    return Application.WebServiceWait("ExportObjectBackup", { auth: Application.auth, view_: view_, src_: src_ });
};

Application.RollbackObject = function (view_) {
    return Application.WebServiceWait("RollbackObject", { auth: Application.auth, view_: view_ });
};

Application.GetDependencies = function (view_) {
    return Application.WebServiceWait("GetDependencies", { auth: Application.auth, view_: view_ });
};

Application.ResyncTables = function (view_) {
    return Application.WebServiceWait("ResyncTables", { auth: Application.auth, view_: view_ });
};

Application.GetOfflineCookie = function(){
    return Application.WebServiceWait("GetOfflineCookie", {auth: Application.auth});
};

Application.GetUserLayout = function (username_, page_) {
    if(Application.IsOffline())
        return "";
    return Application.WebServiceWait("GetUserLayout", { auth: Application.auth, username_: username_, page_: page_ });
};

Application.SaveUserLayout = function (username_, page_, layout_) {
    if(Application.IsOffline())
        return;
    return Application.WebServiceWait("SaveUserLayout", { auth: Application.auth, username_: username_, page_: page_, layout_: layout_ });
};

Application.DeleteUserLayout = function (username_, page_) {
    if(Application.IsOffline())
        return;
    return Application.WebServiceWait("DeleteUserLayout", { auth: Application.auth, username_: username_, page_: page_ });
};

Application.CanSelect = function (type_, name_) {
    return Application.WebServiceWait("CanSelect", { auth: Application.auth, type_:type_, name_:name_ });
};

Application.CanInsert = function (type_, name_) {
    return Application.WebServiceWait("CanInsert", { auth: Application.auth, type_:type_, name_:name_ });
};

Application.CanModify = function (type_, name_) {
    return Application.WebServiceWait("CanModify", { auth: Application.auth, type_:type_, name_:name_ });
};

Application.CanDelete = function (type_, name_) {
    return Application.WebServiceWait("CanDelete", { auth: Application.auth, type_:type_, name_:name_ });
};

Application.Search = function (search_) {
	
	//Protected characters.
	if(search_ && search_.replaceall)
		search_ = search_.replaceall("(","LB;").replaceall(")","RB;");
	
    return Application.WebServiceWait("Search", { auth: Application.auth, search_:search_ });
};

Application.StartMaintenanceMode = function (msg_, time_) {
    return Application.WebServiceWait("StartMaintenanceMode", { auth: Application.auth, msg_: msg_, time_: time_ });
};

Application.EndMaintenanceMode = function () {
    return Application.WebServiceWait("EndMaintenanceMode", { auth: Application.auth });
};

Application.ExportUserLayout = function(user_){
    return Application.WebServiceWait("ExportUserLayout", { auth: Application.auth, user_: user_ });
};

Application.BatchProcess = function(insert_, modify_, delete_){
	return Application.WebServiceWait("BatchProcess", { auth: Application.auth, insert_: insert_, modify_: modify_, delete_: delete_ });
};

//#endregion

//#region Public Functions

Application.ProcessCaption = function(caption_){
	var cap = Application.Fire("ProcessCaption", caption_);
	if(cap)
		return cap;
	return caption_;
};

//#85 - Sanitize string function.
Application.SanitizeString = function(input) {
    
    if (input == null || typeof input != "string") //Only sanitize strings.
        return input;

    //Decode loop.
    var oldinput = "";
    do{
        oldinput = input;
        input = Application.DecodeHTML(input);
    }while(oldinput !== input);

    var output = input.replace(/<script[^>]*?>.*?<\/script>/gi, '').
				    replace(/<[\/\!]*?[^<>]*?>/gi, '').
				    replace(/<style[^>]*?>.*?<\/style>/gi, '').
				    replace(/<![\s\S]*?--[ \t\n\r]*>/gi, '');
    return output;
};

Application.CreateArray = function(len,value){
    var obj = new Array();
    for(var i = 0; i < len; i++){
        obj.push(value);
    }
    return obj;
};

Application.GetUserData = function () {
    if (Application.auth.UserData != "") {
        try {
            var data = $.parseJSON(Application.auth.UserData);
            return data;
        } catch (e) {
        }
    }
    return null;
};

Application.SaveUserData = function (data) {
    Application.auth.UserData = $.toJSON(data);    
};

Application.SwitchMode = function (mobile, instance) {
    
	//This should be in the app module...
	var extra = "";
	if(Application.App.Params()["returnurl"])
		extra += "&returnurl="+Application.App.Params()["returnurl"];
	
    if (mobile) {
        window.location = "https://go.scrubit.com.au/" + instance + "?mobile=true"+extra;
    } else {
        window.location = "https://go.scrubit.com.au/" + instance + "?mobile=false"+extra;
    }   
};

Application.LoadModules = function (windowType_, engineonly_) {

    try {

        //Check if the module manager loaded.
        if (typeof Application.ModuleManager == 'undefined')
            throw "Liveapp Framework failed to load. Please contact support.";		         

        //Set window type.				
        Application.type = windowType_;

        var params = [];         
        Application.LoadParams(params, PAGE_PARAMETERS);
		
        //Load Liveapp Engine Modules.	            
        Application.ModuleManager.LoadModule(new IDEngine());
        Application.ModuleManager.LoadModule(new CodeEngine());        
        Application.ModuleManager.LoadModule(new Logging(0)); //Console Logging
        Application.ModuleManager.LoadModule(new CookieManager());        
		Application.ModuleManager.LoadModule(new LocalStorageManager());
        Application.ModuleManager.LoadModule(new UpdateManager());
        Application.ModuleManager.LoadModule(new NotificationManager());        
        //if (params["offline"] == "true")
        Application.ModuleManager.LoadModule(new OfflineManager());
        Application.ModuleManager.LoadModule(new ZipManager());
        Application.ModuleManager.LoadModule(new FileDownloadManager());
        Application.ModuleManager.LoadModule(new CacheManager());

        //Load Liveapp UI Modules.        
        Application.ModuleManager.LoadModule(new AppUI());
        Application.ModuleManager.LoadModule(new WindowManager());
        Application.ModuleManager.LoadModule(new PhantomManager());
        Application.ModuleManager.LoadModule(new InputManager());        
        Application.ModuleManager.LoadModule(new LoadingManager());
        Application.ModuleManager.LoadModule(new ImageManager());
        Application.ModuleManager.LoadModule(new WrapperManager());
        Application.ModuleManager.LoadModule(new CameraManager());
		Application.ModuleManager.LoadModule(new TourManager());

        //Load Liveapp App Module.
        if(!engineonly_)
            Application.ModuleManager.LoadModule(new App());

    } catch (e) {
        if (e != "")
            Application.Error(e);
    }

};

Application.NavigateToPage = function (id_) {
    
    if(Application.IsInMobile()){
        window.location = "https://go.scrubit.com.au/Pages/"+id_+"?mobile=true";
    }else{
        window.location = "https://go.scrubit.com.au/Pages/"+id_;
    }
};

Application.serviceWorkerReg = null;
Application.HookCacheEvents = function(instance){

    function ShowUpdateMsg(onupdate){
        if(Application.connected){
            Application.Confirm("An updated version of the website has been downloaded. Load the new version?",function(r){
        
                if(!r)return;					  
                onupdate();

            },"Update Available");
        }else{
            onupdate();
        }
    }

    if ('serviceWorker' in navigator){
        
        navigator.serviceWorker.register('./service-worker'+(Application.IsInMobile()?'-mobile':'')+'.js?instance='+instance)
            .then(function(reg) {
                Application.serviceWorkerReg = reg;
                reg.onupdatefound = function() {
                    var installingWorker = reg.installing;
                    installingWorker.onstatechange = function() {
                        switch (installingWorker.state) {
                            case 'installed':
                            if (navigator.serviceWorker.controller) {
                                Application.LogInfo('New or updated content is available.');
                            } else {
                                Application.LogInfo('Content is now available offline!');
                            }
                            break;
                            case 'redundant':
                                Application.LogError('The installing service worker became redundant.');
                            break;
                        }
                    };
                };
                Application.LogInfo("Yes, it did.");
            }).catch(function(err) {
                Application.LogError("No it didn't. This happened: ", err)
            });

    } else if (window.applicationCache) {

        //Issue #41 - Application cache not working in firefox.
        function LogCacheEvent(e) {
            var online, status, type, message;
            online = (navigator.onLine) ? 'yes' : 'no';
            status = Application.cacheValues[cache.status];
            type = e.type;            
            message = 'online: ' + online;
            message += ', event: ' + type;
            message += ', status: ' + status;
            Application.LogDebug(message);
        }

        var cache = window.applicationCache;
        cache.addEventListener('cached', LogCacheEvent, false);
        cache.addEventListener('checking', LogCacheEvent, false);
        cache.addEventListener('downloading', LogCacheEvent, false);
        cache.addEventListener('error', LogCacheEvent, false);
        cache.addEventListener('noupdate', LogCacheEvent, false);
        cache.addEventListener('obsolete', LogCacheEvent, false);
        cache.addEventListener('progress', LogCacheEvent, false);
        cache.addEventListener('updateready', LogCacheEvent, false);        

        window.applicationCache.addEventListener('updateready',
			function () {
			    try {			        
					
			        window.applicationCache.swapCache();                    
                    Application.LogDebug('Swap cache has been called, yo!');			        
                    
                    ShowUpdateMsg(Application.Reload);
			        
			    } catch (e) {
			        Application.LogError(e);
			    }
			},
			false
		);

    } else {
        Application.LogDebug('App cache not supported.');
    }
};

Application.Reload = function(){
    if(Application.IsIE()){
	    window.location = window.location;
    }else{
	    window.location.reload();
    }
};

Application.HookPageEvents = function (instance) {

    Application.HookCacheEvents(instance);

    if (!Application.IsInMobile()) {

        //On resize.
        $(window).resize(app_debouncer(function () {

            //Resize windows.
            if ($moduleloaded("WindowManager")) {
                UI.WindowManager.OnResize();
            }

        },500));

        //On keypress.
        $(document).keydown(function (ev) {
            if ($moduleloaded("InputManager")) {
                return UI.InputManager.OnKeyPress(ev);
            }
        });

    } else {

	
		$(window).resize(function () {
		
			//Resize windows.
            if ($moduleloaded("WindowManager")) {
                UI.WindowManager.OnResize();
            }
		
		});
		
        //On resize.        
        $(window).on("orientationchange", function() {

            $.mobile.resetActivePageHeight();
			
            //Resize windows.
            if ($moduleloaded("WindowManager")) {
                UI.WindowManager.OnResize();
            }
                       
        });      
    }

    //OnClose.
    $(window).unload(function () {
        if ($moduleloaded("App")) {
            Application.App.Close();
        }
    });
};

Application.MergeView = function (view, rec) { 

    if(view == null) return "";

    var check = new RegExp('\=FIELD\\(((.*?))\\)', 'g');
    var consts = view.match(check);
    if (consts && rec) {
        for (var j = 0; j < consts.length; j++) {
            var name = consts[j].replace(check, '$2');
            var f = rec.GetField(name);            
            if (f) {
                if(f.Value == null || f.Value == "" || f.Value == 0)
                    f.Value = null;
                if(f.Value && f.Value.getMonth){           
                    view = view.replace("=FIELD(" + consts[j].replace(check, '$1') + ")", "=CONST(" + $.format.date(f.Value,"dd/MM/yyyy") + ")");
                }else{
                    view = view.replace("=FIELD(" + consts[j].replace(check, '$1') + ")", "=CONST(" + f.Value + ")");
                }
            }         
        }
    }

    view = Application.ViewSubstitute(view);

    return view;
};

Application.LicenseCheck = function(name, dev){

    dev = Default(dev,false);

    if(!Application.license || !Application.license.AvailableParts || !Application.license.AvailableParts.AvailableParts)
        return false;

    var parts = Application.license.AvailableParts.AvailableParts;
    for(var i = 0; i < parts.length; i++){
        if(parts[i].Name == name){
            if(dev && parts[i].Developer)
                return true;
            if(!dev)
                return true;
        }
    }
    return false;
};

$license = Application.LicenseCheck; //Add global access function.

Application.RunSilent = function(func){
    try{
        return func();
    }catch(e){
    }
};

Application.RunNext = function (func, skipDelay, id, trans) {
    
    if(skipDelay)
        return $codeblock(func);	
		
    setZeroTimeout(function () {
        $thread(function () {
			if(!trans){
				return $codeblock(func);
			}else{
				return $codeblock(
					Application.BeginTransaction,
					func,
					Application.CommitTransaction
				);
			}
        },null,null,null,id);
    });
}

Application.TestNumber = function (n) {
    if (isNaN(parseInt(n))) 
        Application.Error("Value must be a number.");
};

Application.IsPortrait = function(){
	return $(window).height() > $(window).width();	
};

Application.IsInFrame = function(){
	return Application.type == Application.windowType.Frame;
};

Application.IsInMobile = function(){
	return Application.type == Application.windowType.Mobile;
};

Application.IsDevice = function () {
    return (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase()));
};

Application.IsAndroid = function(){
	return /(android)/i.test(navigator.userAgent);
};

Application.IsMobileDisplay = function () {
    if(!Application.IsInMobile())
        return false;
    var w = $(window).width();
    if(w > $(window).height())
        w = $(window).height();
    return w <= 650;
};

Application.IsTabletDisplay = function () {
    if(!Application.IsInMobile())
        return false;
    var w = $(window).width();
    if(w > $(window).height())
        w = $(window).height();
    return w > 650;
};

Application.MiniMode = function () {
	//Backwards compat.
    return Application.IsMobileDisplay();
};

Application.IsIE = memoize(function () {
    return $.browser.msie == true;
});
Application.IsSafari = memoize(function () {
    return $.browser.safari == true;
});
Application.IsOpera = memoize(function () {
    return $.browser.opera == true;
});
Application.IsChrome = memoize(function () {
    return $.browser.webkit == true;
});
Application.IsFirefox = memoize(function () {
    return $.browser.mozilla == true;
});

Application.IsPrivate = function(){
	if(!$.browser.safari)
        return false;
	var storageTestKey = 'sTest',
		storage = window.sessionStorage;

	try {
	  storage.setItem(storageTestKey, 'test');
	  storage.removeItem(storageTestKey);
	} catch (e) {
	    return true;
	}
	return false;
};

Application.UnsupportedIE = memoize(function (strict_) {

    if(!$.browser.msie)
        return false;

    strict_ = Default(strict_, false);

    if (jQuery.browser.version.substring(0, 2) == "6.")
        return true;
    if (jQuery.browser.version.substring(0, 2) == "7.")
        return true;
    if (jQuery.browser.version.substring(0, 2) == "8.")
        return true;
    if (jQuery.browser.version.substring(0, 2) == "9." && strict_)
        return true;
    if (!Application.CanvasSupported() && strict_)
        return true;
    return false;
});

Application.CanvasSupported = memoize(function () {    
    var elem = document.createElement('canvas');
    return !!(elem.getContext && elem.getContext('2d'));    
});

Application.HasDisconnected = function(e){
	if(!e || typeof e.indexOf == 'undefined')
		return false;	
	return e.indexOf("Your current session has expired") != -1 || e.indexOf("Invalid request. Please try again.") != -1 || e.indexOf("open DataReader") != -1 || e.indexOf("transaction was rollbacked or commited") != -1;
};

Application.Error = function (msg) {

    //Kill the timeout queue.
    Application.timeouts = [];

    Application.LogError("Application Error: " + msg);    

    Application.Fire("Error",msg);    
    
    if($moduleloaded("AppUI")){
        Application.RunSilent(UI.HideServerProgress);
		UI.StatusBar(false);	
	}
    
    Application.HideProgress();        
	if($moduleloaded("OfflineManager")){
		Application.Offline.HideLoad();
	}

	if (typeof msg.indexOf != 'undefined') {
		if (msg == "error" || msg.toLowerCase() == "unknown") {
				
				//Lost Connection
				setTimeout(function(){
					Application.ExecuteWebService();
				},1000);
				
				Application.Fire("ConnectionLost");
				Application.connected = false;
				
				//Kill execution.
				throw "";
		}
	}
	
    //Restart code engine.
    if ($moduleloaded("CodeEngine"))
        Application.CodeEngine.Restart();

    Application.Fire("ThreadFinished");

    //Use arguments to replace $ const values.
    for (var i = 1; i < arguments.length; i++)
        msg = msg.replace("$" + i, arguments[i]);

    //Lost connection to server.
    if (typeof msg.indexOf != 'undefined') {
        if (msg == "error" || msg.toLowerCase() == "server too busy" || msg.toLowerCase() == "internal server error" || msg.toLowerCase() == "unknown") {
            Application.Fire("ConnectionLost");
            Application.connected = false;
        }
    }

    //Run error handling.
    if (!Application.supressError) {        
        if (Application.OnError) {
            setTimeout(function(){
                Application.OnError(msg);
            },100);
        }
        //Kill execution.
        throw "";
    }
    Application.supressError = false;
    Application.supressServiceErrors = false;
};

Application.ShowError = function (msg, callback) {

    if (Application.noGUI || msg == ""){
        if (callback) 
            setTimeout(callback,50);
        return;
    }

    //Use arguments to replace $ const values.
    for (var i = 2; i < arguments.length; i++)
        msg = msg.replace("$" + i, arguments[i]);

    Application.Message(msg, callback, "Application Error");
}

//Default error handling to ShowError.
Application.OnError = Application.ShowError;

Application.Message = function (msg, callback, title, icon) {

    //Don't show the message if we have no GUI access.
    if (Application.noGUI){
        if (callback) 
            setZeroTimeout(callback);
        return;
    }

    //Default values.
    title = title || 'Application Message';

    if (Application.MessageBox != null) {
        Application.MessageBox(msg, title, callback, icon);
    } else {
        alert(msg);
        if (callback) callback();
    }
};

Application.Confirm = function (msg, callback, title, yescaption, nocaption) {

    //Don't show the message if we have no GUI access.
    if (Application.noGUI){
        if (callback != null)
            setZeroTimeout(function(){
                callback(true);
            });
        return;
    }

    //Default values.
    title = title || 'Application Confirmation';

    if (Application.ConfirmBox != null) {
        Application.ConfirmBox(msg, title, callback, yescaption, nocaption);
    } else {
        if (confirm(msg) == true) {
            if (callback != null)
                callback(true);
        } else {
            if (callback != null)
                callback(false);
        }
    }
};

Application.ShowProgress = function (msg, title, i, num) {

    if (Application.noGUI)
        return;
    
    title = Default(title,'Progress');

    if (Application.ProgressBox) {
        Application.ProgressBox(true, msg, title, i, num);
    }
};

Application.HideProgress = function () {

    if (Application.noGUI)
        return;

    if (Application.ProgressBox) {
        Application.RunSilent(function(){
            Application.ProgressBox(false);
        });
    }
};

Application.StrSubstitute = function (msg) {

    //Use arguments to replace $ const values.
    for (var i = 1; i < arguments.length; i++)
        while (msg.indexOf("$" + i) != -1)
            msg = msg.replace("$" + i, arguments[i]);

    return msg;
};

Application.LoadParams = function (arr, paramstr) {

    if (paramstr == null)
        paramstr = window.location.search.substring(1);

    var parms = paramstr.split('&');

    for (var i = 0; i < parms.length; i++) {
        var pos = parms[i].indexOf('=');
        if (pos > 0) {
            var key = parms[i].substring(0, pos);
            var val = parms[i].substring(pos + 1);
            arr[key] = decodeURIComponent(val);
        }
    }

};

Application.LoadScript = function (id_, code_) {

    $('body').remove("#" + id_);

    if(code_.indexOf("http") == 0){

        var source = $('<script type="text/javascript" src="' + code_ + '"></script>');
        $('head').append(source);

    }else{

        var source = $('<script type="text/javascript" id="' + id_ + '">' + code_ + '</script>');
        $('body').append(source);

    }

};

Application.FriendifyDates = function (view_) {

    var check = new RegExp('([\(\.\<\=\\s])(\\d+)(\/)(\\d+)', 'g');
    var groups = view_.match(check);
    return view_.replace(check, "$1$4$3$2");
};

Application.CheckEmail = function (email) {
    var re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
};

Application.HasOption = function(opts,key){
    if (!opts) 
        return false;
    var options = opts.split(";");
    for (var i = 0; i < options.length; i++) {
        if (options[i] == key) {
            return true;
        }
    }
    return false;
};

Application.OptionValue = function(opts,key){
    if(!opts)
        return null;
    var opt_arr = opts.split(";");
    for(var i = 0; i < opt_arr.length; i++){
        var item = opt_arr[i];
        if(item != ""){
            var item_arr = item.split(":");
            if(item_arr.length > 1){
                if(item_arr[0] == key)
                    return item_arr[1].replace(/COMMA;/g,",");
            }
        }
    }
    return null;
};

Application.dateCache = {};
Application.ConvertDate = function(str,skipTZ) {
    
	if(Application.dateCache[str])
        return new Date(Application.dateCache[str]);
	
    var m = moment(str);
   
    var server_tz = 0;
    var local_tz = 0;    

    if(m._tzm){
		server_tz = m._tzm*-1;
    	local_tz = moment(str).zone();    
    }
	
	Application.dateCache[str] = m.zone(server_tz-local_tz).toDate();
	
    return new Date(Application.dateCache[str]);
};

Application.ExecuteAjax = function (url_, data_, callback_) {

    $.ajax({
        url: url_,
        data: data_,
        error: (function (e) {
            if (e.statusText)
                e = e.statusText;
            Application.Error(e);
        }),
        success: (function (result) {
            if (result != null) {
                if (result.Message) {
                    if (result.Message != "FALSE") {
                        Application.Error(result.Message);
                    }
                }
            }
            if (callback_) callback_(result);
        })
    });
};

Application.ExecuteEndpoint = function (url_, callback_, timeout_, type_) {  
		
    type_ = Default(type_,'json');
	
    var xhr = $.ajax({
        beforeSend: function (xhrObj) {			
            xhrObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
            if(type_ == 'json')
                xhrObj.setRequestHeader("Accept", "application/json");
        },
        async: true,
        crossDomain: true,
        type: "POST",
        url: url_,
        dataType: type_,        
        timeout: timeout_,
        error: (function (e) {
            if (e.statusText)
                e = e.statusText;            
            Application.Error(e);            
            if (callback_) callback_(false);
        }),
        success: (function (result) {
			
            if (result != null) {
                if (result.Message) {
                    if (result.Message != "FALSE") {                        
                        Application.Error(result.Message);                                             
                    }
                }
            }			            
            if (callback_) callback_(result);
        })
    });    
};

Application.RandomArray = function (myArray) {
    var i = myArray.length;
    if (i == 0) return false;
    while (--i) {
        var j = Math.floor(Math.random() * (i + 1));
        var tempi = myArray[i];
        var tempj = myArray[j];
        myArray[i] = tempj;
        myArray[j] = tempi;
    }
};

Application.CleanArray = function (array, deleteValue) {
    for (var i = 0; i < array.length; i++) {
        if (array[i] == deleteValue) {
            array.splice(i, 1);
            i--;
        }
    }
    return array;
};

var app_transferObjectProperties = function(obj_) {
    if (obj_ == null) {
        return false;
    }
    for (var i in obj_) {
        this[i] = obj_[i];
    }
    return true;
};

var app_deepTransferObjectProperties = function(obj_) {
    if (obj_ == null) {
        return false;
    }
    $.extend(true, this, obj_);    
    return true;
};

function app_debouncer(func, timeout) {

    var timeoutID, timeout = timeout || 200;
    return function () {
        var scope = this, args = arguments;
        clearTimeout(timeoutID);
        timeoutID = setTimeout(function () {
            func.apply(scope, Array.prototype.slice.call(args));
        }, timeout);
    }
};

Application.DecodeHTML = function(text){
	var decoded = $('<div/>').html(text).text();
	return decoded;
};

Application.DecryptData = function(inStr, inPass) {
    try {
        //Creating the Vector Key
        var iv = CryptoJS.enc.Hex.parse('d71741b0aa69380636689824d1156c05');
        //Encoding the Password in from UTF8 to byte array
        var Pass = CryptoJS.enc.Utf8.parse(inPass);
        //Encoding the Salt in from UTF8 to byte array
        var Salt = CryptoJS.enc.Utf8.parse("Your salt value");
        //Creating the key in PBKDF2 format to be used during the decryption
        var key128Bits1000Iterations = CryptoJS.PBKDF2(Pass.toString(CryptoJS.enc.Utf8), Salt, { keySize: 128 / 32, iterations: 1000 });

        //Enclosing the test to be decrypted in a CipherParams object as supported by the CryptoJS libarary
        var cipherParams = CryptoJS.lib.CipherParams.create({
            ciphertext: CryptoJS.enc.Base64.parse(inStr)
        });

        //Decrypting the string contained in cipherParams using the PBKDF2 key
        var decrypted = CryptoJS.AES.decrypt(cipherParams, key128Bits1000Iterations, { mode: CryptoJS.mode.CBC, iv: iv, padding: CryptoJS.pad.Pkcs7 });
        var plaintext = decrypted.toString(CryptoJS.enc.Utf8);
        return plaintext;
    }
    //Malformed UTF Data due to incorrect password
    catch (err) {
        return "";
    }
}

Application.EncryptData = function(inStr, inPass) {
    try {
        //Creating the Vector Key
        var iv = CryptoJS.enc.Hex.parse('d71741b0aa69380636689824d1156c05');
        //Encoding the Password in from UTF8 to byte array
        var Pass = CryptoJS.enc.Utf8.parse(inPass);
        //Encoding the Salt in from UTF8 to byte array
        var Salt = CryptoJS.enc.Utf8.parse("Your salt value");
        //Creating the key in PBKDF2 format to be used during the decryption
        var key128Bits1000Iterations = CryptoJS.PBKDF2(Pass.toString(CryptoJS.enc.Utf8), Salt, { keySize: 128 / 32, iterations: 1000 });
        //Decrypting the string contained in cipherParams using the PBKDF2 key

        //Enclosing the test to be decrypted in a CipherParams object as supported by the CryptoJS libarary
        var cipherParams = CryptoJS.lib.CipherParams.create({
            ciphertext: CryptoJS.enc.Utf8.parse(inStr)
        });

        var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(inStr), key128Bits1000Iterations, { mode: CryptoJS.mode.CBC, iv: iv, padding: CryptoJS.pad.Pkcs7 });
        //var plaintext = decrypted.toString(CryptoJS.enc.Base64);
        var plaintext = encrypted.ciphertext.toString(CryptoJS.enc.Base64);
        //var plaintext = encrypted.toString();
        return plaintext;
    }
    //Malformed UTF Data due to incorrect password
    catch (err) {
        return "";
    }
};

moment.locale("en-AU");

Application.FormatDate = function(dte, format){
	if(dte == null)
		return "";
	format = Default(format,"dd/MM/yyyy");
	return $.format.date(dte,format);
};

Application.ParseDate = function(str){
	if(str && str.indexOf("T") != -1)
		return new Date(str);
	return moment(str,"dd/MM/yyyy".toUpperCase()).toDate();    
};

Application.ParseDateTime = function(str){
	if(str && str.indexOf("T") != -1)
		return new Date(str);
	return moment(str,"DD/MM/YYYY hh:mm:ss a").toDate();    
};


Application.ParseTime = function(timeStr, dt) {

    if (!dt) {
        dt = new Date();
    }
 
    var time = timeStr.match(/(\d+)(?::(\d\d))?\s*(p?)/i);
    if (!time) {
        return null;
    }
    var hours = parseInt(time[1], 10);
    if (hours == 12 && !time[3]) {
        hours = 0;
    }
    else {
        hours += (hours < 12 && time[3]) ? 12 : 0;
    }
 
    dt.setDate(1);
    dt.setMonth(0);
    dt.setYear(1900);

    dt.setHours(hours);
    dt.setMinutes(parseInt(time[2], 10) || 0);
    dt.setSeconds(0, 0);

    return dt;
};

Application.OffsetDate = function(dt){
	
	if(dt == null)
		return dt;
	
	//Apply server offset.
	var offset = Application.auth.TZ - moment().zone();
	dt.setTime(dt.getTime()+(offset*60*1000));
	return dt;
};

//#endregion

//#region Record Functions

Application.CombineViews = function(view1_, view2_, overwrite_){
    
	overwrite_ = Default(overwrite_,true);
	
    var ret = "";
    var filters = Application.GetFilters(view2_,false);
    var orgfilters = Application.GetFilters(view1_,false);

    //Handle top.
    var top = Application.GetTop(view2_);
    if(top == "")
        top = Application.GetTop(view1_);
    if(top != "")
        top += " ";

    //Handle sorting.
    var sorting = Application.GetSorting(view2_);
    if(sorting == "")
        sorting = Application.GetSorting(view1_);
    if(sorting != "")
        sorting += " ";

    for(var i = 0; i < filters.length; i++){
        try{
            
            var filts = filters[i].split("=");
            var found = false;

            for(var j = 0; j < orgfilters.length; j++){
                var orgfilts = orgfilters[j].split("=");
                if(orgfilts[0] == filts[0]){
					if(overwrite_)
						orgfilters[j] = filters[i];
                    found = true;
                }    
            }
            if(!found)
                orgfilters.push(filters[i]);

        }catch(e){
        }
    }
    for(var i = 0; i < orgfilters.length; i++){
        if(ret == ""){
            ret = orgfilters[i];
        }else{
            ret += ","+orgfilters[i];
        }
    }
        
    if(ret != "")
        ret = "WHERE("+ret+")";

    return top + sorting + ret;
};

Application.GetFilter = function (name_, view_) {

    if (view_) {
        var filters = Application.GetFilters(view_);
        for (var i = 0; i < filters.length; i++) {
            var filter = filters[i];
            if (filter[0] == name_)
                return filter[1];
        }
    }

    if (Application.auth.UserData != "") {
        try {
            var data = $.parseJSON(Application.auth.UserData);
            if (data.filters)
                if (data.filters[name_] !== undefined)
                    return data.filters[name_];
        } catch (e) {
        }
    }

    return "";
};

Application.ViewSubstitute = function (view) {

    if (view == null)
        return;

    if (view.indexOf("%1") != -1)
        view = view.replace(/%1/g, Application.auth.Username);

    if (view.indexOf("%TODAY") != -1)
        view = view.replace(/%TODAY/g, $.format.date(new Date(), 'dd/MM/yy'));

    if (Application.auth.UserData != "" && view.indexOf("%") != -1) {
        try {
            var data = $.parseJSON(Application.auth.UserData);            
            if (data.filters) {
                for (var i in data.filters) {
                    eval("view = view.replace(/"+i+"/g, \""+data.filters[i]+"\");");
                }
            }
        } catch (e) {
        }
    }

    return view;
};

Application.GetTop = function(view){
    
    var top = ""
    if (view.indexOf("TOP") != -1) {        

        var check = new RegExp("TOP\\s*\\((.*?)\\)", 'g');
        var matches = view.match(check);
        if (matches) {
            if(matches.length > 0){
                top += "TOP(" + matches[0].replace(check, '$1') + ") ";
            }
        }
    }
    return top;
};

Application.GetSorting = function(view){
    
    var sorting = ""
    if (view.indexOf("SORTING") != -1) {        

        var check = new RegExp("SORTING\\s*\\((.*?)\\)", 'g');
        var matches = view.match(check);
        if (matches) {
            if(matches.length > 0){
                sorting += "SORTING(" + matches[0].replace(check, '$1') + ") ";
            }
        }
    }
    if (view.indexOf("ORDER") != -1) {        

        var check = new RegExp("ORDER\\s*\\((.*?)\\)", 'g');
        var matches = view.match(check);
        if (matches) {
            if(matches.length > 0){
                sorting += " ORDER(" + matches[0].replace(check, '$1') + ") ";
            }
        }
    }
    return sorting;
};

Application.GetFilters = function (view, friendify) {

    friendify = Default(friendify,true);

    var arr = new Array();
	
	view = Default(view,"");

    //Issue #36 - View errors when it contains a comma or equals sign.
    if (view.indexOf("WHERE") != -1) {

        view = view.replace("WHERE (", "WHERE(");

        var check = new RegExp("\\,*(.*?)\\=\\s*(\\w+)\\s*\\((.*?)\\)", 'g');
        var matches = view.substr(view.indexOf("WHERE(") + 6).match(check);
        if (matches) {
            for (var i = 0; i < matches.length; i++) {

                var name = matches[i].replace(check, '$1');
                var type = matches[i].replace(check, '$2');
                var filt = matches[i].replace(check, '$3');

                if(!friendify){
                    arr.push(name.trim()+"="+type+"("+filt+")");
                }else{
                    arr.push([name.trim(),filt]);
                }
            }
        }
    }

    return arr;
};

Application.AddFilter = function(view_,field_,filter_){

    filter_ = Default(filter_,"");
	
	//Protected characters.
	if(filter_ && filter_.replaceall)
		filter_ = filter_.replaceall("(","LB;").replaceall(")","RB;");

    var filter = "$1=FILTER($2)";
    filter = Application.StrSubstitute(filter,field_,filter_);

    var blank = (filter_ == "");
    var newview = "$5$1$2$3$4";
    var top = Application.GetTop(view_);
    var sorting = Application.GetSorting(view_);
    var wherebegin = "";
    var whereend = "";
    var filters = "";

    if(!blank){
        wherebegin = "WHERE(";
        whereend = ")";
    }

    var filterarray = Application.GetFilters(view_,false);
    for(var i = 0; i < filterarray.length; i++){
        var v = filterarray[i];
		v = v.trim();
        if(v.indexOf(field_+"=")!=0){
            wherebegin = "WHERE(";
            whereend = ")";
            if(filters == ""){
                filters = v;
            }else{
                filters += ","+v;
            }
        }
    }

    if(!blank){
        if(filters == ""){
            filters = filter;
        }else{
            filters += ","+filter;
        }
    }
    return Application.StrSubstitute(newview,sorting,wherebegin,filters,whereend,top);
};

Application.StripFilters = function (filter) {
    return filter.replace("<", "").replace(">", "").replace("..", "").replace("=", "").toString().toLowerCase();
};

Application.FilterType = function (filter) {

    if (filter.indexOf("<>") != -1) {
        return "!=";
    } else if (filter.indexOf("<") != -1) {
        return "<";
    } else if (filter.indexOf(">") != -1) {
        return ">";
    } else if (filter.indexOf("=") != -1) {
        return "==";
    } else if (filter.indexOf("..") != -1) {
        return "..";
    }

    return "==";
};

Application.MergeLookupView = function (field, viewer, term, value) {

    term = Default(term, "");
    value = Default(value, "");
    if (term != "") {
        if (field.Type == "Integer") {
            value = "<>0";
        } else {
            value = "<>''";
        }
    }

	var filters = field.LookupFilters;
	if(typeof filters == "function")
		filters = field.LookupFilters();
	
    var view = ""
    view = viewer.MergeView(filters);
    view = view.replace("%term", term);
    view = view.replace("%value", value);
    return view;
};

Application.LookupRecord = function (field, viewer, term, response, value) {

    return $codeblock(

        function () {

            Application.LogInfo("LookupRecord: Search: " + term);

            term = Default(term, "");
            value = Default(value, "");
            if (term != "") {
                if (field.Type == "Integer") {
                    value = "<>0";
                } else {
                    value = "<>''";
                }
            }

            var r = new Record();
            r.Table = field.LookupTable;
            r.View = Application.MergeLookupView(field, viewer, term, value);

            //Add lookup columns.
            var cols = field.LookupColumns.split(",");  
            for (var i = 0; i < cols.length; i++) {
                r.AddLookupField(cols[i]);
            }   
            if(field.LookupCategoryField != "")
                r.AddLookupField(field.LookupCategoryField);
            r.AddLookupField(field.LookupField);
			r.AddLookupField(field.LookupDisplayField);

            return r.FindFirst();
        },

        function (r) {

            var result = new Array();

            Application.LogInfo("Found " + r.Count + " records.");            

            var cols = field.LookupColumns.split(",");                        

            if (Application.IsInMobile() && cols.indexOf("Preview") != -1)
                cols.splice(cols.indexOf("Preview"), 1);                            

            var displcol = "";

            if (r.Count > 0)
                do {
                    
                    var item = new Object();
                    item.BlankRow = false;
                    item.BoldField = "";
                    item.DisplayCol = "";
					item.ValueCol = "";
                    item.RID = r.Record.RecID;
                    item.UID = $id();

                    var add = false;
                    for (var i = 0; i < r.Record.Fields.length; i++) {

                        if (r.Record.Fields[i].Name == field.LookupCategoryField)
                            item.BoldField = Default(r.Record.Fields[i].Value,'');													

                        var hidden = (cols.indexOf(r.Record.Fields[i].Name) == -1) && (r.Record.Fields[i].Name != field.LookupField) && (r.Record.Fields[i].Name != field.LookupDisplayField);                                                               
                                                                 
                        if(!hidden){                            

                            r.Record.Fields[i].Value = Default(r.Record.Fields[i].Value,'');
							
							//#120 Dont Search on hidden columns  
                            if (term == "" || 
							(r.Record.Fields[i].Value.toString().toLowerCase().indexOf(term.toLowerCase()) != -1 && 
							(r.Record.Fields[i].Name != field.LookupField || cols.indexOf(r.Record.Fields[i].Name) != -1)))
                                add = true;
                                                        
                            item[r.Record.Fields[i].Name] = r.Record.Fields[i].Value;
							
							//Display and value cols.
							if(r.Record.Fields[i].Name == field.LookupField){ 
								item.ValueCol = r.Record.Fields[i].Value;
								if(field.LookupDisplayField == "")
									item.DisplayCol = r.Record.Fields[i].Value;
							}
							if(r.Record.Fields[i].Name == field.LookupDisplayField)
								item.DisplayCol = r.Record.Fields[i].Value;    
                        }
                    }
                    if (add)
                        result.push(item);
                } while (r.Next());

            if (field.LookupCategoryField != "")
                result.sort(function (a, b) {
                    if (a.BoldField == b.BoldField)
                        return 0;
                    if (a.BoldField > b.BoldField) {
                        return 1;
                    } else {
                        return -1;
                    }
                });

            //Add blank row.            
            if(term == "" && !field.Mandatory){
                var blankrow = new Object();
                blankrow.BlankRow = true;
                blankrow[field.LookupField] = '';
                blankrow[field.LookupCategoryField] = '';
                blankrow[field.LookupDisplayField] = '';
                blankrow.DisplayCol = '';
				blankrow.ValueCol = '';
                for (var i = 0; i < cols.length; i++) {                
                    blankrow[cols[i]] = '';
                }
                result.splice(0,0,blankrow);            
            }

			if(viewer.AddFilterData){
				var name = field.Name;
				if(field.MapTo)
					name = field.MapTo;
				viewer.AddFilterData(name,result);
			}
			
            response(result, value, "DisplayCol");

            return result;
        }

    );
};

//#42 - Created new check function
Application.HasFilterChar = function(filter){
    return !(filter.indexOf("*") == -1 && filter.indexOf("=") == -1 && filter.indexOf("..") == -1 && filter.indexOf("|") == -1
    	&& filter.indexOf("<") == -1 && filter.indexOf(">") == -1 && filter != 'null');
};

Application.GetOptionFilter = function(filter, captions){
	var ret = "";
	if(filter.indexOf("|")){
		var filters = filter.split("|");
		for(var i = 0; i < filters.length; i++){
			if(ret==""){
				ret = captions.split(",")[filters[i]];
			}else{
				ret += "|"+captions.split(",")[filters[i]];
			}
		}
	}else if(filter.indexOf("&")){
		var filters = filter.split("|");
		for(var i = 0; i < filters.length; i++){
			if(ret==""){
				ret = captions.split(",")[filters[i]];
			}else{
				ret += "&"+captions.split(",")[filters[i]];
			}
		}
	}else{
		ret = captions.split(",")[filter];
	}	
	return ret;
};

Application.SetOptionFilter = function(filter, captions){
	var ret = "";
	if(filter.indexOf("|")){
		var filters = filter.split("|");
		for(var i = 0; i < filters.length; i++){
			if(ret==""){
				ret = captions.split(",").indexOf(filters[i]);
			}else{
				ret += "|"+captions.split(",").indexOf(filters[i]);
			}
		}
	}else if(filter.indexOf("&")){
		var filters = filter.split("|");
		for(var i = 0; i < filters.length; i++){
			if(ret==""){
				ret = captions.split(",").indexOf(filters[i]);
			}else{
				ret += "&"+captions.split(",").indexOf(filters[i]);
			}
		}
	}else{
		ret = captions.split(",").indexOf(filter);
	}	
	return ret;
};

Application.GenerateView = function(filters){
	var f = "";
    for (var i in filters) {
        if(f.length == 0){
            f += i + "=CONST("+filters[i]+")";
        }else{
            f += ", "+ i + "=CONST("+filters[i]+")";
        }
    }
    if(f.length > 0)
        f = "WHERE ("+f+")";
	return f;
};

//#endregion

//#region Global Functions

OPENPAGE = function (id, filters, options, parent, singleThread, sorting){    
    if(ThisWindow())
        parent = Default(parent,ThisWindow().ID());
    var f = "";
    for (var i in filters) {
        if(f.length == 0){
            f += i + "=CONST("+filters[i]+")";
        }else{
            f += ", "+ i + "=CONST("+filters[i]+")";
        }
    }
    if(f.length > 0)
        f = "WHERE ("+f+")";
	if(sorting)
		f = sorting + f;
    Application.App.LoadPage(id,f,options,parent,singleThread);
};
CONTROL = function(name_){
    if(ThisViewer())
        return ThisViewer().Control(name_);
    return null;
};
PARENTPAGE = function(){
    if(ThisViewer())
        return ThisViewer().ParentPage();    
    return null;
};
CLOSEPAGE = function(){
    if(ThisViewer())
        Application.RunNext(ThisViewer().Close);
};
REFRESH = function () {
    $codeinsert(
        function () {
            $flag;
            if(ThisViewer())
                return ThisViewer().Update();        
        }
    );    
};
PREVWINDOW = function(){
    if ($moduleloaded("WindowManager")) 
        return UI.WindowManager.PreviousWindow();
};
NEXTWINDOW = function(){
    if ($moduleloaded("WindowManager")) 
        return UI.WindowManager.NextWindow();
};

RECORD = function (id, callback) {
    $codeinsert(
        function () {
            $flag;
            return new Record(id);
        },        
		function (r) {
            $flag;
            return r.New();
        }, 
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
FINDSET = function (id, filters, callback, lookupfields, calculatedfields) {
    $codeinsert(
        function () {
            $flag;
            return new Record(id);
		},
		function(r){
			$flag;
            if(filters){
                if (typeof filters === 'string') {
                    r.View = filters;
                }else{
                    for (var i in filters) {
                        r.Filter(i, filters[i]);
                    }
                }
            }
            if(lookupfields){
                for (var i = 0; i < lookupfields.length; i++) {
                    r.AddLookupField(lookupfields[i]);
                }
            }
			if(calculatedfields){
                for (var i = 0; i < calculatedfields.length; i++) {
                    r.CalculateField(calculatedfields[i]);
                }				
            }
            return r.FindFirst();
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
COUNT = function (id, filters, callback) {
    $codeinsert(
        function () {
            $flag;
            return new Record(id);
        },
		function(r){
		    $flag;
		    if(filters){
		        if (typeof filters === 'string') {
		            r.View = filters;
		        }else{
		            for (var i in filters) {
		                r.Filter(i, filters[i]);
		            }
		        }
		    }
		    return r.CountRecords();
		},
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
GET = function (recid, callback) {
    var recinfo = recid.split(": ");
    $codeinsert(
        function () {
            $flag;
            return new Record(recinfo[0]);
        },
        function (r) {
            $flag;                        
            return r.Get(recinfo[1].split(","));
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
INSERT = function (id, values, callback, trigger, ignoreExisting, viewer) {
    $codeinsert(
        function () {
            $flag;
            return new Record(id);
        },
		function (r) {
            $flag;
            return r.New();
        }, 
        function(r){
            $flag;
            for (var i in values) {
                r[i] = values[i];
            }
            r.SaveCurrent();
            trigger = Default(trigger,true);
            return r.Insert(trigger, ignoreExisting, viewer);
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};

//Issue #46 Error when using validate function.
VALIDATE = function (r, field, value, viewer) {
    $codeinsert(
        function () {
            $flag;
            return r.Validate(field, value, viewer);
        },
        function(rec){
            r = rec;
        }
    );    
};
MODIFY = function (r, field, value, callback, trigger, skipValidate, viewer) {
    $codeinsert(
        function () {
            $flag;
            if(field){
				if(!skipValidate){
					return r.Validate(field,value, viewer);
				}else{
					r[field] = value;
				}
			}
            return r;
        },
        function(r){
            $flag;
            trigger = Default(trigger,true);
            return r.Modify(trigger, viewer);
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
MODIFYALL = function (r, col_, value_, callback) {
    $codeinsert(        
        function(){
            $flag;
            return r.ModifyAll(col_, value_);
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
DELETE = function (r, callback, trigger, viewer) {
    $codeinsert(        
        function(){
            $flag;
            trigger = Default(trigger,true);
            return r.Delete(true, viewer);
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
DELETEALL = function (r, callback) {
    $codeinsert(        
        function(){
            $flag;
            return r.DeleteAll(true);
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};
RESET = function (r, callback) {
    $codeinsert(        
        function(){
            $flag;
            return r.Reset();
        },
        function (r) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(r);
                    }
                );
        }
    );    
};

CODEMODULE = function (id, callback) {
    $codeinsert(
        function () {
            $flag;
            return new CodeModule(id);
        },
        function (c) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(c);
                    }
                );
        }
    );    
};

TABLE = function (id, callback) {
    $codeinsert(
        function () {
            $flag;
            return new Table(id);
        },
        function (t) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(t);
                    }
                );
        }
    );    
};

BEGINTRANSACTION = function (callback) {
    $codeinsert(
        function () {
            $flag;
            return Application.BeginTransaction();
        },
        function (c) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(c);
                    }
                );
        }
    );    
};

COMMITTRANSACTION = function (callback) {
    $codeinsert(
        function () {
            $flag;
            return Application.CommitTransaction();
        },
        function (c) {
            $flag;
            if(callback)
                return $codeblock(
                    function(){
                        return callback(c);
                    }
                );
        }
    );    
};
//#endregion

Define("Collection", null, function () {

    //#region Members

    var _self = this;
	var m_items = {};
	
    //#endregion

    //#region Public Methods

    this.Constructor = function () {		
    };

    this.Item = function (key_) {
		return Default(m_items[key_],null);
    };
	
	this.Remove = function (key_){
		m_items[key_] = null;
	};
	
	this.Add = function (key_, value_){		
		m_items[key_] = value_;		
	};

    //#endregion    

    return this.Constructor();

});


Define("Module", null, function (name_, options_) {

    //#region Members

    var _self = this;
    var m_name = "";
    var m_options = null;
    var m_loaded = false;

    //#endregion

    //#region Public Methods

    this.Constructor = function (name_, options_) {

        if (Application.testMode && arguments[0] == null) return;

        m_name = name_;

        //Default options.
        m_options = options_ || {};

        //Module options.
        m_options.depends = Default(options_.depends, null);
        m_options.singleInstance = Default(options_.singleInstance, false);
        m_options.requiresVersion = Default(options_.requiresVersion, '3.0');

        //Documentation options.
        m_options.created = Default(options_.created, new Date());
        m_options.version = Default(options_.version, '');
        m_options.author = Default(options_.author, '');
        m_options.copyright = Default(options_.copyright, '');
        m_options.changelog = Default(options_.changelog, []);

    };

    //#endregion

    //#region Public Properties
   
    this.Name = function () {
        return m_name;
    };
    
    this.Option = function (name_) {
        return m_options[name_];
    };
    
    this.Loaded = function (value_) {

        if (value_ !== undefined) { //SET
            m_loaded = value_;
        } else { //GET
            return m_loaded;
        }
    };

    //#endregion

    //#region Overrideable Methods
    
    this.OnLoad = function () {        
    };

    //#endregion

    this.Constructor(name_, options_);

});

DefineModule = function (name, options, def) {
    Define(name, function () {
        return new Module(name, options);
    }, def);
};

DefineModule("ModuleManager",

     {
         singleInstance: true,
         requiresVersion: '3.0',
         created: new Date(2013, 09, 03),
         version: '1.1',
         author: 'Liveapp Soultions',
         copyright: 'Copyright 2013, Liveapp Soultions',

         changelog: [
        '03/09/13   PF  Created class.',
        '03/09/13   PF  Added dependancy functionality.'
        ]
     },

    function () {

        //#region Members

        var _self = this;
        var m_modules = [];
        var m_excluded = [];

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Global assign.
            $moduleloaded = Application.ModuleManager.ModuleLoaded;
        };

        this.LoadModule = function (mod_) {

            try {

                //Check type.
                if (mod_.ObjectType() != "Module")
                    throw "Object must be typeof Module.";

                //Check excluded.
                if (m_excluded.indexOf(mod_.Name()) != -1)
                    return;

                mod_.Loaded(false);

                //Check application version.
                if (parseFloat(mod_.Option("requiresVersion")) > parseFloat(Application.version)) {
                    throw mod_.Name() + " requires application version " + mod_.Option("requiresVersion") + ". Current application version is " + Application.version;
                }

                //Check single instance.
                if (mod_.Option("singleInstance")) {
                    var exists = this.GetModule(mod_.Name());
                    if (exists != null)
                        throw "Module already loaded.";
                }

                m_modules.push(mod_);

                //Check depends.
                if (mod_.Option("depends") != null)
                    for (var i = 0; i < mod_.Option("depends").length; i++) {
                        if (this.ModuleLoaded(mod_.Option("depends")[i]) == false)
                            throw "Dependancy " + mod_.Option("depends")[i] + " is not loaded.";
                    }

                //Call the onload function.
                mod_.OnLoad();
                mod_.Loaded(true);

                Application.LogInfo("Module Loaded: " + mod_.Name());

            } catch (e) {
                Application.Error("Module Load Failed (" + mod_.Name() + "): " + e);
            }

        };

        this.GetModule = function (name_) {
            for (var i = 0; i < m_modules.length; i++) {
                if (m_modules[i].Name() == name_) {
                    return m_modules[i];
                }
            }
            return null;
        };

        this.ModuleLoaded = function (name_) {
            var mod = _self.GetModule(name_);
            if (mod != null)
                return mod.Loaded();
            return false;
        };

        this.Exclude = function (name) {
            m_excluded.push(name);
        };

        //#endregion

    });

//Assign module.
Application.ModuleManager = new ModuleManager();

//Load module.
Application.ModuleManager.LoadModule(Application.ModuleManager);


Define("Record", null, function (name_) {

    //#region Members

    var _self = this;
    var m_name = null;    
    var m_records = [];
    var m_xrecords = [];
    var m_mandatory = [];
    var m_lookupCols = [];
    var m_table = null; //TableInfo
    var m_flowfields = [];
	var m_fieldsToCalc = null;

    //#endregion

    //#region Public Methods

    this.Constructor = function (name_) {

        m_name = name_;
        if (m_name != null)
            return $codeblock(
                function(){
                    return new Table(m_name);
                },
                function(t){
                    m_table = t;
                    return _self.Init();
                }                
            );

        var r = Application.Objects.RecordSetInfo();
        app_transferObjectProperties.call(this, r);
        return this;
    };

	this.Dispose = function(){		
		if(m_table) m_table.Dispose();
		m_table = null;
		_self = null;		
	};
	
    this.CheckTableName = function () {
        if (m_name == null)
            m_name = this.Table;
        if (m_name == null)
            Application.Error("Please specify a table name");
    };

    this.Init = function () {

        var w = $wait();

        //Save the set information.
        var count = this.Count;
        var position = this.Position;
        var view = Default(this.View, "");
        var groupfilters = Default(this.GroupFilters, []);

        this.CheckTableName();

        //Check the client side cache for the record.
        var cr = Application.Cache.Check("RecordInit", m_name);
        if (cr) {

            cr.Count = Default(count, 0);
            cr.Position = Default(position, 0);
            cr.NewRecord = false;
            cr.View = view;
			cr.GroupFilters = groupfilters;

            //Save the record.
            app_transferObjectProperties.call(_self, cr);
            _self.GetCurrent();
            cr = _self;
            return cr;
        }

        //Execute the web service.
        Application.ExecuteWebService("RecordInit",
        { auth: Application.auth, name_: m_name, view_: view }, function (r) {
            try {

                //Save the record to the client side cache.
                if (m_name.indexOf("VT$") == -1)
                    Application.Cache.Save("RecordInit", m_name, r);

                //Load the set info back in.
                
                r.Count = Default(count, 0);
                r.Position = Default(position, 0);
                r.NewRecord = false;
                r.View = view;
				r.GroupFilters = groupfilters;

                //Save the record.
                app_transferObjectProperties.call(_self, r);
                _self.GetCurrent();
                r = _self;
                w.resolve(r);

            } catch (e) {
                Application.Error(e);
            }
        });

        return w.promise();

    };

    this.New = function () {

        var w = $wait();

        $code(

            function () {
                return _self.Init();
            },

            function (r) {

                //Add init values.
                if (m_table) {
                    for (var j = 0; j < r.Record.Fields.length; j++) {
                        var col = m_table.Column(r.Record.Fields[j].Name);
                        if (col && Default(col.InitValue, "") != "") {
                            if (r.Record.Fields[j].Type == "Date") {
                                r.Record.Fields[j].Value = Application.ParseDate(col.InitValue);
                            } else {
                                r.Record.Fields[j].Value = col.InitValue;
                            }
                        }
                    }
                }

                //Add view as filters.
                var filters = Application.GetFilters(r.View);
                for (var i = 0; i < filters.length; i++) {
                    var filter = filters[i];
                    for (var j = 0; j < r.Record.Fields.length; j++) {
                        if (filter[0] == r.Record.Fields[j].Name) {
                            if (!Application.HasFilterChar(filter[1])) //#42 - Use new check function
                                if (r.Record.Fields[j].Type == "Date") {
                                    r.Record.Fields[j].Value = Application.ParseDate(filter[1]); //#111 - Date incorrect.
                                } else {
                                    r.Record.Fields[j].Value = filter[1];
                                }
                            break;
                        }
                    }
                }
				
				//Add hidden filters.
				for (var i = 0; i < _self.GroupFilters.length; i++) {
                    var filter = _self.GroupFilters[i];
                    for (var j = 0; j < r.Record.Fields.length; j++) {
                        if (filter[0] == r.Record.Fields[j].Name) {
                            if (!Application.HasFilterChar(filter[1])) //#42 - Use new check function
                                if (r.Record.Fields[j].Type == "Date") {
                                    r.Record.Fields[j].Value = Application.ParseDate(filter[1]); //#111 - Date incorrect.
                                } else {
                                    r.Record.Fields[j].Value = filter[1];
                                }
                            break;
                        }
                    }
				}                

                r.NewRecord = true;
                r.Record.RecID = $id();
                r.xRecord.RecID = r.Record.RecID;

                _self.Record = CloneRecord(r.Record);
                m_records.push(CloneRecord(r.Record));
                _self.xRecord = CloneRecord(r.Record);
                m_xrecords.push(CloneRecord(r.Record));

                _self.Position = m_records.length - 1;
                _self.Count += 1;

                _self.GetCurrent();
                r = _self;
                return r;
            }

        );

        return w.promise();
    };

    this.Reset = function () {

        var w = $wait();

        $code(

            function () {
                return _self.FindSet(true, true);
            },

            function (r) {
                //Save the record.
                app_transferObjectProperties.call(_self, r);
                _self.GetCurrent();
                r = _self;
                return r;
            }

        );

        return w.promise();
    };

    this.Get = function () {

        var w = $wait();

        var keys = null;
        if (arguments.length > 0 && $.isArray(arguments[0])) {
            keys = arguments[0];
        } else {
            keys = arguments;
        }

        //Save the filters.
        var filters = "";
        for (var i = 0; i < keys.length; i++) {
            if (filters == "") {
                filters = keys[i];
            }
            else {
                filters += "|" + keys[i];
            }
        }

        Application.LogDebug("Getting " + m_name + " Record: Filters - " + filters);

        //Get the record.
        Application.ExecuteWebService("RecordGet",
        { auth: Application.auth, table_: m_name, filters_: filters }, function (r) {

            if (r) {
                try {
                    m_records = CloneRecordSet(r);
                    m_xrecords = CloneRecordSet(r);
                    if (r.length == 0) { //No record.
                        Application.LogDebug("No " + m_name + " records found.");
                        _self.Clear();
                        _self.GetCurrent();
                        r = _self;
                    } else { //1 record.
                        Application.LogDebug(m_name + " record found.");
                        _self.Record = CloneRecord(m_records[0]);
                        _self.xRecord = CloneRecord(m_xrecords[0]);
                        _self.Position = 0;
                        _self.Count = 1;
                        _self.Blank = false;
                        _self.GetCurrent();
                        r = _self;
                    }
                } catch (e) {
                    Application.Error(e);
                }
            }

            w.resolve(r);

        });

        return w.promise();
    };

    this.FindSet = function (first_, reset_) {

        if (reset_ == null) reset_ = false;

        this.CheckTableName();

        //Check if we have the table definition.
        if (!m_table) {
            return $codeblock(
                function () {
                    return new Table(m_name);
                },
                function (t) {
                    m_table = t;
                    return _self.FindSet(first_, reset_);
                }
            );
        }

        Application.LogDebug("Getting " + m_name + " RecordSet");

        var w = $wait();

        Application.ExecuteWebService("RecordSet",
        { auth: Application.auth, table_: m_name, view_: Default(this.View, ""), reset_: reset_, calcfields_: this.CalculatedFields, groupFilters_: this.GroupFilters, lookupCols_: m_lookupCols, group_: false }, function (r) {

            if (r) {
                try {

                    if (Application.maxRecords > 0) {
                        var i = r.length - Application.maxRecords;
                        if (i > 0)
                            r.splice(Application.maxRecords, i);
                    }

                    m_records = CloneRecordSet(r);
                    m_xrecords = CloneRecordSet(r);
                    if (r.length == 0) { //No records.
                        Application.LogDebug("No " + m_name + " records found.");
                        _self.Clear();
                        _self.GetCurrent();
                        r = _self;
                    } else if (first_) { //First record.
                        Application.LogDebug(m_records.length + " " + m_name + " records found.");
                        _self.Record = CloneRecord(m_records[0]);
                        _self.xRecord = CloneRecord(m_xrecords[0]);
                        _self.Position = 0;
                        _self.Count = m_records.length;
                        _self.Blank = false;
                        _self.GetCurrent();
                        r = _self;
                    } else { //Last record.
                        Application.LogDebug(m_records.length + " " + m_name + " records found.");
                        _self.Record = CloneRecord(m_records[m_records.length - 1]);
                        _self.xRecord = CloneRecord(m_xrecords[m_xrecords.length - 1]);
                        _self.Position = m_records.length - 1;
                        _self.Count = m_records.length;
                        _self.Blank = false;
                        _self.GetCurrent();
                        r = _self;
                    }
                } catch (e) {
                    Application.Error(e);
                }
            }
            w.resolve(r);

        });

        return w.promise();
    };

    this.CountRecords = function (reset_) {

        if (reset_ == null) reset_ = false;

        this.CheckTableName();

        //Check if we have the table definition.
        if (!m_table) {
            return $codeblock(
                function () {
                    return new Table(m_name);
                },
                function (t) {
                    m_table = t;
                    return _self.CountRecords(reset_);
                }
            );
        }

        Application.LogDebug("Getting " + m_name + " Count");

        var w = $wait();

        Application.ExecuteWebService("RecordSet",
        { auth: Application.auth, table_: m_name, view_: Default(this.View, ""), reset_: reset_, calcfields_: this.CalculatedFields, groupFilters_: this.GroupFilters, lookupCols_: m_lookupCols, group_: true }, function (r) {

            if (r) {
                try {

					if(Application.IsOffline())
						r = r.length;
				
                    Application.LogDebug(r + " " + m_name + " records found.");
                    _self.Count = r;
                                            
                } catch (e) {
                    Application.Error(e);
                }
            }
            w.resolve(_self);

        });

        return w.promise();
    };

    this.FindFirst = function () {
        return this.FindSet(true);
    };

    this.FindLast = function () {
        return this.FindSet(false);
    };

    this.Modification = function (obj_, func_, col_, value_, ignoreExisting_) {

        var w = $wait();

        //Save the current record properties.
        this.SaveCurrent(obj_);

        if (_self.Temp && func_ != "RecordDelete") {
            return _self;
        }

		//Speed fix?
		var o = new Object();
		app_deepTransferObjectProperties.call(o, obj_);
		
		if(m_table){
			
			var hasView = m_table.HasView();
			for(var i = 0; i < o.Record.Fields.length; i++){
				var col = m_table.Column(o.Record.Fields[i].Name);
				if(col && col.FlowField && col.FlowField != "" && !Application.IsOffline()){
					o.Record.Fields[i].Value = null;
					o.xRecord.Fields[i].Value = null;
					o[col.Name] = null;
				}		
				if(hasView && col && col.PrimaryKey == false && (col.Type == "Image" || col.Type == "Blob" || col.Type == "BigBlob") && !Application.IsOffline()){
					if(o.Record.Fields[i].Value == o.xRecord.Fields[i].Value){					
						o[col.Name] = null;
						o.xRec[col.Name] = null;
						o.Record.Fields.splice(i,1);
						o.xRecord.Fields.splice(i,1);
						i -= 1;
					}						
				}
				if (func_ == "RecordDelete" && col && col.PrimaryKey == false){
					o.Record.Fields[i].Value = null;
					o.xRecord.Fields[i].Value = null;
				}					
			}
			o.Functions = [];			
		}
		
        var params = { auth: Application.auth, rec_: o };
        if (func_ == "RecordModifyAll") { //Bug Fix
            params.col_ = col_;
            params.value_ = value_;
        }

        //#103 - Add ignoreExisting param.
        if (func_ == "RecordInsert") {
            ignoreExisting_ = Default(ignoreExisting_, false);
            params.ignoreExisting_ = ignoreExisting_;
        }

        Application.ExecuteWebService(func_, params, function (r) {

            if (r && r.Message) {
                w.resolve(_self);
                return;
            }

            Application.Fire("RecordModification",{func: func_, params: params});

            try {

                if (func_ == "RecordDelete") {

                    obj_.Count -= 1;

                    if (obj_.Count == 0) {
                        obj_.Clear();
                    }
                    else {
                        obj_.RemoveRecord();
                    }

                } else if (func_ == "RecordDeleteAll") {

                    obj_.Clear();

                } else if (func_ == "RecordModifyAll") {

                    //Do we need to do anything here?

                } else {

                    if (func_ == "RecordInsert" && !Application.IsOffline()) {
                        r.NewRecord = true; //#99 - Keep this true incase of errors.
                    }
                    
                    obj_.Record = CloneRecord(r);                    
                    m_records[obj_.Position] = CloneRecord(obj_.Record);
                    
                    obj_.xRecord = CloneRecord(obj_.Record);
                    m_xrecords[obj_.Position] = CloneRecord(obj_.Record);

                }

                //Load the record.
                obj_.GetCurrent();

            } catch (e) {
                Application.Error(e);
            }

            w.resolve(obj_);

        });

        return w.promise();
    };

    this.Insert = function (trigger_, ignoreExisting_, viewer) {

		if(_self.TempRecord() && m_table && Application.IsOffline() && _self.Record.RecID){
			for(var i = 0; i < _self.Record.Fields.length; i++){
				var col = m_table.Column(_self.Record.Fields[i].Name);
				if(col && col.Identity)
					_self[col.Name] = _self.Record.RecID;
			}
		}
		
        //Save the current record properties.
        _self.SaveCurrent();			

        if (_self.NoKeys()) {
            m_records[_self.Position] = CloneRecord(_self.Record);
            return _self;
        }

        _self.DelayInsert = Default(_self.DelayInsert, false);

        return $codeblock(
            function () {
                if (trigger_ && _self.DelayInsert == false)
                    return _self.Trigger("Insert", viewer);
                return _self;
            },
            function (rec) {
                return _self.Modification(rec, "RecordInsert", null, null, ignoreExisting_); //#103 - Ignore existing param
            },
            function () {
                if (trigger_ && _self.DelayInsert == true)
                    return _self.Trigger("Insert", viewer);
                return _self;
            },
            function (rec) {

                //#99 - Fix for error on insert
                _self.Record.NewRecord = false;
                m_records[_self.Position].NewRecord = false;
                m_xrecords[_self.Position] = CloneRecord(_self.Record);
                //_self.GetCurrent();

                if (trigger_ && _self.DelayInsert == true)
                    return _self.Modification(rec, "RecordModify", null, null, ignoreExisting_); //#103 - Ignore existing param
                return _self;
            }
        );
    };

    this.Modify = function (trigger_, viewer) {

        //Save the current record properties.
        _self.SaveCurrent();

        if (_self.NoKeys()) {
            m_records[_self.Position] = CloneRecord(_self.Record);
            return _self;
        }

        return $codeblock(
            function () {
                if (trigger_)
                    return _self.Trigger("Modify", viewer);
                return _self;
            },
            function (rec) {
                return _self.Modification(rec, "RecordModify");
            }
        );
    };

    this.ModifyAll = function (col_, value_) {
        return $codeblock(
            function () {
                return _self.Modification(_self, "RecordModifyAll", col_, value_);
            }
        );
    };

    this.Delete = function (trigger_, viewer) {
        return $codeblock(
            function () {
                if (trigger_ && !_self.NoKeys()) //#113 - Don't run trigger without keys.
                    return _self.Trigger("Delete", viewer);
                return _self;
            },
            function (rec) {
                return _self.Modification(rec, "RecordDelete");
            }
        );
    };

    this.DeleteAll = function () {
        return $codeblock(
            function () {
                return _self.Modification(_self, "RecordDeleteAll");
            }
        );
    };

    this.Next = function () {

        if (this.Count == 0)
            return false;

        this.Position += 1;

        Application.LogDebug("Getting next " + m_name + " Record: #" + this.Position);

        if (this.Position < 0) {
            this.Position = 0;
            return false;
        }
        else if (this.Position >= this.Count) {
            this.Position = this.Count - 1;
            return false;
        }

        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
        this.GetCurrent();
        return true;
    };

    this.Prev = function () {

        if (this.Count == 0)
            return false;

        this.Position -= 1;

        Application.LogDebug("Getting previous " + m_name + " Record: #" + this.Position);

        if (this.Position < 0) {
            this.Position = 0;
            return false;
        }
        else if (this.Position >= this.Count) {
            this.Position = this.Count - 1;
            return false;
        }

        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
        this.GetCurrent();
        return true;
    };

    this.First = function () {

        if (this.Count == 0)
            return false;

        this.Position = 0;
        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
        this.GetCurrent();
        return true;
    };

    this.Last = function () {

        if (this.Count == 0)
            return false;

        this.Position = m_records.length - 1;
        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
        this.GetCurrent();
        return true;
    };
	
	this.SetPosition = function (pos) {

        if (this.Count == 0)
            return false;

        this.Position = pos;
        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
        this.GetCurrent();
        return true;
    };

    this.GetFilter = function (col_, filterGroup_) {
        if (!filterGroup_) {
			return Application.GetFilter(col_, _self.View);
        } else {
			for (var i = 0; i < _self.GroupFilters.length; i++) {
                if (_self.GroupFilters[i].Name == col_) {
                    return _self.GroupFilters[i].Value;
                }
            }
		}
    };

    this.Filter = function (col_, filter_, filterGroup_) {

        filterGroup_ = Default(filterGroup_, null);

        if (filterGroup_ == null) {

            //Add to the view.    
            _self.View = Application.AddFilter(_self.View, col_, filter_);

        } else {

            //Add a group filter.
            for (var i = 0; i < _self.GroupFilters.length; i++) {
                if (_self.GroupFilters[i].Name == col_) {
                    _self.GroupFilters.splice(i, 1);
                    i--;
                }
            }
            if (filter_ != null) {
                var f = new Application.Objects.RecordFieldInfo();
                f.Name = col_;
                f.Value = filter_;
                _self.GroupFilters.push(f);
            }
        }
    };

    this.Filters = function () {
        var filters = Application.GetFilters(_self.View);
        var ret = new Array();
        for (var i = 0; i < filters.length; i++) {
            var f = new Application.Objects.RecordFieldInfo();
            f.Name = filters[i][0];
            f.Value = filters[i][1];
            ret.push(f);
        }
        return ret;
    };

	this.TempRecord = function(){
		if(!_self.Record.RecID)
			return false;
		return _self.Record.RecID.toString().indexOf(":") == -1;
	};
	
	this.Name = function(){
		return m_name;
	};
	
    this.Caption = function (field_) {

        //Get the Field caption.
        for (var i = 0; i < this.Record.Fields.length; i++) {
            if (this.Record.Fields[i].Name == field_) {
                return this.Record.Fields[i].Caption;
            }
        }

        return "";
    };

    this.GetCurrent = function () {

        //Clear the xRec.
        this.xRec = new Object;

        DeFriendifyValues(this);

        for (var i = 0; i < this.Record.Fields.length; i++) {

            //Create/update the record set property.
            this[this.Record.Fields[i].Name] = this.Record.Fields[i].Value;

            //Create/update the xRec property.
            this.xRec[this.Record.Fields[i].Name] = this.xRecord.Fields[i].Value;
        }

        this.NewRecord = this.Record.NewRecord;

        _self.Calcfields();
    };

    this.SaveCurrent = function (rec_, skipff, skipxrec) {

        rec_ = Default(rec_, _self);
        for (var i = 0; i < rec_.Record.Fields.length; i++) {
            if (rec_[rec_.Record.Fields[i].Name] == null && _self.GetField("FF$" + rec_.Record.Fields[i].Name) != null && !skipff) {
                rec_["FF$" + rec_.Record.Fields[i].Name] = "";
            }
            rec_.Record.Fields[i].Value = rec_[rec_.Record.Fields[i].Name];
			if(!skipxrec)
				rec_.xRecord.Fields[i].Value = rec_.xRec[rec_.Record.Fields[i].Name];
        }

        if (this.Count == 0)
            return;

        m_records[_self.Position] = CloneRecord(rec_.Record);
		if(!skipxrec)
			m_xrecords[_self.Position] = CloneRecord(rec_.xRecord);
    };

    this.RemoveRecord = function () {

        m_records.splice(this.Position, 1);
        m_xrecords.splice(this.Position, 1);

        if (this.Position >= this.Count) {
            this.Position = this.Count - 1;
        }

        this.Record = CloneRecord(m_records[this.Position]);
        this.xRecord = CloneRecord(m_xrecords[this.Position]);
    };

    this.Clear = function () {

        this.Blank = true;
        //this.View = "";
        this.NewRecord = true;
        this.Record.UnAssigned = false;
        this.Record.NewRecord = true;
        this.Record.RecID = "";
        this.xRecord.NewRecord = true;
        this.xRecord.UnAssigned = false;
        this.xRecord.RecID = "";
        this.Count = 0;
        this.Position = 0;
        this.Temp = false;
        m_records = [];
        m_xrecords = [];

        for (var i = 0; i < this.Record.Fields.length; i++) {
            var val = this.Record.Fields[i].Value;
            if (typeof val == "string")
                this.Record.Fields[i].Value = null;
            if (typeof val == "number")
                this.Record.Fields[i].Value = null;
            if (typeof val == "boolean")
                this.Record.Fields[i].Value = false;
            if (Object.prototype.toString.call(val) == "[object Date]")
                this.Record.Fields[i].Value = null;
        }
        this.xRecord = CloneRecord(this.Record);
    };

    this.ClearXRec = function (clearkeys, keys) {

        clearkeys = Default(clearkeys, false);
        keys = Default(keys, _self.Keys);

        this.xRecord.NewRecord = true;
        this.xRecord.UnAssigned = false;
        this.xRecord.RecID = "";

        for (var i = 0; i < this.xRecord.Fields.length; i++) {
            if (keys && !clearkeys && keys.indexOf(this.xRecord.Fields[i].Name) != -1) {
            } else {
                var val = this.xRecord.Fields[i].Value;
                if (typeof val == "string")
                    this.xRecord.Fields[i].Value = "";
                if (typeof val == "number")
                    this.xRecord.Fields[i].Value = 0;
                if (typeof val == "boolean")
                    this.xRecord.Fields[i].Value = false;
                if (Object.prototype.toString.call(val) == "[object Date]")
                    this.xRecord.Fields[i].Value = null;
                this.xRec[this.xRecord.Fields[i].Name] = this.xRecord.Fields[i].Value;
            }
        }
    };

    this.Validate = function (col, value, viewer) {

        var func_code = null;
        for (var i = 0; i < this.Functions.length; i++) {
            if (this.Functions[i][0] == col) {
                func_code = this.Functions[i][1];
                break;
            }
        }

        return $codeblock(
            function () {
                _self[col] = value;
                if (func_code != null) {

                    var table = _self;

                    //Issue #46 Error when using validate function.
                    var win = null;
                    if (viewer)
                        win = viewer.Window();

                    eval("var func = function(rec){return $codeblock(" +
                    "function(){" + func_code + "}, " +
                    "function(){rec.SaveCurrent();return rec;}" +
                    ");}");
                    return func(_self);
                } else {
                    _self.SaveCurrent();
                    return _self;
                }
            }
        );
    };

    this.Trigger = function (trigger, viewer) {

        var func_code = null;
        for (var i = 0; i < this.Functions.length; i++) {
            if (this.Functions[i][0] == trigger) {
                func_code = this.Functions[i][1];
                break;
            }
        }

        return $codeblock(
            function () {
                if (func_code != null) {
                    eval("var func = function(rec,viewer){return $codeblock(" +
                    "function(){" + func_code + "}, " +
                    "function(){return rec;}" +
                    ");}");
                    return func(_self,viewer);
                } else {
                    return _self;
                }
            }
        );
    };

    this.TestField = function (col, value) {

        if (value == null) {
            var err = Application.StrSubstitute("You must specify $1.", col);
			
			if (this[col] == null)
				Application.Error(err);
            if (typeof this[col] == "number" && this[col] == 0)
                Application.Error(err);
            if (typeof this[col] == "string" && this[col] == "")
                Application.Error(err);
			
        } else {

            if ($.isArray(value)) {
                if (value.indexOf(this[col]) == -1)
                    Application.Error(Application.StrSubstitute("$1 must be in $2.", col, value.list()));
            } else {
                if (this[col] != value)
                    Application.Error(Application.StrSubstitute("$1 must be $2.", col, value));
            }
        }
    };

    this.UpdateXRec = function () {
        _self.xRecord = CloneRecord(_self.Record);
		m_xrecords[_self.Position] = CloneRecord(_self.Record);
        _self.GetCurrent();
    };

    this.RollBack = function () {
        if (_self.Record.UnAssigned || _self.Record.NewRecord)
            return;
        _self.Record = CloneRecord(_self.xRecord);
		m_records[_self.Position] = CloneRecord(_self.Record);
        _self.GetCurrent();
    };

    this.Copy = function (r) {

		var t = new Object();
		app_deepTransferObjectProperties.call(t, r.DatabaseTable());
								
		m_table = t;
		
        this.Table = r.Table;
        this.Record = CloneRecord(r.Record);
        m_records = [CloneRecord(r.Record)];
        this.xRecord = CloneRecord(r.xRecord);
        m_xrecords = [CloneRecord(r.xRecord)];
        this.Position = r.Position;
        this.Count = r.Count;
        this.Blank = false;
        this.Temp = r.Temp;
        this.Functions = [];
        for (var i = 0; i < r.Functions.length; i++) {
            this.Functions.push(r.Functions[i]);
        }
        m_mandatory = [];
        for (var i = 0; i < r.MandatoryFields().length; i++) {
            m_mandatory.push(r.MandatoryFields()[i]);
        }
        this.GroupFilters = [];
        for (var i = 0; i < r.GroupFilters.length; i++) {
            this.GroupFilters.push(r.GroupFilters[i]);
        }
        this.Keys = [];
        for (var i = 0; i < r.Keys.length; i++) {
            this.Keys.push(r.Keys[i]);
        }
        this.GetCurrent();
    };
	
	this.DatabaseTable = function(){
		return m_table;
	};

    this.AddValue = function (name_, caption_, type_, value_) {
        this.Record.Fields.push({ Name: name_, Caption: caption_, Value: value_, Type: type_ });
        this.UpdateXRec();
        this.GetCurrent();
    };

    this.TransferFields = function (rec_, exclude_, callback_) {

        exclude_ = Default(exclude_, "");
        exclude_ = exclude_.split(",");
        for (var i = 0; i < rec_.Record.Fields.length; i++) {
            for (var j = 0; j < _self.Record.Fields.length; j++) {
                if (_self.Record.Fields[j].Name == rec_.Record.Fields[i].Name) {
                    if (exclude_.indexOf(_self.Record.Fields[j].Name) == -1) {
                        _self.Record.Fields[j].Value = rec_[rec_.Record.Fields[i].Name];
                        if (callback_)
                            callback_(_self.Record.Fields[j].Name, _self.Record.Fields[j].Value);
                    }
                    break;
                }
            }
        }
        this.GetCurrent();
    };

    this.GetField = function (name_) {

        for (var i = 0; i < this.Record.Fields.length; i++) {
            if (this.Record.Fields[i].Name == name_)
                return this.Record.Fields[i];
        }
        return null;
    };

    this.Calcfields = function () {

        if (!m_table)
            return;

        var fields = [];
        if (arguments.length == 0) {
			if(!m_fieldsToCalc){
				m_fieldsToCalc = [];
				for (var i = 0; i < this.Record.Fields.length; i++) {
					var col = m_table.Column(this.Record.Fields[i].Name);
					if (col && col.FlowField && col.FlowField.indexOf("function") == 0) //Only add functions.
						m_fieldsToCalc.push(this.Record.Fields[i].Name);
				}				
			}
			fields = m_fieldsToCalc;
        } else {
            fields = arguments;
        }

        if (fields.length == 0)
            return;

        for (var i = 0; i < fields.length; i++) {

            var f = fields[i];
            var field = m_table.Column(f);

            //Liveapp #75 - Offline flowfield 
            if (field && field.FlowField && field.FlowField.indexOf("FINDSET") == -1 && field.FlowField.indexOf("COUNT") == -1) {

                if (field.FlowField.indexOf("function") == 0) { //Function.

                    eval("var func = " + field.FlowField);
                    var ret = func(_self);
                    _self[f] = ret;

                } else { //Record

                    return $codeblock(
                        function () {
                            return new Record(m_id);
                        },
                        function (r) {
                            var rid = _self.Record.RecID;
                            var parts = rid.split(": ");
                            var keys = parts[1].split(",");
                            return r.Get(keys);
                        },
                        function (r) {
                            _self[f] = r[f];
                        }
                    );

                }
            }
        }
    };

    this.NoKeys = function () {

        if (_self.Keys == null && m_mandatory.length == 0)
            return false;

        var blankrec = new Record();
        blankrec.Copy(_self);
        blankrec.Clear();
        blankrec.GetCurrent();

        if (_self.Keys != null)
            for (var i = 0; i < _self.Keys.length; i++) {
                if (_self[_self.Keys[i]] == blankrec[_self.Keys[i]]) {
                    return true;
                }
            }

        for (var i = 0; i < m_mandatory.length; i++) {
            if (_self[m_mandatory[i]] == blankrec[m_mandatory[i]]) {
                return true;
            }
        }

        return false;
    };

    this.UnsavedChanges = function () {
		if(_self.NoKeys())
			return true;
        for (var i = 0; i < m_records.length; i++) {
            if (m_records[i].UnAssigned || m_records[i].NewRecord)
                return true;
        }
        return false;
    };

    this.AddMandatoryField = function (col_) {
        m_mandatory.push(col_);
    };

    this.MandatoryFields = function () {
        return m_mandatory;
    };

    this.AddLookupField = function (col_) {
        m_lookupCols.push(col_.replace("FF$", ""));
    };

    this.AddFlowField = function (field_) {
        m_flowfields.push(field_);
    };

    this.CalculateField = function (col_) {
        _self.CalculatedFields.push(col_);
    };

    this.Exists = function (recid) {
        for (var i = 0; i < m_records.length; i++) {
            if (m_records[i].RecID == recid)
                return true;
        }
        return false;
    };

    this.AddRecords = function (rec) {
        do {
            if (!_self.Exists(rec.Record.RecID)) {
                m_records.push(CloneRecord(rec.Record));
                m_xrecords.push(CloneRecord(rec.Record));
                _self.Count += 1;
            }
        } while (rec.Next());
    };

    //Liveapp #75 - Offline flowfield
    this.CalcClientSideFields = function () {

        if (!m_table || _self.Count == 0)
            return _self;

        var fields = [];
        for (var i = 0; i < m_table.Columns.length; i++) {
            
            var f = m_table.Columns[i];

            if (f) {

                var code = f.FlowField;                
                if (Application.IsOffline() && f.OfflineCode != "")
                    code = f.OfflineCode;

                if (code != "" && code != null && code.indexOf("function") == 0 && (code.indexOf("FINDSET") != -1 || code.indexOf("COUNT") != -1))
                    fields.push(f);

            }

        }

        //Add run time flow fields.
        for (var i = 0; i < m_flowfields.length; i++) {
            fields.push(m_flowfields[i]);
        }

        if (fields.length > 0)
            return $loop(function (i) {

                return $codeblock(

                    function () {

                        var code = fields[i].FlowField;                        
                        if (Application.IsOffline() && fields[i].OfflineCode != "")
                            code = fields[i].OfflineCode;

                        eval("var func = " + code);
                        return func(_self);
                    },

                    function (ret) {
						if(fields[i].LookupDisplayField != ""){
							_self["FF$"+fields[i].Name] = ret;
						}else{
							_self[fields[i].Name] = ret;	
						}                        
                        _self.SaveCurrent();
                        if (i < fields.length - 1)
                            return $next;
                        return _self;
                    }

                );

            });

        return _self;
    };

    //#endregion

    //#region Private Methods

    function DeFriendifyValues(rec) {

        for (var i = 0; i < rec.Record.Fields.length; i++) {
            if (typeof rec.Record.Fields[i].Value == "string") {

                //Fix dates.
                if (rec.Record.Fields[i].Type == "Date" || rec.Record.Fields[i].Type == "Time" || rec.Record.Fields[i].Type == "DateTime") {
                    rec.Record.Fields[i].Value = Application.ConvertDate(rec.Record.Fields[i].Value);
                    rec.xRecord.Fields[i].Value = Application.ConvertDate(rec.xRecord.Fields[i].Value);
                }
            }
        }
    };

    function CloneRecordSet(recs) {
        var recs2 = [];
        for (var i = 0; i < recs.length; i++) {
            recs2.push(CloneRecord(recs[i]));
        }
        return recs2;
    };

    function CloneRecord(rec) {
        var rec2 = new Object();
        rec2.NewRecord = rec.NewRecord;
        rec2.UnAssigned = rec.UnAssigned;
        rec2.RecID = rec.RecID;
        rec2.Table = rec.Table;
        rec2.Fields = [];
        for (var i = 0; i < rec.Fields.length; i++) {
            var col = new Application.Objects.RecordFieldInfo();
            app_transferObjectProperties.call(col, rec.Fields[i]);
            rec2.Fields.push(col);
        }
        return rec2;
    };

    //#endregion

    return this.Constructor(name_);

});


Define("Table", null, function (id_, useCache_) {

    //#region Members

    var _self = this;
    var m_id = null;
    var m_cache = null;
    var m_blockChange = false;
    var m_blank = true;

    //#endregion

    //#region Public Methods

    this.Constructor = function (id_, useCache_) {

        var w = $wait();

        m_id = id_;
        m_cache = useCache_;

        if (m_id == null)
            return this.Init();

        $code(

            function () {
                return _self.Fetch();
            },

            function (r) {
                if (r == null) {
                    return _self.Init()
                } else {
                    return r;
                }
            }
        );

        return w.promise();

    };
	
	this.Dispose = function(){		
		//if(_self) _self.Columns = null;
		_self = null;		
	};

    this.Init = function () {

        var temptable = Application.Objects.TableInfo();
        app_transferObjectProperties.call(this, temptable);
        this.Name = m_id;

        this.Columns = Application.Objects.ArrayList();
        this.Keys = Application.Objects.ArrayList();

        m_blank = true;

        return this;
    };

    this.Fetch = function () {

        if (this.Name == null)
            this.Name = m_id;

        if (m_cache == null)
            m_cache = true;

        var w = $wait();

        //Check the client side cache for the table.
        var cr = Application.Cache.Check("TableFetch", this.Name);
        if (cr && m_cache) {

            app_transferObjectProperties.call(_self, cr);

            for (var i in _self.Columns) {

                var tempcol = new TableColumn();
                app_transferObjectProperties.call(tempcol, _self.Columns[i]);
                tempcol.XName = tempcol.Name;
                _self.Columns[i] = tempcol;

            }

            m_blank = false;
            return _self;
        }

        Application.ExecuteWebService("TableFetch",
        { auth: Application.auth, name_: this.Name, cache_: m_cache }, function (r) {

            if (r == null || r.Message) {
                w.resolve(null);
                return;
            }

            //Save the table to the client side cache.
            Application.Cache.Save("TableFetch", _self.Name, r);

            app_transferObjectProperties.call(_self, r);

            for (var i in _self.Columns) {

                var tempcol = new TableColumn();
                app_transferObjectProperties.call(tempcol, _self.Columns[i]);
                tempcol.XName = tempcol.Name;
                _self.Columns[i] = tempcol;

            }
            
            m_blank = false;
            w.resolve(_self);
        });

        return w.promise();
    };

    this.Modification = function (func_) {

        var w = $wait();

        Application.ExecuteWebService(func_,
        { auth: Application.auth, table_: this }, function (r) {

            w.resolve(r);

        });

        return w.promise();

    };

    this.Insert = function () {

        return this.Modification("TableInsert");

    };

    this.Modify = function () {

        return this.Modification("TableModify");

    };

    this.Delete = function () {

        return this.Modification("TableDelete");

    };

    this.Rename = function (id_) {

        var oldname = this.Name;
        this.Name = id_;

        var w = $wait();

        Application.ExecuteWebService("TableRename",
        { auth: Application.auth, table_: this, oldName_: oldname }, function (r) {

            w.resolve(r);

        });

        return w.promise();

    };

    this.Blank = function () {
        return m_blank;
    };

    this.Column = function (key_) {
        try {
            for (var i in this.Columns) {
                if (this.Columns[i].Name == key_) {
                    return this.Columns[i];
                }
            }
        }
        catch (e) {
        }

        return null;
    }

    this.RenameColumn = function (key_, newkey_) {
        try {
            for (var i in this.Columns) {
                if (this.Columns[i].Name == key_) {
                    this.Columns[i].Name = newkey_;
                }
            }
        }
        catch (e) {
        }

        return null;
    }

    this.AddColumn = function (col_) {
        try {
            if (this.Column(col_.Name) != null) {
                return false;
            }

            this.Columns[this.Columns.length] = col_;
            return true;
        }
        catch (e) {
            return false;
        }
    }

    this.Key = function (key_) {
        try {
            for (var i in this.Keys) {
                if (this.Keys[i] == key_) {
                    return this.Keys[i];
                }
            }
        }
        catch (e) {
        }

        return null;
    }

    this.AddKey = function (key_) {
        try {
            if (this.Key(key_) != null) {
                return false;
            }

            this.Keys[this.Keys.length] = key_;
            return true;
        }
        catch (e) {
            return false;
        }
    };

    this.UpdateProperty = function (property_, value_) {

        if (m_blockChange == true) {
            return false;
        }

        if (this[property_] != null) {
            if (value_ == null) {
                this[property_] = '';
            }
            else {
                this[property_] = value_;
            }
        }
    };
	
	this.HasView = function(){
		for(var i = 0; i < this.Columns.length; i++){
			var c = this.Columns[i];
			if(c.LookupDisplayField != "" || (c.FlowField != "" && c.FlowField.indexOf("function") == -1) || c.Formula != "" || c.FlowFilter){
                return true;
            }
		}
		return false;
	};

    //#endregion

    return this.Constructor(id_, useCache_);

});

Define("TableColumn", null, function () {

    //#region Members

    var m_blockChange = false;

    //#endregion

    //#region Public Methods

    this.Constructor = function () {
        this.Init();
    };

    this.Init = function () {

        var tempcol = Application.Objects.ColumnInfo();
        app_transferObjectProperties.call(this, tempcol);
    };

    this.UpdateProperty = function (property_, value_) {
    
        if (m_blockChange == true) {
            return false;
        }

        if (this[property_] != null) {
            if (value_ == null) {
                this[property_] = '';
            }
            else {
                this[property_] = value_;
            }
        }
    };

    //#endregion

    this.Constructor();

});


Define("CodeModule", null, function (id_, design_) {

    //Members

    var _self = this;
    var m_id = null;
    var m_design = false;

    //Methods

    this.New = function (id_, design_) {

        var w = $wait();

        m_id = id_;
        m_design = Default(design_, false);

        if (m_id == null)
            return this.Init();

        return $codeblock(

            function () {
                return _self.Fetch();
            },

            function (r) {
                if (r == null) {
                    return _self.Init()
                } else {
                    return r;
                }
            }
        );        

    };

    this.Init = function () {

        var tempcodemodule = Application.Objects.CodeModuleInfo();
        app_transferObjectProperties.call(this, tempcodemodule);
        //this.Name = m_id;

        return this;
    };

    this.Fetch = function () {

        if (this.Name == null)
            this.Name = m_id;

        var w = $wait();

        Application.ExecuteWebService("CodeModuleFetch",
        { auth: Application.auth, name_: this.Name, design_: m_design }, function (r) {

            if (r == null || r.Message) {
                w.resolve(null);
                return;
            }

            app_transferObjectProperties.call(_self, r);

            if (m_design == false) {

                try {
                    var ret = new Object();
                    eval("ret = new function(){var _self = this; " + r.Code + "};");
                    w.resolve(ret);
                } catch (e) {
                    Application.Error(e);
                }

                return;
            };
            w.resolve(_self);
        });

        return w.promise();
    };

    this.Rename = function (id_) {

        var oldname = this.Name;
        this.Name = id_;

        var w = $wait();

        Application.ExecuteWebService("CodeModuleRename",
        { auth: Application.auth, code_: this, oldName_: oldname }, function (r) {

            w.resolve(r);

        });

        return w.promise();

    };

    //Constructor

    return this.New(id_, design_);

});



Define("Page", null, function (id_, useCache_) {

    //#region Members

    var _self = this;
    var m_id = null;

    //#endregion

    //#region Public Methods

    this.Constructor = function (id_, useCache_) {

        m_id = id_;
        if (m_id != null)
            return this.Init(useCache_);

        var p = Application.Objects.PageInfo();
        app_transferObjectProperties.call(this, p);
        return this;
    };

    this.Init = function (cache_) {

        if (cache_ == null) cache_ = true;

        var w = $wait();

        //Check the client side cache for the page.
        var cr = Application.Cache.Check("PageFetch", m_id);
        if (cr && cache_) {

            //Save the record.
            app_transferObjectProperties.call(_self, cr);
            cr = _self;
            return cr;
        }

        //Execute the web service.
        Application.ExecuteWebService("PageFetch",
        { auth: Application.auth, id_: m_id, cache_: cache_ }, function (r) {
            try {

                //Save the page to the client side cache.
                Application.Cache.Save("PageFetch", m_id, r);

                //Save the record.
                app_transferObjectProperties.call(_self, r);
                r = _self;
                w.resolve(r);

            } catch (e) {
                Application.Error(e);
            }
        });

        return w.promise();

    };

    this.Rename = function (id_) {

        var oldname = this.Name;
        this.Name = id_;

        var w = $wait();

        Application.ExecuteWebService("PageRename",
        { auth: Application.auth, page_: this, oldName_: oldname }, function (r) {

            w.resolve(r);

        });

        return w.promise();

    };

    this.Copy = function (p) {
        app_transferObjectProperties.call(_self, p);
    };

    this.GetField = function (name_) {

        for (var i = 0; i < this.Fields.length; i++) {
            if (this.Fields[i].Name == name_)
                return this.Fields[i];
        }
        return null;
    };

    this.GetActionView = function (rec, action) {
        if (action.ActionView && action.ActionView != "")
            return Application.MergeView(action.ActionView, rec);
        return "";
    };

    this.RunActionCode = function (rec, action, viewer) {

        return $codeblock(

            function () {
                if (action.ServerAction)
                    return Application.WebServiceWait("PageRunAction", { auth: Application.auth, rec_: rec.Record, page_: _self, action_: action });
            },
            function (msg) {

                if (action.ServerAction && (m_id == "VP$PageDesigner" || m_id == "VP$ReportDesigner"))
                    Application.Cache.Remove("PageFetch", rec.Name);

                if (action.ServerAction && m_id == "VP$TableDesigner") {
                    Application.Cache.Remove("TableFetch", rec.Name);
                    Application.Cache.Remove("RecordInit", rec.Name);
                }

                if (action.ActionCode && action.ActionCode != "") {
                    eval("var func = function(rec){" + action.ActionCode + "};");
                    var page = _self;
                    var win = null;
                    if (viewer)
                        win = viewer.Window();
                    return $codeblock(
                        function () {
                            return func(rec);
                        },
                        function (ret) {
                            rec.SaveCurrent();
                            if (typeof ret == "string")
                                return ret;
                        }
                    );
                } else {
                    return msg;
                }
            }
        );
    };

    this.GetAction = function (name_) {

        for (var i = 0; i < this.Actions.length; i++) {
            if (this.Actions[i].Name == name_)
                return this.Actions[i];
        }

        if (this.CloseAction != null)
            if (this.CloseAction.Name == name_)
                return this.CloseAction;

        if (this.OpenAction != null)
            if (this.OpenAction.Name == name_)
                return this.OpenAction;

        return null;
    };

    this.OnNewAction = function () {

        for (var i = 0; i < this.Actions.length; i++) {
            if (this.Actions[i].Type == "New")
                return this.Actions[i];
        }
        return null;
    };

    this.OnDeleteAction = function () {

        for (var i = 0; i < this.Actions.length; i++) {
            if (this.Actions[i].Type == "Delete")
                return this.Actions[i];
        }
        return null;
    };

    this.DoubleClickAction = function () {

        for (var i = 0; i < this.Actions.length; i++) {
            if (this.Actions[i].OnDoubleClick)
                return this.Actions[i];
        }
        return null;
    };

    this.SubPages = function () {
        var subpages = 0;
        for (var i = 0; i < this.TabList.length; i++) {
            var tab = this.TabList[i];
            if (tab.ID != "") {
                if ((Application.IsInMobile() && !this.TabOption(tab, "desktoponly")) || (!Application.IsInMobile() && !this.TabOption(tab, "mobileonly")))
                    subpages += 1;
            }
        }
        return subpages;
    };
	
	this.GetSubPages = function () {
        var subpages = [];
        for (var i = 0; i < this.TabList.length; i++) {
            var tab = this.TabList[i];
            if (tab.ID != "") {
                if ((Application.IsInMobile() && !this.TabOption(tab, "desktoponly")) || (!Application.IsInMobile() && !this.TabOption(tab, "mobileonly")))
                    subpages.push(tab);
            }
        }
        return subpages;
    };

    this.GetTabs = function () {
        var tabs = [];
        var gentab = new Object();
        gentab.ID = "";
        gentab.Name = "";
        gentab.View = "";
        tabs.push(gentab);
        for (var i = 0; i < this.TabList.length; i++) {
            if (this.TabList[i].ID == "")
                tabs.push(this.TabList[i]);
        }
        return tabs;
    };

    this.GetFieldsByTab = function (tab_, additional_, hideNonEditable_) {
        var f = [];
        for (var i = 0; i < this.Fields.length; i++) {
            this.Fields[i].TabName = Default(this.Fields[i].TabName, "");
            if (this.Fields[i].TabName == tab_ || (tab_ == "" && this.Fields[i].TabName == "General"))
                if (this.Fields[i].Hidden == false && (!hideNonEditable_ || (hideNonEditable_ && (this.Fields[i].Editable || Application.HasOption(this.Fields[i].Options,"showineditor"))))) {
                    if (this.Fields[i].Importance != "Additional" && !additional_)
                        f.push(this.Fields[i]);
                    if (this.Fields[i].Importance == "Additional" && additional_)
                        f.push(this.Fields[i]);
                }
        }
        return f;
    };

    this.ClearCache = function () {
        return Application.ClearCache(this.Name);
    };
    
    this.Option = function (name) {
        return Application.HasOption(_self.Options, name);
    };

    this.FieldOption = function (field, name) {
        return Application.HasOption(field.Options, name);
    };

    this.TabOption = function (tab, name) {
        return Application.HasOption(tab.Options, name);
    };

    this.ActionOption = function (action, name) {
        return Application.HasOption(action.Options, name);
    };

    //#endregion        

    return this.Constructor(id_, useCache_);

});


Define("Timer", null, function (delay_, onTick_, onStart_, onStop_) {

    //#region Members

    var _self = this;
    var m_id = null;
    var m_delay = 0;
    var m_onTick = null;
    var m_onStart = null;
    var m_onStop = null;
    var m_enabled = false;

    //#endregion

    //#region Public Methods

    this.Constructor = function (delay_, onTick_, onStart_, onStop_) {

        m_delay = delay_;
        m_onTick = onTick_;
        m_onStart = onStart_;
        m_onStop = onStop_;

        //Application.On("ThreadCreated", _self.Stop);
        //Application.On("ThreadFinished", _self.Start);
    };

    this.Start = function (update_) {
        update_ = Default(update_, false);
        if (update_)
            m_enabled = true;
        if (!m_enabled) return;
        m_id = setInterval(function () {
            if (m_onTick) m_onTick();
        }, delay_);
        if (m_onStart) m_onStart();
    };

    this.Stop = function (update_) {
        update_ = Default(update_, false);
        if (update_)
            m_enabled = false;
        if (m_id != null)
            clearInterval(m_id);
        m_id = null;
        if (m_onStop) m_onStop();
    };

    this.Delay = function (value) {

        m_delay = value;

        if (m_id != null) {
            clearInterval(m_id);           
            m_id = setInterval(function () {
                if (m_onTick) m_onTick();
            }, m_delay);
        }
    };

    this.ClearEvents = function () {
        m_onStart = null;
        m_onStop = null;
        m_onTick = null;
    };

    //#endregion    

    return this.Constructor(delay_, onTick_, onStart_, onStop_);

});


Define("Batch", null, function () {

    //#region Members

    var _self = this;
    var m_insert = [];
	var m_modify = [];
	var m_delete = [];
	var m_offlineRecords = [];

    //#endregion

    //#region Public Methods

    this.Constructor = function () {
        return _self;
    };

    this.Insert = function(r){	        

		if(r.Count > 0 && r.Record){

		    if (Application.IsOffline()) {
		        m_offlineRecords.push({ type: "INS", rec: r });
		        return;
		    }

			r.SaveCurrent();
			var rec = CloneRecord(r.Record);			
			rec.Timestamp = $id();
			m_insert.push(rec);
		}			
	};
	
	this.Modify = function(r, table){
		
		if(r.Count > 0 && r.Record){

		    if (Application.IsOffline()) {
		        m_offlineRecords.push({ type: "MOD", rec: r });
		        return;
		    }

			r.SaveCurrent();
			var rec = CloneRecord(r.Record,r.xRecord,table);			
			rec.Timestamp = $id();
			m_modify.push(rec);
		}			
	};
	
	this.Delete = function(r){
		
		if(r.Count > 0 && r.Record){

		    if (Application.IsOffline()) {
		        m_offlineRecords.push({ type: "DEL", rec: r });
		        return;
		    }

			r.SaveCurrent();
			var rec = CloneRecord(r.Record);			
			rec.Timestamp = $id();
			m_delete.push(rec);
		}			
	};

	this.Clear = function(){
		m_insert = [];
		m_modify = [];
		m_delete = [];
		m_offlineRecords = [];
	};
	
	this.Process = function () {

	    if (Application.IsOffline()) {
	        if (m_offlineRecords.length > 0)
	            return $loop(function (i) {
	                return $codeblock(
                        function () {
                            if (m_offlineRecords[i].type == "INS")
                                return m_offlineRecords[i].rec.Insert(true);
                            if (m_offlineRecords[i].type == "MOD")
                                return m_offlineRecords[i].rec.Modify(true);
                            if (m_offlineRecords[i].type == "DEL")
                                return m_offlineRecords[i].rec.Delete(true);
                        },
                        function () {
                            if (i < m_offlineRecords.length - 1)
                                return $next;
                        }
                    );
	            });
            return;
	    }

		return Application.BatchProcess(m_insert,m_modify,m_delete);
	};
	
	this.ProcessAsync = function (timeout, onsuccess, onerror) {

		var callbacks = new Object();
	
		callbacks.onsend = function (xhr) {
		};

		callbacks.onsuccess = function (r) {

			if (r != null)
				if (r.Message)
					if (r.Message != "FALSE") {
						callbacks.onerror(r.Message);
						return;
					}

			if(onsuccess)
				onsuccess(r);
		};

		callbacks.onerror = function (e) {				
			if(onerror)
				onerror(e);
		};

		Application.ExecuteWebService("BatchProcess", { auth: Application.auth, insert_: m_insert, modify_: m_modify, delete_: m_delete }, null, true, null, true, callbacks, timeout);				
	};
	
    //#endregion    

	function CloneRecord(rec, xrec, table) {
        var rec2 = new Object();
        rec2.NewRecord = rec.NewRecord;
        rec2.UnAssigned = rec.UnAssigned;
        rec2.RecID = rec.RecID;
        rec2.Table = rec.Table;
        rec2.Fields = [];		
        for (var i = 0; i < rec.Fields.length; i++) {
			
			var skip = false;
			if(table){
				var c = table.Column(rec.Fields[i].Name);
				if(c && c.PrimaryKey == false)
					skip = true;				
				if(c && c.FlowField && c.FlowField != "")
					skip = true
				if(xrec && rec.Fields[i].Value != xrec.Fields[i].Value)
					skip = false;
			}
			if(!skip){
				var col = new Application.Objects.RecordFieldInfo();
				app_transferObjectProperties.call(col, rec.Fields[i]);
				rec2.Fields.push(col);
			}
			
        }
        return rec2;
    };
	
    return this.Constructor();

});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// This is CodeMirror (http://codemirror.net), a code editor
// implemented in JavaScript on top of the browser's DOM.
//
// You can find some technical background for some of the code below
// at http://marijnhaverbeke.nl/blog/#cm-internals .

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        module.exports = mod();
    else if (typeof define == "function" && define.amd) // AMD
        return define([], mod);
    else // Plain browser env
        this.CodeMirror = mod();
})(function () {
    "use strict";

    // BROWSER SNIFFING

    // Kludges for bugs and behavior differences that can't be feature
    // detected are enabled based on userAgent etc sniffing.

    var gecko = /gecko\/\d/i.test(navigator.userAgent);
    var ie_upto10 = /MSIE \d/.test(navigator.userAgent);
    var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
    var ie = ie_upto10 || ie_11up;
    var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
    var webkit = /WebKit\//.test(navigator.userAgent);
    var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent);
    var chrome = /Chrome\//.test(navigator.userAgent);
    var presto = /Opera\//.test(navigator.userAgent);
    var safari = /Apple Computer/.test(navigator.vendor);
    var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent);
    var phantom = /PhantomJS/.test(navigator.userAgent);

    var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent);
    // This is woefully incomplete. Suggestions for alternative methods welcome.
    var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent);
    var mac = ios || /Mac/.test(navigator.platform);
    var windows = /win/i.test(navigator.platform);

    var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/);
    if (presto_version) presto_version = Number(presto_version[1]);
    if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
    // Some browsers use the wrong event properties to signal cmd/ctrl on OS X
    var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
    var captureRightClick = gecko || (ie && ie_version >= 9);

    // Optimize some code when these features are not used.
    var sawReadOnlySpans = false, sawCollapsedSpans = false;

    // EDITOR CONSTRUCTOR

    // A CodeMirror instance represents an editor. This is the object
    // that user code is usually dealing with.

    function CodeMirror(place, options) {
        if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);

        this.options = options = options ? copyObj(options) : {};
        // Determine effective options based on given values and defaults.
        copyObj(defaults, options, false);
        setGuttersForLineNumbers(options);

        var doc = options.value;
        if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator);
        this.doc = doc;

        var input = new CodeMirror.inputStyles[options.inputStyle](this);
        var display = this.display = new Display(place, doc, input);
        display.wrapper.CodeMirror = this;
        updateGutters(this);
        themeChanged(this);
        if (options.lineWrapping)
            this.display.wrapper.className += " CodeMirror-wrap";
        if (options.autofocus && !mobile) display.input.focus();
        initScrollbars(this);

        this.state = {
            keyMaps: [],  // stores maps added by addKeyMap
            overlays: [], // highlighting overlays, as added by addOverlay
            modeGen: 0,   // bumped when mode/overlay changes, used to invalidate highlighting info
            overwrite: false,
            delayingBlurEvent: false,
            focused: false,
            suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
            pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
            selectingText: false,
            draggingText: false,
            highlight: new Delayed(), // stores highlight worker timeout
            keySeq: null,  // Unfinished key sequence
            specialChars: null
        };

        var cm = this;

        // Override magic textarea content restore that IE sometimes does
        // on our hidden textarea on reload
        if (ie && ie_version < 11) setTimeout(function () { cm.display.input.reset(true); }, 20);

        registerEventHandlers(this);
        ensureGlobalHandlers();

        startOperation(this);
        this.curOp.forceUpdate = true;
        attachDoc(this, doc);

        if ((options.autofocus && !mobile) || cm.hasFocus())
            setTimeout(bind(onFocus, this), 20);
        else
            onBlur(this);

        for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
            optionHandlers[opt](this, options[opt], Init);
        maybeUpdateLineNumberWidth(this);
        if (options.finishInit) options.finishInit(this);
        for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
        endOperation(this);
        // Suppress optimizelegibility in Webkit, since it breaks text
        // measuring on line wrapping boundaries.
        if (webkit && options.lineWrapping &&
            getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
            display.lineDiv.style.textRendering = "auto";
    }

    // DISPLAY CONSTRUCTOR

    // The display handles the DOM integration, both for input reading
    // and content drawing. It holds references to DOM nodes and
    // display-related state.

    function Display(place, doc, input) {
        var d = this;
        this.input = input;

        // Covers bottom-right square when both scrollbars are present.
        d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
        d.scrollbarFiller.setAttribute("cm-not-content", "true");
        // Covers bottom of gutter when coverGutterNextToScrollbar is on
        // and h scrollbar is present.
        d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
        d.gutterFiller.setAttribute("cm-not-content", "true");
        // Will contain the actual code, positioned to cover the viewport.
        d.lineDiv = elt("div", null, "CodeMirror-code");
        // Elements are added to these to represent selection and cursors.
        d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
        d.cursorDiv = elt("div", null, "CodeMirror-cursors");
        // A visibility: hidden element used to find the size of things.
        d.measure = elt("div", null, "CodeMirror-measure");
        // When lines outside of the viewport are measured, they are drawn in this.
        d.lineMeasure = elt("div", null, "CodeMirror-measure");
        // Wraps everything that needs to exist inside the vertically-padded coordinate system
        d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
                          null, "position: relative; outline: none");
        // Moved around its parent to cover visible view.
        d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
        // Set to the height of the document, allowing scrolling.
        d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
        d.sizerWidth = null;
        // Behavior of elts with overflow: auto and padding is
        // inconsistent across browsers. This is used to ensure the
        // scrollable area is big enough.
        d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
        // Will contain the gutters, if any.
        d.gutters = elt("div", null, "CodeMirror-gutters");
        d.lineGutter = null;
        // Actual scrollable element.
        d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
        d.scroller.setAttribute("tabIndex", "-1");
        // The element in which the editor lives.
        d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");

        // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
        if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
        if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;

        if (place) {
            if (place.appendChild) place.appendChild(d.wrapper);
            else place(d.wrapper);
        }

        // Current rendered range (may be bigger than the view window).
        d.viewFrom = d.viewTo = doc.first;
        d.reportedViewFrom = d.reportedViewTo = doc.first;
        // Information about the rendered lines.
        d.view = [];
        d.renderedView = null;
        // Holds info about a single rendered line when it was rendered
        // for measurement, while not in view.
        d.externalMeasured = null;
        // Empty space (in pixels) above the view
        d.viewOffset = 0;
        d.lastWrapHeight = d.lastWrapWidth = 0;
        d.updateLineNumbers = null;

        d.nativeBarWidth = d.barHeight = d.barWidth = 0;
        d.scrollbarsClipped = false;

        // Used to only resize the line number gutter when necessary (when
        // the amount of lines crosses a boundary that makes its width change)
        d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
        // Set to true when a non-horizontal-scrolling line widget is
        // added. As an optimization, line widget aligning is skipped when
        // this is false.
        d.alignWidgets = false;

        d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;

        // Tracks the maximum line length so that the horizontal scrollbar
        // can be kept static when scrolling.
        d.maxLine = null;
        d.maxLineLength = 0;
        d.maxLineChanged = false;

        // Used for measuring wheel scrolling granularity
        d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;

        // True when shift is held down.
        d.shift = false;

        // Used to track whether anything happened since the context menu
        // was opened.
        d.selForContextMenu = null;

        d.activeTouch = null;

        input.init(d);
    }

    // STATE UPDATES

    // Used to get the editor into a consistent state again when options change.

    function loadMode(cm) {
        cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
        resetModeState(cm);
    }

    function resetModeState(cm) {
        cm.doc.iter(function (line) {
            if (line.stateAfter) line.stateAfter = null;
            if (line.styles) line.styles = null;
        });
        cm.doc.frontier = cm.doc.first;
        startWorker(cm, 100);
        cm.state.modeGen++;
        if (cm.curOp) regChange(cm);
    }

    function wrappingChanged(cm) {
        if (cm.options.lineWrapping) {
            addClass(cm.display.wrapper, "CodeMirror-wrap");
            cm.display.sizer.style.minWidth = "";
            cm.display.sizerWidth = null;
        } else {
            rmClass(cm.display.wrapper, "CodeMirror-wrap");
            findMaxLine(cm);
        }
        estimateLineHeights(cm);
        regChange(cm);
        clearCaches(cm);
        setTimeout(function () { updateScrollbars(cm); }, 100);
    }

    // Returns a function that estimates the height of a line, to use as
    // first approximation until the line becomes visible (and is thus
    // properly measurable).
    function estimateHeight(cm) {
        var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
        var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
        return function (line) {
            if (lineIsHidden(cm.doc, line)) return 0;

            var widgetsHeight = 0;
            if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
                if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
            }

            if (wrapping)
                return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
            else
                return widgetsHeight + th;
        };
    }

    function estimateLineHeights(cm) {
        var doc = cm.doc, est = estimateHeight(cm);
        doc.iter(function (line) {
            var estHeight = est(line);
            if (estHeight != line.height) updateLineHeight(line, estHeight);
        });
    }

    function themeChanged(cm) {
        cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
          cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
        clearCaches(cm);
    }

    function guttersChanged(cm) {
        updateGutters(cm);
        regChange(cm);
        setTimeout(function () { alignHorizontally(cm); }, 20);
    }

    // Rebuild the gutter elements, ensure the margin to the left of the
    // code matches their width.
    function updateGutters(cm) {
        var gutters = cm.display.gutters, specs = cm.options.gutters;
        removeChildren(gutters);
        for (var i = 0; i < specs.length; ++i) {
            var gutterClass = specs[i];
            var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
            if (gutterClass == "CodeMirror-linenumbers") {
                cm.display.lineGutter = gElt;
                gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
            }
        }
        gutters.style.display = i ? "" : "none";
        updateGutterSpace(cm);
    }

    function updateGutterSpace(cm) {
        var width = cm.display.gutters.offsetWidth;
        cm.display.sizer.style.marginLeft = width + "px";
    }

    // Compute the character length of a line, taking into account
    // collapsed ranges (see markText) that might hide parts, and join
    // other lines onto it.
    function lineLength(line) {
        if (line.height == 0) return 0;
        var len = line.text.length, merged, cur = line;
        while (merged = collapsedSpanAtStart(cur)) {
            var found = merged.find(0, true);
            cur = found.from.line;
            len += found.from.ch - found.to.ch;
        }
        cur = line;
        while (merged = collapsedSpanAtEnd(cur)) {
            var found = merged.find(0, true);
            len -= cur.text.length - found.from.ch;
            cur = found.to.line;
            len += cur.text.length - found.to.ch;
        }
        return len;
    }

    // Find the longest line in the document.
    function findMaxLine(cm) {
        var d = cm.display, doc = cm.doc;
        d.maxLine = getLine(doc, doc.first);
        d.maxLineLength = lineLength(d.maxLine);
        d.maxLineChanged = true;
        doc.iter(function (line) {
            var len = lineLength(line);
            if (len > d.maxLineLength) {
                d.maxLineLength = len;
                d.maxLine = line;
            }
        });
    }

    // Make sure the gutters options contains the element
    // "CodeMirror-linenumbers" when the lineNumbers option is true.
    function setGuttersForLineNumbers(options) {
        var found = indexOf(options.gutters, "CodeMirror-linenumbers");
        if (found == -1 && options.lineNumbers) {
            options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
        } else if (found > -1 && !options.lineNumbers) {
            options.gutters = options.gutters.slice(0);
            options.gutters.splice(found, 1);
        }
    }

    // SCROLLBARS

    // Prepare DOM reads needed to update the scrollbars. Done in one
    // shot to minimize update/measure roundtrips.
    function measureForScrollbars(cm) {
        var d = cm.display, gutterW = d.gutters.offsetWidth;
        var docH = Math.round(cm.doc.height + paddingVert(cm.display));
        return {
            clientHeight: d.scroller.clientHeight,
            viewHeight: d.wrapper.clientHeight,
            scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
            viewWidth: d.wrapper.clientWidth,
            barLeft: cm.options.fixedGutter ? gutterW : 0,
            docHeight: docH,
            scrollHeight: docH + scrollGap(cm) + d.barHeight,
            nativeBarWidth: d.nativeBarWidth,
            gutterWidth: gutterW
        };
    }

    function NativeScrollbars(place, scroll, cm) {
        this.cm = cm;
        var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
        var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
        place(vert); place(horiz);

        on(vert, "scroll", function () {
            if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
        });
        on(horiz, "scroll", function () {
            if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
        });

        this.checkedOverlay = false;
        // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
        if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
    }

    NativeScrollbars.prototype = copyObj({
        update: function (measure) {
            var needsH = measure.scrollWidth > measure.clientWidth + 1;
            var needsV = measure.scrollHeight > measure.clientHeight + 1;
            var sWidth = measure.nativeBarWidth;

            if (needsV) {
                this.vert.style.display = "block";
                this.vert.style.bottom = needsH ? sWidth + "px" : "0";
                var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
                // A bug in IE8 can cause this value to be negative, so guard it.
                this.vert.firstChild.style.height =
                  Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
            } else {
                this.vert.style.display = "";
                this.vert.firstChild.style.height = "0";
            }

            if (needsH) {
                this.horiz.style.display = "block";
                this.horiz.style.right = needsV ? sWidth + "px" : "0";
                this.horiz.style.left = measure.barLeft + "px";
                var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
                this.horiz.firstChild.style.width =
                  (measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
            } else {
                this.horiz.style.display = "";
                this.horiz.firstChild.style.width = "0";
            }

            if (!this.checkedOverlay && measure.clientHeight > 0) {
                if (sWidth == 0) this.overlayHack();
                this.checkedOverlay = true;
            }

            return { right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0 };
        },
        setScrollLeft: function (pos) {
            if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
        },
        setScrollTop: function (pos) {
            if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
        },
        overlayHack: function () {
            var w = mac && !mac_geMountainLion ? "12px" : "18px";
            this.horiz.style.minHeight = this.vert.style.minWidth = w;
            var self = this;
            var barMouseDown = function (e) {
                if (e_target(e) != self.vert && e_target(e) != self.horiz)
                    operation(self.cm, onMouseDown)(e);
            };
            on(this.vert, "mousedown", barMouseDown);
            on(this.horiz, "mousedown", barMouseDown);
        },
        clear: function () {
            var parent = this.horiz.parentNode;
            parent.removeChild(this.horiz);
            parent.removeChild(this.vert);
        }
    }, NativeScrollbars.prototype);

    function NullScrollbars() { }

    NullScrollbars.prototype = copyObj({
        update: function () { return { bottom: 0, right: 0 }; },
        setScrollLeft: function () { },
        setScrollTop: function () { },
        clear: function () { }
    }, NullScrollbars.prototype);

    CodeMirror.scrollbarModel = { "native": NativeScrollbars, "null": NullScrollbars };

    function initScrollbars(cm) {
        if (cm.display.scrollbars) {
            cm.display.scrollbars.clear();
            if (cm.display.scrollbars.addClass)
                rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
        }

        cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function (node) {
            cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
            // Prevent clicks in the scrollbars from killing focus
            on(node, "mousedown", function () {
                if (cm.state.focused) setTimeout(function () { cm.display.input.focus(); }, 0);
            });
            node.setAttribute("cm-not-content", "true");
        }, function (pos, axis) {
            if (axis == "horizontal") setScrollLeft(cm, pos);
            else setScrollTop(cm, pos);
        }, cm);
        if (cm.display.scrollbars.addClass)
            addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
    }

    function updateScrollbars(cm, measure) {
        if (!measure) measure = measureForScrollbars(cm);
        var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
        updateScrollbarsInner(cm, measure);
        for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
            if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
                updateHeightsInViewport(cm);
            updateScrollbarsInner(cm, measureForScrollbars(cm));
            startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
        }
    }

    // Re-synchronize the fake scrollbars with the actual size of the
    // content.
    function updateScrollbarsInner(cm, measure) {
        var d = cm.display;
        var sizes = d.scrollbars.update(measure);

        d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
        d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";

        if (sizes.right && sizes.bottom) {
            d.scrollbarFiller.style.display = "block";
            d.scrollbarFiller.style.height = sizes.bottom + "px";
            d.scrollbarFiller.style.width = sizes.right + "px";
        } else d.scrollbarFiller.style.display = "";
        if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
            d.gutterFiller.style.display = "block";
            d.gutterFiller.style.height = sizes.bottom + "px";
            d.gutterFiller.style.width = measure.gutterWidth + "px";
        } else d.gutterFiller.style.display = "";
    }

    // Compute the lines that are visible in a given viewport (defaults
    // the the current scroll position). viewport may contain top,
    // height, and ensure (see op.scrollToPos) properties.
    function visibleLines(display, doc, viewport) {
        var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
        top = Math.floor(top - paddingTop(display));
        var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;

        var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
        // Ensure is a {from: {line, ch}, to: {line, ch}} object, and
        // forces those lines into the viewport (if possible).
        if (viewport && viewport.ensure) {
            var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
            if (ensureFrom < from) {
                from = ensureFrom;
                to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
            } else if (Math.min(ensureTo, doc.lastLine()) >= to) {
                from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
                to = ensureTo;
            }
        }
        return { from: from, to: Math.max(to, from + 1) };
    }

    // LINE NUMBERS

    // Re-align line numbers and gutter marks to compensate for
    // horizontal scrolling.
    function alignHorizontally(cm) {
        var display = cm.display, view = display.view;
        if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
        var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
        var gutterW = display.gutters.offsetWidth, left = comp + "px";
        for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
            if (cm.options.fixedGutter && view[i].gutter)
                view[i].gutter.style.left = left;
            var align = view[i].alignable;
            if (align) for (var j = 0; j < align.length; j++)
                align[j].style.left = left;
        }
        if (cm.options.fixedGutter)
            display.gutters.style.left = (comp + gutterW) + "px";
    }

    // Used to ensure that the line number gutter is still the right
    // size for the current document size. Returns true when an update
    // is needed.
    function maybeUpdateLineNumberWidth(cm) {
        if (!cm.options.lineNumbers) return false;
        var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
        if (last.length != display.lineNumChars) {
            var test = display.measure.appendChild(elt("div", [elt("div", last)],
                                                       "CodeMirror-linenumber CodeMirror-gutter-elt"));
            var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
            display.lineGutter.style.width = "";
            display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
            display.lineNumWidth = display.lineNumInnerWidth + padding;
            display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
            display.lineGutter.style.width = display.lineNumWidth + "px";
            updateGutterSpace(cm);
            return true;
        }
        return false;
    }

    function lineNumberFor(options, i) {
        return String(options.lineNumberFormatter(i + options.firstLineNumber));
    }

    // Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
    // but using getBoundingClientRect to get a sub-pixel-accurate
    // result.
    function compensateForHScroll(display) {
        return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
    }

    // DISPLAY DRAWING

    function DisplayUpdate(cm, viewport, force) {
        var display = cm.display;

        this.viewport = viewport;
        // Store some values that we'll need later (but don't want to force a relayout for)
        this.visible = visibleLines(display, cm.doc, viewport);
        this.editorIsHidden = !display.wrapper.offsetWidth;
        this.wrapperHeight = display.wrapper.clientHeight;
        this.wrapperWidth = display.wrapper.clientWidth;
        this.oldDisplayWidth = displayWidth(cm);
        this.force = force;
        this.dims = getDimensions(cm);
        this.events = [];
    }

    DisplayUpdate.prototype.signal = function (emitter, type) {
        if (hasHandler(emitter, type))
            this.events.push(arguments);
    };
    DisplayUpdate.prototype.finish = function () {
        for (var i = 0; i < this.events.length; i++)
            signal.apply(null, this.events[i]);
    };

    function maybeClipScrollbars(cm) {
        var display = cm.display;
        if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
            display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
            display.heightForcer.style.height = scrollGap(cm) + "px";
            display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
            display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
            display.scrollbarsClipped = true;
        }
    }

    // Does the actual updating of the line display. Bails out
    // (returning false) when there is nothing to be done and forced is
    // false.
    function updateDisplayIfNeeded(cm, update) {
        var display = cm.display, doc = cm.doc;

        if (update.editorIsHidden) {
            resetView(cm);
            return false;
        }

        // Bail out if the visible area is already rendered and nothing changed.
        if (!update.force &&
            update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
            (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
            display.renderedView == display.view && countDirtyView(cm) == 0)
            return false;

        if (maybeUpdateLineNumberWidth(cm)) {
            resetView(cm);
            update.dims = getDimensions(cm);
        }

        // Compute a suitable new viewport (from & to)
        var end = doc.first + doc.size;
        var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
        var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
        if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
        if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
        if (sawCollapsedSpans) {
            from = visualLineNo(cm.doc, from);
            to = visualLineEndNo(cm.doc, to);
        }

        var different = from != display.viewFrom || to != display.viewTo ||
          display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
        adjustView(cm, from, to);

        display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
        // Position the mover div to align with the current scroll position
        cm.display.mover.style.top = display.viewOffset + "px";

        var toUpdate = countDirtyView(cm);
        if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
            (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
            return false;

        // For big changes, we hide the enclosing element during the
        // update, since that speeds up the operations on most browsers.
        var focused = activeElt();
        if (toUpdate > 4) display.lineDiv.style.display = "none";
        patchDisplay(cm, display.updateLineNumbers, update.dims);
        if (toUpdate > 4) display.lineDiv.style.display = "";
        display.renderedView = display.view;
        // There might have been a widget with a focused element that got
        // hidden or updated, if so re-focus it.
        if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();

        // Prevent selection and cursors from interfering with the scroll
        // width and height.
        removeChildren(display.cursorDiv);
        removeChildren(display.selectionDiv);
        display.gutters.style.height = display.sizer.style.minHeight = 0;

        if (different) {
            display.lastWrapHeight = update.wrapperHeight;
            display.lastWrapWidth = update.wrapperWidth;
            startWorker(cm, 400);
        }

        display.updateLineNumbers = null;

        return true;
    }

    function postUpdateDisplay(cm, update) {
        var viewport = update.viewport;
        for (var first = true; ; first = false) {
            if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
                // Clip forced viewport to actual scrollable area.
                if (viewport && viewport.top != null)
                    viewport = { top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top) };
                // Updated line heights might result in the drawn area not
                // actually covering the viewport. Keep looping until it does.
                update.visible = visibleLines(cm.display, cm.doc, viewport);
                if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
                    break;
            }
            if (!updateDisplayIfNeeded(cm, update)) break;
            updateHeightsInViewport(cm);
            var barMeasure = measureForScrollbars(cm);
            updateSelection(cm);
            setDocumentHeight(cm, barMeasure);
            updateScrollbars(cm, barMeasure);
        }

        update.signal(cm, "update", cm);
        if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
            update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
            cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
        }
    }

    function updateDisplaySimple(cm, viewport) {
        var update = new DisplayUpdate(cm, viewport);
        if (updateDisplayIfNeeded(cm, update)) {
            updateHeightsInViewport(cm);
            postUpdateDisplay(cm, update);
            var barMeasure = measureForScrollbars(cm);
            updateSelection(cm);
            setDocumentHeight(cm, barMeasure);
            updateScrollbars(cm, barMeasure);
            update.finish();
        }
    }

    function setDocumentHeight(cm, measure) {
        cm.display.sizer.style.minHeight = measure.docHeight + "px";
        var total = measure.docHeight + cm.display.barHeight;
        cm.display.heightForcer.style.top = total + "px";
        cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
    }

    // Read the actual heights of the rendered lines, and update their
    // stored heights to match.
    function updateHeightsInViewport(cm) {
        var display = cm.display;
        var prevBottom = display.lineDiv.offsetTop;
        for (var i = 0; i < display.view.length; i++) {
            var cur = display.view[i], height;
            if (cur.hidden) continue;
            if (ie && ie_version < 8) {
                var bot = cur.node.offsetTop + cur.node.offsetHeight;
                height = bot - prevBottom;
                prevBottom = bot;
            } else {
                var box = cur.node.getBoundingClientRect();
                height = box.bottom - box.top;
            }
            var diff = cur.line.height - height;
            if (height < 2) height = textHeight(display);
            if (diff > .001 || diff < -.001) {
                updateLineHeight(cur.line, height);
                updateWidgetHeight(cur.line);
                if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
                    updateWidgetHeight(cur.rest[j]);
            }
        }
    }

    // Read and store the height of line widgets associated with the
    // given line.
    function updateWidgetHeight(line) {
        if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
            line.widgets[i].height = line.widgets[i].node.offsetHeight;
    }

    // Do a bulk-read of the DOM positions and sizes needed to draw the
    // view, so that we don't interleave reading and writing to the DOM.
    function getDimensions(cm) {
        var d = cm.display, left = {}, width = {};
        var gutterLeft = d.gutters.clientLeft;
        for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
            left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
            width[cm.options.gutters[i]] = n.clientWidth;
        }
        return {
            fixedPos: compensateForHScroll(d),
            gutterTotalWidth: d.gutters.offsetWidth,
            gutterLeft: left,
            gutterWidth: width,
            wrapperWidth: d.wrapper.clientWidth
        };
    }

    // Sync the actual display DOM structure with display.view, removing
    // nodes for lines that are no longer in view, and creating the ones
    // that are not there yet, and updating the ones that are out of
    // date.
    function patchDisplay(cm, updateNumbersFrom, dims) {
        var display = cm.display, lineNumbers = cm.options.lineNumbers;
        var container = display.lineDiv, cur = container.firstChild;

        function rm(node) {
            var next = node.nextSibling;
            // Works around a throw-scroll bug in OS X Webkit
            if (webkit && mac && cm.display.currentWheelTarget == node)
                node.style.display = "none";
            else
                node.parentNode.removeChild(node);
            return next;
        }

        var view = display.view, lineN = display.viewFrom;
        // Loop over the elements in the view, syncing cur (the DOM nodes
        // in display.lineDiv) with the view as we go.
        for (var i = 0; i < view.length; i++) {
            var lineView = view[i];
            if (lineView.hidden) {
            } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
                var node = buildLineElement(cm, lineView, lineN, dims);
                container.insertBefore(node, cur);
            } else { // Already drawn
                while (cur != lineView.node) cur = rm(cur);
                var updateNumber = lineNumbers && updateNumbersFrom != null &&
                  updateNumbersFrom <= lineN && lineView.lineNumber;
                if (lineView.changes) {
                    if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
                    updateLineForChanges(cm, lineView, lineN, dims);
                }
                if (updateNumber) {
                    removeChildren(lineView.lineNumber);
                    lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
                }
                cur = lineView.node.nextSibling;
            }
            lineN += lineView.size;
        }
        while (cur) cur = rm(cur);
    }

    // When an aspect of a line changes, a string is added to
    // lineView.changes. This updates the relevant part of the line's
    // DOM structure.
    function updateLineForChanges(cm, lineView, lineN, dims) {
        for (var j = 0; j < lineView.changes.length; j++) {
            var type = lineView.changes[j];
            if (type == "text") updateLineText(cm, lineView);
            else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
            else if (type == "class") updateLineClasses(lineView);
            else if (type == "widget") updateLineWidgets(cm, lineView, dims);
        }
        lineView.changes = null;
    }

    // Lines with gutter elements, widgets or a background class need to
    // be wrapped, and have the extra elements added to the wrapper div
    function ensureLineWrapped(lineView) {
        if (lineView.node == lineView.text) {
            lineView.node = elt("div", null, null, "position: relative");
            if (lineView.text.parentNode)
                lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
            lineView.node.appendChild(lineView.text);
            if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
        }
        return lineView.node;
    }

    function updateLineBackground(lineView) {
        var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
        if (cls) cls += " CodeMirror-linebackground";
        if (lineView.background) {
            if (cls) lineView.background.className = cls;
            else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
        } else if (cls) {
            var wrap = ensureLineWrapped(lineView);
            lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
        }
    }

    // Wrapper around buildLineContent which will reuse the structure
    // in display.externalMeasured when possible.
    function getLineContent(cm, lineView) {
        var ext = cm.display.externalMeasured;
        if (ext && ext.line == lineView.line) {
            cm.display.externalMeasured = null;
            lineView.measure = ext.measure;
            return ext.built;
        }
        return buildLineContent(cm, lineView);
    }

    // Redraw the line's text. Interacts with the background and text
    // classes because the mode may output tokens that influence these
    // classes.
    function updateLineText(cm, lineView) {
        var cls = lineView.text.className;
        var built = getLineContent(cm, lineView);
        if (lineView.text == lineView.node) lineView.node = built.pre;
        lineView.text.parentNode.replaceChild(built.pre, lineView.text);
        lineView.text = built.pre;
        if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
            lineView.bgClass = built.bgClass;
            lineView.textClass = built.textClass;
            updateLineClasses(lineView);
        } else if (cls) {
            lineView.text.className = cls;
        }
    }

    function updateLineClasses(lineView) {
        updateLineBackground(lineView);
        if (lineView.line.wrapClass)
            ensureLineWrapped(lineView).className = lineView.line.wrapClass;
        else if (lineView.node != lineView.text)
            lineView.node.className = "";
        var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
        lineView.text.className = textClass || "";
    }

    function updateLineGutter(cm, lineView, lineN, dims) {
        if (lineView.gutter) {
            lineView.node.removeChild(lineView.gutter);
            lineView.gutter = null;
        }
        if (lineView.gutterBackground) {
            lineView.node.removeChild(lineView.gutterBackground);
            lineView.gutterBackground = null;
        }
        if (lineView.line.gutterClass) {
            var wrap = ensureLineWrapped(lineView);
            lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
                                            "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
                                            "px; width: " + dims.gutterTotalWidth + "px");
            wrap.insertBefore(lineView.gutterBackground, lineView.text);
        }
        var markers = lineView.line.gutterMarkers;
        if (cm.options.lineNumbers || markers) {
            var wrap = ensureLineWrapped(lineView);
            var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
                                                   (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
            cm.display.input.setUneditable(gutterWrap);
            wrap.insertBefore(gutterWrap, lineView.text);
            if (lineView.line.gutterClass)
                gutterWrap.className += " " + lineView.line.gutterClass;
            if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
                lineView.lineNumber = gutterWrap.appendChild(
                  elt("div", lineNumberFor(cm.options, lineN),
                      "CodeMirror-linenumber CodeMirror-gutter-elt",
                      "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
                      + cm.display.lineNumInnerWidth + "px"));
            if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
                var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
                if (found)
                    gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
                                               dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
            }
        }
    }

    function updateLineWidgets(cm, lineView, dims) {
        if (lineView.alignable) lineView.alignable = null;
        for (var node = lineView.node.firstChild, next; node; node = next) {
            var next = node.nextSibling;
            if (node.className == "CodeMirror-linewidget")
                lineView.node.removeChild(node);
        }
        insertLineWidgets(cm, lineView, dims);
    }

    // Build a line's DOM representation from scratch
    function buildLineElement(cm, lineView, lineN, dims) {
        var built = getLineContent(cm, lineView);
        lineView.text = lineView.node = built.pre;
        if (built.bgClass) lineView.bgClass = built.bgClass;
        if (built.textClass) lineView.textClass = built.textClass;

        updateLineClasses(lineView);
        updateLineGutter(cm, lineView, lineN, dims);
        insertLineWidgets(cm, lineView, dims);
        return lineView.node;
    }

    // A lineView may contain multiple logical lines (when merged by
    // collapsed spans). The widgets for all of them need to be drawn.
    function insertLineWidgets(cm, lineView, dims) {
        insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
        if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
            insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
    }

    function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
        if (!line.widgets) return;
        var wrap = ensureLineWrapped(lineView);
        for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
            var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
            if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
            positionLineWidget(widget, node, lineView, dims);
            cm.display.input.setUneditable(node);
            if (allowAbove && widget.above)
                wrap.insertBefore(node, lineView.gutter || lineView.text);
            else
                wrap.appendChild(node);
            signalLater(widget, "redraw");
        }
    }

    function positionLineWidget(widget, node, lineView, dims) {
        if (widget.noHScroll) {
            (lineView.alignable || (lineView.alignable = [])).push(node);
            var width = dims.wrapperWidth;
            node.style.left = dims.fixedPos + "px";
            if (!widget.coverGutter) {
                width -= dims.gutterTotalWidth;
                node.style.paddingLeft = dims.gutterTotalWidth + "px";
            }
            node.style.width = width + "px";
        }
        if (widget.coverGutter) {
            node.style.zIndex = 5;
            node.style.position = "relative";
            if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
        }
    }

    // POSITION OBJECT

    // A Pos instance represents a position within the text.
    var Pos = CodeMirror.Pos = function (line, ch) {
        if (!(this instanceof Pos)) return new Pos(line, ch);
        this.line = line; this.ch = ch;
    };

    // Compare two positions, return 0 if they are the same, a negative
    // number when a is less, and a positive number otherwise.
    var cmp = CodeMirror.cmpPos = function (a, b) { return a.line - b.line || a.ch - b.ch; };

    function copyPos(x) { return Pos(x.line, x.ch); }
    function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
    function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }

    // INPUT HANDLING

    function ensureFocus(cm) {
        if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
    }

    function isReadOnly(cm) {
        return cm.options.readOnly || cm.doc.cantEdit;
    }

    // This will be set to an array of strings when copying, so that,
    // when pasting, we know what kind of selections the copied text
    // was made out of.
    var lastCopied = null;

    function applyTextInput(cm, inserted, deleted, sel, origin) {
        var doc = cm.doc;
        cm.display.shift = false;
        if (!sel) sel = doc.sel;

        var paste = cm.state.pasteIncoming || origin == "paste";
        var textLines = doc.splitLines(inserted), multiPaste = null;
        // When pasing N lines into N selections, insert one line per selection
        if (paste && sel.ranges.length > 1) {
            if (lastCopied && lastCopied.join("\n") == inserted) {
                if (sel.ranges.length % lastCopied.length == 0) {
                    multiPaste = [];
                    for (var i = 0; i < lastCopied.length; i++)
                        multiPaste.push(doc.splitLines(lastCopied[i]));
                }
            } else if (textLines.length == sel.ranges.length) {
                multiPaste = map(textLines, function (l) { return [l]; });
            }
        }

        // Normal behavior is to insert the new text into every selection
        for (var i = sel.ranges.length - 1; i >= 0; i--) {
            var range = sel.ranges[i];
            var from = range.from(), to = range.to();
            if (range.empty()) {
                if (deleted && deleted > 0) // Handle deletion
                    from = Pos(from.line, from.ch - deleted);
                else if (cm.state.overwrite && !paste) // Handle overwrite
                    to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
            }
            var updateInput = cm.curOp.updateInput;
            var changeEvent = {
                from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
                origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")
            };
            makeChange(cm.doc, changeEvent);
            signalLater(cm, "inputRead", cm, changeEvent);
        }
        if (inserted && !paste)
            triggerElectric(cm, inserted);

        ensureCursorVisible(cm);
        cm.curOp.updateInput = updateInput;
        cm.curOp.typing = true;
        cm.state.pasteIncoming = cm.state.cutIncoming = false;
    }

    function handlePaste(e, cm) {
        var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
        if (pasted) {
            e.preventDefault();
            if (!isReadOnly(cm) && !cm.options.disableInput)
                runInOp(cm, function () { applyTextInput(cm, pasted, 0, null, "paste"); });
            return true;
        }
    }

    function triggerElectric(cm, inserted) {
        // When an 'electric' character is inserted, immediately trigger a reindent
        if (!cm.options.electricChars || !cm.options.smartIndent) return;
        var sel = cm.doc.sel;

        for (var i = sel.ranges.length - 1; i >= 0; i--) {
            var range = sel.ranges[i];
            if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;
            var mode = cm.getModeAt(range.head);
            var indented = false;
            if (mode.electricChars) {
                for (var j = 0; j < mode.electricChars.length; j++)
                    if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
                        indented = indentLine(cm, range.head.line, "smart");
                        break;
                    }
            } else if (mode.electricInput) {
                if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
                    indented = indentLine(cm, range.head.line, "smart");
            }
            if (indented) signalLater(cm, "electricInput", cm, range.head.line);
        }
    }

    function copyableRanges(cm) {
        var text = [], ranges = [];
        for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
            var line = cm.doc.sel.ranges[i].head.line;
            var lineRange = { anchor: Pos(line, 0), head: Pos(line + 1, 0) };
            ranges.push(lineRange);
            text.push(cm.getRange(lineRange.anchor, lineRange.head));
        }
        return { text: text, ranges: ranges };
    }

    function disableBrowserMagic(field) {
        field.setAttribute("autocorrect", "off");
        field.setAttribute("autocapitalize", "off");
        field.setAttribute("spellcheck", "false");
    }

    // TEXTAREA INPUT STYLE

    function TextareaInput(cm) {
        this.cm = cm;
        // See input.poll and input.reset
        this.prevInput = "";

        // Flag that indicates whether we expect input to appear real soon
        // now (after some event like 'keypress' or 'input') and are
        // polling intensively.
        this.pollingFast = false;
        // Self-resetting timeout for the poller
        this.polling = new Delayed();
        // Tracks when input.reset has punted to just putting a short
        // string into the textarea instead of the full selection.
        this.inaccurateSelection = false;
        // Used to work around IE issue with selection being forgotten when focus moves away from textarea
        this.hasSelection = false;
        this.composing = null;
    };

    function hiddenTextarea() {
        var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
        var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
        // The textarea is kept positioned near the cursor to prevent the
        // fact that it'll be scrolled into view on input from scrolling
        // our fake cursor out of view. On webkit, when wrap=off, paste is
        // very slow. So make the area wide instead.
        if (webkit) te.style.width = "1000px";
        else te.setAttribute("wrap", "off");
        // If border: 0; -- iOS fails to open keyboard (issue #1287)
        if (ios) te.style.border = "1px solid black";
        disableBrowserMagic(te);
        return div;
    }

    TextareaInput.prototype = copyObj({
        init: function (display) {
            var input = this, cm = this.cm;

            // Wraps and hides input textarea
            var div = this.wrapper = hiddenTextarea();
            // The semihidden textarea that is focused when the editor is
            // focused, and receives input.
            var te = this.textarea = div.firstChild;
            display.wrapper.insertBefore(div, display.wrapper.firstChild);

            // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
            if (ios) te.style.width = "0px";

            on(te, "input", function () {
                if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
                input.poll();
            });

            on(te, "paste", function (e) {
                if (handlePaste(e, cm)) return true;

                cm.state.pasteIncoming = true;
                input.fastPoll();
            });

            function prepareCopyCut(e) {
                if (cm.somethingSelected()) {
                    lastCopied = cm.getSelections();
                    if (input.inaccurateSelection) {
                        input.prevInput = "";
                        input.inaccurateSelection = false;
                        te.value = lastCopied.join("\n");
                        selectInput(te);
                    }
                } else if (!cm.options.lineWiseCopyCut) {
                    return;
                } else {
                    var ranges = copyableRanges(cm);
                    lastCopied = ranges.text;
                    if (e.type == "cut") {
                        cm.setSelections(ranges.ranges, null, sel_dontScroll);
                    } else {
                        input.prevInput = "";
                        te.value = ranges.text.join("\n");
                        selectInput(te);
                    }
                }
                if (e.type == "cut") cm.state.cutIncoming = true;
            }
            on(te, "cut", prepareCopyCut);
            on(te, "copy", prepareCopyCut);

            on(display.scroller, "paste", function (e) {
                if (eventInWidget(display, e)) return;
                cm.state.pasteIncoming = true;
                input.focus();
            });

            // Prevent normal selection in the editor (we handle our own)
            on(display.lineSpace, "selectstart", function (e) {
                if (!eventInWidget(display, e)) e_preventDefault(e);
            });

            on(te, "compositionstart", function () {
                var start = cm.getCursor("from");
                if (input.composing) input.composing.range.clear()
                input.composing = {
                    start: start,
                    range: cm.markText(start, cm.getCursor("to"), { className: "CodeMirror-composing" })
                };
            });
            on(te, "compositionend", function () {
                if (input.composing) {
                    input.poll();
                    input.composing.range.clear();
                    input.composing = null;
                }
            });
        },

        prepareSelection: function () {
            // Redraw the selection and/or cursor
            var cm = this.cm, display = cm.display, doc = cm.doc;
            var result = prepareSelection(cm);

            // Move the hidden textarea near the cursor to prevent scrolling artifacts
            if (cm.options.moveInputWithCursor) {
                var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
                var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
                result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
                                                    headPos.top + lineOff.top - wrapOff.top));
                result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
                                                     headPos.left + lineOff.left - wrapOff.left));
            }

            return result;
        },

        showSelection: function (drawn) {
            var cm = this.cm, display = cm.display;
            removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
            removeChildrenAndAdd(display.selectionDiv, drawn.selection);
            if (drawn.teTop != null) {
                this.wrapper.style.top = drawn.teTop + "px";
                this.wrapper.style.left = drawn.teLeft + "px";
            }
        },

        // Reset the input to correspond to the selection (or to be empty,
        // when not typing and nothing is selected)
        reset: function (typing) {
            if (this.contextMenuPending) return;
            var minimal, selected, cm = this.cm, doc = cm.doc;
            if (cm.somethingSelected()) {
                this.prevInput = "";
                var range = doc.sel.primary();
                minimal = hasCopyEvent &&
                  (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
                var content = minimal ? "-" : selected || cm.getSelection();
                this.textarea.value = content;
                if (cm.state.focused) selectInput(this.textarea);
                if (ie && ie_version >= 9) this.hasSelection = content;
            } else if (!typing) {
                this.prevInput = this.textarea.value = "";
                if (ie && ie_version >= 9) this.hasSelection = null;
            }
            this.inaccurateSelection = minimal;
        },

        getField: function () { return this.textarea; },

        supportsTouch: function () { return false; },

        focus: function () {
            if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
                try { this.textarea.focus(); }
                catch (e) { } // IE8 will throw if the textarea is display: none or not in DOM
            }
        },

        blur: function () { this.textarea.blur(); },

        resetPosition: function () {
            this.wrapper.style.top = this.wrapper.style.left = 0;
        },

        receivedFocus: function () { this.slowPoll(); },

        // Poll for input changes, using the normal rate of polling. This
        // runs as long as the editor is focused.
        slowPoll: function () {
            var input = this;
            if (input.pollingFast) return;
            input.polling.set(this.cm.options.pollInterval, function () {
                input.poll();
                if (input.cm.state.focused) input.slowPoll();
            });
        },

        // When an event has just come in that is likely to add or change
        // something in the input textarea, we poll faster, to ensure that
        // the change appears on the screen quickly.
        fastPoll: function () {
            var missed = false, input = this;
            input.pollingFast = true;
            function p() {
                var changed = input.poll();
                if (!changed && !missed) { missed = true; input.polling.set(60, p); }
                else { input.pollingFast = false; input.slowPoll(); }
            }
            input.polling.set(20, p);
        },

        // Read input from the textarea, and update the document to match.
        // When something is selected, it is present in the textarea, and
        // selected (unless it is huge, in which case a placeholder is
        // used). When nothing is selected, the cursor sits after previously
        // seen text (can be empty), which is stored in prevInput (we must
        // not reset the textarea when typing, because that breaks IME).
        poll: function () {
            var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
            // Since this is called a *lot*, try to bail out as cheaply as
            // possible when it is clear that nothing happened. hasSelection
            // will be the case when there is a lot of text in the textarea,
            // in which case reading its value would be expensive.
            if (this.contextMenuPending || !cm.state.focused ||
                (hasSelection(input) && !prevInput && !this.composing) ||
                isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
                return false;

            var text = input.value;
            // If nothing changed, bail.
            if (text == prevInput && !cm.somethingSelected()) return false;
            // Work around nonsensical selection resetting in IE9/10, and
            // inexplicable appearance of private area unicode characters on
            // some key combos in Mac (#2689).
            if (ie && ie_version >= 9 && this.hasSelection === text ||
                mac && /[\uf700-\uf7ff]/.test(text)) {
                cm.display.input.reset();
                return false;
            }

            if (cm.doc.sel == cm.display.selForContextMenu) {
                var first = text.charCodeAt(0);
                if (first == 0x200b && !prevInput) prevInput = "\u200b";
                if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
            }
            // Find the part of the input that is actually new
            var same = 0, l = Math.min(prevInput.length, text.length);
            while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same))++same;

            var self = this;
            runInOp(cm, function () {
                applyTextInput(cm, text.slice(same), prevInput.length - same,
                               null, self.composing ? "*compose" : null);

                // Don't leave long text in the textarea, since it makes further polling slow
                if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
                else self.prevInput = text;

                if (self.composing) {
                    self.composing.range.clear();
                    self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
                                                       { className: "CodeMirror-composing" });
                }
            });
            return true;
        },

        ensurePolled: function () {
            if (this.pollingFast && this.poll()) this.pollingFast = false;
        },

        onKeyPress: function () {
            if (ie && ie_version >= 9) this.hasSelection = null;
            this.fastPoll();
        },

        onContextMenu: function (e) {
            var input = this, cm = input.cm, display = cm.display, te = input.textarea;
            var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
            if (!pos || presto) return; // Opera is difficult.

            // Reset the current text selection only if the click is done outside of the selection
            // and 'resetSelectionOnContextMenu' option is true.
            var reset = cm.options.resetSelectionOnContextMenu;
            if (reset && cm.doc.sel.contains(pos) == -1)
                operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);

            var oldCSS = te.style.cssText;
            input.wrapper.style.position = "absolute";
            te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
              "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
              (ie ? "rgba(255, 255, 255, .05)" : "transparent") +
              "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
            if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
            display.input.focus();
            if (webkit) window.scrollTo(null, oldScrollY);
            display.input.reset();
            // Adds "Select all" to context menu in FF
            if (!cm.somethingSelected()) te.value = input.prevInput = " ";
            input.contextMenuPending = true;
            display.selForContextMenu = cm.doc.sel;
            clearTimeout(display.detectingSelectAll);

            // Select-all will be greyed out if there's nothing to select, so
            // this adds a zero-width space so that we can later check whether
            // it got selected.
            function prepareSelectAllHack() {
                if (te.selectionStart != null) {
                    var selected = cm.somethingSelected();
                    var extval = "\u200b" + (selected ? te.value : "");
                    te.value = "\u21da"; // Used to catch context-menu undo
                    te.value = extval;
                    input.prevInput = selected ? "" : "\u200b";
                    te.selectionStart = 1; te.selectionEnd = extval.length;
                    // Re-set this, in case some other handler touched the
                    // selection in the meantime.
                    display.selForContextMenu = cm.doc.sel;
                }
            }
            function rehide() {
                input.contextMenuPending = false;
                input.wrapper.style.position = "relative";
                te.style.cssText = oldCSS;
                if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);

                // Try to detect the user choosing select-all
                if (te.selectionStart != null) {
                    if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
                    var i = 0, poll = function () {
                        if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
                            te.selectionEnd > 0 && input.prevInput == "\u200b")
                            operation(cm, commands.selectAll)(cm);
                        else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
                        else display.input.reset();
                    };
                    display.detectingSelectAll = setTimeout(poll, 200);
                }
            }

            if (ie && ie_version >= 9) prepareSelectAllHack();
            if (captureRightClick) {
                e_stop(e);
                var mouseup = function () {
                    off(window, "mouseup", mouseup);
                    setTimeout(rehide, 20);
                };
                on(window, "mouseup", mouseup);
            } else {
                setTimeout(rehide, 50);
            }
        },

        readOnlyChanged: function (val) {
            if (!val) this.reset();
        },

        setUneditable: nothing,

        needsContentAttribute: false
    }, TextareaInput.prototype);

    // CONTENTEDITABLE INPUT STYLE

    function ContentEditableInput(cm) {
        this.cm = cm;
        this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
        this.polling = new Delayed();
        this.gracePeriod = false;
    }

    ContentEditableInput.prototype = copyObj({
        init: function (display) {
            var input = this, cm = input.cm;
            var div = input.div = display.lineDiv;
            disableBrowserMagic(div);

            on(div, "paste", function (e) { handlePaste(e, cm); })

            on(div, "compositionstart", function (e) {
                var data = e.data;
                input.composing = { sel: cm.doc.sel, data: data, startData: data };
                if (!data) return;
                var prim = cm.doc.sel.primary();
                var line = cm.getLine(prim.head.line);
                var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
                if (found > -1 && found <= prim.head.ch)
                    input.composing.sel = simpleSelection(Pos(prim.head.line, found),
                                                          Pos(prim.head.line, found + data.length));
            });
            on(div, "compositionupdate", function (e) {
                input.composing.data = e.data;
            });
            on(div, "compositionend", function (e) {
                var ours = input.composing;
                if (!ours) return;
                if (e.data != ours.startData && !/\u200b/.test(e.data))
                    ours.data = e.data;
                // Need a small delay to prevent other code (input event,
                // selection polling) from doing damage when fired right after
                // compositionend.
                setTimeout(function () {
                    if (!ours.handled)
                        input.applyComposition(ours);
                    if (input.composing == ours)
                        input.composing = null;
                }, 50);
            });

            on(div, "touchstart", function () {
                input.forceCompositionEnd();
            });

            on(div, "input", function () {
                if (input.composing) return;
                if (isReadOnly(cm) || !input.pollContent())
                    runInOp(input.cm, function () { regChange(cm); });
            });

            function onCopyCut(e) {
                if (cm.somethingSelected()) {
                    lastCopied = cm.getSelections();
                    if (e.type == "cut") cm.replaceSelection("", null, "cut");
                } else if (!cm.options.lineWiseCopyCut) {
                    return;
                } else {
                    var ranges = copyableRanges(cm);
                    lastCopied = ranges.text;
                    if (e.type == "cut") {
                        cm.operation(function () {
                            cm.setSelections(ranges.ranges, 0, sel_dontScroll);
                            cm.replaceSelection("", null, "cut");
                        });
                    }
                }
                // iOS exposes the clipboard API, but seems to discard content inserted into it
                if (e.clipboardData && !ios) {
                    e.preventDefault();
                    e.clipboardData.clearData();
                    e.clipboardData.setData("text/plain", lastCopied.join("\n"));
                } else {
                    // Old-fashioned briefly-focus-a-textarea hack
                    var kludge = hiddenTextarea(), te = kludge.firstChild;
                    cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
                    te.value = lastCopied.join("\n");
                    var hadFocus = document.activeElement;
                    selectInput(te);
                    setTimeout(function () {
                        cm.display.lineSpace.removeChild(kludge);
                        hadFocus.focus();
                    }, 50);
                }
            }
            on(div, "copy", onCopyCut);
            on(div, "cut", onCopyCut);
        },

        prepareSelection: function () {
            var result = prepareSelection(this.cm, false);
            result.focus = this.cm.state.focused;
            return result;
        },

        showSelection: function (info) {
            if (!info || !this.cm.display.view.length) return;
            if (info.focus) this.showPrimarySelection();
            this.showMultipleSelections(info);
        },

        showPrimarySelection: function () {
            var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
            var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
            var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
            if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
                cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
                cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
                return;

            var start = posToDOM(this.cm, prim.from());
            var end = posToDOM(this.cm, prim.to());
            if (!start && !end) return;

            var view = this.cm.display.view;
            var old = sel.rangeCount && sel.getRangeAt(0);
            if (!start) {
                start = { node: view[0].measure.map[2], offset: 0 };
            } else if (!end) { // FIXME dangerously hacky
                var measure = view[view.length - 1].measure;
                var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
                end = { node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3] };
            }

            try { var rng = range(start.node, start.offset, end.offset, end.node); }
            catch (e) { } // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
            if (rng) {
                sel.removeAllRanges();
                sel.addRange(rng);
                if (old && sel.anchorNode == null) sel.addRange(old);
                else if (gecko) this.startGracePeriod();
            }
            this.rememberSelection();
        },

        startGracePeriod: function () {
            var input = this;
            clearTimeout(this.gracePeriod);
            this.gracePeriod = setTimeout(function () {
                input.gracePeriod = false;
                if (input.selectionChanged())
                    input.cm.operation(function () { input.cm.curOp.selectionChanged = true; });
            }, 20);
        },

        showMultipleSelections: function (info) {
            removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
            removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
        },

        rememberSelection: function () {
            var sel = window.getSelection();
            this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
            this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
        },

        selectionInEditor: function () {
            var sel = window.getSelection();
            if (!sel.rangeCount) return false;
            var node = sel.getRangeAt(0).commonAncestorContainer;
            return contains(this.div, node);
        },

        focus: function () {
            if (this.cm.options.readOnly != "nocursor") this.div.focus();
        },
        blur: function () { this.div.blur(); },
        getField: function () { return this.div; },

        supportsTouch: function () { return true; },

        receivedFocus: function () {
            var input = this;
            if (this.selectionInEditor())
                this.pollSelection();
            else
                runInOp(this.cm, function () { input.cm.curOp.selectionChanged = true; });

            function poll() {
                if (input.cm.state.focused) {
                    input.pollSelection();
                    input.polling.set(input.cm.options.pollInterval, poll);
                }
            }
            this.polling.set(this.cm.options.pollInterval, poll);
        },

        selectionChanged: function () {
            var sel = window.getSelection();
            return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
              sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
        },

        pollSelection: function () {
            if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
                var sel = window.getSelection(), cm = this.cm;
                this.rememberSelection();
                var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
                var head = domToPos(cm, sel.focusNode, sel.focusOffset);
                if (anchor && head) runInOp(cm, function () {
                    setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
                    if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
                });
            }
        },

        pollContent: function () {
            var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
            var from = sel.from(), to = sel.to();
            if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;

            var fromIndex;
            if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
                var fromLine = lineNo(display.view[0].line);
                var fromNode = display.view[0].node;
            } else {
                var fromLine = lineNo(display.view[fromIndex].line);
                var fromNode = display.view[fromIndex - 1].node.nextSibling;
            }
            var toIndex = findViewIndex(cm, to.line);
            if (toIndex == display.view.length - 1) {
                var toLine = display.viewTo - 1;
                var toNode = display.lineDiv.lastChild;
            } else {
                var toLine = lineNo(display.view[toIndex + 1].line) - 1;
                var toNode = display.view[toIndex + 1].node.previousSibling;
            }

            var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
            var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
            while (newText.length > 1 && oldText.length > 1) {
                if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
                else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
                else break;
            }

            var cutFront = 0, cutEnd = 0;
            var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
            while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
                ++cutFront;
            var newBot = lst(newText), oldBot = lst(oldText);
            var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
                                     oldBot.length - (oldText.length == 1 ? cutFront : 0));
            while (cutEnd < maxCutEnd &&
                   newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
                ++cutEnd;

            newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
            newText[0] = newText[0].slice(cutFront);

            var chFrom = Pos(fromLine, cutFront);
            var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
            if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
                replaceRange(cm.doc, newText, chFrom, chTo, "+input");
                return true;
            }
        },

        ensurePolled: function () {
            this.forceCompositionEnd();
        },
        reset: function () {
            this.forceCompositionEnd();
        },
        forceCompositionEnd: function () {
            if (!this.composing || this.composing.handled) return;
            this.applyComposition(this.composing);
            this.composing.handled = true;
            this.div.blur();
            this.div.focus();
        },
        applyComposition: function (composing) {
            if (isReadOnly(this.cm))
                operation(this.cm, regChange)(this.cm)
            else if (composing.data && composing.data != composing.startData)
                operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
        },

        setUneditable: function (node) {
            node.contentEditable = "false"
        },

        onKeyPress: function (e) {
            e.preventDefault();
            if (!isReadOnly(this.cm))
                operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
        },

        readOnlyChanged: function (val) {
            this.div.contentEditable = String(val != "nocursor")
        },

        onContextMenu: nothing,
        resetPosition: nothing,

        needsContentAttribute: true
    }, ContentEditableInput.prototype);

    function posToDOM(cm, pos) {
        var view = findViewForLine(cm, pos.line);
        if (!view || view.hidden) return null;
        var line = getLine(cm.doc, pos.line);
        var info = mapFromLineView(view, line, pos.line);

        var order = getOrder(line), side = "left";
        if (order) {
            var partPos = getBidiPartAt(order, pos.ch);
            side = partPos % 2 ? "right" : "left";
        }
        var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
        result.offset = result.collapse == "right" ? result.end : result.start;
        return result;
    }

    function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }

    function domToPos(cm, node, offset) {
        var lineNode;
        if (node == cm.display.lineDiv) {
            lineNode = cm.display.lineDiv.childNodes[offset];
            if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
            node = null; offset = 0;
        } else {
            for (lineNode = node; ; lineNode = lineNode.parentNode) {
                if (!lineNode || lineNode == cm.display.lineDiv) return null;
                if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
            }
        }
        for (var i = 0; i < cm.display.view.length; i++) {
            var lineView = cm.display.view[i];
            if (lineView.node == lineNode)
                return locateNodeInLineView(lineView, node, offset);
        }
    }

    function locateNodeInLineView(lineView, node, offset) {
        var wrapper = lineView.text.firstChild, bad = false;
        if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
        if (node == wrapper) {
            bad = true;
            node = wrapper.childNodes[offset];
            offset = 0;
            if (!node) {
                var line = lineView.rest ? lst(lineView.rest) : lineView.line;
                return badPos(Pos(lineNo(line), line.text.length), bad);
            }
        }

        var textNode = node.nodeType == 3 ? node : null, topNode = node;
        if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
            textNode = node.firstChild;
            if (offset) offset = textNode.nodeValue.length;
        }
        while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
        var measure = lineView.measure, maps = measure.maps;

        function find(textNode, topNode, offset) {
            for (var i = -1; i < (maps ? maps.length : 0) ; i++) {
                var map = i < 0 ? measure.map : maps[i];
                for (var j = 0; j < map.length; j += 3) {
                    var curNode = map[j + 2];
                    if (curNode == textNode || curNode == topNode) {
                        var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
                        var ch = map[j] + offset;
                        if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
                        return Pos(line, ch);
                    }
                }
            }
        }
        var found = find(textNode, topNode, offset);
        if (found) return badPos(found, bad);

        // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
        for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
            found = find(after, after.firstChild, 0);
            if (found)
                return badPos(Pos(found.line, found.ch - dist), bad);
            else
                dist += after.textContent.length;
        }
        for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
            found = find(before, before.firstChild, -1);
            if (found)
                return badPos(Pos(found.line, found.ch + dist), bad);
            else
                dist += after.textContent.length;
        }
    }

    function domTextBetween(cm, from, to, fromLine, toLine) {
        var text = "", closing = false, lineSep = cm.doc.lineSeparator();
        function recognizeMarker(id) { return function (marker) { return marker.id == id; }; }
        function walk(node) {
            if (node.nodeType == 1) {
                var cmText = node.getAttribute("cm-text");
                if (cmText != null) {
                    if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
                    text += cmText;
                    return;
                }
                var markerID = node.getAttribute("cm-marker"), range;
                if (markerID) {
                    var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
                    if (found.length && (range = found[0].find()))
                        text += getBetween(cm.doc, range.from, range.to).join(lineSep);
                    return;
                }
                if (node.getAttribute("contenteditable") == "false") return;
                for (var i = 0; i < node.childNodes.length; i++)
                    walk(node.childNodes[i]);
                if (/^(pre|div|p)$/i.test(node.nodeName))
                    closing = true;
            } else if (node.nodeType == 3) {
                var val = node.nodeValue;
                if (!val) return;
                if (closing) {
                    text += lineSep;
                    closing = false;
                }
                text += val;
            }
        }
        for (; ;) {
            walk(from);
            if (from == to) break;
            from = from.nextSibling;
        }
        return text;
    }

    CodeMirror.inputStyles = { "textarea": TextareaInput, "contenteditable": ContentEditableInput };

    // SELECTION / CURSOR

    // Selection objects are immutable. A new one is created every time
    // the selection changes. A selection is one or more non-overlapping
    // (and non-touching) ranges, sorted, and an integer that indicates
    // which one is the primary selection (the one that's scrolled into
    // view, that getCursor returns, etc).
    function Selection(ranges, primIndex) {
        this.ranges = ranges;
        this.primIndex = primIndex;
    }

    Selection.prototype = {
        primary: function () { return this.ranges[this.primIndex]; },
        equals: function (other) {
            if (other == this) return true;
            if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
            for (var i = 0; i < this.ranges.length; i++) {
                var here = this.ranges[i], there = other.ranges[i];
                if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
            }
            return true;
        },
        deepCopy: function () {
            for (var out = [], i = 0; i < this.ranges.length; i++)
                out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
            return new Selection(out, this.primIndex);
        },
        somethingSelected: function () {
            for (var i = 0; i < this.ranges.length; i++)
                if (!this.ranges[i].empty()) return true;
            return false;
        },
        contains: function (pos, end) {
            if (!end) end = pos;
            for (var i = 0; i < this.ranges.length; i++) {
                var range = this.ranges[i];
                if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
                    return i;
            }
            return -1;
        }
    };

    function Range(anchor, head) {
        this.anchor = anchor; this.head = head;
    }

    Range.prototype = {
        from: function () { return minPos(this.anchor, this.head); },
        to: function () { return maxPos(this.anchor, this.head); },
        empty: function () {
            return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
        }
    };

    // Take an unsorted, potentially overlapping set of ranges, and
    // build a selection out of it. 'Consumes' ranges array (modifying
    // it).
    function normalizeSelection(ranges, primIndex) {
        var prim = ranges[primIndex];
        ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
        primIndex = indexOf(ranges, prim);
        for (var i = 1; i < ranges.length; i++) {
            var cur = ranges[i], prev = ranges[i - 1];
            if (cmp(prev.to(), cur.from()) >= 0) {
                var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
                var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
                if (i <= primIndex)--primIndex;
                ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
            }
        }
        return new Selection(ranges, primIndex);
    }

    function simpleSelection(anchor, head) {
        return new Selection([new Range(anchor, head || anchor)], 0);
    }

    // Most of the external API clips given positions to make sure they
    // actually exist within the document.
    function clipLine(doc, n) { return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1)); }
    function clipPos(doc, pos) {
        if (pos.line < doc.first) return Pos(doc.first, 0);
        var last = doc.first + doc.size - 1;
        if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
        return clipToLen(pos, getLine(doc, pos.line).text.length);
    }
    function clipToLen(pos, linelen) {
        var ch = pos.ch;
        if (ch == null || ch > linelen) return Pos(pos.line, linelen);
        else if (ch < 0) return Pos(pos.line, 0);
        else return pos;
    }
    function isLine(doc, l) { return l >= doc.first && l < doc.first + doc.size; }
    function clipPosArray(doc, array) {
        for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
        return out;
    }

    // SELECTION UPDATES

    // The 'scroll' parameter given to many of these indicated whether
    // the new cursor position should be scrolled into view after
    // modifying the selection.

    // If shift is held or the extend flag is set, extends a range to
    // include a given position (and optionally a second position).
    // Otherwise, simply returns the range between the given positions.
    // Used for cursor motion and such.
    function extendRange(doc, range, head, other) {
        if (doc.cm && doc.cm.display.shift || doc.extend) {
            var anchor = range.anchor;
            if (other) {
                var posBefore = cmp(head, anchor) < 0;
                if (posBefore != (cmp(other, anchor) < 0)) {
                    anchor = head;
                    head = other;
                } else if (posBefore != (cmp(head, other) < 0)) {
                    head = other;
                }
            }
            return new Range(anchor, head);
        } else {
            return new Range(other || head, head);
        }
    }

    // Extend the primary selection range, discard the rest.
    function extendSelection(doc, head, other, options) {
        setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
    }

    // Extend all selections (pos is an array of selections with length
    // equal the number of selections)
    function extendSelections(doc, heads, options) {
        for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
            out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
        var newSel = normalizeSelection(out, doc.sel.primIndex);
        setSelection(doc, newSel, options);
    }

    // Updates a single range in the selection.
    function replaceOneSelection(doc, i, range, options) {
        var ranges = doc.sel.ranges.slice(0);
        ranges[i] = range;
        setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
    }

    // Reset the selection to a single range.
    function setSimpleSelection(doc, anchor, head, options) {
        setSelection(doc, simpleSelection(anchor, head), options);
    }

    // Give beforeSelectionChange handlers a change to influence a
    // selection update.
    function filterSelectionChange(doc, sel) {
        var obj = {
            ranges: sel.ranges,
            update: function (ranges) {
                this.ranges = [];
                for (var i = 0; i < ranges.length; i++)
                    this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
                                               clipPos(doc, ranges[i].head));
            }
        };
        signal(doc, "beforeSelectionChange", doc, obj);
        if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
        if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
        else return sel;
    }

    function setSelectionReplaceHistory(doc, sel, options) {
        var done = doc.history.done, last = lst(done);
        if (last && last.ranges) {
            done[done.length - 1] = sel;
            setSelectionNoUndo(doc, sel, options);
        } else {
            setSelection(doc, sel, options);
        }
    }

    // Set a new selection.
    function setSelection(doc, sel, options) {
        setSelectionNoUndo(doc, sel, options);
        addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
    }

    function setSelectionNoUndo(doc, sel, options) {
        if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
            sel = filterSelectionChange(doc, sel);

        var bias = options && options.bias ||
          (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
        setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));

        if (!(options && options.scroll === false) && doc.cm)
            ensureCursorVisible(doc.cm);
    }

    function setSelectionInner(doc, sel) {
        if (sel.equals(doc.sel)) return;

        doc.sel = sel;

        if (doc.cm) {
            doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
            signalCursorActivity(doc.cm);
        }
        signalLater(doc, "cursorActivity", doc);
    }

    // Verify that the selection does not partially select any atomic
    // marked ranges.
    function reCheckSelection(doc) {
        setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
    }

    // Return a selection that does not partially select any atomic
    // ranges.
    function skipAtomicInSelection(doc, sel, bias, mayClear) {
        var out;
        for (var i = 0; i < sel.ranges.length; i++) {
            var range = sel.ranges[i];
            var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear);
            var newHead = skipAtomic(doc, range.head, bias, mayClear);
            if (out || newAnchor != range.anchor || newHead != range.head) {
                if (!out) out = sel.ranges.slice(0, i);
                out[i] = new Range(newAnchor, newHead);
            }
        }
        return out ? normalizeSelection(out, sel.primIndex) : sel;
    }

    // Ensure a given position is not inside an atomic range.
    function skipAtomic(doc, pos, bias, mayClear) {
        var flipped = false, curPos = pos;
        var dir = bias || 1;
        doc.cantEdit = false;
        search: for (; ;) {
            var line = getLine(doc, curPos.line);
            if (line.markedSpans) {
                for (var i = 0; i < line.markedSpans.length; ++i) {
                    var sp = line.markedSpans[i], m = sp.marker;
                    if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) &&
                        (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) {
                        if (mayClear) {
                            signal(m, "beforeCursorEnter");
                            if (m.explicitlyCleared) {
                                if (!line.markedSpans) break;
                                else { --i; continue; }
                            }
                        }
                        if (!m.atomic) continue;
                        var newPos = m.find(dir < 0 ? -1 : 1);
                        if (cmp(newPos, curPos) == 0) {
                            newPos.ch += dir;
                            if (newPos.ch < 0) {
                                if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1));
                                else newPos = null;
                            } else if (newPos.ch > line.text.length) {
                                if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0);
                                else newPos = null;
                            }
                            if (!newPos) {
                                if (flipped) {
                                    // Driven in a corner -- no valid cursor position found at all
                                    // -- try again *with* clearing, if we didn't already
                                    if (!mayClear) return skipAtomic(doc, pos, bias, true);
                                    // Otherwise, turn off editing until further notice, and return the start of the doc
                                    doc.cantEdit = true;
                                    return Pos(doc.first, 0);
                                }
                                flipped = true; newPos = pos; dir = -dir;
                            }
                        }
                        curPos = newPos;
                        continue search;
                    }
                }
            }
            return curPos;
        }
    }

    // SELECTION DRAWING

    function updateSelection(cm) {
        cm.display.input.showSelection(cm.display.input.prepareSelection());
    }

    function prepareSelection(cm, primary) {
        var doc = cm.doc, result = {};
        var curFragment = result.cursors = document.createDocumentFragment();
        var selFragment = result.selection = document.createDocumentFragment();

        for (var i = 0; i < doc.sel.ranges.length; i++) {
            if (primary === false && i == doc.sel.primIndex) continue;
            var range = doc.sel.ranges[i];
            var collapsed = range.empty();
            if (collapsed || cm.options.showCursorWhenSelecting)
                drawSelectionCursor(cm, range.head, curFragment);
            if (!collapsed)
                drawSelectionRange(cm, range, selFragment);
        }
        return result;
    }

    // Draws a cursor for the given range
    function drawSelectionCursor(cm, head, output) {
        var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);

        var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
        cursor.style.left = pos.left + "px";
        cursor.style.top = pos.top + "px";
        cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";

        if (pos.other) {
            // Secondary cursor, shown when on a 'jump' in bi-directional text
            var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
            otherCursor.style.display = "";
            otherCursor.style.left = pos.other.left + "px";
            otherCursor.style.top = pos.other.top + "px";
            otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
        }
    }

    // Draws the given range as a highlighted selection
    function drawSelectionRange(cm, range, output) {
        var display = cm.display, doc = cm.doc;
        var fragment = document.createDocumentFragment();
        var padding = paddingH(cm.display), leftSide = padding.left;
        var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;

        function add(left, top, width, bottom) {
            if (top < 0) top = 0;
            top = Math.round(top);
            bottom = Math.round(bottom);
            fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
                                     "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
                                     "px; height: " + (bottom - top) + "px"));
        }

        function drawForLine(line, fromArg, toArg) {
            var lineObj = getLine(doc, line);
            var lineLen = lineObj.text.length;
            var start, end;
            function coords(ch, bias) {
                return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
            }

            iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir) {
                var leftPos = coords(from, "left"), rightPos, left, right;
                if (from == to) {
                    rightPos = leftPos;
                    left = right = leftPos.left;
                } else {
                    rightPos = coords(to - 1, "right");
                    if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
                    left = leftPos.left;
                    right = rightPos.right;
                }
                if (fromArg == null && from == 0) left = leftSide;
                if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
                    add(left, leftPos.top, null, leftPos.bottom);
                    left = leftSide;
                    if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
                }
                if (toArg == null && to == lineLen) right = rightSide;
                if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
                    start = leftPos;
                if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
                    end = rightPos;
                if (left < leftSide + 1) left = leftSide;
                add(left, rightPos.top, right - left, rightPos.bottom);
            });
            return { start: start, end: end };
        }

        var sFrom = range.from(), sTo = range.to();
        if (sFrom.line == sTo.line) {
            drawForLine(sFrom.line, sFrom.ch, sTo.ch);
        } else {
            var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
            var singleVLine = visualLine(fromLine) == visualLine(toLine);
            var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
            var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
            if (singleVLine) {
                if (leftEnd.top < rightStart.top - 2) {
                    add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
                    add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
                } else {
                    add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
                }
            }
            if (leftEnd.bottom < rightStart.top)
                add(leftSide, leftEnd.bottom, null, rightStart.top);
        }

        output.appendChild(fragment);
    }

    // Cursor-blinking
    function restartBlink(cm) {
        if (!cm.state.focused) return;
        var display = cm.display;
        clearInterval(display.blinker);
        var on = true;
        display.cursorDiv.style.visibility = "";
        if (cm.options.cursorBlinkRate > 0)
            display.blinker = setInterval(function () {
                display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
            }, cm.options.cursorBlinkRate);
        else if (cm.options.cursorBlinkRate < 0)
            display.cursorDiv.style.visibility = "hidden";
    }

    // HIGHLIGHT WORKER

    function startWorker(cm, time) {
        if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
            cm.state.highlight.set(time, bind(highlightWorker, cm));
    }

    function highlightWorker(cm) {
        var doc = cm.doc;
        if (doc.frontier < doc.first) doc.frontier = doc.first;
        if (doc.frontier >= cm.display.viewTo) return;
        var end = +new Date + cm.options.workTime;
        var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
        var changedLines = [];

        doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
            if (doc.frontier >= cm.display.viewFrom) { // Visible
                var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
                var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
                line.styles = highlighted.styles;
                var oldCls = line.styleClasses, newCls = highlighted.classes;
                if (newCls) line.styleClasses = newCls;
                else if (oldCls) line.styleClasses = null;
                var ischange = !oldStyles || oldStyles.length != line.styles.length ||
                  oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
                for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
                if (ischange) changedLines.push(doc.frontier);
                line.stateAfter = tooLong ? state : copyState(doc.mode, state);
            } else {
                if (line.text.length <= cm.options.maxHighlightLength)
                    processLine(cm, line.text, state);
                line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
            }
            ++doc.frontier;
            if (+new Date > end) {
                startWorker(cm, cm.options.workDelay);
                return true;
            }
        });
        if (changedLines.length) runInOp(cm, function () {
            for (var i = 0; i < changedLines.length; i++)
                regLineChange(cm, changedLines[i], "text");
        });
    }

    // Finds the line to start with when starting a parse. Tries to
    // find a line with a stateAfter, so that it can start with a
    // valid state. If that fails, it returns the line with the
    // smallest indentation, which tends to need the least context to
    // parse correctly.
    function findStartLine(cm, n, precise) {
        var minindent, minline, doc = cm.doc;
        var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
        for (var search = n; search > lim; --search) {
            if (search <= doc.first) return doc.first;
            var line = getLine(doc, search - 1);
            if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
            var indented = countColumn(line.text, null, cm.options.tabSize);
            if (minline == null || minindent > indented) {
                minline = search - 1;
                minindent = indented;
            }
        }
        return minline;
    }

    function getStateBefore(cm, n, precise) {
        var doc = cm.doc, display = cm.display;
        if (!doc.mode.startState) return true;
        var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos - 1).stateAfter;
        if (!state) state = startState(doc.mode);
        else state = copyState(doc.mode, state);
        doc.iter(pos, n, function (line) {
            processLine(cm, line.text, state);
            var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
            line.stateAfter = save ? copyState(doc.mode, state) : null;
            ++pos;
        });
        if (precise) doc.frontier = pos;
        return state;
    }

    // POSITION MEASUREMENT

    function paddingTop(display) { return display.lineSpace.offsetTop; }
    function paddingVert(display) { return display.mover.offsetHeight - display.lineSpace.offsetHeight; }
    function paddingH(display) {
        if (display.cachedPaddingH) return display.cachedPaddingH;
        var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
        var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
        var data = { left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight) };
        if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
        return data;
    }

    function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
    function displayWidth(cm) {
        return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
    }
    function displayHeight(cm) {
        return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
    }

    // Ensure the lineView.wrapping.heights array is populated. This is
    // an array of bottom offsets for the lines that make up a drawn
    // line. When lineWrapping is on, there might be more than one
    // height.
    function ensureLineHeights(cm, lineView, rect) {
        var wrapping = cm.options.lineWrapping;
        var curWidth = wrapping && displayWidth(cm);
        if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
            var heights = lineView.measure.heights = [];
            if (wrapping) {
                lineView.measure.width = curWidth;
                var rects = lineView.text.firstChild.getClientRects();
                for (var i = 0; i < rects.length - 1; i++) {
                    var cur = rects[i], next = rects[i + 1];
                    if (Math.abs(cur.bottom - next.bottom) > 2)
                        heights.push((cur.bottom + next.top) / 2 - rect.top);
                }
            }
            heights.push(rect.bottom - rect.top);
        }
    }

    // Find a line map (mapping character offsets to text nodes) and a
    // measurement cache for the given line number. (A line view might
    // contain multiple lines when collapsed ranges are present.)
    function mapFromLineView(lineView, line, lineN) {
        if (lineView.line == line)
            return { map: lineView.measure.map, cache: lineView.measure.cache };
        for (var i = 0; i < lineView.rest.length; i++)
            if (lineView.rest[i] == line)
                return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i] };
        for (var i = 0; i < lineView.rest.length; i++)
            if (lineNo(lineView.rest[i]) > lineN)
                return { map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true };
    }

    // Render a line into the hidden node display.externalMeasured. Used
    // when measurement is needed for a line that's not in the viewport.
    function updateExternalMeasurement(cm, line) {
        line = visualLine(line);
        var lineN = lineNo(line);
        var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
        view.lineN = lineN;
        var built = view.built = buildLineContent(cm, view);
        view.text = built.pre;
        removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
        return view;
    }

    // Get a {top, bottom, left, right} box (in line-local coordinates)
    // for a given character.
    function measureChar(cm, line, ch, bias) {
        return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
    }

    // Find a line view that corresponds to the given line number.
    function findViewForLine(cm, lineN) {
        if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
            return cm.display.view[findViewIndex(cm, lineN)];
        var ext = cm.display.externalMeasured;
        if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
            return ext;
    }

    // Measurement can be split in two steps, the set-up work that
    // applies to the whole line, and the measurement of the actual
    // character. Functions like coordsChar, that need to do a lot of
    // measurements in a row, can thus ensure that the set-up work is
    // only done once.
    function prepareMeasureForLine(cm, line) {
        var lineN = lineNo(line);
        var view = findViewForLine(cm, lineN);
        if (view && !view.text) {
            view = null;
        } else if (view && view.changes) {
            updateLineForChanges(cm, view, lineN, getDimensions(cm));
            cm.curOp.forceUpdate = true;
        }
        if (!view)
            view = updateExternalMeasurement(cm, line);

        var info = mapFromLineView(view, line, lineN);
        return {
            line: line, view: view, rect: null,
            map: info.map, cache: info.cache, before: info.before,
            hasHeights: false
        };
    }

    // Given a prepared measurement object, measures the position of an
    // actual character (or fetches it from the cache).
    function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
        if (prepared.before) ch = -1;
        var key = ch + (bias || ""), found;
        if (prepared.cache.hasOwnProperty(key)) {
            found = prepared.cache[key];
        } else {
            if (!prepared.rect)
                prepared.rect = prepared.view.text.getBoundingClientRect();
            if (!prepared.hasHeights) {
                ensureLineHeights(cm, prepared.view, prepared.rect);
                prepared.hasHeights = true;
            }
            found = measureCharInner(cm, prepared, ch, bias);
            if (!found.bogus) prepared.cache[key] = found;
        }
        return {
            left: found.left, right: found.right,
            top: varHeight ? found.rtop : found.top,
            bottom: varHeight ? found.rbottom : found.bottom
        };
    }

    var nullRect = { left: 0, right: 0, top: 0, bottom: 0 };

    function nodeAndOffsetInLineMap(map, ch, bias) {
        var node, start, end, collapse;
        // First, search the line map for the text node corresponding to,
        // or closest to, the target character.
        for (var i = 0; i < map.length; i += 3) {
            var mStart = map[i], mEnd = map[i + 1];
            if (ch < mStart) {
                start = 0; end = 1;
                collapse = "left";
            } else if (ch < mEnd) {
                start = ch - mStart;
                end = start + 1;
            } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
                end = mEnd - mStart;
                start = end - 1;
                if (ch >= mEnd) collapse = "right";
            }
            if (start != null) {
                node = map[i + 2];
                if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
                    collapse = bias;
                if (bias == "left" && start == 0)
                    while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
                        node = map[(i -= 3) + 2];
                        collapse = "left";
                    }
                if (bias == "right" && start == mEnd - mStart)
                    while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
                        node = map[(i += 3) + 2];
                        collapse = "right";
                    }
                break;
            }
        }
        return { node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd };
    }

    function measureCharInner(cm, prepared, ch, bias) {
        var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
        var node = place.node, start = place.start, end = place.end, collapse = place.collapse;

        var rect;
        if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
            for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
                while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start)))--start;
                while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end)))++end;
                if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
                    rect = node.parentNode.getBoundingClientRect();
                } else if (ie && cm.options.lineWrapping) {
                    var rects = range(node, start, end).getClientRects();
                    if (rects.length)
                        rect = rects[bias == "right" ? rects.length - 1 : 0];
                    else
                        rect = nullRect;
                } else {
                    rect = range(node, start, end).getBoundingClientRect() || nullRect;
                }
                if (rect.left || rect.right || start == 0) break;
                end = start;
                start = start - 1;
                collapse = "right";
            }
            if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
        } else { // If it is a widget, simply get the box for the whole widget.
            if (start > 0) collapse = bias = "right";
            var rects;
            if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
                rect = rects[bias == "right" ? rects.length - 1 : 0];
            else
                rect = node.getBoundingClientRect();
        }
        if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
            var rSpan = node.parentNode.getClientRects()[0];
            if (rSpan)
                rect = { left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom };
            else
                rect = nullRect;
        }

        var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
        var mid = (rtop + rbot) / 2;
        var heights = prepared.view.measure.heights;
        for (var i = 0; i < heights.length - 1; i++)
            if (mid < heights[i]) break;
        var top = i ? heights[i - 1] : 0, bot = heights[i];
        var result = {
            left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
            right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
            top: top, bottom: bot
        };
        if (!rect.left && !rect.right) result.bogus = true;
        if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }

        return result;
    }

    // Work around problem with bounding client rects on ranges being
    // returned incorrectly when zoomed on IE10 and below.
    function maybeUpdateRectForZooming(measure, rect) {
        if (!window.screen || screen.logicalXDPI == null ||
            screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
            return rect;
        var scaleX = screen.logicalXDPI / screen.deviceXDPI;
        var scaleY = screen.logicalYDPI / screen.deviceYDPI;
        return {
            left: rect.left * scaleX, right: rect.right * scaleX,
            top: rect.top * scaleY, bottom: rect.bottom * scaleY
        };
    }

    function clearLineMeasurementCacheFor(lineView) {
        if (lineView.measure) {
            lineView.measure.cache = {};
            lineView.measure.heights = null;
            if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
                lineView.measure.caches[i] = {};
        }
    }

    function clearLineMeasurementCache(cm) {
        cm.display.externalMeasure = null;
        removeChildren(cm.display.lineMeasure);
        for (var i = 0; i < cm.display.view.length; i++)
            clearLineMeasurementCacheFor(cm.display.view[i]);
    }

    function clearCaches(cm) {
        clearLineMeasurementCache(cm);
        cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
        if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
        cm.display.lineNumChars = null;
    }

    function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
    function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }

    // Converts a {top, bottom, left, right} box from line-local
    // coordinates into another coordinate system. Context may be one of
    // "line", "div" (display.lineDiv), "local"/null (editor), "window",
    // or "page".
    function intoCoordSystem(cm, lineObj, rect, context) {
        if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
            var size = widgetHeight(lineObj.widgets[i]);
            rect.top += size; rect.bottom += size;
        }
        if (context == "line") return rect;
        if (!context) context = "local";
        var yOff = heightAtLine(lineObj);
        if (context == "local") yOff += paddingTop(cm.display);
        else yOff -= cm.display.viewOffset;
        if (context == "page" || context == "window") {
            var lOff = cm.display.lineSpace.getBoundingClientRect();
            yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
            var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
            rect.left += xOff; rect.right += xOff;
        }
        rect.top += yOff; rect.bottom += yOff;
        return rect;
    }

    // Coverts a box from "div" coords to another coordinate system.
    // Context may be "window", "page", "div", or "local"/null.
    function fromCoordSystem(cm, coords, context) {
        if (context == "div") return coords;
        var left = coords.left, top = coords.top;
        // First move into "page" coordinate system
        if (context == "page") {
            left -= pageScrollX();
            top -= pageScrollY();
        } else if (context == "local" || !context) {
            var localBox = cm.display.sizer.getBoundingClientRect();
            left += localBox.left;
            top += localBox.top;
        }

        var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
        return { left: left - lineSpaceBox.left, top: top - lineSpaceBox.top };
    }

    function charCoords(cm, pos, context, lineObj, bias) {
        if (!lineObj) lineObj = getLine(cm.doc, pos.line);
        return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
    }

    // Returns a box for a given cursor position, which may have an
    // 'other' property containing the position of the secondary cursor
    // on a bidi boundary.
    function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
        lineObj = lineObj || getLine(cm.doc, pos.line);
        if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
        function get(ch, right) {
            var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
            if (right) m.left = m.right; else m.right = m.left;
            return intoCoordSystem(cm, lineObj, m, context);
        }
        function getBidi(ch, partPos) {
            var part = order[partPos], right = part.level % 2;
            if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
                part = order[--partPos];
                ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
                right = true;
            } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
                part = order[++partPos];
                ch = bidiLeft(part) - part.level % 2;
                right = false;
            }
            if (right && ch == part.to && ch > part.from) return get(ch - 1);
            return get(ch, right);
        }
        var order = getOrder(lineObj), ch = pos.ch;
        if (!order) return get(ch);
        var partPos = getBidiPartAt(order, ch);
        var val = getBidi(ch, partPos);
        if (bidiOther != null) val.other = getBidi(ch, bidiOther);
        return val;
    }

    // Used to cheaply estimate the coordinates for a position. Used for
    // intermediate scroll updates.
    function estimateCoords(cm, pos) {
        var left = 0, pos = clipPos(cm.doc, pos);
        if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
        var lineObj = getLine(cm.doc, pos.line);
        var top = heightAtLine(lineObj) + paddingTop(cm.display);
        return { left: left, right: left, top: top, bottom: top + lineObj.height };
    }

    // Positions returned by coordsChar contain some extra information.
    // xRel is the relative x position of the input coordinates compared
    // to the found position (so xRel > 0 means the coordinates are to
    // the right of the character position, for example). When outside
    // is true, that means the coordinates lie outside the line's
    // vertical range.
    function PosWithInfo(line, ch, outside, xRel) {
        var pos = Pos(line, ch);
        pos.xRel = xRel;
        if (outside) pos.outside = true;
        return pos;
    }

    // Compute the character position closest to the given coordinates.
    // Input must be lineSpace-local ("div" coordinate system).
    function coordsChar(cm, x, y) {
        var doc = cm.doc;
        y += cm.display.viewOffset;
        if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
        var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
        if (lineN > last)
            return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
        if (x < 0) x = 0;

        var lineObj = getLine(doc, lineN);
        for (; ;) {
            var found = coordsCharInner(cm, lineObj, lineN, x, y);
            var merged = collapsedSpanAtEnd(lineObj);
            var mergedPos = merged && merged.find(0, true);
            if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
                lineN = lineNo(lineObj = mergedPos.to.line);
            else
                return found;
        }
    }

    function coordsCharInner(cm, lineObj, lineNo, x, y) {
        var innerOff = y - heightAtLine(lineObj);
        var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
        var preparedMeasure = prepareMeasureForLine(cm, lineObj);

        function getX(ch) {
            var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
            wrongLine = true;
            if (innerOff > sp.bottom) return sp.left - adjust;
            else if (innerOff < sp.top) return sp.left + adjust;
            else wrongLine = false;
            return sp.left;
        }

        var bidi = getOrder(lineObj), dist = lineObj.text.length;
        var from = lineLeft(lineObj), to = lineRight(lineObj);
        var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;

        if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
        // Do a binary search between these bounds.
        for (; ;) {
            if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
                var ch = x < fromX || x - fromX <= toX - x ? from : to;
                var xDiff = x - (ch == from ? fromX : toX);
                while (isExtendingChar(lineObj.text.charAt(ch)))++ch;
                var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
                                      xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
                return pos;
            }
            var step = Math.ceil(dist / 2), middle = from + step;
            if (bidi) {
                middle = from;
                for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
            }
            var middleX = getX(middle);
            if (middleX > x) { to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step; }
            else { from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step; }
        }
    }

    var measureText;
    // Compute the default text height.
    function textHeight(display) {
        if (display.cachedTextHeight != null) return display.cachedTextHeight;
        if (measureText == null) {
            measureText = elt("pre");
            // Measure a bunch of lines, for browsers that compute
            // fractional heights.
            for (var i = 0; i < 49; ++i) {
                measureText.appendChild(document.createTextNode("x"));
                measureText.appendChild(elt("br"));
            }
            measureText.appendChild(document.createTextNode("x"));
        }
        removeChildrenAndAdd(display.measure, measureText);
        var height = measureText.offsetHeight / 50;
        if (height > 3) display.cachedTextHeight = height;
        removeChildren(display.measure);
        return height || 1;
    }

    // Compute the default character width.
    function charWidth(display) {
        if (display.cachedCharWidth != null) return display.cachedCharWidth;
        var anchor = elt("span", "xxxxxxxxxx");
        var pre = elt("pre", [anchor]);
        removeChildrenAndAdd(display.measure, pre);
        var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
        if (width > 2) display.cachedCharWidth = width;
        return width || 10;
    }

    // OPERATIONS

    // Operations are used to wrap a series of changes to the editor
    // state in such a way that each change won't have to update the
    // cursor and display (which would be awkward, slow, and
    // error-prone). Instead, display updates are batched and then all
    // combined and executed at once.

    var operationGroup = null;

    var nextOpId = 0;
    // Start a new operation.
    function startOperation(cm) {
        cm.curOp = {
            cm: cm,
            viewChanged: false,      // Flag that indicates that lines might need to be redrawn
            startHeight: cm.doc.height, // Used to detect need to update scrollbar
            forceUpdate: false,      // Used to force a redraw
            updateInput: null,       // Whether to reset the input textarea
            typing: false,           // Whether this reset should be careful to leave existing text (for compositing)
            changeObjs: null,        // Accumulated changes, for firing change events
            cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
            cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
            selectionChanged: false, // Whether the selection needs to be redrawn
            updateMaxLine: false,    // Set when the widest line needs to be determined anew
            scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
            scrollToPos: null,       // Used to scroll to a specific position
            focus: false,
            id: ++nextOpId           // Unique ID
        };
        if (operationGroup) {
            operationGroup.ops.push(cm.curOp);
        } else {
            cm.curOp.ownsGroup = operationGroup = {
                ops: [cm.curOp],
                delayedCallbacks: []
            };
        }
    }

    function fireCallbacksForOps(group) {
        // Calls delayed callbacks and cursorActivity handlers until no
        // new ones appear
        var callbacks = group.delayedCallbacks, i = 0;
        do {
            for (; i < callbacks.length; i++)
                callbacks[i].call(null);
            for (var j = 0; j < group.ops.length; j++) {
                var op = group.ops[j];
                if (op.cursorActivityHandlers)
                    while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
                        op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
            }
        } while (i < callbacks.length);
    }

    // Finish an operation, updating the display and signalling delayed events
    function endOperation(cm) {
        var op = cm.curOp, group = op.ownsGroup;
        if (!group) return;

        try { fireCallbacksForOps(group); }
        finally {
            operationGroup = null;
            for (var i = 0; i < group.ops.length; i++)
                group.ops[i].cm.curOp = null;
            endOperations(group);
        }
    }

    // The DOM updates done when an operation finishes are batched so
    // that the minimum number of relayouts are required.
    function endOperations(group) {
        var ops = group.ops;
        for (var i = 0; i < ops.length; i++) // Read DOM
            endOperation_R1(ops[i]);
        for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
            endOperation_W1(ops[i]);
        for (var i = 0; i < ops.length; i++) // Read DOM
            endOperation_R2(ops[i]);
        for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
            endOperation_W2(ops[i]);
        for (var i = 0; i < ops.length; i++) // Read DOM
            endOperation_finish(ops[i]);
    }

    function endOperation_R1(op) {
        var cm = op.cm, display = cm.display;
        maybeClipScrollbars(cm);
        if (op.updateMaxLine) findMaxLine(cm);

        op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
          op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
                             op.scrollToPos.to.line >= display.viewTo) ||
          display.maxLineChanged && cm.options.lineWrapping;
        op.update = op.mustUpdate &&
          new DisplayUpdate(cm, op.mustUpdate && { top: op.scrollTop, ensure: op.scrollToPos }, op.forceUpdate);
    }

    function endOperation_W1(op) {
        op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
    }

    function endOperation_R2(op) {
        var cm = op.cm, display = cm.display;
        if (op.updatedDisplay) updateHeightsInViewport(cm);

        op.barMeasure = measureForScrollbars(cm);

        // If the max line changed since it was last measured, measure it,
        // and ensure the document's width matches it.
        // updateDisplay_W2 will use these properties to do the actual resizing
        if (display.maxLineChanged && !cm.options.lineWrapping) {
            op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
            cm.display.sizerWidth = op.adjustWidthTo;
            op.barMeasure.scrollWidth =
              Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
            op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
        }

        if (op.updatedDisplay || op.selectionChanged)
            op.preparedSelection = display.input.prepareSelection();
    }

    function endOperation_W2(op) {
        var cm = op.cm;

        if (op.adjustWidthTo != null) {
            cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
            if (op.maxScrollLeft < cm.doc.scrollLeft)
                setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
            cm.display.maxLineChanged = false;
        }

        if (op.preparedSelection)
            cm.display.input.showSelection(op.preparedSelection);
        if (op.updatedDisplay)
            setDocumentHeight(cm, op.barMeasure);
        if (op.updatedDisplay || op.startHeight != cm.doc.height)
            updateScrollbars(cm, op.barMeasure);

        if (op.selectionChanged) restartBlink(cm);

        if (cm.state.focused && op.updateInput)
            cm.display.input.reset(op.typing);
        if (op.focus && op.focus == activeElt()) ensureFocus(op.cm);
    }

    function endOperation_finish(op) {
        var cm = op.cm, display = cm.display, doc = cm.doc;

        if (op.updatedDisplay) postUpdateDisplay(cm, op.update);

        // Abort mouse wheel delta measurement, when scrolling explicitly
        if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
            display.wheelStartX = display.wheelStartY = null;

        // Propagate the scroll position to the actual DOM scroller
        if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
            doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
            display.scrollbars.setScrollTop(doc.scrollTop);
            display.scroller.scrollTop = doc.scrollTop;
        }
        if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
            doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
            display.scrollbars.setScrollLeft(doc.scrollLeft);
            display.scroller.scrollLeft = doc.scrollLeft;
            alignHorizontally(cm);
        }
        // If we need to scroll a specific position into view, do so.
        if (op.scrollToPos) {
            var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
                                           clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
            if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
        }

        // Fire events for markers that are hidden/unidden by editing or
        // undoing
        var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
        if (hidden) for (var i = 0; i < hidden.length; ++i)
            if (!hidden[i].lines.length) signal(hidden[i], "hide");
        if (unhidden) for (var i = 0; i < unhidden.length; ++i)
            if (unhidden[i].lines.length) signal(unhidden[i], "unhide");

        if (display.wrapper.offsetHeight)
            doc.scrollTop = cm.display.scroller.scrollTop;

        // Fire change events, and delayed event handlers
        if (op.changeObjs)
            signal(cm, "changes", cm, op.changeObjs);
        if (op.update)
            op.update.finish();
    }

    // Run the given function in an operation
    function runInOp(cm, f) {
        if (cm.curOp) return f();
        startOperation(cm);
        try { return f(); }
        finally { endOperation(cm); }
    }
    // Wraps a function in an operation. Returns the wrapped function.
    function operation(cm, f) {
        return function () {
            if (cm.curOp) return f.apply(cm, arguments);
            startOperation(cm);
            try { return f.apply(cm, arguments); }
            finally { endOperation(cm); }
        };
    }
    // Used to add methods to editor and doc instances, wrapping them in
    // operations.
    function methodOp(f) {
        return function () {
            if (this.curOp) return f.apply(this, arguments);
            startOperation(this);
            try { return f.apply(this, arguments); }
            finally { endOperation(this); }
        };
    }
    function docMethodOp(f) {
        return function () {
            var cm = this.cm;
            if (!cm || cm.curOp) return f.apply(this, arguments);
            startOperation(cm);
            try { return f.apply(this, arguments); }
            finally { endOperation(cm); }
        };
    }

    // VIEW TRACKING

    // These objects are used to represent the visible (currently drawn)
    // part of the document. A LineView may correspond to multiple
    // logical lines, if those are connected by collapsed ranges.
    function LineView(doc, line, lineN) {
        // The starting line
        this.line = line;
        // Continuing lines, if any
        this.rest = visualLineContinued(line);
        // Number of logical lines in this visual line
        this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
        this.node = this.text = null;
        this.hidden = lineIsHidden(doc, line);
    }

    // Create a range of LineView objects for the given lines.
    function buildViewArray(cm, from, to) {
        var array = [], nextPos;
        for (var pos = from; pos < to; pos = nextPos) {
            var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
            nextPos = pos + view.size;
            array.push(view);
        }
        return array;
    }

    // Updates the display.view data structure for a given change to the
    // document. From and to are in pre-change coordinates. Lendiff is
    // the amount of lines added or subtracted by the change. This is
    // used for changes that span multiple lines, or change the way
    // lines are divided into visual lines. regLineChange (below)
    // registers single-line changes.
    function regChange(cm, from, to, lendiff) {
        if (from == null) from = cm.doc.first;
        if (to == null) to = cm.doc.first + cm.doc.size;
        if (!lendiff) lendiff = 0;

        var display = cm.display;
        if (lendiff && to < display.viewTo &&
            (display.updateLineNumbers == null || display.updateLineNumbers > from))
            display.updateLineNumbers = from;

        cm.curOp.viewChanged = true;

        if (from >= display.viewTo) { // Change after
            if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
                resetView(cm);
        } else if (to <= display.viewFrom) { // Change before
            if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
                resetView(cm);
            } else {
                display.viewFrom += lendiff;
                display.viewTo += lendiff;
            }
        } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
            resetView(cm);
        } else if (from <= display.viewFrom) { // Top overlap
            var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
            if (cut) {
                display.view = display.view.slice(cut.index);
                display.viewFrom = cut.lineN;
                display.viewTo += lendiff;
            } else {
                resetView(cm);
            }
        } else if (to >= display.viewTo) { // Bottom overlap
            var cut = viewCuttingPoint(cm, from, from, -1);
            if (cut) {
                display.view = display.view.slice(0, cut.index);
                display.viewTo = cut.lineN;
            } else {
                resetView(cm);
            }
        } else { // Gap in the middle
            var cutTop = viewCuttingPoint(cm, from, from, -1);
            var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
            if (cutTop && cutBot) {
                display.view = display.view.slice(0, cutTop.index)
                  .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
                  .concat(display.view.slice(cutBot.index));
                display.viewTo += lendiff;
            } else {
                resetView(cm);
            }
        }

        var ext = display.externalMeasured;
        if (ext) {
            if (to < ext.lineN)
                ext.lineN += lendiff;
            else if (from < ext.lineN + ext.size)
                display.externalMeasured = null;
        }
    }

    // Register a change to a single line. Type must be one of "text",
    // "gutter", "class", "widget"
    function regLineChange(cm, line, type) {
        cm.curOp.viewChanged = true;
        var display = cm.display, ext = cm.display.externalMeasured;
        if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
            display.externalMeasured = null;

        if (line < display.viewFrom || line >= display.viewTo) return;
        var lineView = display.view[findViewIndex(cm, line)];
        if (lineView.node == null) return;
        var arr = lineView.changes || (lineView.changes = []);
        if (indexOf(arr, type) == -1) arr.push(type);
    }

    // Clear the view.
    function resetView(cm) {
        cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
        cm.display.view = [];
        cm.display.viewOffset = 0;
    }

    // Find the view element corresponding to a given line. Return null
    // when the line isn't visible.
    function findViewIndex(cm, n) {
        if (n >= cm.display.viewTo) return null;
        n -= cm.display.viewFrom;
        if (n < 0) return null;
        var view = cm.display.view;
        for (var i = 0; i < view.length; i++) {
            n -= view[i].size;
            if (n < 0) return i;
        }
    }

    function viewCuttingPoint(cm, oldN, newN, dir) {
        var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
        if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
            return { index: index, lineN: newN };
        for (var i = 0, n = cm.display.viewFrom; i < index; i++)
            n += view[i].size;
        if (n != oldN) {
            if (dir > 0) {
                if (index == view.length - 1) return null;
                diff = (n + view[index].size) - oldN;
                index++;
            } else {
                diff = n - oldN;
            }
            oldN += diff; newN += diff;
        }
        while (visualLineNo(cm.doc, newN) != newN) {
            if (index == (dir < 0 ? 0 : view.length - 1)) return null;
            newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
            index += dir;
        }
        return { index: index, lineN: newN };
    }

    // Force the view to cover a given range, adding empty view element
    // or clipping off existing ones as needed.
    function adjustView(cm, from, to) {
        var display = cm.display, view = display.view;
        if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
            display.view = buildViewArray(cm, from, to);
            display.viewFrom = from;
        } else {
            if (display.viewFrom > from)
                display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
            else if (display.viewFrom < from)
                display.view = display.view.slice(findViewIndex(cm, from));
            display.viewFrom = from;
            if (display.viewTo < to)
                display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
            else if (display.viewTo > to)
                display.view = display.view.slice(0, findViewIndex(cm, to));
        }
        display.viewTo = to;
    }

    // Count the number of lines in the view whose DOM representation is
    // out of date (or nonexistent).
    function countDirtyView(cm) {
        var view = cm.display.view, dirty = 0;
        for (var i = 0; i < view.length; i++) {
            var lineView = view[i];
            if (!lineView.hidden && (!lineView.node || lineView.changes))++dirty;
        }
        return dirty;
    }

    // EVENT HANDLERS

    // Attach the necessary event handlers when initializing the editor
    function registerEventHandlers(cm) {
        var d = cm.display;
        on(d.scroller, "mousedown", operation(cm, onMouseDown));
        // Older IE's will not fire a second mousedown for a double click
        if (ie && ie_version < 11)
            on(d.scroller, "dblclick", operation(cm, function (e) {
                if (signalDOMEvent(cm, e)) return;
                var pos = posFromMouse(cm, e);
                if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
                e_preventDefault(e);
                var word = cm.findWordAt(pos);
                extendSelection(cm.doc, word.anchor, word.head);
            }));
        else
            on(d.scroller, "dblclick", function (e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
        // Some browsers fire contextmenu *after* opening the menu, at
        // which point we can't mess with it anymore. Context menu is
        // handled in onMouseDown for these browsers.
        if (!captureRightClick) on(d.scroller, "contextmenu", function (e) { onContextMenu(cm, e); });

        // Used to suppress mouse event handling when a touch happens
        var touchFinished, prevTouch = { end: 0 };
        function finishTouch() {
            if (d.activeTouch) {
                touchFinished = setTimeout(function () { d.activeTouch = null; }, 1000);
                prevTouch = d.activeTouch;
                prevTouch.end = +new Date;
            }
        };
        function isMouseLikeTouchEvent(e) {
            if (e.touches.length != 1) return false;
            var touch = e.touches[0];
            return touch.radiusX <= 1 && touch.radiusY <= 1;
        }
        function farAway(touch, other) {
            if (other.left == null) return true;
            var dx = other.left - touch.left, dy = other.top - touch.top;
            return dx * dx + dy * dy > 20 * 20;
        }
        on(d.scroller, "touchstart", function (e) {
            if (!isMouseLikeTouchEvent(e)) {
                clearTimeout(touchFinished);
                var now = +new Date;
                d.activeTouch = {
                    start: now, moved: false,
                    prev: now - prevTouch.end <= 300 ? prevTouch : null
                };
                if (e.touches.length == 1) {
                    d.activeTouch.left = e.touches[0].pageX;
                    d.activeTouch.top = e.touches[0].pageY;
                }
            }
        });
        on(d.scroller, "touchmove", function () {
            if (d.activeTouch) d.activeTouch.moved = true;
        });
        on(d.scroller, "touchend", function (e) {
            var touch = d.activeTouch;
            if (touch && !eventInWidget(d, e) && touch.left != null &&
                !touch.moved && new Date - touch.start < 300) {
                var pos = cm.coordsChar(d.activeTouch, "page"), range;
                if (!touch.prev || farAway(touch, touch.prev)) // Single tap
                    range = new Range(pos, pos);
                else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
                    range = cm.findWordAt(pos);
                else // Triple tap
                    range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
                cm.setSelection(range.anchor, range.head);
                cm.focus();
                e_preventDefault(e);
            }
            finishTouch();
        });
        on(d.scroller, "touchcancel", finishTouch);

        // Sync scrolling between fake scrollbars and real scrollable
        // area, ensure viewport is updated when scrolling.
        on(d.scroller, "scroll", function () {
            if (d.scroller.clientHeight) {
                setScrollTop(cm, d.scroller.scrollTop);
                setScrollLeft(cm, d.scroller.scrollLeft, true);
                signal(cm, "scroll", cm);
            }
        });

        // Listen to wheel events in order to try and update the viewport on time.
        on(d.scroller, "mousewheel", function (e) { onScrollWheel(cm, e); });
        on(d.scroller, "DOMMouseScroll", function (e) { onScrollWheel(cm, e); });

        // Prevent wrapper from ever scrolling
        on(d.wrapper, "scroll", function () { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });

        d.dragFunctions = {
            enter: function (e) { if (!signalDOMEvent(cm, e)) e_stop(e); },
            over: function (e) { if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); } },
            start: function (e) { onDragStart(cm, e); },
            drop: operation(cm, onDrop),
            leave: function () { clearDragCursor(cm); }
        };

        var inp = d.input.getField();
        on(inp, "keyup", function (e) { onKeyUp.call(cm, e); });
        on(inp, "keydown", operation(cm, onKeyDown));
        on(inp, "keypress", operation(cm, onKeyPress));
        on(inp, "focus", bind(onFocus, cm));
        on(inp, "blur", bind(onBlur, cm));
    }

    function dragDropChanged(cm, value, old) {
        var wasOn = old && old != CodeMirror.Init;
        if (!value != !wasOn) {
            var funcs = cm.display.dragFunctions;
            var toggle = value ? on : off;
            toggle(cm.display.scroller, "dragstart", funcs.start);
            toggle(cm.display.scroller, "dragenter", funcs.enter);
            toggle(cm.display.scroller, "dragover", funcs.over);
            toggle(cm.display.scroller, "dragleave", funcs.leave);
            toggle(cm.display.scroller, "drop", funcs.drop);
        }
    }

    // Called when the window resizes
    function onResize(cm) {
        var d = cm.display;
        if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
            return;
        // Might be a text scaling operation, clear size caches.
        d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
        d.scrollbarsClipped = false;
        cm.setSize();
    }

    // MOUSE EVENTS

    // Return true when the given mouse event happened in a widget
    function eventInWidget(display, e) {
        for (var n = e_target(e) ; n != display.wrapper; n = n.parentNode) {
            if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
                (n.parentNode == display.sizer && n != display.mover))
                return true;
        }
    }

    // Given a mouse event, find the corresponding position. If liberal
    // is false, it checks whether a gutter or scrollbar was clicked,
    // and returns null if it was. forRect is used by rectangular
    // selections, and tries to estimate a character position even for
    // coordinates beyond the right of the text.
    function posFromMouse(cm, e, liberal, forRect) {
        var display = cm.display;
        if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;

        var x, y, space = display.lineSpace.getBoundingClientRect();
        // Fails unpredictably on IE[67] when mouse is dragged around quickly.
        try { x = e.clientX - space.left; y = e.clientY - space.top; }
        catch (e) { return null; }
        var coords = coordsChar(cm, x, y), line;
        if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
            var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
            coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
        }
        return coords;
    }

    // A mouse down can be a single click, double click, triple click,
    // start of selection drag, start of text drag, new cursor
    // (ctrl-click), rectangle drag (alt-drag), or xwin
    // middle-click-paste. Or it might be a click on something we should
    // not interfere with, such as a scrollbar or widget.
    function onMouseDown(e) {
        var cm = this, display = cm.display;
        if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
        display.shift = e.shiftKey;

        if (eventInWidget(display, e)) {
            if (!webkit) {
                // Briefly turn off draggability, to allow widgets to do
                // normal dragging things.
                display.scroller.draggable = false;
                setTimeout(function () { display.scroller.draggable = true; }, 100);
            }
            return;
        }
        if (clickInGutter(cm, e)) return;
        var start = posFromMouse(cm, e);
        window.focus();

        switch (e_button(e)) {
            case 1:
                // #3261: make sure, that we're not starting a second selection
                if (cm.state.selectingText)
                    cm.state.selectingText(e);
                else if (start)
                    leftButtonDown(cm, e, start);
                else if (e_target(e) == display.scroller)
                    e_preventDefault(e);
                break;
            case 2:
                if (webkit) cm.state.lastMiddleDown = +new Date;
                if (start) extendSelection(cm.doc, start);
                setTimeout(function () { display.input.focus(); }, 20);
                e_preventDefault(e);
                break;
            case 3:
                if (captureRightClick) onContextMenu(cm, e);
                else delayBlurEvent(cm);
                break;
        }
    }

    var lastClick, lastDoubleClick;
    function leftButtonDown(cm, e, start) {
        if (ie) setTimeout(bind(ensureFocus, cm), 0);
        else cm.curOp.focus = activeElt();

        var now = +new Date, type;
        if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
            type = "triple";
        } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
            type = "double";
            lastDoubleClick = { time: now, pos: start };
        } else {
            type = "single";
            lastClick = { time: now, pos: start };
        }

        var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
        if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
            type == "single" && (contained = sel.contains(start)) > -1 &&
            (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
            (cmp(contained.to(), start) > 0 || start.xRel < 0))
            leftButtonStartDrag(cm, e, start, modifier);
        else
            leftButtonSelect(cm, e, start, type, modifier);
    }

    // Start a text drag. When it ends, see if any dragging actually
    // happen, and treat as a click if it didn't.
    function leftButtonStartDrag(cm, e, start, modifier) {
        var display = cm.display, startTime = +new Date;
        var dragEnd = operation(cm, function (e2) {
            if (webkit) display.scroller.draggable = false;
            cm.state.draggingText = false;
            off(document, "mouseup", dragEnd);
            off(display.scroller, "drop", dragEnd);
            if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
                e_preventDefault(e2);
                if (!modifier && +new Date - 200 < startTime)
                    extendSelection(cm.doc, start);
                // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
                if (webkit || ie && ie_version == 9)
                    setTimeout(function () { document.body.focus(); display.input.focus(); }, 20);
                else
                    display.input.focus();
            }
        });
        // Let the drag handler handle this.
        if (webkit) display.scroller.draggable = true;
        cm.state.draggingText = dragEnd;
        // IE's approach to draggable
        if (display.scroller.dragDrop) display.scroller.dragDrop();
        on(document, "mouseup", dragEnd);
        on(display.scroller, "drop", dragEnd);
    }

    // Normal selection, as opposed to text dragging.
    function leftButtonSelect(cm, e, start, type, addNew) {
        var display = cm.display, doc = cm.doc;
        e_preventDefault(e);

        var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
        if (addNew && !e.shiftKey) {
            ourIndex = doc.sel.contains(start);
            if (ourIndex > -1)
                ourRange = ranges[ourIndex];
            else
                ourRange = new Range(start, start);
        } else {
            ourRange = doc.sel.primary();
            ourIndex = doc.sel.primIndex;
        }

        if (e.altKey) {
            type = "rect";
            if (!addNew) ourRange = new Range(start, start);
            start = posFromMouse(cm, e, true, true);
            ourIndex = -1;
        } else if (type == "double") {
            var word = cm.findWordAt(start);
            if (cm.display.shift || doc.extend)
                ourRange = extendRange(doc, ourRange, word.anchor, word.head);
            else
                ourRange = word;
        } else if (type == "triple") {
            var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
            if (cm.display.shift || doc.extend)
                ourRange = extendRange(doc, ourRange, line.anchor, line.head);
            else
                ourRange = line;
        } else {
            ourRange = extendRange(doc, ourRange, start);
        }

        if (!addNew) {
            ourIndex = 0;
            setSelection(doc, new Selection([ourRange], 0), sel_mouse);
            startSel = doc.sel;
        } else if (ourIndex == -1) {
            ourIndex = ranges.length;
            setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
                         { scroll: false, origin: "*mouse" });
        } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
            setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
                         { scroll: false, origin: "*mouse" });
            startSel = doc.sel;
        } else {
            replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
        }

        var lastPos = start;
        function extendTo(pos) {
            if (cmp(lastPos, pos) == 0) return;
            lastPos = pos;

            if (type == "rect") {
                var ranges = [], tabSize = cm.options.tabSize;
                var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
                var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
                var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
                for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)) ;
                     line <= end; line++) {
                    var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
                    if (left == right)
                        ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
                    else if (text.length > leftPos)
                        ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
                }
                if (!ranges.length) ranges.push(new Range(start, start));
                setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
                             { origin: "*mouse", scroll: false });
                cm.scrollIntoView(pos);
            } else {
                var oldRange = ourRange;
                var anchor = oldRange.anchor, head = pos;
                if (type != "single") {
                    if (type == "double")
                        var range = cm.findWordAt(pos);
                    else
                        var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
                    if (cmp(range.anchor, anchor) > 0) {
                        head = range.head;
                        anchor = minPos(oldRange.from(), range.anchor);
                    } else {
                        head = range.anchor;
                        anchor = maxPos(oldRange.to(), range.head);
                    }
                }
                var ranges = startSel.ranges.slice(0);
                ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
                setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
            }
        }

        var editorSize = display.wrapper.getBoundingClientRect();
        // Used to ensure timeout re-tries don't fire when another extend
        // happened in the meantime (clearTimeout isn't reliable -- at
        // least on Chrome, the timeouts still happen even when cleared,
        // if the clear happens after their scheduled firing time).
        var counter = 0;

        function extend(e) {
            var curCount = ++counter;
            var cur = posFromMouse(cm, e, true, type == "rect");
            if (!cur) return;
            if (cmp(cur, lastPos) != 0) {
                cm.curOp.focus = activeElt();
                extendTo(cur);
                var visible = visibleLines(display, doc);
                if (cur.line >= visible.to || cur.line < visible.from)
                    setTimeout(operation(cm, function () { if (counter == curCount) extend(e); }), 150);
            } else {
                var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
                if (outside) setTimeout(operation(cm, function () {
                    if (counter != curCount) return;
                    display.scroller.scrollTop += outside;
                    extend(e);
                }), 50);
            }
        }

        function done(e) {
            cm.state.selectingText = false;
            counter = Infinity;
            e_preventDefault(e);
            display.input.focus();
            off(document, "mousemove", move);
            off(document, "mouseup", up);
            doc.history.lastSelOrigin = null;
        }

        var move = operation(cm, function (e) {
            if (!e_button(e)) done(e);
            else extend(e);
        });
        var up = operation(cm, done);
        cm.state.selectingText = up;
        on(document, "mousemove", move);
        on(document, "mouseup", up);
    }

    // Determines whether an event happened in the gutter, and fires the
    // handlers for the corresponding event.
    function gutterEvent(cm, e, type, prevent, signalfn) {
        try { var mX = e.clientX, mY = e.clientY; }
        catch (e) { return false; }
        if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
        if (prevent) e_preventDefault(e);

        var display = cm.display;
        var lineBox = display.lineDiv.getBoundingClientRect();

        if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
        mY -= lineBox.top - display.viewOffset;

        for (var i = 0; i < cm.options.gutters.length; ++i) {
            var g = display.gutters.childNodes[i];
            if (g && g.getBoundingClientRect().right >= mX) {
                var line = lineAtHeight(cm.doc, mY);
                var gutter = cm.options.gutters[i];
                signalfn(cm, type, cm, line, gutter, e);
                return e_defaultPrevented(e);
            }
        }
    }

    function clickInGutter(cm, e) {
        return gutterEvent(cm, e, "gutterClick", true, signalLater);
    }

    // Kludge to work around strange IE behavior where it'll sometimes
    // re-fire a series of drag-related events right after the drop (#1551)
    var lastDrop = 0;

    function onDrop(e) {
        var cm = this;
        clearDragCursor(cm);
        if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
            return;
        e_preventDefault(e);
        if (ie) lastDrop = +new Date;
        var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
        if (!pos || isReadOnly(cm)) return;
        // Might be a file drop, in which case we simply extract the text
        // and insert it.
        if (files && files.length && window.FileReader && window.File) {
            var n = files.length, text = Array(n), read = 0;
            var loadFile = function (file, i) {
                var reader = new FileReader;
                reader.onload = operation(cm, function () {
                    text[i] = reader.result;
                    if (++read == n) {
                        pos = clipPos(cm.doc, pos);
                        var change = {
                            from: pos, to: pos,
                            text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
                            origin: "paste"
                        };
                        makeChange(cm.doc, change);
                        setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
                    }
                });
                reader.readAsText(file);
            };
            for (var i = 0; i < n; ++i) loadFile(files[i], i);
        } else { // Normal drop
            // Don't do a replace if the drop happened inside of the selected text.
            if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
                cm.state.draggingText(e);
                // Ensure the editor is re-focused
                setTimeout(function () { cm.display.input.focus(); }, 20);
                return;
            }
            try {
                var text = e.dataTransfer.getData("Text");
                if (text) {
                    if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
                        var selected = cm.listSelections();
                    setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
                    if (selected) for (var i = 0; i < selected.length; ++i)
                        replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
                    cm.replaceSelection(text, "around", "paste");
                    cm.display.input.focus();
                }
            }
            catch (e) { }
        }
    }

    function onDragStart(cm, e) {
        if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
        if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;

        e.dataTransfer.setData("Text", cm.getSelection());

        // Use dummy image instead of default browsers image.
        // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
        if (e.dataTransfer.setDragImage && !safari) {
            var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
            img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
            if (presto) {
                img.width = img.height = 1;
                cm.display.wrapper.appendChild(img);
                // Force a relayout, or Opera won't use our image for some obscure reason
                img._top = img.offsetTop;
            }
            e.dataTransfer.setDragImage(img, 0, 0);
            if (presto) img.parentNode.removeChild(img);
        }
    }

    function onDragOver(cm, e) {
        var pos = posFromMouse(cm, e);
        if (!pos) return;
        var frag = document.createDocumentFragment();
        drawSelectionCursor(cm, pos, frag);
        if (!cm.display.dragCursor) {
            cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
            cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
        }
        removeChildrenAndAdd(cm.display.dragCursor, frag);
    }

    function clearDragCursor(cm) {
        if (cm.display.dragCursor) {
            cm.display.lineSpace.removeChild(cm.display.dragCursor);
            cm.display.dragCursor = null;
        }
    }

    // SCROLL EVENTS

    // Sync the scrollable area and scrollbars, ensure the viewport
    // covers the visible area.
    function setScrollTop(cm, val) {
        if (Math.abs(cm.doc.scrollTop - val) < 2) return;
        cm.doc.scrollTop = val;
        if (!gecko) updateDisplaySimple(cm, { top: val });
        if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
        cm.display.scrollbars.setScrollTop(val);
        if (gecko) updateDisplaySimple(cm);
        startWorker(cm, 100);
    }
    // Sync scroller and scrollbar, ensure the gutter elements are
    // aligned.
    function setScrollLeft(cm, val, isScroller) {
        if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
        val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
        cm.doc.scrollLeft = val;
        alignHorizontally(cm);
        if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
        cm.display.scrollbars.setScrollLeft(val);
    }

    // Since the delta values reported on mouse wheel events are
    // unstandardized between browsers and even browser versions, and
    // generally horribly unpredictable, this code starts by measuring
    // the scroll effect that the first few mouse wheel events have,
    // and, from that, detects the way it can convert deltas to pixel
    // offsets afterwards.
    //
    // The reason we want to know the amount a wheel event will scroll
    // is that it gives us a chance to update the display before the
    // actual scrolling happens, reducing flickering.

    var wheelSamples = 0, wheelPixelsPerUnit = null;
    // Fill in a browser-detected starting value on browsers where we
    // know one. These don't have to be accurate -- the result of them
    // being wrong would just be a slight flicker on the first wheel
    // scroll (if it is large enough).
    if (ie) wheelPixelsPerUnit = -.53;
    else if (gecko) wheelPixelsPerUnit = 15;
    else if (chrome) wheelPixelsPerUnit = -.7;
    else if (safari) wheelPixelsPerUnit = -1 / 3;

    var wheelEventDelta = function (e) {
        var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
        if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
        if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
        else if (dy == null) dy = e.wheelDelta;
        return { x: dx, y: dy };
    };
    CodeMirror.wheelEventPixels = function (e) {
        var delta = wheelEventDelta(e);
        delta.x *= wheelPixelsPerUnit;
        delta.y *= wheelPixelsPerUnit;
        return delta;
    };

    function onScrollWheel(cm, e) {
        var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;

        var display = cm.display, scroll = display.scroller;
        // Quit if there's nothing to scroll here
        if (!(dx && scroll.scrollWidth > scroll.clientWidth ||
              dy && scroll.scrollHeight > scroll.clientHeight)) return;

        // Webkit browsers on OS X abort momentum scrolls when the target
        // of the scroll event is removed from the scrollable element.
        // This hack (see related code in patchDisplay) makes sure the
        // element is kept around.
        if (dy && mac && webkit) {
            outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
                for (var i = 0; i < view.length; i++) {
                    if (view[i].node == cur) {
                        cm.display.currentWheelTarget = cur;
                        break outer;
                    }
                }
            }
        }

        // On some browsers, horizontal scrolling will cause redraws to
        // happen before the gutter has been realigned, causing it to
        // wriggle around in a most unseemly way. When we have an
        // estimated pixels/delta value, we just handle horizontal
        // scrolling entirely here. It'll be slightly off from native, but
        // better than glitching out.
        if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
            if (dy)
                setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
            setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
            e_preventDefault(e);
            display.wheelStartX = null; // Abort measurement, if in progress
            return;
        }

        // 'Project' the visible viewport to cover the area that is being
        // scrolled into view (if we know enough to estimate it).
        if (dy && wheelPixelsPerUnit != null) {
            var pixels = dy * wheelPixelsPerUnit;
            var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
            if (pixels < 0) top = Math.max(0, top + pixels - 50);
            else bot = Math.min(cm.doc.height, bot + pixels + 50);
            updateDisplaySimple(cm, { top: top, bottom: bot });
        }

        if (wheelSamples < 20) {
            if (display.wheelStartX == null) {
                display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
                display.wheelDX = dx; display.wheelDY = dy;
                setTimeout(function () {
                    if (display.wheelStartX == null) return;
                    var movedX = scroll.scrollLeft - display.wheelStartX;
                    var movedY = scroll.scrollTop - display.wheelStartY;
                    var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
                      (movedX && display.wheelDX && movedX / display.wheelDX);
                    display.wheelStartX = display.wheelStartY = null;
                    if (!sample) return;
                    wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
                    ++wheelSamples;
                }, 200);
            } else {
                display.wheelDX += dx; display.wheelDY += dy;
            }
        }
    }

    // KEY EVENTS

    // Run a handler that was bound to a key.
    function doHandleBinding(cm, bound, dropShift) {
        if (typeof bound == "string") {
            bound = commands[bound];
            if (!bound) return false;
        }
        // Ensure previous input has been read, so that the handler sees a
        // consistent view of the document
        cm.display.input.ensurePolled();
        var prevShift = cm.display.shift, done = false;
        try {
            if (isReadOnly(cm)) cm.state.suppressEdits = true;
            if (dropShift) cm.display.shift = false;
            done = bound(cm) != Pass;
        } finally {
            cm.display.shift = prevShift;
            cm.state.suppressEdits = false;
        }
        return done;
    }

    function lookupKeyForEditor(cm, name, handle) {
        for (var i = 0; i < cm.state.keyMaps.length; i++) {
            var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
            if (result) return result;
        }
        return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
          || lookupKey(name, cm.options.keyMap, handle, cm);
    }

    var stopSeq = new Delayed;
    function dispatchKey(cm, name, e, handle) {
        var seq = cm.state.keySeq;
        if (seq) {
            if (isModifierKey(name)) return "handled";
            stopSeq.set(50, function () {
                if (cm.state.keySeq == seq) {
                    cm.state.keySeq = null;
                    cm.display.input.reset();
                }
            });
            name = seq + " " + name;
        }
        var result = lookupKeyForEditor(cm, name, handle);

        if (result == "multi")
            cm.state.keySeq = name;
        if (result == "handled")
            signalLater(cm, "keyHandled", cm, name, e);

        if (result == "handled" || result == "multi") {
            e_preventDefault(e);
            restartBlink(cm);
        }

        if (seq && !result && /\'$/.test(name)) {
            e_preventDefault(e);
            return true;
        }
        return !!result;
    }

    // Handle a key from the keydown event.
    function handleKeyBinding(cm, e) {
        var name = keyName(e, true);
        if (!name) return false;

        if (e.shiftKey && !cm.state.keySeq) {
            // First try to resolve full name (including 'Shift-'). Failing
            // that, see if there is a cursor-motion command (starting with
            // 'go') bound to the keyname without 'Shift-'.
            return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
                || dispatchKey(cm, name, e, function (b) {
                    if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
                        return doHandleBinding(cm, b);
                });
        } else {
            return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); });
        }
    }

    // Handle a key from the keypress event
    function handleCharBinding(cm, e, ch) {
        return dispatchKey(cm, "'" + ch + "'", e,
                           function (b) { return doHandleBinding(cm, b, true); });
    }

    var lastStoppedKey = null;
    function onKeyDown(e) {
        var cm = this;
        cm.curOp.focus = activeElt();
        if (signalDOMEvent(cm, e)) return;
        // IE does strange things with escape.
        if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
        var code = e.keyCode;
        cm.display.shift = code == 16 || e.shiftKey;
        var handled = handleKeyBinding(cm, e);
        if (presto) {
            lastStoppedKey = handled ? code : null;
            // Opera has no cut event... we try to at least catch the key combo
            if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
                cm.replaceSelection("", null, "cut");
        }

        // Turn mouse into crosshair when Alt is held on Mac.
        if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
            showCrossHair(cm);
    }

    function showCrossHair(cm) {
        var lineDiv = cm.display.lineDiv;
        addClass(lineDiv, "CodeMirror-crosshair");

        function up(e) {
            if (e.keyCode == 18 || !e.altKey) {
                rmClass(lineDiv, "CodeMirror-crosshair");
                off(document, "keyup", up);
                off(document, "mouseover", up);
            }
        }
        on(document, "keyup", up);
        on(document, "mouseover", up);
    }

    function onKeyUp(e) {
        if (e.keyCode == 16) this.doc.sel.shift = false;
        signalDOMEvent(this, e);
    }

    function onKeyPress(e) {
        var cm = this;
        if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
        var keyCode = e.keyCode, charCode = e.charCode;
        if (presto && keyCode == lastStoppedKey) { lastStoppedKey = null; e_preventDefault(e); return; }
        if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
        var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
        if (handleCharBinding(cm, e, ch)) return;
        cm.display.input.onKeyPress(e);
    }

    // FOCUS/BLUR EVENTS

    function delayBlurEvent(cm) {
        cm.state.delayingBlurEvent = true;
        setTimeout(function () {
            if (cm.state.delayingBlurEvent) {
                cm.state.delayingBlurEvent = false;
                onBlur(cm);
            }
        }, 100);
    }

    function onFocus(cm) {
        if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;

        if (cm.options.readOnly == "nocursor") return;
        if (!cm.state.focused) {
            signal(cm, "focus", cm);
            cm.state.focused = true;
            addClass(cm.display.wrapper, "CodeMirror-focused");
            // This test prevents this from firing when a context
            // menu is closed (since the input reset would kill the
            // select-all detection hack)
            if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
                cm.display.input.reset();
                if (webkit) setTimeout(function () { cm.display.input.reset(true); }, 20); // Issue #1730
            }
            cm.display.input.receivedFocus();
        }
        restartBlink(cm);
    }
    function onBlur(cm) {
        if (cm.state.delayingBlurEvent) return;

        if (cm.state.focused) {
            signal(cm, "blur", cm);
            cm.state.focused = false;
            rmClass(cm.display.wrapper, "CodeMirror-focused");
        }
        clearInterval(cm.display.blinker);
        setTimeout(function () { if (!cm.state.focused) cm.display.shift = false; }, 150);
    }

    // CONTEXT MENU HANDLING

    // To make the context menu work, we need to briefly unhide the
    // textarea (making it as unobtrusive as possible) to let the
    // right-click take effect on it.
    function onContextMenu(cm, e) {
        if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
        if (signalDOMEvent(cm, e, "contextmenu")) return;
        cm.display.input.onContextMenu(e);
    }

    function contextMenuInGutter(cm, e) {
        if (!hasHandler(cm, "gutterContextMenu")) return false;
        return gutterEvent(cm, e, "gutterContextMenu", false, signal);
    }

    // UPDATING

    // Compute the position of the end of a change (its 'to' property
    // refers to the pre-change end).
    var changeEnd = CodeMirror.changeEnd = function (change) {
        if (!change.text) return change.to;
        return Pos(change.from.line + change.text.length - 1,
                   lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
    };

    // Adjust a position to refer to the post-change position of the
    // same text, or the end of the change if the change covers it.
    function adjustForChange(pos, change) {
        if (cmp(pos, change.from) < 0) return pos;
        if (cmp(pos, change.to) <= 0) return changeEnd(change);

        var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
        if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
        return Pos(line, ch);
    }

    function computeSelAfterChange(doc, change) {
        var out = [];
        for (var i = 0; i < doc.sel.ranges.length; i++) {
            var range = doc.sel.ranges[i];
            out.push(new Range(adjustForChange(range.anchor, change),
                               adjustForChange(range.head, change)));
        }
        return normalizeSelection(out, doc.sel.primIndex);
    }

    function offsetPos(pos, old, nw) {
        if (pos.line == old.line)
            return Pos(nw.line, pos.ch - old.ch + nw.ch);
        else
            return Pos(nw.line + (pos.line - old.line), pos.ch);
    }

    // Used by replaceSelections to allow moving the selection to the
    // start or around the replaced test. Hint may be "start" or "around".
    function computeReplacedSel(doc, changes, hint) {
        var out = [];
        var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
        for (var i = 0; i < changes.length; i++) {
            var change = changes[i];
            var from = offsetPos(change.from, oldPrev, newPrev);
            var to = offsetPos(changeEnd(change), oldPrev, newPrev);
            oldPrev = change.to;
            newPrev = to;
            if (hint == "around") {
                var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
                out[i] = new Range(inv ? to : from, inv ? from : to);
            } else {
                out[i] = new Range(from, from);
            }
        }
        return new Selection(out, doc.sel.primIndex);
    }

    // Allow "beforeChange" event handlers to influence a change
    function filterChange(doc, change, update) {
        var obj = {
            canceled: false,
            from: change.from,
            to: change.to,
            text: change.text,
            origin: change.origin,
            cancel: function () { this.canceled = true; }
        };
        if (update) obj.update = function (from, to, text, origin) {
            if (from) this.from = clipPos(doc, from);
            if (to) this.to = clipPos(doc, to);
            if (text) this.text = text;
            if (origin !== undefined) this.origin = origin;
        };
        signal(doc, "beforeChange", doc, obj);
        if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);

        if (obj.canceled) return null;
        return { from: obj.from, to: obj.to, text: obj.text, origin: obj.origin };
    }

    // Apply a change to a document, and add it to the document's
    // history, and propagating it to all linked documents.
    function makeChange(doc, change, ignoreReadOnly) {
        if (doc.cm) {
            if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
            if (doc.cm.state.suppressEdits) return;
        }

        if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
            change = filterChange(doc, change, true);
            if (!change) return;
        }

        // Possibly split or suppress the update based on the presence
        // of read-only spans in its range.
        var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
        if (split) {
            for (var i = split.length - 1; i >= 0; --i)
                makeChangeInner(doc, { from: split[i].from, to: split[i].to, text: i ? [""] : change.text });
        } else {
            makeChangeInner(doc, change);
        }
    }

    function makeChangeInner(doc, change) {
        if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
        var selAfter = computeSelAfterChange(doc, change);
        addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);

        makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
        var rebased = [];

        linkedDocs(doc, function (doc, sharedHist) {
            if (!sharedHist && indexOf(rebased, doc.history) == -1) {
                rebaseHist(doc.history, change);
                rebased.push(doc.history);
            }
            makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
        });
    }

    // Revert a change stored in a document's history.
    function makeChangeFromHistory(doc, type, allowSelectionOnly) {
        if (doc.cm && doc.cm.state.suppressEdits) return;

        var hist = doc.history, event, selAfter = doc.sel;
        var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;

        // Verify that there is a useable event (so that ctrl-z won't
        // needlessly clear selection events)
        for (var i = 0; i < source.length; i++) {
            event = source[i];
            if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
                break;
        }
        if (i == source.length) return;
        hist.lastOrigin = hist.lastSelOrigin = null;

        for (; ;) {
            event = source.pop();
            if (event.ranges) {
                pushSelectionToHistory(event, dest);
                if (allowSelectionOnly && !event.equals(doc.sel)) {
                    setSelection(doc, event, { clearRedo: false });
                    return;
                }
                selAfter = event;
            }
            else break;
        }

        // Build up a reverse change object to add to the opposite history
        // stack (redo when undoing, and vice versa).
        var antiChanges = [];
        pushSelectionToHistory(selAfter, dest);
        dest.push({ changes: antiChanges, generation: hist.generation });
        hist.generation = event.generation || ++hist.maxGeneration;

        var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");

        for (var i = event.changes.length - 1; i >= 0; --i) {
            var change = event.changes[i];
            change.origin = type;
            if (filter && !filterChange(doc, change, false)) {
                source.length = 0;
                return;
            }

            antiChanges.push(historyChangeFromChange(doc, change));

            var after = i ? computeSelAfterChange(doc, change) : lst(source);
            makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
            if (!i && doc.cm) doc.cm.scrollIntoView({ from: change.from, to: changeEnd(change) });
            var rebased = [];

            // Propagate to the linked documents
            linkedDocs(doc, function (doc, sharedHist) {
                if (!sharedHist && indexOf(rebased, doc.history) == -1) {
                    rebaseHist(doc.history, change);
                    rebased.push(doc.history);
                }
                makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
            });
        }
    }

    // Sub-views need their line numbers shifted when text is added
    // above or below them in the parent document.
    function shiftDoc(doc, distance) {
        if (distance == 0) return;
        doc.first += distance;
        doc.sel = new Selection(map(doc.sel.ranges, function (range) {
            return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
                             Pos(range.head.line + distance, range.head.ch));
        }), doc.sel.primIndex);
        if (doc.cm) {
            regChange(doc.cm, doc.first, doc.first - distance, distance);
            for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
                regLineChange(doc.cm, l, "gutter");
        }
    }

    // More lower-level change function, handling only a single document
    // (not linked ones).
    function makeChangeSingleDoc(doc, change, selAfter, spans) {
        if (doc.cm && !doc.cm.curOp)
            return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);

        if (change.to.line < doc.first) {
            shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
            return;
        }
        if (change.from.line > doc.lastLine()) return;

        // Clip the change to the size of this doc
        if (change.from.line < doc.first) {
            var shift = change.text.length - 1 - (doc.first - change.from.line);
            shiftDoc(doc, shift);
            change = {
                from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
                text: [lst(change.text)], origin: change.origin
            };
        }
        var last = doc.lastLine();
        if (change.to.line > last) {
            change = {
                from: change.from, to: Pos(last, getLine(doc, last).text.length),
                text: [change.text[0]], origin: change.origin
            };
        }

        change.removed = getBetween(doc, change.from, change.to);

        if (!selAfter) selAfter = computeSelAfterChange(doc, change);
        if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
        else updateDoc(doc, change, spans);
        setSelectionNoUndo(doc, selAfter, sel_dontScroll);
    }

    // Handle the interaction of a change to a document with the editor
    // that this document is part of.
    function makeChangeSingleDocInEditor(cm, change, spans) {
        var doc = cm.doc, display = cm.display, from = change.from, to = change.to;

        var recomputeMaxLength = false, checkWidthStart = from.line;
        if (!cm.options.lineWrapping) {
            checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
            doc.iter(checkWidthStart, to.line + 1, function (line) {
                if (line == display.maxLine) {
                    recomputeMaxLength = true;
                    return true;
                }
            });
        }

        if (doc.sel.contains(change.from, change.to) > -1)
            signalCursorActivity(cm);

        updateDoc(doc, change, spans, estimateHeight(cm));

        if (!cm.options.lineWrapping) {
            doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
                var len = lineLength(line);
                if (len > display.maxLineLength) {
                    display.maxLine = line;
                    display.maxLineLength = len;
                    display.maxLineChanged = true;
                    recomputeMaxLength = false;
                }
            });
            if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
        }

        // Adjust frontier, schedule worker
        doc.frontier = Math.min(doc.frontier, from.line);
        startWorker(cm, 400);

        var lendiff = change.text.length - (to.line - from.line) - 1;
        // Remember that these lines changed, for updating the display
        if (change.full)
            regChange(cm);
        else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
            regLineChange(cm, from.line, "text");
        else
            regChange(cm, from.line, to.line + 1, lendiff);

        var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
        if (changeHandler || changesHandler) {
            var obj = {
                from: from, to: to,
                text: change.text,
                removed: change.removed,
                origin: change.origin
            };
            if (changeHandler) signalLater(cm, "change", cm, obj);
            if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
        }
        cm.display.selForContextMenu = null;
    }

    function replaceRange(doc, code, from, to, origin) {
        if (!to) to = from;
        if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
        if (typeof code == "string") code = doc.splitLines(code);
        makeChange(doc, { from: from, to: to, text: code, origin: origin });
    }

    // SCROLLING THINGS INTO VIEW

    // If an editor sits on the top or bottom of the window, partially
    // scrolled out of view, this ensures that the cursor is visible.
    function maybeScrollWindow(cm, coords) {
        if (signalDOMEvent(cm, "scrollCursorIntoView")) return;

        var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
        if (coords.top + box.top < 0) doScroll = true;
        else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
        if (doScroll != null && !phantom) {
            var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
                                 (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
                                 (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
                                 coords.left + "px; width: 2px;");
            cm.display.lineSpace.appendChild(scrollNode);
            scrollNode.scrollIntoView(doScroll);
            cm.display.lineSpace.removeChild(scrollNode);
        }
    }

    // Scroll a given position into view (immediately), verifying that
    // it actually became visible (as line heights are accurately
    // measured, the position of something may 'drift' during drawing).
    function scrollPosIntoView(cm, pos, end, margin) {
        if (margin == null) margin = 0;
        for (var limit = 0; limit < 5; limit++) {
            var changed = false, coords = cursorCoords(cm, pos);
            var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
            var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
                                               Math.min(coords.top, endCoords.top) - margin,
                                               Math.max(coords.left, endCoords.left),
                                               Math.max(coords.bottom, endCoords.bottom) + margin);
            var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
            if (scrollPos.scrollTop != null) {
                setScrollTop(cm, scrollPos.scrollTop);
                if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
            }
            if (scrollPos.scrollLeft != null) {
                setScrollLeft(cm, scrollPos.scrollLeft);
                if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
            }
            if (!changed) break;
        }
        return coords;
    }

    // Scroll a given set of coordinates into view (immediately).
    function scrollIntoView(cm, x1, y1, x2, y2) {
        var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
        if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
        if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
    }

    // Calculate a new scroll position needed to scroll the given
    // rectangle into view. Returns an object with scrollTop and
    // scrollLeft properties. When these are undefined, the
    // vertical/horizontal position does not need to be adjusted.
    function calculateScrollPos(cm, x1, y1, x2, y2) {
        var display = cm.display, snapMargin = textHeight(cm.display);
        if (y1 < 0) y1 = 0;
        var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
        var screen = displayHeight(cm), result = {};
        if (y2 - y1 > screen) y2 = y1 + screen;
        var docBottom = cm.doc.height + paddingVert(display);
        var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
        if (y1 < screentop) {
            result.scrollTop = atTop ? 0 : y1;
        } else if (y2 > screentop + screen) {
            var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
            if (newTop != screentop) result.scrollTop = newTop;
        }

        var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
        var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
        var tooWide = x2 - x1 > screenw;
        if (tooWide) x2 = x1 + screenw;
        if (x1 < 10)
            result.scrollLeft = 0;
        else if (x1 < screenleft)
            result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
        else if (x2 > screenw + screenleft - 3)
            result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
        return result;
    }

    // Store a relative adjustment to the scroll position in the current
    // operation (to be applied when the operation finishes).
    function addToScrollPos(cm, left, top) {
        if (left != null || top != null) resolveScrollToPos(cm);
        if (left != null)
            cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
        if (top != null)
            cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
    }

    // Make sure that at the end of the operation the current cursor is
    // shown.
    function ensureCursorVisible(cm) {
        resolveScrollToPos(cm);
        var cur = cm.getCursor(), from = cur, to = cur;
        if (!cm.options.lineWrapping) {
            from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
            to = Pos(cur.line, cur.ch + 1);
        }
        cm.curOp.scrollToPos = { from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true };
    }

    // When an operation has its scrollToPos property set, and another
    // scroll action is applied before the end of the operation, this
    // 'simulates' scrolling that position into view in a cheap way, so
    // that the effect of intermediate scroll commands is not ignored.
    function resolveScrollToPos(cm) {
        var range = cm.curOp.scrollToPos;
        if (range) {
            cm.curOp.scrollToPos = null;
            var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
            var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
                                          Math.min(from.top, to.top) - range.margin,
                                          Math.max(from.right, to.right),
                                          Math.max(from.bottom, to.bottom) + range.margin);
            cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
        }
    }

    // API UTILITIES

    // Indent the given line. The how parameter can be "smart",
    // "add"/null, "subtract", or "prev". When aggressive is false
    // (typically set to true for forced single-line indents), empty
    // lines are not indented, and places where the mode returns Pass
    // are left alone.
    function indentLine(cm, n, how, aggressive) {
        var doc = cm.doc, state;
        if (how == null) how = "add";
        if (how == "smart") {
            // Fall back to "prev" when the mode doesn't have an indentation
            // method.
            if (!doc.mode.indent) how = "prev";
            else state = getStateBefore(cm, n);
        }

        var tabSize = cm.options.tabSize;
        var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
        if (line.stateAfter) line.stateAfter = null;
        var curSpaceString = line.text.match(/^\s*/)[0], indentation;
        if (!aggressive && !/\S/.test(line.text)) {
            indentation = 0;
            how = "not";
        } else if (how == "smart") {
            indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
            if (indentation == Pass || indentation > 150) {
                if (!aggressive) return;
                how = "prev";
            }
        }
        if (how == "prev") {
            if (n > doc.first) indentation = countColumn(getLine(doc, n - 1).text, null, tabSize);
            else indentation = 0;
        } else if (how == "add") {
            indentation = curSpace + cm.options.indentUnit;
        } else if (how == "subtract") {
            indentation = curSpace - cm.options.indentUnit;
        } else if (typeof how == "number") {
            indentation = curSpace + how;
        }
        indentation = Math.max(0, indentation);

        var indentString = "", pos = 0;
        if (cm.options.indentWithTabs)
            for (var i = Math.floor(indentation / tabSize) ; i; --i) { pos += tabSize; indentString += "\t"; }
        if (pos < indentation) indentString += spaceStr(indentation - pos);

        if (indentString != curSpaceString) {
            replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
            line.stateAfter = null;
            return true;
        } else {
            // Ensure that, if the cursor was in the whitespace at the start
            // of the line, it is moved to the end of that space.
            for (var i = 0; i < doc.sel.ranges.length; i++) {
                var range = doc.sel.ranges[i];
                if (range.head.line == n && range.head.ch < curSpaceString.length) {
                    var pos = Pos(n, curSpaceString.length);
                    replaceOneSelection(doc, i, new Range(pos, pos));
                    break;
                }
            }
        }
    }

    // Utility for applying a change to a line by handle or number,
    // returning the number and optionally registering the line as
    // changed.
    function changeLine(doc, handle, changeType, op) {
        var no = handle, line = handle;
        if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
        else no = lineNo(handle);
        if (no == null) return null;
        if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
        return line;
    }

    // Helper for deleting text near the selection(s), used to implement
    // backspace, delete, and similar functionality.
    function deleteNearSelection(cm, compute) {
        var ranges = cm.doc.sel.ranges, kill = [];
        // Build up a set of ranges to kill first, merging overlapping
        // ranges.
        for (var i = 0; i < ranges.length; i++) {
            var toKill = compute(ranges[i]);
            while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
                var replaced = kill.pop();
                if (cmp(replaced.from, toKill.from) < 0) {
                    toKill.from = replaced.from;
                    break;
                }
            }
            kill.push(toKill);
        }
        // Next, remove those actual ranges.
        runInOp(cm, function () {
            for (var i = kill.length - 1; i >= 0; i--)
                replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
            ensureCursorVisible(cm);
        });
    }

    // Used for horizontal relative motion. Dir is -1 or 1 (left or
    // right), unit can be "char", "column" (like char, but doesn't
    // cross line boundaries), "word" (across next word), or "group" (to
    // the start of next group of word or non-word-non-whitespace
    // chars). The visually param controls whether, in right-to-left
    // text, direction 1 means to move towards the next index in the
    // string, or towards the character to the right of the current
    // position. The resulting position will have a hitSide=true
    // property if it reached the end of the document.
    function findPosH(doc, pos, dir, unit, visually) {
        var line = pos.line, ch = pos.ch, origDir = dir;
        var lineObj = getLine(doc, line);
        var possible = true;
        function findNextLine() {
            var l = line + dir;
            if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
            line = l;
            return lineObj = getLine(doc, l);
        }
        function moveOnce(boundToLine) {
            var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
            if (next == null) {
                if (!boundToLine && findNextLine()) {
                    if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
                    else ch = dir < 0 ? lineObj.text.length : 0;
                } else return (possible = false);
            } else ch = next;
            return true;
        }

        if (unit == "char") moveOnce();
        else if (unit == "column") moveOnce(true);
        else if (unit == "word" || unit == "group") {
            var sawType = null, group = unit == "group";
            var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
            for (var first = true; ; first = false) {
                if (dir < 0 && !moveOnce(!first)) break;
                var cur = lineObj.text.charAt(ch) || "\n";
                var type = isWordChar(cur, helper) ? "w"
                  : group && cur == "\n" ? "n"
                  : !group || /\s/.test(cur) ? null
                  : "p";
                if (group && !first && !type) type = "s";
                if (sawType && sawType != type) {
                    if (dir < 0) { dir = 1; moveOnce(); }
                    break;
                }

                if (type) sawType = type;
                if (dir > 0 && !moveOnce(!first)) break;
            }
        }
        var result = skipAtomic(doc, Pos(line, ch), origDir, true);
        if (!possible) result.hitSide = true;
        return result;
    }

    // For relative vertical movement. Dir may be -1 or 1. Unit can be
    // "page" or "line". The resulting position will have a hitSide=true
    // property if it reached the end of the document.
    function findPosV(cm, pos, dir, unit) {
        var doc = cm.doc, x = pos.left, y;
        if (unit == "page") {
            var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
            y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
        } else if (unit == "line") {
            y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
        }
        for (; ;) {
            var target = coordsChar(cm, x, y);
            if (!target.outside) break;
            if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
            y += dir * 5;
        }
        return target;
    }

    // EDITOR METHODS

    // The publicly visible API. Note that methodOp(f) means
    // 'wrap f in an operation, performed on its `this` parameter'.

    // This is not the complete set of editor methods. Most of the
    // methods defined on the Doc type are also injected into
    // CodeMirror.prototype, for backwards compatibility and
    // convenience.

    CodeMirror.prototype = {
        constructor: CodeMirror,
        focus: function () { window.focus(); this.display.input.focus(); },

        setOption: function (option, value) {
            var options = this.options, old = options[option];
            if (options[option] == value && option != "mode") return;
            options[option] = value;
            if (optionHandlers.hasOwnProperty(option))
                operation(this, optionHandlers[option])(this, value, old);
        },

        getOption: function (option) { return this.options[option]; },
        getDoc: function () { return this.doc; },

        addKeyMap: function (map, bottom) {
            this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
        },
        removeKeyMap: function (map) {
            var maps = this.state.keyMaps;
            for (var i = 0; i < maps.length; ++i)
                if (maps[i] == map || maps[i].name == map) {
                    maps.splice(i, 1);
                    return true;
                }
        },

        addOverlay: methodOp(function (spec, options) {
            var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
            if (mode.startState) throw new Error("Overlays may not be stateful.");
            this.state.overlays.push({ mode: mode, modeSpec: spec, opaque: options && options.opaque });
            this.state.modeGen++;
            regChange(this);
        }),
        removeOverlay: methodOp(function (spec) {
            var overlays = this.state.overlays;
            for (var i = 0; i < overlays.length; ++i) {
                var cur = overlays[i].modeSpec;
                if (cur == spec || typeof spec == "string" && cur.name == spec) {
                    overlays.splice(i, 1);
                    this.state.modeGen++;
                    regChange(this);
                    return;
                }
            }
        }),

        indentLine: methodOp(function (n, dir, aggressive) {
            if (typeof dir != "string" && typeof dir != "number") {
                if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
                else dir = dir ? "add" : "subtract";
            }
            if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
        }),
        indentSelection: methodOp(function (how) {
            var ranges = this.doc.sel.ranges, end = -1;
            for (var i = 0; i < ranges.length; i++) {
                var range = ranges[i];
                if (!range.empty()) {
                    var from = range.from(), to = range.to();
                    var start = Math.max(end, from.line);
                    end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
                    for (var j = start; j < end; ++j)
                        indentLine(this, j, how);
                    var newRanges = this.doc.sel.ranges;
                    if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
                        replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
                } else if (range.head.line > end) {
                    indentLine(this, range.head.line, how, true);
                    end = range.head.line;
                    if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
                }
            }
        }),

        // Fetch the parser token for a given character. Useful for hacks
        // that want to inspect the mode state (say, for completion).
        getTokenAt: function (pos, precise) {
            return takeToken(this, pos, precise);
        },

        getLineTokens: function (line, precise) {
            return takeToken(this, Pos(line), precise, true);
        },

        getTokenTypeAt: function (pos) {
            pos = clipPos(this.doc, pos);
            var styles = getLineStyles(this, getLine(this.doc, pos.line));
            var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
            var type;
            if (ch == 0) type = styles[2];
            else for (; ;) {
                var mid = (before + after) >> 1;
                if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
                else if (styles[mid * 2 + 1] < ch) before = mid + 1;
                else { type = styles[mid * 2 + 2]; break; }
            }
            var cut = type ? type.indexOf("cm-overlay ") : -1;
            return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
        },

        getModeAt: function (pos) {
            var mode = this.doc.mode;
            if (!mode.innerMode) return mode;
            return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
        },

        getHelper: function (pos, type) {
            return this.getHelpers(pos, type)[0];
        },

        getHelpers: function (pos, type) {
            var found = [];
            if (!helpers.hasOwnProperty(type)) return found;
            var help = helpers[type], mode = this.getModeAt(pos);
            if (typeof mode[type] == "string") {
                if (help[mode[type]]) found.push(help[mode[type]]);
            } else if (mode[type]) {
                for (var i = 0; i < mode[type].length; i++) {
                    var val = help[mode[type][i]];
                    if (val) found.push(val);
                }
            } else if (mode.helperType && help[mode.helperType]) {
                found.push(help[mode.helperType]);
            } else if (help[mode.name]) {
                found.push(help[mode.name]);
            }
            for (var i = 0; i < help._global.length; i++) {
                var cur = help._global[i];
                if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
                    found.push(cur.val);
            }
            return found;
        },

        getStateAfter: function (line, precise) {
            var doc = this.doc;
            line = clipLine(doc, line == null ? doc.first + doc.size - 1 : line);
            return getStateBefore(this, line + 1, precise);
        },

        cursorCoords: function (start, mode) {
            var pos, range = this.doc.sel.primary();
            if (start == null) pos = range.head;
            else if (typeof start == "object") pos = clipPos(this.doc, start);
            else pos = start ? range.from() : range.to();
            return cursorCoords(this, pos, mode || "page");
        },

        charCoords: function (pos, mode) {
            return charCoords(this, clipPos(this.doc, pos), mode || "page");
        },

        coordsChar: function (coords, mode) {
            coords = fromCoordSystem(this, coords, mode || "page");
            return coordsChar(this, coords.left, coords.top);
        },

        lineAtHeight: function (height, mode) {
            height = fromCoordSystem(this, { top: height, left: 0 }, mode || "page").top;
            return lineAtHeight(this.doc, height + this.display.viewOffset);
        },
        heightAtLine: function (line, mode) {
            var end = false, lineObj;
            if (typeof line == "number") {
                var last = this.doc.first + this.doc.size - 1;
                if (line < this.doc.first) line = this.doc.first;
                else if (line > last) { line = last; end = true; }
                lineObj = getLine(this.doc, line);
            } else {
                lineObj = line;
            }
            return intoCoordSystem(this, lineObj, { top: 0, left: 0 }, mode || "page").top +
              (end ? this.doc.height - heightAtLine(lineObj) : 0);
        },

        defaultTextHeight: function () { return textHeight(this.display); },
        defaultCharWidth: function () { return charWidth(this.display); },

        setGutterMarker: methodOp(function (line, gutterID, value) {
            return changeLine(this.doc, line, "gutter", function (line) {
                var markers = line.gutterMarkers || (line.gutterMarkers = {});
                markers[gutterID] = value;
                if (!value && isEmpty(markers)) line.gutterMarkers = null;
                return true;
            });
        }),

        clearGutter: methodOp(function (gutterID) {
            var cm = this, doc = cm.doc, i = doc.first;
            doc.iter(function (line) {
                if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
                    line.gutterMarkers[gutterID] = null;
                    regLineChange(cm, i, "gutter");
                    if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
                }
                ++i;
            });
        }),

        lineInfo: function (line) {
            if (typeof line == "number") {
                if (!isLine(this.doc, line)) return null;
                var n = line;
                line = getLine(this.doc, line);
                if (!line) return null;
            } else {
                var n = lineNo(line);
                if (n == null) return null;
            }
            return {
                line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
                textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
                widgets: line.widgets
            };
        },

        getViewport: function () { return { from: this.display.viewFrom, to: this.display.viewTo }; },

        addWidget: function (pos, node, scroll, vert, horiz) {
            var display = this.display;
            pos = cursorCoords(this, clipPos(this.doc, pos));
            var top = pos.bottom, left = pos.left;
            node.style.position = "absolute";
            node.setAttribute("cm-ignore-events", "true");
            this.display.input.setUneditable(node);
            display.sizer.appendChild(node);
            if (vert == "over") {
                top = pos.top;
            } else if (vert == "above" || vert == "near") {
                var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
                hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
                // Default to positioning above (if specified and possible); otherwise default to positioning below
                if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
                    top = pos.top - node.offsetHeight;
                else if (pos.bottom + node.offsetHeight <= vspace)
                    top = pos.bottom;
                if (left + node.offsetWidth > hspace)
                    left = hspace - node.offsetWidth;
            }
            node.style.top = top + "px";
            node.style.left = node.style.right = "";
            if (horiz == "right") {
                left = display.sizer.clientWidth - node.offsetWidth;
                node.style.right = "0px";
            } else {
                if (horiz == "left") left = 0;
                else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
                node.style.left = left + "px";
            }
            if (scroll)
                scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
        },

        triggerOnKeyDown: methodOp(onKeyDown),
        triggerOnKeyPress: methodOp(onKeyPress),
        triggerOnKeyUp: onKeyUp,

        execCommand: function (cmd) {
            if (commands.hasOwnProperty(cmd))
                return commands[cmd].call(null, this);
        },

        triggerElectric: methodOp(function (text) { triggerElectric(this, text); }),

        findPosH: function (from, amount, unit, visually) {
            var dir = 1;
            if (amount < 0) { dir = -1; amount = -amount; }
            for (var i = 0, cur = clipPos(this.doc, from) ; i < amount; ++i) {
                cur = findPosH(this.doc, cur, dir, unit, visually);
                if (cur.hitSide) break;
            }
            return cur;
        },

        moveH: methodOp(function (dir, unit) {
            var cm = this;
            cm.extendSelectionsBy(function (range) {
                if (cm.display.shift || cm.doc.extend || range.empty())
                    return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
                else
                    return dir < 0 ? range.from() : range.to();
            }, sel_move);
        }),

        deleteH: methodOp(function (dir, unit) {
            var sel = this.doc.sel, doc = this.doc;
            if (sel.somethingSelected())
                doc.replaceSelection("", null, "+delete");
            else
                deleteNearSelection(this, function (range) {
                    var other = findPosH(doc, range.head, dir, unit, false);
                    return dir < 0 ? { from: other, to: range.head } : { from: range.head, to: other };
                });
        }),

        findPosV: function (from, amount, unit, goalColumn) {
            var dir = 1, x = goalColumn;
            if (amount < 0) { dir = -1; amount = -amount; }
            for (var i = 0, cur = clipPos(this.doc, from) ; i < amount; ++i) {
                var coords = cursorCoords(this, cur, "div");
                if (x == null) x = coords.left;
                else coords.left = x;
                cur = findPosV(this, coords, dir, unit);
                if (cur.hitSide) break;
            }
            return cur;
        },

        moveV: methodOp(function (dir, unit) {
            var cm = this, doc = this.doc, goals = [];
            var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
            doc.extendSelectionsBy(function (range) {
                if (collapse)
                    return dir < 0 ? range.from() : range.to();
                var headPos = cursorCoords(cm, range.head, "div");
                if (range.goalColumn != null) headPos.left = range.goalColumn;
                goals.push(headPos.left);
                var pos = findPosV(cm, headPos, dir, unit);
                if (unit == "page" && range == doc.sel.primary())
                    addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
                return pos;
            }, sel_move);
            if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
                doc.sel.ranges[i].goalColumn = goals[i];
        }),

        // Find the word at the given position (as returned by coordsChar).
        findWordAt: function (pos) {
            var doc = this.doc, line = getLine(doc, pos.line).text;
            var start = pos.ch, end = pos.ch;
            if (line) {
                var helper = this.getHelper(pos, "wordChars");
                if ((pos.xRel < 0 || end == line.length) && start)--start; else ++end;
                var startChar = line.charAt(start);
                var check = isWordChar(startChar, helper)
                  ? function (ch) { return isWordChar(ch, helper); }
                  : /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
                  : function (ch) { return !/\s/.test(ch) && !isWordChar(ch); };
                while (start > 0 && check(line.charAt(start - 1)))--start;
                while (end < line.length && check(line.charAt(end)))++end;
            }
            return new Range(Pos(pos.line, start), Pos(pos.line, end));
        },

        toggleOverwrite: function (value) {
            if (value != null && value == this.state.overwrite) return;
            if (this.state.overwrite = !this.state.overwrite)
                addClass(this.display.cursorDiv, "CodeMirror-overwrite");
            else
                rmClass(this.display.cursorDiv, "CodeMirror-overwrite");

            signal(this, "overwriteToggle", this, this.state.overwrite);
        },
        hasFocus: function () { return this.display.input.getField() == activeElt(); },

        scrollTo: methodOp(function (x, y) {
            if (x != null || y != null) resolveScrollToPos(this);
            if (x != null) this.curOp.scrollLeft = x;
            if (y != null) this.curOp.scrollTop = y;
        }),
        getScrollInfo: function () {
            var scroller = this.display.scroller;
            return {
                left: scroller.scrollLeft, top: scroller.scrollTop,
                height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
                width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
                clientHeight: displayHeight(this), clientWidth: displayWidth(this)
            };
        },

        scrollIntoView: methodOp(function (range, margin) {
            if (range == null) {
                range = { from: this.doc.sel.primary().head, to: null };
                if (margin == null) margin = this.options.cursorScrollMargin;
            } else if (typeof range == "number") {
                range = { from: Pos(range, 0), to: null };
            } else if (range.from == null) {
                range = { from: range, to: null };
            }
            if (!range.to) range.to = range.from;
            range.margin = margin || 0;

            if (range.from.line != null) {
                resolveScrollToPos(this);
                this.curOp.scrollToPos = range;
            } else {
                var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
                                              Math.min(range.from.top, range.to.top) - range.margin,
                                              Math.max(range.from.right, range.to.right),
                                              Math.max(range.from.bottom, range.to.bottom) + range.margin);
                this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
            }
        }),

        setSize: methodOp(function (width, height) {
            var cm = this;
            function interpret(val) {
                return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
            }
            if (width != null) cm.display.wrapper.style.width = interpret(width);
            if (height != null) cm.display.wrapper.style.height = interpret(height);
            if (cm.options.lineWrapping) clearLineMeasurementCache(this);
            var lineNo = cm.display.viewFrom;
            cm.doc.iter(lineNo, cm.display.viewTo, function (line) {
                if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
                    if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
                ++lineNo;
            });
            cm.curOp.forceUpdate = true;
            signal(cm, "refresh", this);
        }),

        operation: function (f) { return runInOp(this, f); },

        refresh: methodOp(function () {
            var oldHeight = this.display.cachedTextHeight;
            regChange(this);
            this.curOp.forceUpdate = true;
            clearCaches(this);
            this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
            updateGutterSpace(this);
            if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
                estimateLineHeights(this);
            signal(this, "refresh", this);
        }),

        swapDoc: methodOp(function (doc) {
            var old = this.doc;
            old.cm = null;
            attachDoc(this, doc);
            clearCaches(this);
            this.display.input.reset();
            this.scrollTo(doc.scrollLeft, doc.scrollTop);
            this.curOp.forceScroll = true;
            signalLater(this, "swapDoc", this, old);
            return old;
        }),

        getInputField: function () { return this.display.input.getField(); },
        getWrapperElement: function () { return this.display.wrapper; },
        getScrollerElement: function () { return this.display.scroller; },
        getGutterElement: function () { return this.display.gutters; }
    };
    eventMixin(CodeMirror);

    // OPTION DEFAULTS

    // The default configuration options.
    var defaults = CodeMirror.defaults = {};
    // Functions to run when options are changed.
    var optionHandlers = CodeMirror.optionHandlers = {};

    function option(name, deflt, handle, notOnInit) {
        CodeMirror.defaults[name] = deflt;
        if (handle) optionHandlers[name] =
          notOnInit ? function (cm, val, old) { if (old != Init) handle(cm, val, old); } : handle;
    }

    // Passed to option handlers when there is no old value.
    var Init = CodeMirror.Init = { toString: function () { return "CodeMirror.Init"; } };

    // These two are, on init, called from the constructor because they
    // have to be initialized before the editor can start at all.
    option("value", "", function (cm, val) {
        cm.setValue(val);
    }, true);
    option("mode", null, function (cm, val) {
        cm.doc.modeOption = val;
        loadMode(cm);
    }, true);

    option("indentUnit", 2, loadMode, true);
    option("indentWithTabs", false);
    option("smartIndent", true);
    option("tabSize", 4, function (cm) {
        resetModeState(cm);
        clearCaches(cm);
        regChange(cm);
    }, true);
    option("lineSeparator", null, function (cm, val) {
        cm.doc.lineSep = val;
        if (!val) return;
        var newBreaks = [], lineNo = cm.doc.first;
        cm.doc.iter(function (line) {
            for (var pos = 0; ;) {
                var found = line.text.indexOf(val, pos);
                if (found == -1) break;
                pos = found + val.length;
                newBreaks.push(Pos(lineNo, found));
            }
            lineNo++;
        });
        for (var i = newBreaks.length - 1; i >= 0; i--)
            replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
    });
    option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
        cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
        if (old != CodeMirror.Init) cm.refresh();
    });
    option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { cm.refresh(); }, true);
    option("electricChars", true);
    option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
        throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
    }, true);
    option("rtlMoveVisually", !windows);
    option("wholeLineUpdateBefore", true);

    option("theme", "default", function (cm) {
        themeChanged(cm);
        guttersChanged(cm);
    }, true);
    option("keyMap", "default", function (cm, val, old) {
        var next = getKeyMap(val);
        var prev = old != CodeMirror.Init && getKeyMap(old);
        if (prev && prev.detach) prev.detach(cm, next);
        if (next.attach) next.attach(cm, prev || null);
    });
    option("extraKeys", null);

    option("lineWrapping", false, wrappingChanged, true);
    option("gutters", [], function (cm) {
        setGuttersForLineNumbers(cm.options);
        guttersChanged(cm);
    }, true);
    option("fixedGutter", true, function (cm, val) {
        cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
        cm.refresh();
    }, true);
    option("coverGutterNextToScrollbar", false, function (cm) { updateScrollbars(cm); }, true);
    option("scrollbarStyle", "native", function (cm) {
        initScrollbars(cm);
        updateScrollbars(cm);
        cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
        cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
    }, true);
    option("lineNumbers", false, function (cm) {
        setGuttersForLineNumbers(cm.options);
        guttersChanged(cm);
    }, true);
    option("firstLineNumber", 1, guttersChanged, true);
    option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
    option("showCursorWhenSelecting", false, updateSelection, true);

    option("resetSelectionOnContextMenu", true);
    option("lineWiseCopyCut", true);

    option("readOnly", false, function (cm, val) {
        if (val == "nocursor") {
            onBlur(cm);
            cm.display.input.blur();
            cm.display.disabled = true;
        } else {
            cm.display.disabled = false;
        }
        cm.display.input.readOnlyChanged(val)
    });
    option("disableInput", false, function (cm, val) { if (!val) cm.display.input.reset(); }, true);
    option("dragDrop", true, dragDropChanged);

    option("cursorBlinkRate", 530);
    option("cursorScrollMargin", 0);
    option("cursorHeight", 1, updateSelection, true);
    option("singleCursorHeightPerLine", true, updateSelection, true);
    option("workTime", 100);
    option("workDelay", 100);
    option("flattenSpans", true, resetModeState, true);
    option("addModeClass", false, resetModeState, true);
    option("pollInterval", 100);
    option("undoDepth", 200, function (cm, val) { cm.doc.history.undoDepth = val; });
    option("historyEventDelay", 1250);
    option("viewportMargin", 10, function (cm) { cm.refresh(); }, true);
    option("maxHighlightLength", 10000, resetModeState, true);
    option("moveInputWithCursor", true, function (cm, val) {
        if (!val) cm.display.input.resetPosition();
    });

    option("tabindex", null, function (cm, val) {
        cm.display.input.getField().tabIndex = val || "";
    });
    option("autofocus", null);

    // MODE DEFINITION AND QUERYING

    // Known modes, by name and by MIME
    var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};

    // Extra arguments are stored as the mode's dependencies, which is
    // used by (legacy) mechanisms like loadmode.js to automatically
    // load a mode. (Preferred mechanism is the require/define calls.)
    CodeMirror.defineMode = function (name, mode) {
        if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
        if (arguments.length > 2)
            mode.dependencies = Array.prototype.slice.call(arguments, 2);
        modes[name] = mode;
    };

    CodeMirror.defineMIME = function (mime, spec) {
        mimeModes[mime] = spec;
    };

    // Given a MIME type, a {name, ...options} config object, or a name
    // string, return a mode config object.
    CodeMirror.resolveMode = function (spec) {
        if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
            spec = mimeModes[spec];
        } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
            var found = mimeModes[spec.name];
            if (typeof found == "string") found = { name: found };
            spec = createObj(found, spec);
            spec.name = found.name;
        } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
            return CodeMirror.resolveMode("application/xml");
        }
        if (typeof spec == "string") return { name: spec };
        else return spec || { name: "null" };
    };

    // Given a mode spec (anything that resolveMode accepts), find and
    // initialize an actual mode object.
    CodeMirror.getMode = function (options, spec) {
        var spec = CodeMirror.resolveMode(spec);
        var mfactory = modes[spec.name];
        if (!mfactory) return CodeMirror.getMode(options, "text/plain");
        var modeObj = mfactory(options, spec);
        if (modeExtensions.hasOwnProperty(spec.name)) {
            var exts = modeExtensions[spec.name];
            for (var prop in exts) {
                if (!exts.hasOwnProperty(prop)) continue;
                if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
                modeObj[prop] = exts[prop];
            }
        }
        modeObj.name = spec.name;
        if (spec.helperType) modeObj.helperType = spec.helperType;
        if (spec.modeProps) for (var prop in spec.modeProps)
            modeObj[prop] = spec.modeProps[prop];

        return modeObj;
    };

    // Minimal default mode.
    CodeMirror.defineMode("null", function () {
        return { token: function (stream) { stream.skipToEnd(); } };
    });
    CodeMirror.defineMIME("text/plain", "null");

    // This can be used to attach properties to mode objects from
    // outside the actual mode definition.
    var modeExtensions = CodeMirror.modeExtensions = {};
    CodeMirror.extendMode = function (mode, properties) {
        var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
        copyObj(properties, exts);
    };

    // EXTENSIONS

    CodeMirror.defineExtension = function (name, func) {
        CodeMirror.prototype[name] = func;
    };
    CodeMirror.defineDocExtension = function (name, func) {
        Doc.prototype[name] = func;
    };
    CodeMirror.defineOption = option;

    var initHooks = [];
    CodeMirror.defineInitHook = function (f) { initHooks.push(f); };

    var helpers = CodeMirror.helpers = {};
    CodeMirror.registerHelper = function (type, name, value) {
        if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = { _global: [] };
        helpers[type][name] = value;
    };
    CodeMirror.registerGlobalHelper = function (type, name, predicate, value) {
        CodeMirror.registerHelper(type, name, value);
        helpers[type]._global.push({ pred: predicate, val: value });
    };

    // MODE STATE HANDLING

    // Utility functions for working with state. Exported because nested
    // modes need to do this for their inner modes.

    var copyState = CodeMirror.copyState = function (mode, state) {
        if (state === true) return state;
        if (mode.copyState) return mode.copyState(state);
        var nstate = {};
        for (var n in state) {
            var val = state[n];
            if (val instanceof Array) val = val.concat([]);
            nstate[n] = val;
        }
        return nstate;
    };

    var startState = CodeMirror.startState = function (mode, a1, a2) {
        return mode.startState ? mode.startState(a1, a2) : true;
    };

    // Given a mode and a state (for that mode), find the inner mode and
    // state at the position that the state refers to.
    CodeMirror.innerMode = function (mode, state) {
        while (mode.innerMode) {
            var info = mode.innerMode(state);
            if (!info || info.mode == mode) break;
            state = info.state;
            mode = info.mode;
        }
        return info || { mode: mode, state: state };
    };

    // STANDARD COMMANDS

    // Commands are parameter-less actions that can be performed on an
    // editor, mostly used for keybindings.
    var commands = CodeMirror.commands = {
        selectAll: function (cm) { cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll); },
        singleSelection: function (cm) {
            cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
        },
        killLine: function (cm) {
            deleteNearSelection(cm, function (range) {
                if (range.empty()) {
                    var len = getLine(cm.doc, range.head.line).text.length;
                    if (range.head.ch == len && range.head.line < cm.lastLine())
                        return { from: range.head, to: Pos(range.head.line + 1, 0) };
                    else
                        return { from: range.head, to: Pos(range.head.line, len) };
                } else {
                    return { from: range.from(), to: range.to() };
                }
            });
        },
        deleteLine: function (cm) {
            deleteNearSelection(cm, function (range) {
                return {
                    from: Pos(range.from().line, 0),
                    to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
                };
            });
        },
        delLineLeft: function (cm) {
            deleteNearSelection(cm, function (range) {
                return { from: Pos(range.from().line, 0), to: range.from() };
            });
        },
        delWrappedLineLeft: function (cm) {
            deleteNearSelection(cm, function (range) {
                var top = cm.charCoords(range.head, "div").top + 5;
                var leftPos = cm.coordsChar({ left: 0, top: top }, "div");
                return { from: leftPos, to: range.from() };
            });
        },
        delWrappedLineRight: function (cm) {
            deleteNearSelection(cm, function (range) {
                var top = cm.charCoords(range.head, "div").top + 5;
                var rightPos = cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div");
                return { from: range.from(), to: rightPos };
            });
        },
        undo: function (cm) { cm.undo(); },
        redo: function (cm) { cm.redo(); },
        undoSelection: function (cm) { cm.undoSelection(); },
        redoSelection: function (cm) { cm.redoSelection(); },
        goDocStart: function (cm) { cm.extendSelection(Pos(cm.firstLine(), 0)); },
        goDocEnd: function (cm) { cm.extendSelection(Pos(cm.lastLine())); },
        goLineStart: function (cm) {
            cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
                                  { origin: "+move", bias: 1 });
        },
        goLineStartSmart: function (cm) {
            cm.extendSelectionsBy(function (range) {
                return lineStartSmart(cm, range.head);
            }, { origin: "+move", bias: 1 });
        },
        goLineEnd: function (cm) {
            cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
                                  { origin: "+move", bias: -1 });
        },
        goLineRight: function (cm) {
            cm.extendSelectionsBy(function (range) {
                var top = cm.charCoords(range.head, "div").top + 5;
                return cm.coordsChar({ left: cm.display.lineDiv.offsetWidth + 100, top: top }, "div");
            }, sel_move);
        },
        goLineLeft: function (cm) {
            cm.extendSelectionsBy(function (range) {
                var top = cm.charCoords(range.head, "div").top + 5;
                return cm.coordsChar({ left: 0, top: top }, "div");
            }, sel_move);
        },
        goLineLeftSmart: function (cm) {
            cm.extendSelectionsBy(function (range) {
                var top = cm.charCoords(range.head, "div").top + 5;
                var pos = cm.coordsChar({ left: 0, top: top }, "div");
                if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
                return pos;
            }, sel_move);
        },
        goLineUp: function (cm) { cm.moveV(-1, "line"); },
        goLineDown: function (cm) { cm.moveV(1, "line"); },
        goPageUp: function (cm) { cm.moveV(-1, "page"); },
        goPageDown: function (cm) { cm.moveV(1, "page"); },
        goCharLeft: function (cm) { cm.moveH(-1, "char"); },
        goCharRight: function (cm) { cm.moveH(1, "char"); },
        goColumnLeft: function (cm) { cm.moveH(-1, "column"); },
        goColumnRight: function (cm) { cm.moveH(1, "column"); },
        goWordLeft: function (cm) { cm.moveH(-1, "word"); },
        goGroupRight: function (cm) { cm.moveH(1, "group"); },
        goGroupLeft: function (cm) { cm.moveH(-1, "group"); },
        goWordRight: function (cm) { cm.moveH(1, "word"); },
        delCharBefore: function (cm) { cm.deleteH(-1, "char"); },
        delCharAfter: function (cm) { cm.deleteH(1, "char"); },
        delWordBefore: function (cm) { cm.deleteH(-1, "word"); },
        delWordAfter: function (cm) { cm.deleteH(1, "word"); },
        delGroupBefore: function (cm) { cm.deleteH(-1, "group"); },
        delGroupAfter: function (cm) { cm.deleteH(1, "group"); },
        indentAuto: function (cm) { cm.indentSelection("smart"); },
        indentMore: function (cm) { cm.indentSelection("add"); },
        indentLess: function (cm) { cm.indentSelection("subtract"); },
        insertTab: function (cm) { cm.replaceSelection("\t"); },
        insertSoftTab: function (cm) {
            var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
            for (var i = 0; i < ranges.length; i++) {
                var pos = ranges[i].from();
                var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
                spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
            }
            cm.replaceSelections(spaces);
        },
        defaultTab: function (cm) {
            if (cm.somethingSelected()) cm.indentSelection("add");
            else cm.execCommand("insertTab");
        },
        transposeChars: function (cm) {
            runInOp(cm, function () {
                var ranges = cm.listSelections(), newSel = [];
                for (var i = 0; i < ranges.length; i++) {
                    var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
                    if (line) {
                        if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
                        if (cur.ch > 0) {
                            cur = new Pos(cur.line, cur.ch + 1);
                            cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
                                            Pos(cur.line, cur.ch - 2), cur, "+transpose");
                        } else if (cur.line > cm.doc.first) {
                            var prev = getLine(cm.doc, cur.line - 1).text;
                            if (prev)
                                cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
                                                prev.charAt(prev.length - 1),
                                                Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
                        }
                    }
                    newSel.push(new Range(cur, cur));
                }
                cm.setSelections(newSel);
            });
        },
        newlineAndIndent: function (cm) {
            runInOp(cm, function () {
                var len = cm.listSelections().length;
                for (var i = 0; i < len; i++) {
                    var range = cm.listSelections()[i];
                    cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
                    cm.indentLine(range.from().line + 1, null, true);
                    ensureCursorVisible(cm);
                }
            });
        },
        toggleOverwrite: function (cm) { cm.toggleOverwrite(); }
    };


    // STANDARD KEYMAPS

    var keyMap = CodeMirror.keyMap = {};

    keyMap.basic = {
        "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
        "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
        "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
        "Tab": "defaultTab", "Shift-Tab": "indentAuto",
        "Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
        "Esc": "singleSelection"
    };
    // Note that the save and find-related commands aren't defined by
    // default. User code or addons can define them. Unknown commands
    // are simply ignored.
    keyMap.pcDefault = {
        "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
        "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
        "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
        "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
        "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
        "Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
        "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
        fallthrough: "basic"
    };
    // Very basic readline/emacs-style bindings, which are standard on Mac.
    keyMap.emacsy = {
        "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
        "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
        "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
        "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
    };
    keyMap.macDefault = {
        "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
        "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
        "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
        "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
        "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
        "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
        "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
        fallthrough: ["basic", "emacsy"]
    };
    keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;

    // KEYMAP DISPATCH

    function normalizeKeyName(name) {
        var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
        var alt, ctrl, shift, cmd;
        for (var i = 0; i < parts.length - 1; i++) {
            var mod = parts[i];
            if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
            else if (/^a(lt)?$/i.test(mod)) alt = true;
            else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
            else if (/^s(hift)$/i.test(mod)) shift = true;
            else throw new Error("Unrecognized modifier name: " + mod);
        }
        if (alt) name = "Alt-" + name;
        if (ctrl) name = "Ctrl-" + name;
        if (cmd) name = "Cmd-" + name;
        if (shift) name = "Shift-" + name;
        return name;
    }

    // This is a kludge to keep keymaps mostly working as raw objects
    // (backwards compatibility) while at the same time support features
    // like normalization and multi-stroke key bindings. It compiles a
    // new normalized keymap, and then updates the old object to reflect
    // this.
    CodeMirror.normalizeKeyMap = function (keymap) {
        var copy = {};
        for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
            var value = keymap[keyname];
            if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
            if (value == "...") { delete keymap[keyname]; continue; }

            var keys = map(keyname.split(" "), normalizeKeyName);
            for (var i = 0; i < keys.length; i++) {
                var val, name;
                if (i == keys.length - 1) {
                    name = keys.join(" ");
                    val = value;
                } else {
                    name = keys.slice(0, i + 1).join(" ");
                    val = "...";
                }
                var prev = copy[name];
                if (!prev) copy[name] = val;
                else if (prev != val) throw new Error("Inconsistent bindings for " + name);
            }
            delete keymap[keyname];
        }
        for (var prop in copy) keymap[prop] = copy[prop];
        return keymap;
    };

    var lookupKey = CodeMirror.lookupKey = function (key, map, handle, context) {
        map = getKeyMap(map);
        var found = map.call ? map.call(key, context) : map[key];
        if (found === false) return "nothing";
        if (found === "...") return "multi";
        if (found != null && handle(found)) return "handled";

        if (map.fallthrough) {
            if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
                return lookupKey(key, map.fallthrough, handle, context);
            for (var i = 0; i < map.fallthrough.length; i++) {
                var result = lookupKey(key, map.fallthrough[i], handle, context);
                if (result) return result;
            }
        }
    };

    // Modifier key presses don't count as 'real' key presses for the
    // purpose of keymap fallthrough.
    var isModifierKey = CodeMirror.isModifierKey = function (value) {
        var name = typeof value == "string" ? value : keyNames[value.keyCode];
        return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
    };

    // Look up the name of a key as indicated by an event object.
    var keyName = CodeMirror.keyName = function (event, noShift) {
        if (presto && event.keyCode == 34 && event["char"]) return false;
        var base = keyNames[event.keyCode], name = base;
        if (name == null || event.altGraphKey) return false;
        if (event.altKey && base != "Alt") name = "Alt-" + name;
        if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
        if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
        if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
        return name;
    };

    function getKeyMap(val) {
        return typeof val == "string" ? keyMap[val] : val;
    }

    // FROMTEXTAREA

    CodeMirror.fromTextArea = function (textarea, options) {
        options = options ? copyObj(options) : {};
        options.value = textarea.value;
        if (!options.tabindex && textarea.tabIndex)
            options.tabindex = textarea.tabIndex;
        if (!options.placeholder && textarea.placeholder)
            options.placeholder = textarea.placeholder;
        // Set autofocus to true if this textarea is focused, or if it has
        // autofocus and no other element is focused.
        if (options.autofocus == null) {
            var hasFocus = activeElt();
            options.autofocus = hasFocus == textarea ||
              textarea.getAttribute("autofocus") != null && hasFocus == document.body;
        }

        function save() { textarea.value = cm.getValue(); }
        if (textarea.form) {
            on(textarea.form, "submit", save);
            // Deplorable hack to make the submit method do the right thing.
            if (!options.leaveSubmitMethodAlone) {
                var form = textarea.form, realSubmit = form.submit;
                try {
                    var wrappedSubmit = form.submit = function () {
                        save();
                        form.submit = realSubmit;
                        form.submit();
                        form.submit = wrappedSubmit;
                    };
                } catch (e) { }
            }
        }

        options.finishInit = function (cm) {
            cm.save = save;
            cm.getTextArea = function () { return textarea; };
            cm.toTextArea = function () {
                cm.toTextArea = isNaN; // Prevent this from being ran twice
                save();
                textarea.parentNode.removeChild(cm.getWrapperElement());
                textarea.style.display = "";
                if (textarea.form) {
                    off(textarea.form, "submit", save);
                    if (typeof textarea.form.submit == "function")
                        textarea.form.submit = realSubmit;
                }
            };
        };

        textarea.style.display = "none";
        var cm = CodeMirror(function (node) {
            textarea.parentNode.insertBefore(node, textarea.nextSibling);
        }, options);
        return cm;
    };

    // STRING STREAM

    // Fed to the mode parsers, provides helper functions to make
    // parsers more succinct.

    var StringStream = CodeMirror.StringStream = function (string, tabSize) {
        this.pos = this.start = 0;
        this.string = string;
        this.tabSize = tabSize || 8;
        this.lastColumnPos = this.lastColumnValue = 0;
        this.lineStart = 0;
    };

    StringStream.prototype = {
        eol: function () { return this.pos >= this.string.length; },
        sol: function () { return this.pos == this.lineStart; },
        peek: function () { return this.string.charAt(this.pos) || undefined; },
        next: function () {
            if (this.pos < this.string.length)
                return this.string.charAt(this.pos++);
        },
        eat: function (match) {
            var ch = this.string.charAt(this.pos);
            if (typeof match == "string") var ok = ch == match;
            else var ok = ch && (match.test ? match.test(ch) : match(ch));
            if (ok) { ++this.pos; return ch; }
        },
        eatWhile: function (match) {
            var start = this.pos;
            while (this.eat(match)) { }
            return this.pos > start;
        },
        eatSpace: function () {
            var start = this.pos;
            while (/[\s\u00a0]/.test(this.string.charAt(this.pos)))++this.pos;
            return this.pos > start;
        },
        skipToEnd: function () { this.pos = this.string.length; },
        skipTo: function (ch) {
            var found = this.string.indexOf(ch, this.pos);
            if (found > -1) { this.pos = found; return true; }
        },
        backUp: function (n) { this.pos -= n; },
        column: function () {
            if (this.lastColumnPos < this.start) {
                this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
                this.lastColumnPos = this.start;
            }
            return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
        },
        indentation: function () {
            return countColumn(this.string, null, this.tabSize) -
              (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
        },
        match: function (pattern, consume, caseInsensitive) {
            if (typeof pattern == "string") {
                var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
                var substr = this.string.substr(this.pos, pattern.length);
                if (cased(substr) == cased(pattern)) {
                    if (consume !== false) this.pos += pattern.length;
                    return true;
                }
            } else {
                var match = this.string.slice(this.pos).match(pattern);
                if (match && match.index > 0) return null;
                if (match && consume !== false) this.pos += match[0].length;
                return match;
            }
        },
        current: function () { return this.string.slice(this.start, this.pos); },
        hideFirstChars: function (n, inner) {
            this.lineStart += n;
            try { return inner(); }
            finally { this.lineStart -= n; }
        }
    };

    // TEXTMARKERS

    // Created with markText and setBookmark methods. A TextMarker is a
    // handle that can be used to clear or find a marked position in the
    // document. Line objects hold arrays (markedSpans) containing
    // {from, to, marker} object pointing to such marker objects, and
    // indicating that such a marker is present on that line. Multiple
    // lines may point to the same marker when it spans across lines.
    // The spans will have null for their from/to properties when the
    // marker continues beyond the start/end of the line. Markers have
    // links back to the lines they currently touch.

    var nextMarkerId = 0;

    var TextMarker = CodeMirror.TextMarker = function (doc, type) {
        this.lines = [];
        this.type = type;
        this.doc = doc;
        this.id = ++nextMarkerId;
    };
    eventMixin(TextMarker);

    // Clear the marker.
    TextMarker.prototype.clear = function () {
        if (this.explicitlyCleared) return;
        var cm = this.doc.cm, withOp = cm && !cm.curOp;
        if (withOp) startOperation(cm);
        if (hasHandler(this, "clear")) {
            var found = this.find();
            if (found) signalLater(this, "clear", found.from, found.to);
        }
        var min = null, max = null;
        for (var i = 0; i < this.lines.length; ++i) {
            var line = this.lines[i];
            var span = getMarkedSpanFor(line.markedSpans, this);
            if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
            else if (cm) {
                if (span.to != null) max = lineNo(line);
                if (span.from != null) min = lineNo(line);
            }
            line.markedSpans = removeMarkedSpan(line.markedSpans, span);
            if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
                updateLineHeight(line, textHeight(cm.display));
        }
        if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
            var visual = visualLine(this.lines[i]), len = lineLength(visual);
            if (len > cm.display.maxLineLength) {
                cm.display.maxLine = visual;
                cm.display.maxLineLength = len;
                cm.display.maxLineChanged = true;
            }
        }

        if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
        this.lines.length = 0;
        this.explicitlyCleared = true;
        if (this.atomic && this.doc.cantEdit) {
            this.doc.cantEdit = false;
            if (cm) reCheckSelection(cm.doc);
        }
        if (cm) signalLater(cm, "markerCleared", cm, this);
        if (withOp) endOperation(cm);
        if (this.parent) this.parent.clear();
    };

    // Find the position of the marker in the document. Returns a {from,
    // to} object by default. Side can be passed to get a specific side
    // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
    // Pos objects returned contain a line object, rather than a line
    // number (used to prevent looking up the same line twice).
    TextMarker.prototype.find = function (side, lineObj) {
        if (side == null && this.type == "bookmark") side = 1;
        var from, to;
        for (var i = 0; i < this.lines.length; ++i) {
            var line = this.lines[i];
            var span = getMarkedSpanFor(line.markedSpans, this);
            if (span.from != null) {
                from = Pos(lineObj ? line : lineNo(line), span.from);
                if (side == -1) return from;
            }
            if (span.to != null) {
                to = Pos(lineObj ? line : lineNo(line), span.to);
                if (side == 1) return to;
            }
        }
        return from && { from: from, to: to };
    };

    // Signals that the marker's widget changed, and surrounding layout
    // should be recomputed.
    TextMarker.prototype.changed = function () {
        var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
        if (!pos || !cm) return;
        runInOp(cm, function () {
            var line = pos.line, lineN = lineNo(pos.line);
            var view = findViewForLine(cm, lineN);
            if (view) {
                clearLineMeasurementCacheFor(view);
                cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
            }
            cm.curOp.updateMaxLine = true;
            if (!lineIsHidden(widget.doc, line) && widget.height != null) {
                var oldHeight = widget.height;
                widget.height = null;
                var dHeight = widgetHeight(widget) - oldHeight;
                if (dHeight)
                    updateLineHeight(line, line.height + dHeight);
            }
        });
    };

    TextMarker.prototype.attachLine = function (line) {
        if (!this.lines.length && this.doc.cm) {
            var op = this.doc.cm.curOp;
            if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
                (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
        }
        this.lines.push(line);
    };
    TextMarker.prototype.detachLine = function (line) {
        this.lines.splice(indexOf(this.lines, line), 1);
        if (!this.lines.length && this.doc.cm) {
            var op = this.doc.cm.curOp;
            (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
        }
    };

    // Collapsed markers have unique ids, in order to be able to order
    // them, which is needed for uniquely determining an outer marker
    // when they overlap (they may nest, but not partially overlap).
    var nextMarkerId = 0;

    // Create a marker, wire it up to the right lines, and
    function markText(doc, from, to, options, type) {
        // Shared markers (across linked documents) are handled separately
        // (markTextShared will call out to this again, once per
        // document).
        if (options && options.shared) return markTextShared(doc, from, to, options, type);
        // Ensure we are in an operation.
        if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);

        var marker = new TextMarker(doc, type), diff = cmp(from, to);
        if (options) copyObj(options, marker, false);
        // Don't connect empty markers unless clearWhenEmpty is false
        if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
            return marker;
        if (marker.replacedWith) {
            // Showing up as a widget implies collapsed (widget replaces text)
            marker.collapsed = true;
            marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
            if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
            if (options.insertLeft) marker.widgetNode.insertLeft = true;
        }
        if (marker.collapsed) {
            if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
                from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
                throw new Error("Inserting collapsed marker partially overlapping an existing one");
            sawCollapsedSpans = true;
        }

        if (marker.addToHistory)
            addChangeToHistory(doc, { from: from, to: to, origin: "markText" }, doc.sel, NaN);

        var curLine = from.line, cm = doc.cm, updateMaxLine;
        doc.iter(curLine, to.line + 1, function (line) {
            if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
                updateMaxLine = true;
            if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
            addMarkedSpan(line, new MarkedSpan(marker,
                                               curLine == from.line ? from.ch : null,
                                               curLine == to.line ? to.ch : null));
            ++curLine;
        });
        // lineIsHidden depends on the presence of the spans, so needs a second pass
        if (marker.collapsed) doc.iter(from.line, to.line + 1, function (line) {
            if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
        });

        if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function () { marker.clear(); });

        if (marker.readOnly) {
            sawReadOnlySpans = true;
            if (doc.history.done.length || doc.history.undone.length)
                doc.clearHistory();
        }
        if (marker.collapsed) {
            marker.id = ++nextMarkerId;
            marker.atomic = true;
        }
        if (cm) {
            // Sync editor state
            if (updateMaxLine) cm.curOp.updateMaxLine = true;
            if (marker.collapsed)
                regChange(cm, from.line, to.line + 1);
            else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
                for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
            if (marker.atomic) reCheckSelection(cm.doc);
            signalLater(cm, "markerAdded", cm, marker);
        }
        return marker;
    }

    // SHARED TEXTMARKERS

    // A shared marker spans multiple linked documents. It is
    // implemented as a meta-marker-object controlling multiple normal
    // markers.
    var SharedTextMarker = CodeMirror.SharedTextMarker = function (markers, primary) {
        this.markers = markers;
        this.primary = primary;
        for (var i = 0; i < markers.length; ++i)
            markers[i].parent = this;
    };
    eventMixin(SharedTextMarker);

    SharedTextMarker.prototype.clear = function () {
        if (this.explicitlyCleared) return;
        this.explicitlyCleared = true;
        for (var i = 0; i < this.markers.length; ++i)
            this.markers[i].clear();
        signalLater(this, "clear");
    };
    SharedTextMarker.prototype.find = function (side, lineObj) {
        return this.primary.find(side, lineObj);
    };

    function markTextShared(doc, from, to, options, type) {
        options = copyObj(options);
        options.shared = false;
        var markers = [markText(doc, from, to, options, type)], primary = markers[0];
        var widget = options.widgetNode;
        linkedDocs(doc, function (doc) {
            if (widget) options.widgetNode = widget.cloneNode(true);
            markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
            for (var i = 0; i < doc.linked.length; ++i)
                if (doc.linked[i].isParent) return;
            primary = lst(markers);
        });
        return new SharedTextMarker(markers, primary);
    }

    function findSharedMarkers(doc) {
        return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
                             function (m) { return m.parent; });
    }

    function copySharedMarkers(doc, markers) {
        for (var i = 0; i < markers.length; i++) {
            var marker = markers[i], pos = marker.find();
            var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
            if (cmp(mFrom, mTo)) {
                var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
                marker.markers.push(subMark);
                subMark.parent = marker;
            }
        }
    }

    function detachSharedMarkers(markers) {
        for (var i = 0; i < markers.length; i++) {
            var marker = markers[i], linked = [marker.primary.doc];;
            linkedDocs(marker.primary.doc, function (d) { linked.push(d); });
            for (var j = 0; j < marker.markers.length; j++) {
                var subMarker = marker.markers[j];
                if (indexOf(linked, subMarker.doc) == -1) {
                    subMarker.parent = null;
                    marker.markers.splice(j--, 1);
                }
            }
        }
    }

    // TEXTMARKER SPANS

    function MarkedSpan(marker, from, to) {
        this.marker = marker;
        this.from = from; this.to = to;
    }

    // Search an array of spans for a span matching the given marker.
    function getMarkedSpanFor(spans, marker) {
        if (spans) for (var i = 0; i < spans.length; ++i) {
            var span = spans[i];
            if (span.marker == marker) return span;
        }
    }
    // Remove a span from an array, returning undefined if no spans are
    // left (we don't store arrays for lines without spans).
    function removeMarkedSpan(spans, span) {
        for (var r, i = 0; i < spans.length; ++i)
            if (spans[i] != span) (r || (r = [])).push(spans[i]);
        return r;
    }
    // Add a span to a line.
    function addMarkedSpan(line, span) {
        line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
        span.marker.attachLine(line);
    }

    // Used for the algorithm that adjusts markers for a change in the
    // document. These functions cut an array of spans at a given
    // character position, returning an array of remaining chunks (or
    // undefined if nothing remains).
    function markedSpansBefore(old, startCh, isInsert) {
        if (old) for (var i = 0, nw; i < old.length; ++i) {
            var span = old[i], marker = span.marker;
            var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
            if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
                var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
                (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
            }
        }
        return nw;
    }
    function markedSpansAfter(old, endCh, isInsert) {
        if (old) for (var i = 0, nw; i < old.length; ++i) {
            var span = old[i], marker = span.marker;
            var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
            if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
                var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
                (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
                                                      span.to == null ? null : span.to - endCh));
            }
        }
        return nw;
    }

    // Given a change object, compute the new set of marker spans that
    // cover the line in which the change took place. Removes spans
    // entirely within the change, reconnects spans belonging to the
    // same marker that appear on both sides of the change, and cuts off
    // spans partially within the change. Returns an array of span
    // arrays with one element for each line in (after) the change.
    function stretchSpansOverChange(doc, change) {
        if (change.full) return null;
        var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
        var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
        if (!oldFirst && !oldLast) return null;

        var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
        // Get the spans that 'stick out' on both sides
        var first = markedSpansBefore(oldFirst, startCh, isInsert);
        var last = markedSpansAfter(oldLast, endCh, isInsert);

        // Next, merge those two ends
        var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
        if (first) {
            // Fix up .to properties of first
            for (var i = 0; i < first.length; ++i) {
                var span = first[i];
                if (span.to == null) {
                    var found = getMarkedSpanFor(last, span.marker);
                    if (!found) span.to = startCh;
                    else if (sameLine) span.to = found.to == null ? null : found.to + offset;
                }
            }
        }
        if (last) {
            // Fix up .from in last (or move them into first in case of sameLine)
            for (var i = 0; i < last.length; ++i) {
                var span = last[i];
                if (span.to != null) span.to += offset;
                if (span.from == null) {
                    var found = getMarkedSpanFor(first, span.marker);
                    if (!found) {
                        span.from = offset;
                        if (sameLine) (first || (first = [])).push(span);
                    }
                } else {
                    span.from += offset;
                    if (sameLine) (first || (first = [])).push(span);
                }
            }
        }
        // Make sure we didn't create any zero-length spans
        if (first) first = clearEmptySpans(first);
        if (last && last != first) last = clearEmptySpans(last);

        var newMarkers = [first];
        if (!sameLine) {
            // Fill gap with whole-line-spans
            var gap = change.text.length - 2, gapMarkers;
            if (gap > 0 && first)
                for (var i = 0; i < first.length; ++i)
                    if (first[i].to == null)
                        (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
            for (var i = 0; i < gap; ++i)
                newMarkers.push(gapMarkers);
            newMarkers.push(last);
        }
        return newMarkers;
    }

    // Remove spans that are empty and don't have a clearWhenEmpty
    // option of false.
    function clearEmptySpans(spans) {
        for (var i = 0; i < spans.length; ++i) {
            var span = spans[i];
            if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
                spans.splice(i--, 1);
        }
        if (!spans.length) return null;
        return spans;
    }

    // Used for un/re-doing changes from the history. Combines the
    // result of computing the existing spans with the set of spans that
    // existed in the history (so that deleting around a span and then
    // undoing brings back the span).
    function mergeOldSpans(doc, change) {
        var old = getOldSpans(doc, change);
        var stretched = stretchSpansOverChange(doc, change);
        if (!old) return stretched;
        if (!stretched) return old;

        for (var i = 0; i < old.length; ++i) {
            var oldCur = old[i], stretchCur = stretched[i];
            if (oldCur && stretchCur) {
                spans: for (var j = 0; j < stretchCur.length; ++j) {
                    var span = stretchCur[j];
                    for (var k = 0; k < oldCur.length; ++k)
                        if (oldCur[k].marker == span.marker) continue spans;
                    oldCur.push(span);
                }
            } else if (stretchCur) {
                old[i] = stretchCur;
            }
        }
        return old;
    }

    // Used to 'clip' out readOnly ranges when making a change.
    function removeReadOnlyRanges(doc, from, to) {
        var markers = null;
        doc.iter(from.line, to.line + 1, function (line) {
            if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
                var mark = line.markedSpans[i].marker;
                if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
                    (markers || (markers = [])).push(mark);
            }
        });
        if (!markers) return null;
        var parts = [{ from: from, to: to }];
        for (var i = 0; i < markers.length; ++i) {
            var mk = markers[i], m = mk.find(0);
            for (var j = 0; j < parts.length; ++j) {
                var p = parts[j];
                if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
                var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
                if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
                    newParts.push({ from: p.from, to: m.from });
                if (dto > 0 || !mk.inclusiveRight && !dto)
                    newParts.push({ from: m.to, to: p.to });
                parts.splice.apply(parts, newParts);
                j += newParts.length - 1;
            }
        }
        return parts;
    }

    // Connect or disconnect spans from a line.
    function detachMarkedSpans(line) {
        var spans = line.markedSpans;
        if (!spans) return;
        for (var i = 0; i < spans.length; ++i)
            spans[i].marker.detachLine(line);
        line.markedSpans = null;
    }
    function attachMarkedSpans(line, spans) {
        if (!spans) return;
        for (var i = 0; i < spans.length; ++i)
            spans[i].marker.attachLine(line);
        line.markedSpans = spans;
    }

    // Helpers used when computing which overlapping collapsed span
    // counts as the larger one.
    function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
    function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }

    // Returns a number indicating which of two overlapping collapsed
    // spans is larger (and thus includes the other). Falls back to
    // comparing ids when the spans cover exactly the same range.
    function compareCollapsedMarkers(a, b) {
        var lenDiff = a.lines.length - b.lines.length;
        if (lenDiff != 0) return lenDiff;
        var aPos = a.find(), bPos = b.find();
        var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
        if (fromCmp) return -fromCmp;
        var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
        if (toCmp) return toCmp;
        return b.id - a.id;
    }

    // Find out whether a line ends or starts in a collapsed span. If
    // so, return the marker for that span.
    function collapsedSpanAtSide(line, start) {
        var sps = sawCollapsedSpans && line.markedSpans, found;
        if (sps) for (var sp, i = 0; i < sps.length; ++i) {
            sp = sps[i];
            if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
                (!found || compareCollapsedMarkers(found, sp.marker) < 0))
                found = sp.marker;
        }
        return found;
    }
    function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
    function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }

    // Test whether there exists a collapsed span that partially
    // overlaps (covers the start or end, but not both) of a new span.
    // Such overlap is not allowed.
    function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
        var line = getLine(doc, lineNo);
        var sps = sawCollapsedSpans && line.markedSpans;
        if (sps) for (var i = 0; i < sps.length; ++i) {
            var sp = sps[i];
            if (!sp.marker.collapsed) continue;
            var found = sp.marker.find(0);
            var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
            var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
            if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
            if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
                fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
                return true;
        }
    }

    // A visual line is a line as drawn on the screen. Folding, for
    // example, can cause multiple logical lines to appear on the same
    // visual line. This finds the start of the visual line that the
    // given line is part of (usually that is the line itself).
    function visualLine(line) {
        var merged;
        while (merged = collapsedSpanAtStart(line))
            line = merged.find(-1, true).line;
        return line;
    }

    // Returns an array of logical lines that continue the visual line
    // started by the argument, or undefined if there are no such lines.
    function visualLineContinued(line) {
        var merged, lines;
        while (merged = collapsedSpanAtEnd(line)) {
            line = merged.find(1, true).line;
            (lines || (lines = [])).push(line);
        }
        return lines;
    }

    // Get the line number of the start of the visual line that the
    // given line number is part of.
    function visualLineNo(doc, lineN) {
        var line = getLine(doc, lineN), vis = visualLine(line);
        if (line == vis) return lineN;
        return lineNo(vis);
    }
    // Get the line number of the start of the next visual line after
    // the given line.
    function visualLineEndNo(doc, lineN) {
        if (lineN > doc.lastLine()) return lineN;
        var line = getLine(doc, lineN), merged;
        if (!lineIsHidden(doc, line)) return lineN;
        while (merged = collapsedSpanAtEnd(line))
            line = merged.find(1, true).line;
        return lineNo(line) + 1;
    }

    // Compute whether a line is hidden. Lines count as hidden when they
    // are part of a visual line that starts with another line, or when
    // they are entirely covered by collapsed, non-widget span.
    function lineIsHidden(doc, line) {
        var sps = sawCollapsedSpans && line.markedSpans;
        if (sps) for (var sp, i = 0; i < sps.length; ++i) {
            sp = sps[i];
            if (!sp.marker.collapsed) continue;
            if (sp.from == null) return true;
            if (sp.marker.widgetNode) continue;
            if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
                return true;
        }
    }
    function lineIsHiddenInner(doc, line, span) {
        if (span.to == null) {
            var end = span.marker.find(1, true);
            return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
        }
        if (span.marker.inclusiveRight && span.to == line.text.length)
            return true;
        for (var sp, i = 0; i < line.markedSpans.length; ++i) {
            sp = line.markedSpans[i];
            if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
                (sp.to == null || sp.to != span.from) &&
                (sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
                lineIsHiddenInner(doc, line, sp)) return true;
        }
    }

    // LINE WIDGETS

    // Line widgets are block elements displayed above or below a line.

    var LineWidget = CodeMirror.LineWidget = function (doc, node, options) {
        if (options) for (var opt in options) if (options.hasOwnProperty(opt))
            this[opt] = options[opt];
        this.doc = doc;
        this.node = node;
    };
    eventMixin(LineWidget);

    function adjustScrollWhenAboveVisible(cm, line, diff) {
        if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
            addToScrollPos(cm, null, diff);
    }

    LineWidget.prototype.clear = function () {
        var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
        if (no == null || !ws) return;
        for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
        if (!ws.length) line.widgets = null;
        var height = widgetHeight(this);
        updateLineHeight(line, Math.max(0, line.height - height));
        if (cm) runInOp(cm, function () {
            adjustScrollWhenAboveVisible(cm, line, -height);
            regLineChange(cm, no, "widget");
        });
    };
    LineWidget.prototype.changed = function () {
        var oldH = this.height, cm = this.doc.cm, line = this.line;
        this.height = null;
        var diff = widgetHeight(this) - oldH;
        if (!diff) return;
        updateLineHeight(line, line.height + diff);
        if (cm) runInOp(cm, function () {
            cm.curOp.forceUpdate = true;
            adjustScrollWhenAboveVisible(cm, line, diff);
        });
    };

    function widgetHeight(widget) {
        if (widget.height != null) return widget.height;
        var cm = widget.doc.cm;
        if (!cm) return 0;
        if (!contains(document.body, widget.node)) {
            var parentStyle = "position: relative;";
            if (widget.coverGutter)
                parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
            if (widget.noHScroll)
                parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
            removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
        }
        return widget.height = widget.node.offsetHeight;
    }

    function addLineWidget(doc, handle, node, options) {
        var widget = new LineWidget(doc, node, options);
        var cm = doc.cm;
        if (cm && widget.noHScroll) cm.display.alignWidgets = true;
        changeLine(doc, handle, "widget", function (line) {
            var widgets = line.widgets || (line.widgets = []);
            if (widget.insertAt == null) widgets.push(widget);
            else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
            widget.line = line;
            if (cm && !lineIsHidden(doc, line)) {
                var aboveVisible = heightAtLine(line) < doc.scrollTop;
                updateLineHeight(line, line.height + widgetHeight(widget));
                if (aboveVisible) addToScrollPos(cm, null, widget.height);
                cm.curOp.forceUpdate = true;
            }
            return true;
        });
        return widget;
    }

    // LINE DATA STRUCTURE

    // Line objects. These hold state related to a line, including
    // highlighting info (the styles array).
    var Line = CodeMirror.Line = function (text, markedSpans, estimateHeight) {
        this.text = text;
        attachMarkedSpans(this, markedSpans);
        this.height = estimateHeight ? estimateHeight(this) : 1;
    };
    eventMixin(Line);
    Line.prototype.lineNo = function () { return lineNo(this); };

    // Change the content (text, markers) of a line. Automatically
    // invalidates cached information and tries to re-estimate the
    // line's height.
    function updateLine(line, text, markedSpans, estimateHeight) {
        line.text = text;
        if (line.stateAfter) line.stateAfter = null;
        if (line.styles) line.styles = null;
        if (line.order != null) line.order = null;
        detachMarkedSpans(line);
        attachMarkedSpans(line, markedSpans);
        var estHeight = estimateHeight ? estimateHeight(line) : 1;
        if (estHeight != line.height) updateLineHeight(line, estHeight);
    }

    // Detach a line from the document tree and its markers.
    function cleanUpLine(line) {
        line.parent = null;
        detachMarkedSpans(line);
    }

    function extractLineClasses(type, output) {
        if (type) for (; ;) {
            var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
            if (!lineClass) break;
            type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
            var prop = lineClass[1] ? "bgClass" : "textClass";
            if (output[prop] == null)
                output[prop] = lineClass[2];
            else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
                output[prop] += " " + lineClass[2];
        }
        return type;
    }

    function callBlankLine(mode, state) {
        if (mode.blankLine) return mode.blankLine(state);
        if (!mode.innerMode) return;
        var inner = CodeMirror.innerMode(mode, state);
        if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
    }

    function readToken(mode, stream, state, inner) {
        for (var i = 0; i < 10; i++) {
            if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
            var style = mode.token(stream, state);
            if (stream.pos > stream.start) return style;
        }
        throw new Error("Mode " + mode.name + " failed to advance stream.");
    }

    // Utility for getTokenAt and getLineTokens
    function takeToken(cm, pos, precise, asArray) {
        function getObj(copy) {
            return {
                start: stream.start, end: stream.pos,
                string: stream.current(),
                type: style || null,
                state: copy ? copyState(doc.mode, state) : state
            };
        }

        var doc = cm.doc, mode = doc.mode, style;
        pos = clipPos(doc, pos);
        var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
        var stream = new StringStream(line.text, cm.options.tabSize), tokens;
        if (asArray) tokens = [];
        while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
            stream.start = stream.pos;
            style = readToken(mode, stream, state);
            if (asArray) tokens.push(getObj(true));
        }
        return asArray ? tokens : getObj();
    }

    // Run the given mode's parser over a line, calling f for each token.
    function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
        var flattenSpans = mode.flattenSpans;
        if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
        var curStart = 0, curStyle = null;
        var stream = new StringStream(text, cm.options.tabSize), style;
        var inner = cm.options.addModeClass && [null];
        if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
        while (!stream.eol()) {
            if (stream.pos > cm.options.maxHighlightLength) {
                flattenSpans = false;
                if (forceToEnd) processLine(cm, text, state, stream.pos);
                stream.pos = text.length;
                style = null;
            } else {
                style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
            }
            if (inner) {
                var mName = inner[0].name;
                if (mName) style = "m-" + (style ? mName + " " + style : mName);
            }
            if (!flattenSpans || curStyle != style) {
                while (curStart < stream.start) {
                    curStart = Math.min(stream.start, curStart + 50000);
                    f(curStart, curStyle);
                }
                curStyle = style;
            }
            stream.start = stream.pos;
        }
        while (curStart < stream.pos) {
            // Webkit seems to refuse to render text nodes longer than 57444 characters
            var pos = Math.min(stream.pos, curStart + 50000);
            f(pos, curStyle);
            curStart = pos;
        }
    }

    // Compute a style array (an array starting with a mode generation
    // -- for invalidation -- followed by pairs of end positions and
    // style strings), which is used to highlight the tokens on the
    // line.
    function highlightLine(cm, line, state, forceToEnd) {
        // A styles array always starts with a number identifying the
        // mode/overlays that it is based on (for easy invalidation).
        var st = [cm.state.modeGen], lineClasses = {};
        // Compute the base array of styles
        runMode(cm, line.text, cm.doc.mode, state, function (end, style) {
            st.push(end, style);
        }, lineClasses, forceToEnd);

        // Run overlays, adjust style array.
        for (var o = 0; o < cm.state.overlays.length; ++o) {
            var overlay = cm.state.overlays[o], i = 1, at = 0;
            runMode(cm, line.text, overlay.mode, true, function (end, style) {
                var start = i;
                // Ensure there's a token end at the current position, and that i points at it
                while (at < end) {
                    var i_end = st[i];
                    if (i_end > end)
                        st.splice(i, 1, end, st[i + 1], i_end);
                    i += 2;
                    at = Math.min(end, i_end);
                }
                if (!style) return;
                if (overlay.opaque) {
                    st.splice(start, i - start, end, "cm-overlay " + style);
                    i = start + 2;
                } else {
                    for (; start < i; start += 2) {
                        var cur = st[start + 1];
                        st[start + 1] = (cur ? cur + " " : "") + "cm-overlay " + style;
                    }
                }
            }, lineClasses);
        }

        return { styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null };
    }

    function getLineStyles(cm, line, updateFrontier) {
        if (!line.styles || line.styles[0] != cm.state.modeGen) {
            var state = getStateBefore(cm, lineNo(line));
            var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
            line.stateAfter = state;
            line.styles = result.styles;
            if (result.classes) line.styleClasses = result.classes;
            else if (line.styleClasses) line.styleClasses = null;
            if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
        }
        return line.styles;
    }

    // Lightweight form of highlight -- proceed over this line and
    // update state, but don't save a style array. Used for lines that
    // aren't currently visible.
    function processLine(cm, text, state, startAt) {
        var mode = cm.doc.mode;
        var stream = new StringStream(text, cm.options.tabSize);
        stream.start = stream.pos = startAt || 0;
        if (text == "") callBlankLine(mode, state);
        while (!stream.eol()) {
            readToken(mode, stream, state);
            stream.start = stream.pos;
        }
    }

    // Convert a style as returned by a mode (either null, or a string
    // containing one or more styles) to a CSS style. This is cached,
    // and also looks for line-wide styles.
    var styleToClassCache = {}, styleToClassCacheWithMode = {};
    function interpretTokenStyle(style, options) {
        if (!style || /^\s*$/.test(style)) return null;
        var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
        return cache[style] ||
          (cache[style] = style.replace(/\S+/g, "cm-$&"));
    }

    // Render the DOM representation of the text of a line. Also builds
    // up a 'line map', which points at the DOM nodes that represent
    // specific stretches of text, and is used by the measuring code.
    // The returned object contains the DOM node, this map, and
    // information about line-wide styles that were set by the mode.
    function buildLineContent(cm, lineView) {
        // The padding-right forces the element to have a 'border', which
        // is needed on Webkit to be able to get line-level bounding
        // rectangles for it (in measureChar).
        var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
        var builder = {
            pre: elt("pre", [content], "CodeMirror-line"), content: content,
            col: 0, pos: 0, cm: cm,
            splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")
        };
        lineView.measure = {};

        // Iterate over the logical lines that make up this visual line.
        for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0) ; i++) {
            var line = i ? lineView.rest[i - 1] : lineView.line, order;
            builder.pos = 0;
            builder.addToken = buildToken;
            // Optionally wire in some hacks into the token-rendering
            // algorithm, to deal with browser quirks.
            if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
                builder.addToken = buildTokenBadBidi(builder.addToken, order);
            builder.map = [];
            var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
            insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
            if (line.styleClasses) {
                if (line.styleClasses.bgClass)
                    builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
                if (line.styleClasses.textClass)
                    builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
            }

            // Ensure at least a single node is present, for measuring.
            if (builder.map.length == 0)
                builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));

            // Store the map and a cache object for the current logical line
            if (i == 0) {
                lineView.measure.map = builder.map;
                lineView.measure.cache = {};
            } else {
                (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
                (lineView.measure.caches || (lineView.measure.caches = [])).push({});
            }
        }

        // See issue #2901
        if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
            builder.content.className = "cm-tab-wrap-hack";

        signal(cm, "renderLine", cm, lineView.line, builder.pre);
        if (builder.pre.className)
            builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");

        return builder;
    }

    function defaultSpecialCharPlaceholder(ch) {
        var token = elt("span", "\u2022", "cm-invalidchar");
        token.title = "\\u" + ch.charCodeAt(0).toString(16);
        token.setAttribute("aria-label", token.title);
        return token;
    }

    // Build up the DOM representation for a single token, and add it to
    // the line map. Takes care to render special characters separately.
    function buildToken(builder, text, style, startStyle, endStyle, title, css) {
        if (!text) return;
        var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
        var special = builder.cm.state.specialChars, mustWrap = false;
        if (!special.test(text)) {
            builder.col += text.length;
            var content = document.createTextNode(displayText);
            builder.map.push(builder.pos, builder.pos + text.length, content);
            if (ie && ie_version < 9) mustWrap = true;
            builder.pos += text.length;
        } else {
            var content = document.createDocumentFragment(), pos = 0;
            while (true) {
                special.lastIndex = pos;
                var m = special.exec(text);
                var skipped = m ? m.index - pos : text.length - pos;
                if (skipped) {
                    var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
                    if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
                    else content.appendChild(txt);
                    builder.map.push(builder.pos, builder.pos + skipped, txt);
                    builder.col += skipped;
                    builder.pos += skipped;
                }
                if (!m) break;
                pos += skipped + 1;
                if (m[0] == "\t") {
                    var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
                    var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
                    txt.setAttribute("role", "presentation");
                    txt.setAttribute("cm-text", "\t");
                    builder.col += tabWidth;
                } else if (m[0] == "\r" || m[0] == "\n") {
                    var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
                    txt.setAttribute("cm-text", m[0]);
                    builder.col += 1;
                } else {
                    var txt = builder.cm.options.specialCharPlaceholder(m[0]);
                    txt.setAttribute("cm-text", m[0]);
                    if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
                    else content.appendChild(txt);
                    builder.col += 1;
                }
                builder.map.push(builder.pos, builder.pos + 1, txt);
                builder.pos++;
            }
        }
        if (style || startStyle || endStyle || mustWrap || css) {
            var fullStyle = style || "";
            if (startStyle) fullStyle += startStyle;
            if (endStyle) fullStyle += endStyle;
            var token = elt("span", [content], fullStyle, css);
            if (title) token.title = title;
            return builder.content.appendChild(token);
        }
        builder.content.appendChild(content);
    }

    function splitSpaces(old) {
        var out = " ";
        for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
        out += " ";
        return out;
    }

    // Work around nonsense dimensions being reported for stretches of
    // right-to-left text.
    function buildTokenBadBidi(inner, order) {
        return function (builder, text, style, startStyle, endStyle, title, css) {
            style = style ? style + " cm-force-border" : "cm-force-border";
            var start = builder.pos, end = start + text.length;
            for (; ;) {
                // Find the part that overlaps with the start of this text
                for (var i = 0; i < order.length; i++) {
                    var part = order[i];
                    if (part.to > start && part.from <= start) break;
                }
                if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
                inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
                startStyle = null;
                text = text.slice(part.to - start);
                start = part.to;
            }
        };
    }

    function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
        var widget = !ignoreWidget && marker.widgetNode;
        if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
        if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
            if (!widget)
                widget = builder.content.appendChild(document.createElement("span"));
            widget.setAttribute("cm-marker", marker.id);
        }
        if (widget) {
            builder.cm.display.input.setUneditable(widget);
            builder.content.appendChild(widget);
        }
        builder.pos += size;
    }

    // Outputs a number of spans to make up a line, taking highlighting
    // and marked text into account.
    function insertLineContent(line, builder, styles) {
        var spans = line.markedSpans, allText = line.text, at = 0;
        if (!spans) {
            for (var i = 1; i < styles.length; i += 2)
                builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i + 1], builder.cm.options));
            return;
        }

        var len = allText.length, pos = 0, i = 1, text = "", style, css;
        var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
        for (; ;) {
            if (nextChange == pos) { // Update current marker set
                spanStyle = spanEndStyle = spanStartStyle = title = css = "";
                collapsed = null; nextChange = Infinity;
                var foundBookmarks = [];
                for (var j = 0; j < spans.length; ++j) {
                    var sp = spans[j], m = sp.marker;
                    if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
                        foundBookmarks.push(m);
                    } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
                        if (sp.to != null && sp.to != pos && nextChange > sp.to) {
                            nextChange = sp.to;
                            spanEndStyle = "";
                        }
                        if (m.className) spanStyle += " " + m.className;
                        if (m.css) css = m.css;
                        if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
                        if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
                        if (m.title && !title) title = m.title;
                        if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
                            collapsed = sp;
                    } else if (sp.from > pos && nextChange > sp.from) {
                        nextChange = sp.from;
                    }
                }
                if (collapsed && (collapsed.from || 0) == pos) {
                    buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
                                       collapsed.marker, collapsed.from == null);
                    if (collapsed.to == null) return;
                    if (collapsed.to == pos) collapsed = false;
                }
                if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
                    buildCollapsedSpan(builder, 0, foundBookmarks[j]);
            }
            if (pos >= len) break;

            var upto = Math.min(len, nextChange);
            while (true) {
                if (text) {
                    var end = pos + text.length;
                    if (!collapsed) {
                        var tokenText = end > upto ? text.slice(0, upto - pos) : text;
                        builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
                                         spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
                    }
                    if (end >= upto) { text = text.slice(upto - pos); pos = upto; break; }
                    pos = end;
                    spanStartStyle = "";
                }
                text = allText.slice(at, at = styles[i++]);
                style = interpretTokenStyle(styles[i++], builder.cm.options);
            }
        }
    }

    // DOCUMENT DATA STRUCTURE

    // By default, updates that start and end at the beginning of a line
    // are treated specially, in order to make the association of line
    // widgets and marker elements with the text behave more intuitive.
    function isWholeLineUpdate(doc, change) {
        return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
          (!doc.cm || doc.cm.options.wholeLineUpdateBefore);
    }

    // Perform a change on the document data structure.
    function updateDoc(doc, change, markedSpans, estimateHeight) {
        function spansFor(n) { return markedSpans ? markedSpans[n] : null; }
        function update(line, text, spans) {
            updateLine(line, text, spans, estimateHeight);
            signalLater(line, "change", line, change);
        }
        function linesFor(start, end) {
            for (var i = start, result = []; i < end; ++i)
                result.push(new Line(text[i], spansFor(i), estimateHeight));
            return result;
        }

        var from = change.from, to = change.to, text = change.text;
        var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
        var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;

        // Adjust the line structure
        if (change.full) {
            doc.insert(0, linesFor(0, text.length));
            doc.remove(text.length, doc.size - text.length);
        } else if (isWholeLineUpdate(doc, change)) {
            // This is a whole-line replace. Treated specially to make
            // sure line objects move the way they are supposed to.
            var added = linesFor(0, text.length - 1);
            update(lastLine, lastLine.text, lastSpans);
            if (nlines) doc.remove(from.line, nlines);
            if (added.length) doc.insert(from.line, added);
        } else if (firstLine == lastLine) {
            if (text.length == 1) {
                update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
            } else {
                var added = linesFor(1, text.length - 1);
                added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
                update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
                doc.insert(from.line + 1, added);
            }
        } else if (text.length == 1) {
            update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
            doc.remove(from.line + 1, nlines);
        } else {
            update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
            update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
            var added = linesFor(1, text.length - 1);
            if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
            doc.insert(from.line + 1, added);
        }

        signalLater(doc, "change", doc, change);
    }

    // The document is represented as a BTree consisting of leaves, with
    // chunk of lines in them, and branches, with up to ten leaves or
    // other branch nodes below them. The top node is always a branch
    // node, and is the document object itself (meaning it has
    // additional methods and properties).
    //
    // All nodes have parent links. The tree is used both to go from
    // line numbers to line objects, and to go from objects to numbers.
    // It also indexes by height, and is used to convert between height
    // and line object, and to find the total height of the document.
    //
    // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html

    function LeafChunk(lines) {
        this.lines = lines;
        this.parent = null;
        for (var i = 0, height = 0; i < lines.length; ++i) {
            lines[i].parent = this;
            height += lines[i].height;
        }
        this.height = height;
    }

    LeafChunk.prototype = {
        chunkSize: function () { return this.lines.length; },
        // Remove the n lines at offset 'at'.
        removeInner: function (at, n) {
            for (var i = at, e = at + n; i < e; ++i) {
                var line = this.lines[i];
                this.height -= line.height;
                cleanUpLine(line);
                signalLater(line, "delete");
            }
            this.lines.splice(at, n);
        },
        // Helper used to collapse a small branch into a single leaf.
        collapse: function (lines) {
            lines.push.apply(lines, this.lines);
        },
        // Insert the given array of lines at offset 'at', count them as
        // having the given height.
        insertInner: function (at, lines, height) {
            this.height += height;
            this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
            for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
        },
        // Used to iterate over a part of the tree.
        iterN: function (at, n, op) {
            for (var e = at + n; at < e; ++at)
                if (op(this.lines[at])) return true;
        }
    };

    function BranchChunk(children) {
        this.children = children;
        var size = 0, height = 0;
        for (var i = 0; i < children.length; ++i) {
            var ch = children[i];
            size += ch.chunkSize(); height += ch.height;
            ch.parent = this;
        }
        this.size = size;
        this.height = height;
        this.parent = null;
    }

    BranchChunk.prototype = {
        chunkSize: function () { return this.size; },
        removeInner: function (at, n) {
            this.size -= n;
            for (var i = 0; i < this.children.length; ++i) {
                var child = this.children[i], sz = child.chunkSize();
                if (at < sz) {
                    var rm = Math.min(n, sz - at), oldHeight = child.height;
                    child.removeInner(at, rm);
                    this.height -= oldHeight - child.height;
                    if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
                    if ((n -= rm) == 0) break;
                    at = 0;
                } else at -= sz;
            }
            // If the result is smaller than 25 lines, ensure that it is a
            // single leaf node.
            if (this.size - n < 25 &&
                (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
                var lines = [];
                this.collapse(lines);
                this.children = [new LeafChunk(lines)];
                this.children[0].parent = this;
            }
        },
        collapse: function (lines) {
            for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
        },
        insertInner: function (at, lines, height) {
            this.size += lines.length;
            this.height += height;
            for (var i = 0; i < this.children.length; ++i) {
                var child = this.children[i], sz = child.chunkSize();
                if (at <= sz) {
                    child.insertInner(at, lines, height);
                    if (child.lines && child.lines.length > 50) {
                        while (child.lines.length > 50) {
                            var spilled = child.lines.splice(child.lines.length - 25, 25);
                            var newleaf = new LeafChunk(spilled);
                            child.height -= newleaf.height;
                            this.children.splice(i + 1, 0, newleaf);
                            newleaf.parent = this;
                        }
                        this.maybeSpill();
                    }
                    break;
                }
                at -= sz;
            }
        },
        // When a node has grown, check whether it should be split.
        maybeSpill: function () {
            if (this.children.length <= 10) return;
            var me = this;
            do {
                var spilled = me.children.splice(me.children.length - 5, 5);
                var sibling = new BranchChunk(spilled);
                if (!me.parent) { // Become the parent node
                    var copy = new BranchChunk(me.children);
                    copy.parent = me;
                    me.children = [copy, sibling];
                    me = copy;
                } else {
                    me.size -= sibling.size;
                    me.height -= sibling.height;
                    var myIndex = indexOf(me.parent.children, me);
                    me.parent.children.splice(myIndex + 1, 0, sibling);
                }
                sibling.parent = me.parent;
            } while (me.children.length > 10);
            me.parent.maybeSpill();
        },
        iterN: function (at, n, op) {
            for (var i = 0; i < this.children.length; ++i) {
                var child = this.children[i], sz = child.chunkSize();
                if (at < sz) {
                    var used = Math.min(n, sz - at);
                    if (child.iterN(at, used, op)) return true;
                    if ((n -= used) == 0) break;
                    at = 0;
                } else at -= sz;
            }
        }
    };

    var nextDocId = 0;
    var Doc = CodeMirror.Doc = function (text, mode, firstLine, lineSep) {
        if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
        if (firstLine == null) firstLine = 0;

        BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
        this.first = firstLine;
        this.scrollTop = this.scrollLeft = 0;
        this.cantEdit = false;
        this.cleanGeneration = 1;
        this.frontier = firstLine;
        var start = Pos(firstLine, 0);
        this.sel = simpleSelection(start);
        this.history = new History(null);
        this.id = ++nextDocId;
        this.modeOption = mode;
        this.lineSep = lineSep;

        if (typeof text == "string") text = this.splitLines(text);
        updateDoc(this, { from: start, to: start, text: text });
        setSelection(this, simpleSelection(start), sel_dontScroll);
    };

    Doc.prototype = createObj(BranchChunk.prototype, {
        constructor: Doc,
        // Iterate over the document. Supports two forms -- with only one
        // argument, it calls that for each line in the document. With
        // three, it iterates over the range given by the first two (with
        // the second being non-inclusive).
        iter: function (from, to, op) {
            if (op) this.iterN(from - this.first, to - from, op);
            else this.iterN(this.first, this.first + this.size, from);
        },

        // Non-public interface for adding and removing lines.
        insert: function (at, lines) {
            var height = 0;
            for (var i = 0; i < lines.length; ++i) height += lines[i].height;
            this.insertInner(at - this.first, lines, height);
        },
        remove: function (at, n) { this.removeInner(at - this.first, n); },

        // From here, the methods are part of the public interface. Most
        // are also available from CodeMirror (editor) instances.

        getValue: function (lineSep) {
            var lines = getLines(this, this.first, this.first + this.size);
            if (lineSep === false) return lines;
            return lines.join(lineSep || this.lineSeparator());
        },
        setValue: docMethodOp(function (code) {
            var top = Pos(this.first, 0), last = this.first + this.size - 1;
            makeChange(this, {
                from: top, to: Pos(last, getLine(this, last).text.length),
                text: this.splitLines(code), origin: "setValue", full: true
            }, true);
            setSelection(this, simpleSelection(top));
        }),
        replaceRange: function (code, from, to, origin) {
            from = clipPos(this, from);
            to = to ? clipPos(this, to) : from;
            replaceRange(this, code, from, to, origin);
        },
        getRange: function (from, to, lineSep) {
            var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
            if (lineSep === false) return lines;
            return lines.join(lineSep || this.lineSeparator());
        },

        getLine: function (line) { var l = this.getLineHandle(line); return l && l.text; },

        getLineHandle: function (line) { if (isLine(this, line)) return getLine(this, line); },
        getLineNumber: function (line) { return lineNo(line); },

        getLineHandleVisualStart: function (line) {
            if (typeof line == "number") line = getLine(this, line);
            return visualLine(line);
        },

        lineCount: function () { return this.size; },
        firstLine: function () { return this.first; },
        lastLine: function () { return this.first + this.size - 1; },

        clipPos: function (pos) { return clipPos(this, pos); },

        getCursor: function (start) {
            var range = this.sel.primary(), pos;
            if (start == null || start == "head") pos = range.head;
            else if (start == "anchor") pos = range.anchor;
            else if (start == "end" || start == "to" || start === false) pos = range.to();
            else pos = range.from();
            return pos;
        },
        listSelections: function () { return this.sel.ranges; },
        somethingSelected: function () { return this.sel.somethingSelected(); },

        setCursor: docMethodOp(function (line, ch, options) {
            setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
        }),
        setSelection: docMethodOp(function (anchor, head, options) {
            setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
        }),
        extendSelection: docMethodOp(function (head, other, options) {
            extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
        }),
        extendSelections: docMethodOp(function (heads, options) {
            extendSelections(this, clipPosArray(this, heads, options));
        }),
        extendSelectionsBy: docMethodOp(function (f, options) {
            extendSelections(this, map(this.sel.ranges, f), options);
        }),
        setSelections: docMethodOp(function (ranges, primary, options) {
            if (!ranges.length) return;
            for (var i = 0, out = []; i < ranges.length; i++)
                out[i] = new Range(clipPos(this, ranges[i].anchor),
                                   clipPos(this, ranges[i].head));
            if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
            setSelection(this, normalizeSelection(out, primary), options);
        }),
        addSelection: docMethodOp(function (anchor, head, options) {
            var ranges = this.sel.ranges.slice(0);
            ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
            setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
        }),

        getSelection: function (lineSep) {
            var ranges = this.sel.ranges, lines;
            for (var i = 0; i < ranges.length; i++) {
                var sel = getBetween(this, ranges[i].from(), ranges[i].to());
                lines = lines ? lines.concat(sel) : sel;
            }
            if (lineSep === false) return lines;
            else return lines.join(lineSep || this.lineSeparator());
        },
        getSelections: function (lineSep) {
            var parts = [], ranges = this.sel.ranges;
            for (var i = 0; i < ranges.length; i++) {
                var sel = getBetween(this, ranges[i].from(), ranges[i].to());
                if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
                parts[i] = sel;
            }
            return parts;
        },
        replaceSelection: function (code, collapse, origin) {
            var dup = [];
            for (var i = 0; i < this.sel.ranges.length; i++)
                dup[i] = code;
            this.replaceSelections(dup, collapse, origin || "+input");
        },
        replaceSelections: docMethodOp(function (code, collapse, origin) {
            var changes = [], sel = this.sel;
            for (var i = 0; i < sel.ranges.length; i++) {
                var range = sel.ranges[i];
                changes[i] = { from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin };
            }
            var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
            for (var i = changes.length - 1; i >= 0; i--)
                makeChange(this, changes[i]);
            if (newSel) setSelectionReplaceHistory(this, newSel);
            else if (this.cm) ensureCursorVisible(this.cm);
        }),
        undo: docMethodOp(function () { makeChangeFromHistory(this, "undo"); }),
        redo: docMethodOp(function () { makeChangeFromHistory(this, "redo"); }),
        undoSelection: docMethodOp(function () { makeChangeFromHistory(this, "undo", true); }),
        redoSelection: docMethodOp(function () { makeChangeFromHistory(this, "redo", true); }),

        setExtending: function (val) { this.extend = val; },
        getExtending: function () { return this.extend; },

        historySize: function () {
            var hist = this.history, done = 0, undone = 0;
            for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges)++done;
            for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges)++undone;
            return { undo: done, redo: undone };
        },
        clearHistory: function () { this.history = new History(this.history.maxGeneration); },

        markClean: function () {
            this.cleanGeneration = this.changeGeneration(true);
        },
        changeGeneration: function (forceSplit) {
            if (forceSplit)
                this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
            return this.history.generation;
        },
        isClean: function (gen) {
            return this.history.generation == (gen || this.cleanGeneration);
        },

        getHistory: function () {
            return {
                done: copyHistoryArray(this.history.done),
                undone: copyHistoryArray(this.history.undone)
            };
        },
        setHistory: function (histData) {
            var hist = this.history = new History(this.history.maxGeneration);
            hist.done = copyHistoryArray(histData.done.slice(0), null, true);
            hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
        },

        addLineClass: docMethodOp(function (handle, where, cls) {
            return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
                var prop = where == "text" ? "textClass"
                         : where == "background" ? "bgClass"
                         : where == "gutter" ? "gutterClass" : "wrapClass";
                if (!line[prop]) line[prop] = cls;
                else if (classTest(cls).test(line[prop])) return false;
                else line[prop] += " " + cls;
                return true;
            });
        }),
        removeLineClass: docMethodOp(function (handle, where, cls) {
            return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
                var prop = where == "text" ? "textClass"
                         : where == "background" ? "bgClass"
                         : where == "gutter" ? "gutterClass" : "wrapClass";
                var cur = line[prop];
                if (!cur) return false;
                else if (cls == null) line[prop] = null;
                else {
                    var found = cur.match(classTest(cls));
                    if (!found) return false;
                    var end = found.index + found[0].length;
                    line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
                }
                return true;
            });
        }),

        addLineWidget: docMethodOp(function (handle, node, options) {
            return addLineWidget(this, handle, node, options);
        }),
        removeLineWidget: function (widget) { widget.clear(); },

        markText: function (from, to, options) {
            return markText(this, clipPos(this, from), clipPos(this, to), options, "range");
        },
        setBookmark: function (pos, options) {
            var realOpts = {
                replacedWith: options && (options.nodeType == null ? options.widget : options),
                insertLeft: options && options.insertLeft,
                clearWhenEmpty: false, shared: options && options.shared,
                handleMouseEvents: options && options.handleMouseEvents
            };
            pos = clipPos(this, pos);
            return markText(this, pos, pos, realOpts, "bookmark");
        },
        findMarksAt: function (pos) {
            pos = clipPos(this, pos);
            var markers = [], spans = getLine(this, pos.line).markedSpans;
            if (spans) for (var i = 0; i < spans.length; ++i) {
                var span = spans[i];
                if ((span.from == null || span.from <= pos.ch) &&
                    (span.to == null || span.to >= pos.ch))
                    markers.push(span.marker.parent || span.marker);
            }
            return markers;
        },
        findMarks: function (from, to, filter) {
            from = clipPos(this, from); to = clipPos(this, to);
            var found = [], lineNo = from.line;
            this.iter(from.line, to.line + 1, function (line) {
                var spans = line.markedSpans;
                if (spans) for (var i = 0; i < spans.length; i++) {
                    var span = spans[i];
                    if (!(lineNo == from.line && from.ch > span.to ||
                          span.from == null && lineNo != from.line ||
                          lineNo == to.line && span.from > to.ch) &&
                        (!filter || filter(span.marker)))
                        found.push(span.marker.parent || span.marker);
                }
                ++lineNo;
            });
            return found;
        },
        getAllMarks: function () {
            var markers = [];
            this.iter(function (line) {
                var sps = line.markedSpans;
                if (sps) for (var i = 0; i < sps.length; ++i)
                    if (sps[i].from != null) markers.push(sps[i].marker);
            });
            return markers;
        },

        posFromIndex: function (off) {
            var ch, lineNo = this.first;
            this.iter(function (line) {
                var sz = line.text.length + 1;
                if (sz > off) { ch = off; return true; }
                off -= sz;
                ++lineNo;
            });
            return clipPos(this, Pos(lineNo, ch));
        },
        indexFromPos: function (coords) {
            coords = clipPos(this, coords);
            var index = coords.ch;
            if (coords.line < this.first || coords.ch < 0) return 0;
            this.iter(this.first, coords.line, function (line) {
                index += line.text.length + 1;
            });
            return index;
        },

        copy: function (copyHistory) {
            var doc = new Doc(getLines(this, this.first, this.first + this.size),
                              this.modeOption, this.first, this.lineSep);
            doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
            doc.sel = this.sel;
            doc.extend = false;
            if (copyHistory) {
                doc.history.undoDepth = this.history.undoDepth;
                doc.setHistory(this.getHistory());
            }
            return doc;
        },

        linkedDoc: function (options) {
            if (!options) options = {};
            var from = this.first, to = this.first + this.size;
            if (options.from != null && options.from > from) from = options.from;
            if (options.to != null && options.to < to) to = options.to;
            var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
            if (options.sharedHist) copy.history = this.history;
            (this.linked || (this.linked = [])).push({ doc: copy, sharedHist: options.sharedHist });
            copy.linked = [{ doc: this, isParent: true, sharedHist: options.sharedHist }];
            copySharedMarkers(copy, findSharedMarkers(this));
            return copy;
        },
        unlinkDoc: function (other) {
            if (other instanceof CodeMirror) other = other.doc;
            if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
                var link = this.linked[i];
                if (link.doc != other) continue;
                this.linked.splice(i, 1);
                other.unlinkDoc(this);
                detachSharedMarkers(findSharedMarkers(this));
                break;
            }
            // If the histories were shared, split them again
            if (other.history == this.history) {
                var splitIds = [other.id];
                linkedDocs(other, function (doc) { splitIds.push(doc.id); }, true);
                other.history = new History(null);
                other.history.done = copyHistoryArray(this.history.done, splitIds);
                other.history.undone = copyHistoryArray(this.history.undone, splitIds);
            }
        },
        iterLinkedDocs: function (f) { linkedDocs(this, f); },

        getMode: function () { return this.mode; },
        getEditor: function () { return this.cm; },

        splitLines: function (str) {
            if (this.lineSep) return str.split(this.lineSep);
            return splitLinesAuto(str);
        },
        lineSeparator: function () { return this.lineSep || "\n"; }
    });

    // Public alias.
    Doc.prototype.eachLine = Doc.prototype.iter;

    // Set up methods on CodeMirror's prototype to redirect to the editor's document.
    var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
    for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
        CodeMirror.prototype[prop] = (function (method) {
            return function () { return method.apply(this.doc, arguments); };
        })(Doc.prototype[prop]);

    eventMixin(Doc);

    // Call f for all linked documents.
    function linkedDocs(doc, f, sharedHistOnly) {
        function propagate(doc, skip, sharedHist) {
            if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
                var rel = doc.linked[i];
                if (rel.doc == skip) continue;
                var shared = sharedHist && rel.sharedHist;
                if (sharedHistOnly && !shared) continue;
                f(rel.doc, shared);
                propagate(rel.doc, doc, shared);
            }
        }
        propagate(doc, null, true);
    }

    // Attach a document to an editor.
    function attachDoc(cm, doc) {
        if (doc.cm) throw new Error("This document is already in use.");
        cm.doc = doc;
        doc.cm = cm;
        estimateLineHeights(cm);
        loadMode(cm);
        if (!cm.options.lineWrapping) findMaxLine(cm);
        cm.options.mode = doc.modeOption;
        regChange(cm);
    }

    // LINE UTILITIES

    // Find the line object corresponding to the given line number.
    function getLine(doc, n) {
        n -= doc.first;
        if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
        for (var chunk = doc; !chunk.lines;) {
            for (var i = 0; ; ++i) {
                var child = chunk.children[i], sz = child.chunkSize();
                if (n < sz) { chunk = child; break; }
                n -= sz;
            }
        }
        return chunk.lines[n];
    }

    // Get the part of a document between two positions, as an array of
    // strings.
    function getBetween(doc, start, end) {
        var out = [], n = start.line;
        doc.iter(start.line, end.line + 1, function (line) {
            var text = line.text;
            if (n == end.line) text = text.slice(0, end.ch);
            if (n == start.line) text = text.slice(start.ch);
            out.push(text);
            ++n;
        });
        return out;
    }
    // Get the lines between from and to, as array of strings.
    function getLines(doc, from, to) {
        var out = [];
        doc.iter(from, to, function (line) { out.push(line.text); });
        return out;
    }

    // Update the height of a line, propagating the height change
    // upwards to parent nodes.
    function updateLineHeight(line, height) {
        var diff = height - line.height;
        if (diff) for (var n = line; n; n = n.parent) n.height += diff;
    }

    // Given a line object, find its line number by walking up through
    // its parent links.
    function lineNo(line) {
        if (line.parent == null) return null;
        var cur = line.parent, no = indexOf(cur.lines, line);
        for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
            for (var i = 0; ; ++i) {
                if (chunk.children[i] == cur) break;
                no += chunk.children[i].chunkSize();
            }
        }
        return no + cur.first;
    }

    // Find the line at the given vertical position, using the height
    // information in the document tree.
    function lineAtHeight(chunk, h) {
        var n = chunk.first;
        outer: do {
            for (var i = 0; i < chunk.children.length; ++i) {
                var child = chunk.children[i], ch = child.height;
                if (h < ch) { chunk = child; continue outer; }
                h -= ch;
                n += child.chunkSize();
            }
            return n;
        } while (!chunk.lines);
        for (var i = 0; i < chunk.lines.length; ++i) {
            var line = chunk.lines[i], lh = line.height;
            if (h < lh) break;
            h -= lh;
        }
        return n + i;
    }


    // Find the height above the given line.
    function heightAtLine(lineObj) {
        lineObj = visualLine(lineObj);

        var h = 0, chunk = lineObj.parent;
        for (var i = 0; i < chunk.lines.length; ++i) {
            var line = chunk.lines[i];
            if (line == lineObj) break;
            else h += line.height;
        }
        for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
            for (var i = 0; i < p.children.length; ++i) {
                var cur = p.children[i];
                if (cur == chunk) break;
                else h += cur.height;
            }
        }
        return h;
    }

    // Get the bidi ordering for the given line (and cache it). Returns
    // false for lines that are fully left-to-right, and an array of
    // BidiSpan objects otherwise.
    function getOrder(line) {
        var order = line.order;
        if (order == null) order = line.order = bidiOrdering(line.text);
        return order;
    }

    // HISTORY

    function History(startGen) {
        // Arrays of change events and selections. Doing something adds an
        // event to done and clears undo. Undoing moves events from done
        // to undone, redoing moves them in the other direction.
        this.done = []; this.undone = [];
        this.undoDepth = Infinity;
        // Used to track when changes can be merged into a single undo
        // event
        this.lastModTime = this.lastSelTime = 0;
        this.lastOp = this.lastSelOp = null;
        this.lastOrigin = this.lastSelOrigin = null;
        // Used by the isClean() method
        this.generation = this.maxGeneration = startGen || 1;
    }

    // Create a history change event from an updateDoc-style change
    // object.
    function historyChangeFromChange(doc, change) {
        var histChange = { from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to) };
        attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
        linkedDocs(doc, function (doc) { attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
        return histChange;
    }

    // Pop all selection events off the end of a history array. Stop at
    // a change event.
    function clearSelectionEvents(array) {
        while (array.length) {
            var last = lst(array);
            if (last.ranges) array.pop();
            else break;
        }
    }

    // Find the top change event in the history. Pop off selection
    // events that are in the way.
    function lastChangeEvent(hist, force) {
        if (force) {
            clearSelectionEvents(hist.done);
            return lst(hist.done);
        } else if (hist.done.length && !lst(hist.done).ranges) {
            return lst(hist.done);
        } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
            hist.done.pop();
            return lst(hist.done);
        }
    }

    // Register a change in the history. Merges changes that are within
    // a single operation, ore are close together with an origin that
    // allows merging (starting with "+") into a single event.
    function addChangeToHistory(doc, change, selAfter, opId) {
        var hist = doc.history;
        hist.undone.length = 0;
        var time = +new Date, cur;

        if ((hist.lastOp == opId ||
             hist.lastOrigin == change.origin && change.origin &&
             ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
              change.origin.charAt(0) == "*")) &&
            (cur = lastChangeEvent(hist, hist.lastOp == opId))) {
            // Merge this change into the last event
            var last = lst(cur.changes);
            if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
                // Optimized case for simple insertion -- don't want to add
                // new changesets for every character typed
                last.to = changeEnd(change);
            } else {
                // Add new sub-event
                cur.changes.push(historyChangeFromChange(doc, change));
            }
        } else {
            // Can not be merged, start a new event.
            var before = lst(hist.done);
            if (!before || !before.ranges)
                pushSelectionToHistory(doc.sel, hist.done);
            cur = {
                changes: [historyChangeFromChange(doc, change)],
                generation: hist.generation
            };
            hist.done.push(cur);
            while (hist.done.length > hist.undoDepth) {
                hist.done.shift();
                if (!hist.done[0].ranges) hist.done.shift();
            }
        }
        hist.done.push(selAfter);
        hist.generation = ++hist.maxGeneration;
        hist.lastModTime = hist.lastSelTime = time;
        hist.lastOp = hist.lastSelOp = opId;
        hist.lastOrigin = hist.lastSelOrigin = change.origin;

        if (!last) signal(doc, "historyAdded");
    }

    function selectionEventCanBeMerged(doc, origin, prev, sel) {
        var ch = origin.charAt(0);
        return ch == "*" ||
          ch == "+" &&
          prev.ranges.length == sel.ranges.length &&
          prev.somethingSelected() == sel.somethingSelected() &&
          new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
    }

    // Called whenever the selection changes, sets the new selection as
    // the pending selection in the history, and pushes the old pending
    // selection into the 'done' array when it was significantly
    // different (in number of selected ranges, emptiness, or time).
    function addSelectionToHistory(doc, sel, opId, options) {
        var hist = doc.history, origin = options && options.origin;

        // A new event is started when the previous origin does not match
        // the current, or the origins don't allow matching. Origins
        // starting with * are always merged, those starting with + are
        // merged when similar and close together in time.
        if (opId == hist.lastSelOp ||
            (origin && hist.lastSelOrigin == origin &&
             (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
              selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
            hist.done[hist.done.length - 1] = sel;
        else
            pushSelectionToHistory(sel, hist.done);

        hist.lastSelTime = +new Date;
        hist.lastSelOrigin = origin;
        hist.lastSelOp = opId;
        if (options && options.clearRedo !== false)
            clearSelectionEvents(hist.undone);
    }

    function pushSelectionToHistory(sel, dest) {
        var top = lst(dest);
        if (!(top && top.ranges && top.equals(sel)))
            dest.push(sel);
    }

    // Used to store marked span information in the history.
    function attachLocalSpans(doc, change, from, to) {
        var existing = change["spans_" + doc.id], n = 0;
        doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
            if (line.markedSpans)
                (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
            ++n;
        });
    }

    // When un/re-doing restores text containing marked spans, those
    // that have been explicitly cleared should not be restored.
    function removeClearedSpans(spans) {
        if (!spans) return null;
        for (var i = 0, out; i < spans.length; ++i) {
            if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
            else if (out) out.push(spans[i]);
        }
        return !out ? spans : out.length ? out : null;
    }

    // Retrieve and filter the old marked spans stored in a change event.
    function getOldSpans(doc, change) {
        var found = change["spans_" + doc.id];
        if (!found) return null;
        for (var i = 0, nw = []; i < change.text.length; ++i)
            nw.push(removeClearedSpans(found[i]));
        return nw;
    }

    // Used both to provide a JSON-safe object in .getHistory, and, when
    // detaching a document, to split the history in two
    function copyHistoryArray(events, newGroup, instantiateSel) {
        for (var i = 0, copy = []; i < events.length; ++i) {
            var event = events[i];
            if (event.ranges) {
                copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
                continue;
            }
            var changes = event.changes, newChanges = [];
            copy.push({ changes: newChanges });
            for (var j = 0; j < changes.length; ++j) {
                var change = changes[j], m;
                newChanges.push({ from: change.from, to: change.to, text: change.text });
                if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
                    if (indexOf(newGroup, Number(m[1])) > -1) {
                        lst(newChanges)[prop] = change[prop];
                        delete change[prop];
                    }
                }
            }
        }
        return copy;
    }

    // Rebasing/resetting history to deal with externally-sourced changes

    function rebaseHistSelSingle(pos, from, to, diff) {
        if (to < pos.line) {
            pos.line += diff;
        } else if (from < pos.line) {
            pos.line = from;
            pos.ch = 0;
        }
    }

    // Tries to rebase an array of history events given a change in the
    // document. If the change touches the same lines as the event, the
    // event, and everything 'behind' it, is discarded. If the change is
    // before the event, the event's positions are updated. Uses a
    // copy-on-write scheme for the positions, to avoid having to
    // reallocate them all on every rebase, but also avoid problems with
    // shared position objects being unsafely updated.
    function rebaseHistArray(array, from, to, diff) {
        for (var i = 0; i < array.length; ++i) {
            var sub = array[i], ok = true;
            if (sub.ranges) {
                if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
                for (var j = 0; j < sub.ranges.length; j++) {
                    rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
                    rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
                }
                continue;
            }
            for (var j = 0; j < sub.changes.length; ++j) {
                var cur = sub.changes[j];
                if (to < cur.from.line) {
                    cur.from = Pos(cur.from.line + diff, cur.from.ch);
                    cur.to = Pos(cur.to.line + diff, cur.to.ch);
                } else if (from <= cur.to.line) {
                    ok = false;
                    break;
                }
            }
            if (!ok) {
                array.splice(0, i + 1);
                i = 0;
            }
        }
    }

    function rebaseHist(hist, change) {
        var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
        rebaseHistArray(hist.done, from, to, diff);
        rebaseHistArray(hist.undone, from, to, diff);
    }

    // EVENT UTILITIES

    // Due to the fact that we still support jurassic IE versions, some
    // compatibility wrappers are needed.

    var e_preventDefault = CodeMirror.e_preventDefault = function (e) {
        if (e.preventDefault) e.preventDefault();
        else e.returnValue = false;
    };
    var e_stopPropagation = CodeMirror.e_stopPropagation = function (e) {
        if (e.stopPropagation) e.stopPropagation();
        else e.cancelBubble = true;
    };
    function e_defaultPrevented(e) {
        return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
    }
    var e_stop = CodeMirror.e_stop = function (e) { e_preventDefault(e); e_stopPropagation(e); };

    function e_target(e) { return e.target || e.srcElement; }
    function e_button(e) {
        var b = e.which;
        if (b == null) {
            if (e.button & 1) b = 1;
            else if (e.button & 2) b = 3;
            else if (e.button & 4) b = 2;
        }
        if (mac && e.ctrlKey && b == 1) b = 3;
        return b;
    }

    // EVENT HANDLING

    // Lightweight event framework. on/off also work on DOM nodes,
    // registering native DOM handlers.

    var on = CodeMirror.on = function (emitter, type, f) {
        if (emitter.addEventListener)
            emitter.addEventListener(type, f, false);
        else if (emitter.attachEvent)
            emitter.attachEvent("on" + type, f);
        else {
            var map = emitter._handlers || (emitter._handlers = {});
            var arr = map[type] || (map[type] = []);
            arr.push(f);
        }
    };

    var noHandlers = []
    function getHandlers(emitter, type, copy) {
        var arr = emitter._handlers && emitter._handlers[type]
        if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
        else return arr || noHandlers
    }

    var off = CodeMirror.off = function (emitter, type, f) {
        if (emitter.removeEventListener)
            emitter.removeEventListener(type, f, false);
        else if (emitter.detachEvent)
            emitter.detachEvent("on" + type, f);
        else {
            var handlers = getHandlers(emitter, type, false)
            for (var i = 0; i < handlers.length; ++i)
                if (handlers[i] == f) { handlers.splice(i, 1); break; }
        }
    };

    var signal = CodeMirror.signal = function (emitter, type /*, values...*/) {
        var handlers = getHandlers(emitter, type, true)
        if (!handlers.length) return;
        var args = Array.prototype.slice.call(arguments, 2);
        for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
    };

    var orphanDelayedCallbacks = null;

    // Often, we want to signal events at a point where we are in the
    // middle of some work, but don't want the handler to start calling
    // other methods on the editor, which might be in an inconsistent
    // state or simply not expect any other events to happen.
    // signalLater looks whether there are any handlers, and schedules
    // them to be executed when the last operation ends, or, if no
    // operation is active, when a timeout fires.
    function signalLater(emitter, type /*, values...*/) {
        var arr = getHandlers(emitter, type, false)
        if (!arr.length) return;
        var args = Array.prototype.slice.call(arguments, 2), list;
        if (operationGroup) {
            list = operationGroup.delayedCallbacks;
        } else if (orphanDelayedCallbacks) {
            list = orphanDelayedCallbacks;
        } else {
            list = orphanDelayedCallbacks = [];
            setTimeout(fireOrphanDelayed, 0);
        }
        function bnd(f) { return function () { f.apply(null, args); }; };
        for (var i = 0; i < arr.length; ++i)
            list.push(bnd(arr[i]));
    }

    function fireOrphanDelayed() {
        var delayed = orphanDelayedCallbacks;
        orphanDelayedCallbacks = null;
        for (var i = 0; i < delayed.length; ++i) delayed[i]();
    }

    // The DOM events that CodeMirror handles can be overridden by
    // registering a (non-DOM) handler on the editor for the event name,
    // and preventDefault-ing the event in that handler.
    function signalDOMEvent(cm, e, override) {
        if (typeof e == "string")
            e = { type: e, preventDefault: function () { this.defaultPrevented = true; } };
        signal(cm, override || e.type, cm, e);
        return e_defaultPrevented(e) || e.codemirrorIgnore;
    }

    function signalCursorActivity(cm) {
        var arr = cm._handlers && cm._handlers.cursorActivity;
        if (!arr) return;
        var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
        for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
            set.push(arr[i]);
    }

    function hasHandler(emitter, type) {
        return getHandlers(emitter, type).length > 0
    }

    // Add on and off methods to a constructor's prototype, to make
    // registering events on such objects more convenient.
    function eventMixin(ctor) {
        ctor.prototype.on = function (type, f) { on(this, type, f); };
        ctor.prototype.off = function (type, f) { off(this, type, f); };
    }

    // MISC UTILITIES

    // Number of pixels added to scroller and sizer to hide scrollbar
    var scrollerGap = 30;

    // Returned or thrown by various protocols to signal 'I'm not
    // handling this'.
    var Pass = CodeMirror.Pass = { toString: function () { return "CodeMirror.Pass"; } };

    // Reused option objects for setSelection & friends
    var sel_dontScroll = { scroll: false }, sel_mouse = { origin: "*mouse" }, sel_move = { origin: "+move" };

    function Delayed() { this.id = null; }
    Delayed.prototype.set = function (ms, f) {
        clearTimeout(this.id);
        this.id = setTimeout(f, ms);
    };

    // Counts the column offset in a string, taking tabs into account.
    // Used mostly to find indentation.
    var countColumn = CodeMirror.countColumn = function (string, end, tabSize, startIndex, startValue) {
        if (end == null) {
            end = string.search(/[^\s\u00a0]/);
            if (end == -1) end = string.length;
        }
        for (var i = startIndex || 0, n = startValue || 0; ;) {
            var nextTab = string.indexOf("\t", i);
            if (nextTab < 0 || nextTab >= end)
                return n + (end - i);
            n += nextTab - i;
            n += tabSize - (n % tabSize);
            i = nextTab + 1;
        }
    };

    // The inverse of countColumn -- find the offset that corresponds to
    // a particular column.
    var findColumn = CodeMirror.findColumn = function (string, goal, tabSize) {
        for (var pos = 0, col = 0; ;) {
            var nextTab = string.indexOf("\t", pos);
            if (nextTab == -1) nextTab = string.length;
            var skipped = nextTab - pos;
            if (nextTab == string.length || col + skipped >= goal)
                return pos + Math.min(skipped, goal - col);
            col += nextTab - pos;
            col += tabSize - (col % tabSize);
            pos = nextTab + 1;
            if (col >= goal) return pos;
        }
    }

    var spaceStrs = [""];
    function spaceStr(n) {
        while (spaceStrs.length <= n)
            spaceStrs.push(lst(spaceStrs) + " ");
        return spaceStrs[n];
    }

    function lst(arr) { return arr[arr.length - 1]; }

    var selectInput = function (node) { node.select(); };
    if (ios) // Mobile Safari apparently has a bug where select() is broken.
        selectInput = function (node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
    else if (ie) // Suppress mysterious IE10 errors
        selectInput = function (node) { try { node.select(); } catch (_e) { } };

    function indexOf(array, elt) {
        for (var i = 0; i < array.length; ++i)
            if (array[i] == elt) return i;
        return -1;
    }
    function map(array, f) {
        var out = [];
        for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
        return out;
    }

    function nothing() { }

    function createObj(base, props) {
        var inst;
        if (Object.create) {
            inst = Object.create(base);
        } else {
            nothing.prototype = base;
            inst = new nothing();
        }
        if (props) copyObj(props, inst);
        return inst;
    };

    function copyObj(obj, target, overwrite) {
        if (!target) target = {};
        for (var prop in obj)
            if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
                target[prop] = obj[prop];
        return target;
    }

    function bind(f) {
        var args = Array.prototype.slice.call(arguments, 1);
        return function () { return f.apply(null, args); };
    }

    var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
    var isWordCharBasic = CodeMirror.isWordChar = function (ch) {
        return /\w/.test(ch) || ch > "\x80" &&
          (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
    };
    function isWordChar(ch, helper) {
        if (!helper) return isWordCharBasic(ch);
        if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
        return helper.test(ch);
    }

    function isEmpty(obj) {
        for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
        return true;
    }

    // Extending unicode characters. A series of a non-extending char +
    // any number of extending chars is treated as a single unit as far
    // as editing and measuring is concerned. This is not fully correct,
    // since some scripts/fonts/browsers also treat other configurations
    // of code points as a group.
    var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
    function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }

    // DOM UTILITIES

    function elt(tag, content, className, style) {
        var e = document.createElement(tag);
        if (className) e.className = className;
        if (style) e.style.cssText = style;
        if (typeof content == "string") e.appendChild(document.createTextNode(content));
        else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
        return e;
    }

    var range;
    if (document.createRange) range = function (node, start, end, endNode) {
        var r = document.createRange();
        r.setEnd(endNode || node, end);
        r.setStart(node, start);
        return r;
    };
    else range = function (node, start, end) {
        var r = document.body.createTextRange();
        try { r.moveToElementText(node.parentNode); }
        catch (e) { return r; }
        r.collapse(true);
        r.moveEnd("character", end);
        r.moveStart("character", start);
        return r;
    };

    function removeChildren(e) {
        for (var count = e.childNodes.length; count > 0; --count)
            e.removeChild(e.firstChild);
        return e;
    }

    function removeChildrenAndAdd(parent, e) {
        return removeChildren(parent).appendChild(e);
    }

    var contains = CodeMirror.contains = function (parent, child) {
        if (child.nodeType == 3) // Android browser always returns false when child is a textnode
            child = child.parentNode;
        if (parent.contains)
            return parent.contains(child);
        do {
            if (child.nodeType == 11) child = child.host;
            if (child == parent) return true;
        } while (child = child.parentNode);
    };

    function activeElt() {
        var activeElement = document.activeElement;
        while (activeElement && activeElement.root && activeElement.root.activeElement)
            activeElement = activeElement.root.activeElement;
        return activeElement;
    }
    // Older versions of IE throws unspecified error when touching
    // document.activeElement in some cases (during loading, in iframe)
    if (ie && ie_version < 11) activeElt = function () {
        try { return document.activeElement; }
        catch (e) { return document.body; }
    };

    function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
    var rmClass = CodeMirror.rmClass = function (node, cls) {
        var current = node.className;
        var match = classTest(cls).exec(current);
        if (match) {
            var after = current.slice(match.index + match[0].length);
            node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
        }
    };
    var addClass = CodeMirror.addClass = function (node, cls) {
        var current = node.className;
        if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
    };
    function joinClasses(a, b) {
        var as = a.split(" ");
        for (var i = 0; i < as.length; i++)
            if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
        return b;
    }

    // WINDOW-WIDE EVENTS

    // These must be handled carefully, because naively registering a
    // handler for each editor will cause the editors to never be
    // garbage collected.

    function forEachCodeMirror(f) {
        if (!document.body.getElementsByClassName) return;
        var byClass = document.body.getElementsByClassName("CodeMirror");
        for (var i = 0; i < byClass.length; i++) {
            var cm = byClass[i].CodeMirror;
            if (cm) f(cm);
        }
    }

    var globalsRegistered = false;
    function ensureGlobalHandlers() {
        if (globalsRegistered) return;
        registerGlobalHandlers();
        globalsRegistered = true;
    }
    function registerGlobalHandlers() {
        // When the window resizes, we need to refresh active editors.
        var resizeTimer;
        on(window, "resize", function () {
            if (resizeTimer == null) resizeTimer = setTimeout(function () {
                resizeTimer = null;
                forEachCodeMirror(onResize);
            }, 100);
        });
        // When the window loses focus, we want to show the editor as blurred
        on(window, "blur", function () {
            forEachCodeMirror(onBlur);
        });
    }

    // FEATURE DETECTION

    // Detect drag-and-drop
    var dragAndDrop = function () {
        // There is *some* kind of drag-and-drop support in IE6-8, but I
        // couldn't get it to work yet.
        if (ie && ie_version < 9) return false;
        var div = elt('div');
        return "draggable" in div || "dragDrop" in div;
    }();

    var zwspSupported;
    function zeroWidthElement(measure) {
        if (zwspSupported == null) {
            var test = elt("span", "\u200b");
            removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
            if (measure.firstChild.offsetHeight != 0)
                zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
        }
        var node = zwspSupported ? elt("span", "\u200b") :
          elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
        node.setAttribute("cm-text", "");
        return node;
    }

    // Feature-detect IE's crummy client rect reporting for bidi text
    var badBidiRects;
    function hasBadBidiRects(measure) {
        if (badBidiRects != null) return badBidiRects;
        var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
        var r0 = range(txt, 0, 1).getBoundingClientRect();
        if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
        var r1 = range(txt, 1, 2).getBoundingClientRect();
        return badBidiRects = (r1.right - r0.right < 3);
    }

    // See if "".split is the broken IE version, if so, provide an
    // alternative way to split lines.
    var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function (string) {
        var pos = 0, result = [], l = string.length;
        while (pos <= l) {
            var nl = string.indexOf("\n", pos);
            if (nl == -1) nl = string.length;
            var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
            var rt = line.indexOf("\r");
            if (rt != -1) {
                result.push(line.slice(0, rt));
                pos += rt + 1;
            } else {
                result.push(line);
                pos = nl + 1;
            }
        }
        return result;
    } : function (string) { return string.split(/\r\n?|\n/); };

    var hasSelection = window.getSelection ? function (te) {
        try { return te.selectionStart != te.selectionEnd; }
        catch (e) { return false; }
    } : function (te) {
        try { var range = te.ownerDocument.selection.createRange(); }
        catch (e) { }
        if (!range || range.parentElement() != te) return false;
        return range.compareEndPoints("StartToEnd", range) != 0;
    };

    var hasCopyEvent = (function () {
        var e = elt("div");
        if ("oncopy" in e) return true;
        e.setAttribute("oncopy", "return;");
        return typeof e.oncopy == "function";
    })();

    var badZoomedRects = null;
    function hasBadZoomedRects(measure) {
        if (badZoomedRects != null) return badZoomedRects;
        var node = removeChildrenAndAdd(measure, elt("span", "x"));
        var normal = node.getBoundingClientRect();
        var fromRange = range(node, 0, 1).getBoundingClientRect();
        return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
    }

    // KEY NAMES

    var keyNames = CodeMirror.keyNames = {
        3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
        19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
        36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
        46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
        106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
        173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
        221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
        63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
    };
    (function () {
        // Number keys
        for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
        // Alphabetic keys
        for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
        // Function keys
        for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
    })();

    // BIDI HELPERS

    function iterateBidiSections(order, from, to, f) {
        if (!order) return f(from, to, "ltr");
        var found = false;
        for (var i = 0; i < order.length; ++i) {
            var part = order[i];
            if (part.from < to && part.to > from || from == to && part.to == from) {
                f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
                found = true;
            }
        }
        if (!found) f(from, to, "ltr");
    }

    function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
    function bidiRight(part) { return part.level % 2 ? part.from : part.to; }

    function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
    function lineRight(line) {
        var order = getOrder(line);
        if (!order) return line.text.length;
        return bidiRight(lst(order));
    }

    function lineStart(cm, lineN) {
        var line = getLine(cm.doc, lineN);
        var visual = visualLine(line);
        if (visual != line) lineN = lineNo(visual);
        var order = getOrder(visual);
        var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
        return Pos(lineN, ch);
    }
    function lineEnd(cm, lineN) {
        var merged, line = getLine(cm.doc, lineN);
        while (merged = collapsedSpanAtEnd(line)) {
            line = merged.find(1, true).line;
            lineN = null;
        }
        var order = getOrder(line);
        var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
        return Pos(lineN == null ? lineNo(line) : lineN, ch);
    }
    function lineStartSmart(cm, pos) {
        var start = lineStart(cm, pos.line);
        var line = getLine(cm.doc, start.line);
        var order = getOrder(line);
        if (!order || order[0].level == 0) {
            var firstNonWS = Math.max(0, line.text.search(/\S/));
            var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
            return Pos(start.line, inWS ? 0 : firstNonWS);
        }
        return start;
    }

    function compareBidiLevel(order, a, b) {
        var linedir = order[0].level;
        if (a == linedir) return true;
        if (b == linedir) return false;
        return a < b;
    }
    var bidiOther;
    function getBidiPartAt(order, pos) {
        bidiOther = null;
        for (var i = 0, found; i < order.length; ++i) {
            var cur = order[i];
            if (cur.from < pos && cur.to > pos) return i;
            if ((cur.from == pos || cur.to == pos)) {
                if (found == null) {
                    found = i;
                } else if (compareBidiLevel(order, cur.level, order[found].level)) {
                    if (cur.from != cur.to) bidiOther = found;
                    return i;
                } else {
                    if (cur.from != cur.to) bidiOther = i;
                    return found;
                }
            }
        }
        return found;
    }

    function moveInLine(line, pos, dir, byUnit) {
        if (!byUnit) return pos + dir;
        do pos += dir;
        while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
        return pos;
    }

    // This is needed in order to move 'visually' through bi-directional
    // text -- i.e., pressing left should make the cursor go left, even
    // when in RTL text. The tricky part is the 'jumps', where RTL and
    // LTR text touch each other. This often requires the cursor offset
    // to move more than one unit, in order to visually move one unit.
    function moveVisually(line, start, dir, byUnit) {
        var bidi = getOrder(line);
        if (!bidi) return moveLogically(line, start, dir, byUnit);
        var pos = getBidiPartAt(bidi, start), part = bidi[pos];
        var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);

        for (; ;) {
            if (target > part.from && target < part.to) return target;
            if (target == part.from || target == part.to) {
                if (getBidiPartAt(bidi, target) == pos) return target;
                part = bidi[pos += dir];
                return (dir > 0) == part.level % 2 ? part.to : part.from;
            } else {
                part = bidi[pos += dir];
                if (!part) return null;
                if ((dir > 0) == part.level % 2)
                    target = moveInLine(line, part.to, -1, byUnit);
                else
                    target = moveInLine(line, part.from, 1, byUnit);
            }
        }
    }

    function moveLogically(line, start, dir, byUnit) {
        var target = start + dir;
        if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
        return target < 0 || target > line.text.length ? null : target;
    }

    // Bidirectional ordering algorithm
    // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
    // that this (partially) implements.

    // One-char codes used for character types:
    // L (L):   Left-to-Right
    // R (R):   Right-to-Left
    // r (AL):  Right-to-Left Arabic
    // 1 (EN):  European Number
    // + (ES):  European Number Separator
    // % (ET):  European Number Terminator
    // n (AN):  Arabic Number
    // , (CS):  Common Number Separator
    // m (NSM): Non-Spacing Mark
    // b (BN):  Boundary Neutral
    // s (B):   Paragraph Separator
    // t (S):   Segment Separator
    // w (WS):  Whitespace
    // N (ON):  Other Neutrals

    // Returns null if characters are ordered as they appear
    // (left-to-right), or an array of sections ({from, to, level}
    // objects) in the order in which they occur visually.
    var bidiOrdering = (function () {
        // Character types for codepoints 0 to 0xff
        var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
        // Character types for codepoints 0x600 to 0x6ff
        var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
        function charType(code) {
            if (code <= 0xf7) return lowTypes.charAt(code);
            else if (0x590 <= code && code <= 0x5f4) return "R";
            else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
            else if (0x6ee <= code && code <= 0x8ac) return "r";
            else if (0x2000 <= code && code <= 0x200b) return "w";
            else if (code == 0x200c) return "b";
            else return "L";
        }

        var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
        var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
        // Browsers seem to always treat the boundaries of block elements as being L.
        var outerType = "L";

        function BidiSpan(level, from, to) {
            this.level = level;
            this.from = from; this.to = to;
        }

        return function (str) {
            if (!bidiRE.test(str)) return false;
            var len = str.length, types = [];
            for (var i = 0, type; i < len; ++i)
                types.push(type = charType(str.charCodeAt(i)));

            // W1. Examine each non-spacing mark (NSM) in the level run, and
            // change the type of the NSM to the type of the previous
            // character. If the NSM is at the start of the level run, it will
            // get the type of sor.
            for (var i = 0, prev = outerType; i < len; ++i) {
                var type = types[i];
                if (type == "m") types[i] = prev;
                else prev = type;
            }

            // W2. Search backwards from each instance of a European number
            // until the first strong type (R, L, AL, or sor) is found. If an
            // AL is found, change the type of the European number to Arabic
            // number.
            // W3. Change all ALs to R.
            for (var i = 0, cur = outerType; i < len; ++i) {
                var type = types[i];
                if (type == "1" && cur == "r") types[i] = "n";
                else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
            }

            // W4. A single European separator between two European numbers
            // changes to a European number. A single common separator between
            // two numbers of the same type changes to that type.
            for (var i = 1, prev = types[0]; i < len - 1; ++i) {
                var type = types[i];
                if (type == "+" && prev == "1" && types[i + 1] == "1") types[i] = "1";
                else if (type == "," && prev == types[i + 1] &&
                         (prev == "1" || prev == "n")) types[i] = prev;
                prev = type;
            }

            // W5. A sequence of European terminators adjacent to European
            // numbers changes to all European numbers.
            // W6. Otherwise, separators and terminators change to Other
            // Neutral.
            for (var i = 0; i < len; ++i) {
                var type = types[i];
                if (type == ",") types[i] = "N";
                else if (type == "%") {
                    for (var end = i + 1; end < len && types[end] == "%"; ++end) { }
                    var replace = (i && types[i - 1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
                    for (var j = i; j < end; ++j) types[j] = replace;
                    i = end - 1;
                }
            }

            // W7. Search backwards from each instance of a European number
            // until the first strong type (R, L, or sor) is found. If an L is
            // found, then change the type of the European number to L.
            for (var i = 0, cur = outerType; i < len; ++i) {
                var type = types[i];
                if (cur == "L" && type == "1") types[i] = "L";
                else if (isStrong.test(type)) cur = type;
            }

            // N1. A sequence of neutrals takes the direction of the
            // surrounding strong text if the text on both sides has the same
            // direction. European and Arabic numbers act as if they were R in
            // terms of their influence on neutrals. Start-of-level-run (sor)
            // and end-of-level-run (eor) are used at level run boundaries.
            // N2. Any remaining neutrals take the embedding direction.
            for (var i = 0; i < len; ++i) {
                if (isNeutral.test(types[i])) {
                    for (var end = i + 1; end < len && isNeutral.test(types[end]) ; ++end) { }
                    var before = (i ? types[i - 1] : outerType) == "L";
                    var after = (end < len ? types[end] : outerType) == "L";
                    var replace = before || after ? "L" : "R";
                    for (var j = i; j < end; ++j) types[j] = replace;
                    i = end - 1;
                }
            }

            // Here we depart from the documented algorithm, in order to avoid
            // building up an actual levels array. Since there are only three
            // levels (0, 1, 2) in an implementation that doesn't take
            // explicit embedding into account, we can build up the order on
            // the fly, without following the level-based algorithm.
            var order = [], m;
            for (var i = 0; i < len;) {
                if (countsAsLeft.test(types[i])) {
                    var start = i;
                    for (++i; i < len && countsAsLeft.test(types[i]) ; ++i) { }
                    order.push(new BidiSpan(0, start, i));
                } else {
                    var pos = i, at = order.length;
                    for (++i; i < len && types[i] != "L"; ++i) { }
                    for (var j = pos; j < i;) {
                        if (countsAsNum.test(types[j])) {
                            if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
                            var nstart = j;
                            for (++j; j < i && countsAsNum.test(types[j]) ; ++j) { }
                            order.splice(at, 0, new BidiSpan(2, nstart, j));
                            pos = j;
                        } else ++j;
                    }
                    if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
                }
            }
            if (order[0].level == 1 && (m = str.match(/^\s+/))) {
                order[0].from = m[0].length;
                order.unshift(new BidiSpan(0, 0, m[0].length));
            }
            if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
                lst(order).to -= m[0].length;
                order.push(new BidiSpan(0, len - m[0].length, len));
            }
            if (order[0].level == 2)
                order.unshift(new BidiSpan(1, order[0].to, order[0].to));
            if (order[0].level != lst(order).level)
                order.push(new BidiSpan(order[0].level, len, len));

            return order;
        };
    })();

    // THE END

    CodeMirror.version = "5.7.1";

    return CodeMirror;
});

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

// TODO actually recognize syntax of TypeScript constructs

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    "use strict";

    CodeMirror.defineMode("javascript", function (config, parserConfig) {
        var indentUnit = config.indentUnit;
        var statementIndent = parserConfig.statementIndent;
        var jsonldMode = parserConfig.jsonld;
        var jsonMode = parserConfig.json || jsonldMode;
        var isTS = parserConfig.typescript;
        var wordRE = parserConfig.wordCharacters || /[\w$\xa1-\uffff]/;

        // Tokenizer

        var keywords = function () {
            function kw(type) { return { type: type, style: "keyword" }; }
            var A = kw("keyword a"), B = kw("keyword b"), C = kw("keyword c");
            var operator = kw("operator"), atom = { type: "atom", style: "atom" };

            var jsKeywords = {
                "if": kw("if"), "while": A, "with": A, "else": B, "do": B, "try": B, "finally": B,
                "return": C, "break": C, "continue": C, "new": C, "delete": C, "throw": C, "debugger": C,
                "var": kw("var"), "const": kw("var"), "let": kw("var"),
                "async": kw("async"), "function": kw("function"), "catch": kw("catch"),
                "for": kw("for"), "switch": kw("switch"), "case": kw("case"), "default": kw("default"),
                "in": operator, "typeof": operator, "instanceof": operator,
                "true": atom, "false": atom, "null": atom, "undefined": atom, "NaN": atom, "Infinity": atom,
                "this": kw("this"), "class": kw("class"), "super": kw("atom"),
                "await": C, "yield": C, "export": kw("export"), "import": kw("import"), "extends": C
            };

            // Extend the 'normal' keywords with the TypeScript language extensions
            if (isTS) {
                var type = { type: "variable", style: "variable-3" };
                var tsKeywords = {
                    // object-like things
                    "interface": kw("interface"),
                    "extends": kw("extends"),
                    "constructor": kw("constructor"),

                    // scope modifiers
                    "public": kw("public"),
                    "private": kw("private"),
                    "protected": kw("protected"),
                    "static": kw("static"),

                    // types
                    "string": type, "number": type, "bool": type, "any": type
                };

                for (var attr in tsKeywords) {
                    jsKeywords[attr] = tsKeywords[attr];
                }
            }

            return jsKeywords;
        }();

        var isOperatorChar = /[+\-*&%=<>!?|~^]/;
        var isJsonldKeyword = /^@(context|id|value|language|type|container|list|set|reverse|index|base|vocab|graph)"/;

        function readRegexp(stream) {
            var escaped = false, next, inSet = false;
            while ((next = stream.next()) != null) {
                if (!escaped) {
                    if (next == "/" && !inSet) return;
                    if (next == "[") inSet = true;
                    else if (inSet && next == "]") inSet = false;
                }
                escaped = !escaped && next == "\\";
            }
        }

        // Used as scratch variables to communicate multiple values without
        // consing up tons of objects.
        var type, content;
        function ret(tp, style, cont) {
            type = tp; content = cont;
            return style;
        }
        function tokenBase(stream, state) {
            var ch = stream.next();
            if (ch == '"' || ch == "'") {
                state.tokenize = tokenString(ch);
                return state.tokenize(stream, state);
            } else if (ch == "." && stream.match(/^\d+(?:[eE][+\-]?\d+)?/)) {
                return ret("number", "number");
            } else if (ch == "." && stream.match("..")) {
                return ret("spread", "meta");
            } else if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
                return ret(ch);
            } else if (ch == "=" && stream.eat(">")) {
                return ret("=>", "operator");
            } else if (ch == "0" && stream.eat(/x/i)) {
                stream.eatWhile(/[\da-f]/i);
                return ret("number", "number");
            } else if (ch == "0" && stream.eat(/o/i)) {
                stream.eatWhile(/[0-7]/i);
                return ret("number", "number");
            } else if (ch == "0" && stream.eat(/b/i)) {
                stream.eatWhile(/[01]/i);
                return ret("number", "number");
            } else if (/\d/.test(ch)) {
                stream.match(/^\d*(?:\.\d*)?(?:[eE][+\-]?\d+)?/);
                return ret("number", "number");
            } else if (ch == "/") {
                if (stream.eat("*")) {
                    state.tokenize = tokenComment;
                    return tokenComment(stream, state);
                } else if (stream.eat("/")) {
                    stream.skipToEnd();
                    return ret("comment", "comment");
                } else if (state.lastType == "operator" || state.lastType == "keyword c" ||
                         state.lastType == "sof" || /^[\[{}\(,;:]$/.test(state.lastType)) {
                    readRegexp(stream);
                    stream.match(/^\b(([gimyu])(?![gimyu]*\2))+\b/);
                    return ret("regexp", "string-2");
                } else {
                    stream.eatWhile(isOperatorChar);
                    return ret("operator", "operator", stream.current());
                }
            } else if (ch == "`") {
                state.tokenize = tokenQuasi;
                return tokenQuasi(stream, state);
            } else if (ch == "#") {
                stream.skipToEnd();
                return ret("error", "error");
            } else if (isOperatorChar.test(ch)) {
                stream.eatWhile(isOperatorChar);
                return ret("operator", "operator", stream.current());
            } else if (wordRE.test(ch)) {
                stream.eatWhile(wordRE);
                var word = stream.current(), known = keywords.propertyIsEnumerable(word) && keywords[word];
                return (known && state.lastType != ".") ? ret(known.type, known.style, word) :
                               ret("variable", "variable", word);
            }
        }

        function tokenString(quote) {
            return function (stream, state) {
                var escaped = false, next;
                if (jsonldMode && stream.peek() == "@" && stream.match(isJsonldKeyword)) {
                    state.tokenize = tokenBase;
                    return ret("jsonld-keyword", "meta");
                }
                while ((next = stream.next()) != null) {
                    if (next == quote && !escaped) break;
                    escaped = !escaped && next == "\\";
                }
                if (!escaped) state.tokenize = tokenBase;
                return ret("string", "string");
            };
        }

        function tokenComment(stream, state) {
            var maybeEnd = false, ch;
            while (ch = stream.next()) {
                if (ch == "/" && maybeEnd) {
                    state.tokenize = tokenBase;
                    break;
                }
                maybeEnd = (ch == "*");
            }
            return ret("comment", "comment");
        }

        function tokenQuasi(stream, state) {
            var escaped = false, next;
            while ((next = stream.next()) != null) {
                if (!escaped && (next == "`" || next == "$" && stream.eat("{"))) {
                    state.tokenize = tokenBase;
                    break;
                }
                escaped = !escaped && next == "\\";
            }
            return ret("quasi", "string-2", stream.current());
        }

        var brackets = "([{}])";
        // This is a crude lookahead trick to try and notice that we're
        // parsing the argument patterns for a fat-arrow function before we
        // actually hit the arrow token. It only works if the arrow is on
        // the same line as the arguments and there's no strange noise
        // (comments) in between. Fallback is to only notice when we hit the
        // arrow, and not declare the arguments as locals for the arrow
        // body.
        function findFatArrow(stream, state) {
            if (state.fatArrowAt) state.fatArrowAt = null;
            var arrow = stream.string.indexOf("=>", stream.start);
            if (arrow < 0) return;

            var depth = 0, sawSomething = false;
            for (var pos = arrow - 1; pos >= 0; --pos) {
                var ch = stream.string.charAt(pos);
                var bracket = brackets.indexOf(ch);
                if (bracket >= 0 && bracket < 3) {
                    if (!depth) { ++pos; break; }
                    if (--depth == 0) break;
                } else if (bracket >= 3 && bracket < 6) {
                    ++depth;
                } else if (wordRE.test(ch)) {
                    sawSomething = true;
                } else if (/["'\/]/.test(ch)) {
                    return;
                } else if (sawSomething && !depth) {
                    ++pos;
                    break;
                }
            }
            if (sawSomething && !depth) state.fatArrowAt = pos;
        }

        // Parser

        var atomicTypes = { "atom": true, "number": true, "variable": true, "string": true, "regexp": true, "this": true, "jsonld-keyword": true };

        function JSLexical(indented, column, type, align, prev, info) {
            this.indented = indented;
            this.column = column;
            this.type = type;
            this.prev = prev;
            this.info = info;
            if (align != null) this.align = align;
        }

        function inScope(state, varname) {
            for (var v = state.localVars; v; v = v.next)
                if (v.name == varname) return true;
            for (var cx = state.context; cx; cx = cx.prev) {
                for (var v = cx.vars; v; v = v.next)
                    if (v.name == varname) return true;
            }
        }

        function parseJS(state, style, type, content, stream) {
            var cc = state.cc;
            // Communicate our context to the combinators.
            // (Less wasteful than consing up a hundred closures on every call.)
            cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc; cx.style = style;

            if (!state.lexical.hasOwnProperty("align"))
                state.lexical.align = true;

            while (true) {
                var combinator = cc.length ? cc.pop() : jsonMode ? expression : statement;
                if (combinator(type, content)) {
                    while (cc.length && cc[cc.length - 1].lex)
                        cc.pop()();
                    if (cx.marked) return cx.marked;
                    if (type == "variable" && inScope(state, content)) return "variable-2";
                    return style;
                }
            }
        }

        // Combinator utils

        var cx = { state: null, column: null, marked: null, cc: null };
        function pass() {
            for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
        }
        function cont() {
            pass.apply(null, arguments);
            return true;
        }
        function register(varname) {
            function inList(list) {
                for (var v = list; v; v = v.next)
                    if (v.name == varname) return true;
                return false;
            }
            var state = cx.state;
            if (state.context) {
                cx.marked = "def";
                if (inList(state.localVars)) return;
                state.localVars = { name: varname, next: state.localVars };
            } else {
                if (inList(state.globalVars)) return;
                if (parserConfig.globalVars)
                    state.globalVars = { name: varname, next: state.globalVars };
            }
        }

        // Combinators

        var defaultVars = { name: "this", next: { name: "arguments" } };
        function pushcontext() {
            cx.state.context = { prev: cx.state.context, vars: cx.state.localVars };
            cx.state.localVars = defaultVars;
        }
        function popcontext() {
            cx.state.localVars = cx.state.context.vars;
            cx.state.context = cx.state.context.prev;
        }
        function pushlex(type, info) {
            var result = function () {
                var state = cx.state, indent = state.indented;
                if (state.lexical.type == "stat") indent = state.lexical.indented;
                else for (var outer = state.lexical; outer && outer.type == ")" && outer.align; outer = outer.prev)
                    indent = outer.indented;
                state.lexical = new JSLexical(indent, cx.stream.column(), type, null, state.lexical, info);
            };
            result.lex = true;
            return result;
        }
        function poplex() {
            var state = cx.state;
            if (state.lexical.prev) {
                if (state.lexical.type == ")")
                    state.indented = state.lexical.indented;
                state.lexical = state.lexical.prev;
            }
        }
        poplex.lex = true;

        function expect(wanted) {
            function exp(type) {
                if (type == wanted) return cont();
                else if (wanted == ";") return pass();
                else return cont(exp);
            };
            return exp;
        }

        function statement(type, value) {
            if (type == "var") return cont(pushlex("vardef", value.length), vardef, expect(";"), poplex);
            if (type == "keyword a") return cont(pushlex("form"), expression, statement, poplex);
            if (type == "keyword b") return cont(pushlex("form"), statement, poplex);
            if (type == "{") return cont(pushlex("}"), block, poplex);
            if (type == ";") return cont();
            if (type == "if") {
                if (cx.state.lexical.info == "else" && cx.state.cc[cx.state.cc.length - 1] == poplex)
                    cx.state.cc.pop()();
                return cont(pushlex("form"), expression, statement, poplex, maybeelse);
            }
            if (type == "function") return cont(functiondef);
            if (type == "for") return cont(pushlex("form"), forspec, statement, poplex);
            if (type == "variable") return cont(pushlex("stat"), maybelabel);
            if (type == "switch") return cont(pushlex("form"), expression, pushlex("}", "switch"), expect("{"),
                                              block, poplex, poplex);
            if (type == "case") return cont(expression, expect(":"));
            if (type == "default") return cont(expect(":"));
            if (type == "catch") return cont(pushlex("form"), pushcontext, expect("("), funarg, expect(")"),
                                             statement, poplex, popcontext);
            if (type == "class") return cont(pushlex("form"), className, poplex);
            if (type == "export") return cont(pushlex("stat"), afterExport, poplex);
            if (type == "import") return cont(pushlex("stat"), afterImport, poplex);
            return pass(pushlex("stat"), expression, expect(";"), poplex);
        }
        function expression(type) {
            return expressionInner(type, false);
        }
        function expressionNoComma(type) {
            return expressionInner(type, true);
        }
        function expressionInner(type, noComma) {
            if (cx.state.fatArrowAt == cx.stream.start) {
                var body = noComma ? arrowBodyNoComma : arrowBody;
                if (type == "(") return cont(pushcontext, pushlex(")"), commasep(pattern, ")"), poplex, expect("=>"), body, popcontext);
                else if (type == "variable") return pass(pushcontext, pattern, expect("=>"), body, popcontext);
            }

            var maybeop = noComma ? maybeoperatorNoComma : maybeoperatorComma;
            if (atomicTypes.hasOwnProperty(type)) return cont(maybeop);
            if (type == "async") return cont(expression);
            if (type == "function") return cont(functiondef, maybeop);
            if (type == "keyword c") return cont(noComma ? maybeexpressionNoComma : maybeexpression);
            if (type == "(") return cont(pushlex(")"), maybeexpression, comprehension, expect(")"), poplex, maybeop);
            if (type == "operator" || type == "spread") return cont(noComma ? expressionNoComma : expression);
            if (type == "[") return cont(pushlex("]"), arrayLiteral, poplex, maybeop);
            if (type == "{") return contCommasep(objprop, "}", null, maybeop);
            if (type == "quasi") { return pass(quasi, maybeop); }
            return cont();
        }
        function maybeexpression(type) {
            if (type.match(/[;\}\)\],]/)) return pass();
            return pass(expression);
        }
        function maybeexpressionNoComma(type) {
            if (type.match(/[;\}\)\],]/)) return pass();
            return pass(expressionNoComma);
        }

        function maybeoperatorComma(type, value) {
            if (type == ",") return cont(expression);
            return maybeoperatorNoComma(type, value, false);
        }
        function maybeoperatorNoComma(type, value, noComma) {
            var me = noComma == false ? maybeoperatorComma : maybeoperatorNoComma;
            var expr = noComma == false ? expression : expressionNoComma;
            if (type == "=>") return cont(pushcontext, noComma ? arrowBodyNoComma : arrowBody, popcontext);
            if (type == "operator") {
                if (/\+\+|--/.test(value)) return cont(me);
                if (value == "?") return cont(expression, expect(":"), expr);
                return cont(expr);
            }
            if (type == "quasi") { return pass(quasi, me); }
            if (type == ";") return;
            if (type == "(") return contCommasep(expressionNoComma, ")", "call", me);
            if (type == ".") return cont(property, me);
            if (type == "[") return cont(pushlex("]"), maybeexpression, expect("]"), poplex, me);
        }
        function quasi(type, value) {
            if (type != "quasi") return pass();
            if (value.slice(value.length - 2) != "${") return cont(quasi);
            return cont(expression, continueQuasi);
        }
        function continueQuasi(type) {
            if (type == "}") {
                cx.marked = "string-2";
                cx.state.tokenize = tokenQuasi;
                return cont(quasi);
            }
        }
        function arrowBody(type) {
            findFatArrow(cx.stream, cx.state);
            return pass(type == "{" ? statement : expression);
        }
        function arrowBodyNoComma(type) {
            findFatArrow(cx.stream, cx.state);
            return pass(type == "{" ? statement : expressionNoComma);
        }
        function maybelabel(type) {
            if (type == ":") return cont(poplex, statement);
            return pass(maybeoperatorComma, expect(";"), poplex);
        }
        function property(type) {
            if (type == "variable") { cx.marked = "property"; return cont(); }
        }
        function objprop(type, value) {
            if (type == "async") {
                return cont(objprop);
            } else if (type == "variable" || cx.style == "keyword") {
                cx.marked = "property";
                if (value == "get" || value == "set") return cont(getterSetter);
                return cont(afterprop);
            } else if (type == "number" || type == "string") {
                cx.marked = jsonldMode ? "property" : (cx.style + " property");
                return cont(afterprop);
            } else if (type == "jsonld-keyword") {
                return cont(afterprop);
            } else if (type == "[") {
                return cont(expression, expect("]"), afterprop);
            }
        }
        function getterSetter(type) {
            if (type != "variable") return pass(afterprop);
            cx.marked = "property";
            return cont(functiondef);
        }
        function afterprop(type) {
            if (type == ":") return cont(expressionNoComma);
            if (type == "(") return pass(functiondef);
        }
        function commasep(what, end) {
            function proceed(type) {
                if (type == ",") {
                    var lex = cx.state.lexical;
                    if (lex.info == "call") lex.pos = (lex.pos || 0) + 1;
                    return cont(what, proceed);
                }
                if (type == end) return cont();
                return cont(expect(end));
            }
            return function (type) {
                if (type == end) return cont();
                return pass(what, proceed);
            };
        }
        function contCommasep(what, end, info) {
            for (var i = 3; i < arguments.length; i++)
                cx.cc.push(arguments[i]);
            return cont(pushlex(end, info), commasep(what, end), poplex);
        }
        function block(type) {
            if (type == "}") return cont();
            return pass(statement, block);
        }
        function maybetype(type) {
            if (isTS && type == ":") return cont(typedef);
        }
        function maybedefault(_, value) {
            if (value == "=") return cont(expressionNoComma);
        }
        function typedef(type) {
            if (type == "variable") { cx.marked = "variable-3"; return cont(); }
        }
        function vardef() {
            return pass(pattern, maybetype, maybeAssign, vardefCont);
        }
        function pattern(type, value) {
            if (type == "variable") { register(value); return cont(); }
            if (type == "spread") return cont(pattern);
            if (type == "[") return contCommasep(pattern, "]");
            if (type == "{") return contCommasep(proppattern, "}");
        }
        function proppattern(type, value) {
            if (type == "variable" && !cx.stream.match(/^\s*:/, false)) {
                register(value);
                return cont(maybeAssign);
            }
            if (type == "variable") cx.marked = "property";
            if (type == "spread") return cont(pattern);
            return cont(expect(":"), pattern, maybeAssign);
        }
        function maybeAssign(_type, value) {
            if (value == "=") return cont(expressionNoComma);
        }
        function vardefCont(type) {
            if (type == ",") return cont(vardef);
        }
        function maybeelse(type, value) {
            if (type == "keyword b" && value == "else") return cont(pushlex("form", "else"), statement, poplex);
        }
        function forspec(type) {
            if (type == "(") return cont(pushlex(")"), forspec1, expect(")"), poplex);
        }
        function forspec1(type) {
            if (type == "var") return cont(vardef, expect(";"), forspec2);
            if (type == ";") return cont(forspec2);
            if (type == "variable") return cont(formaybeinof);
            return pass(expression, expect(";"), forspec2);
        }
        function formaybeinof(_type, value) {
            if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
            return cont(maybeoperatorComma, forspec2);
        }
        function forspec2(type, value) {
            if (type == ";") return cont(forspec3);
            if (value == "in" || value == "of") { cx.marked = "keyword"; return cont(expression); }
            return pass(expression, expect(";"), forspec3);
        }
        function forspec3(type) {
            if (type != ")") cont(expression);
        }
        function functiondef(type, value) {
            if (value == "*") { cx.marked = "keyword"; return cont(functiondef); }
            if (type == "variable") { register(value); return cont(functiondef); }
            if (type == "(") return cont(pushcontext, pushlex(")"), commasep(funarg, ")"), poplex, statement, popcontext);
        }
        function funarg(type) {
            if (type == "spread") return cont(funarg);
            return pass(pattern, maybetype, maybedefault);
        }
        function className(type, value) {
            if (type == "variable") { register(value); return cont(classNameAfter); }
        }
        function classNameAfter(type, value) {
            if (value == "extends") return cont(expression, classNameAfter);
            if (type == "{") return cont(pushlex("}"), classBody, poplex);
        }
        function classBody(type, value) {
            if (type == "variable" || cx.style == "keyword") {
                if (value == "static") {
                    cx.marked = "keyword";
                    return cont(classBody);
                }
                cx.marked = "property";
                if (value == "get" || value == "set") return cont(classGetterSetter, functiondef, classBody);
                return cont(functiondef, classBody);
            }
            if (value == "*") {
                cx.marked = "keyword";
                return cont(classBody);
            }
            if (type == ";") return cont(classBody);
            if (type == "}") return cont();
        }
        function classGetterSetter(type) {
            if (type != "variable") return pass();
            cx.marked = "property";
            return cont();
        }
        function afterExport(_type, value) {
            if (value == "*") { cx.marked = "keyword"; return cont(maybeFrom, expect(";")); }
            if (value == "default") { cx.marked = "keyword"; return cont(expression, expect(";")); }
            return pass(statement);
        }
        function afterImport(type) {
            if (type == "string") return cont();
            return pass(importSpec, maybeFrom);
        }
        function importSpec(type, value) {
            if (type == "{") return contCommasep(importSpec, "}");
            if (type == "variable") register(value);
            if (value == "*") cx.marked = "keyword";
            return cont(maybeAs);
        }
        function maybeAs(_type, value) {
            if (value == "as") { cx.marked = "keyword"; return cont(importSpec); }
        }
        function maybeFrom(_type, value) {
            if (value == "from") { cx.marked = "keyword"; return cont(expression); }
        }
        function arrayLiteral(type) {
            if (type == "]") return cont();
            return pass(expressionNoComma, maybeArrayComprehension);
        }
        function maybeArrayComprehension(type) {
            if (type == "for") return pass(comprehension, expect("]"));
            if (type == ",") return cont(commasep(maybeexpressionNoComma, "]"));
            return pass(commasep(expressionNoComma, "]"));
        }
        function comprehension(type) {
            if (type == "for") return cont(forspec, comprehension);
            if (type == "if") return cont(expression, comprehension);
        }

        function isContinuedStatement(state, textAfter) {
            return state.lastType == "operator" || state.lastType == "," ||
              isOperatorChar.test(textAfter.charAt(0)) ||
              /[,.]/.test(textAfter.charAt(0));
        }

        // Interface

        return {
            startState: function (basecolumn) {
                var state = {
                    tokenize: tokenBase,
                    lastType: "sof",
                    cc: [],
                    lexical: new JSLexical((basecolumn || 0) - indentUnit, 0, "block", false),
                    localVars: parserConfig.localVars,
                    context: parserConfig.localVars && { vars: parserConfig.localVars },
                    indented: 0
                };
                if (parserConfig.globalVars && typeof parserConfig.globalVars == "object")
                    state.globalVars = parserConfig.globalVars;
                return state;
            },

            token: function (stream, state) {
                if (stream.sol()) {
                    if (!state.lexical.hasOwnProperty("align"))
                        state.lexical.align = false;
                    state.indented = stream.indentation();
                    findFatArrow(stream, state);
                }
                if (state.tokenize != tokenComment && stream.eatSpace()) return null;
                var style = state.tokenize(stream, state);
                if (type == "comment") return style;
                state.lastType = type == "operator" && (content == "++" || content == "--") ? "incdec" : type;
                return parseJS(state, style, type, content, stream);
            },

            indent: function (state, textAfter) {
                if (state.tokenize == tokenComment) return CodeMirror.Pass;
                if (state.tokenize != tokenBase) return 0;
                var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical;
                // Kludge to prevent 'maybelse' from blocking lexical scope pops
                if (!/^\s*else\b/.test(textAfter)) for (var i = state.cc.length - 1; i >= 0; --i) {
                    var c = state.cc[i];
                    if (c == poplex) lexical = lexical.prev;
                    else if (c != maybeelse) break;
                }
                if (lexical.type == "stat" && firstChar == "}") lexical = lexical.prev;
                if (statementIndent && lexical.type == ")" && lexical.prev.type == "stat")
                    lexical = lexical.prev;
                var type = lexical.type, closing = firstChar == type;

                if (type == "vardef") return lexical.indented + (state.lastType == "operator" || state.lastType == "," ? lexical.info + 1 : 0);
                else if (type == "form" && firstChar == "{") return lexical.indented;
                else if (type == "form") return lexical.indented + indentUnit;
                else if (type == "stat")
                    return lexical.indented + (isContinuedStatement(state, textAfter) ? statementIndent || indentUnit : 0);
                else if (lexical.info == "switch" && !closing && parserConfig.doubleIndentSwitch != false)
                    return lexical.indented + (/^(?:case|default)\b/.test(textAfter) ? indentUnit : 2 * indentUnit);
                else if (lexical.align) return lexical.column + (closing ? 0 : 1);
                else return lexical.indented + (closing ? 0 : indentUnit);
            },

            electricInput: /^\s*(?:case .*?:|default:|\{|\})$/,
            blockCommentStart: jsonMode ? null : "/*",
            blockCommentEnd: jsonMode ? null : "*/",
            lineComment: jsonMode ? null : "//",
            fold: "brace",
            closeBrackets: "()[]{}''\"\"``",

            helperType: jsonMode ? "json" : "javascript",
            jsonldMode: jsonldMode,
            jsonMode: jsonMode
        };
    });

    CodeMirror.registerHelper("wordChars", "javascript", /[\w$]/);

    CodeMirror.defineMIME("text/javascript", "javascript");
    CodeMirror.defineMIME("text/ecmascript", "javascript");
    CodeMirror.defineMIME("application/javascript", "javascript");
    CodeMirror.defineMIME("application/x-javascript", "javascript");
    CodeMirror.defineMIME("application/ecmascript", "javascript");
    CodeMirror.defineMIME("application/json", { name: "javascript", json: true });
    CodeMirror.defineMIME("application/x-json", { name: "javascript", json: true });
    CodeMirror.defineMIME("application/ld+json", { name: "javascript", jsonld: true });
    CodeMirror.defineMIME("text/typescript", { name: "javascript", typescript: true });
    CodeMirror.defineMIME("application/typescript", { name: "javascript", typescript: true });

});

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    "use strict";

    var HINT_ELEMENT_CLASS = "CodeMirror-hint";
    var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active";

    // This is the old interface, kept around for now to stay
    // backwards-compatible.
    CodeMirror.showHint = function (cm, getHints, options) {
        if (!getHints) return cm.showHint(options);
        if (options && options.async) getHints.async = true;
        var newOpts = { hint: getHints };
        if (options) for (var prop in options) newOpts[prop] = options[prop];
        return cm.showHint(newOpts);
    };

    CodeMirror.defineExtension("showHint", function (options) {
        options = parseOptions(this, this.getCursor("start"), options);
        var selections = this.listSelections()
        if (selections.length > 1) return;
        // By default, don't allow completion when something is selected.
        // A hint function can have a `supportsSelection` property to
        // indicate that it can handle selections.
        if (this.somethingSelected()) {
            if (!options.hint.supportsSelection) return;
            // Don't try with cross-line selections
            for (var i = 0; i < selections.length; i++)
                if (selections[i].head.line != selections[i].anchor.line) return;
        }

        if (this.state.completionActive) this.state.completionActive.close();
        var completion = this.state.completionActive = new Completion(this, options);
        if (!completion.options.hint) return;

        CodeMirror.signal(this, "startCompletion", this);
        completion.update(true);
    });

    function Completion(cm, options) {
        this.cm = cm;
        this.options = options;
        this.widget = null;
        this.debounce = 0;
        this.tick = 0;
        this.startPos = this.cm.getCursor("start");
        this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length;

        var self = this;
        cm.on("cursorActivity", this.activityFunc = function () { self.cursorActivity(); });
    }

    var requestAnimationFrame = window.requestAnimationFrame || function (fn) {
        return setTimeout(fn, 1000 / 60);
    };
    var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout;

    Completion.prototype = {
        close: function () {
            if (!this.active()) return;
            this.cm.state.completionActive = null;
            this.tick = null;
            this.cm.off("cursorActivity", this.activityFunc);

            if (this.widget && this.data) CodeMirror.signal(this.data, "close");
            if (this.widget) this.widget.close();
            CodeMirror.signal(this.cm, "endCompletion", this.cm);
        },

        active: function () {
            return this.cm.state.completionActive == this;
        },

        pick: function (data, i) {
            var completion = data.list[i];
            if (completion.hint) completion.hint(this.cm, data, completion);
            else this.cm.replaceRange(getText(completion), completion.from || data.from,
                                      completion.to || data.to, "complete");
            CodeMirror.signal(data, "pick", completion);
            this.close();
        },

        cursorActivity: function () {
            if (this.debounce) {
                cancelAnimationFrame(this.debounce);
                this.debounce = 0;
            }

            var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line);
            if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch ||
                pos.ch < this.startPos.ch || this.cm.somethingSelected() ||
                (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) {
                this.close();
            } else {
                var self = this;
                this.debounce = requestAnimationFrame(function () { self.update(); });
                if (this.widget) this.widget.disable();
            }
        },

        update: function (first) {
            if (this.tick == null) return;
            if (!this.options.hint.async) {
                this.finishUpdate(this.options.hint(this.cm, this.options), first);
            } else {
                var myTick = ++this.tick, self = this;
                this.options.hint(this.cm, function (data) {
                    if (self.tick == myTick) self.finishUpdate(data, first);
                }, this.options);
            }
        },

        finishUpdate: function (data, first) {
            if (this.data) CodeMirror.signal(this.data, "update");
            if (data && this.data && CodeMirror.cmpPos(data.from, this.data.from)) data = null;
            this.data = data;

            var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle);
            if (this.widget) this.widget.close();
            if (data && data.list.length) {
                if (picked && data.list.length == 1) {
                    this.pick(data, 0);
                } else {
                    this.widget = new Widget(this, data);
                    CodeMirror.signal(data, "shown");
                }
            }
        }
    };

    function parseOptions(cm, pos, options) {
        var editor = cm.options.hintOptions;
        var out = {};
        for (var prop in defaultOptions) out[prop] = defaultOptions[prop];
        if (editor) for (var prop in editor)
            if (editor[prop] !== undefined) out[prop] = editor[prop];
        if (options) for (var prop in options)
            if (options[prop] !== undefined) out[prop] = options[prop];
        if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos)
        return out;
    }

    function getText(completion) {
        if (typeof completion == "string") return completion;
        else return completion.text;
    }

    function buildKeyMap(completion, handle) {
        var baseMap = {
            Up: function () { handle.moveFocus(-1); },
            Down: function () { handle.moveFocus(1); },
            PageUp: function () { handle.moveFocus(-handle.menuSize() + 1, true); },
            PageDown: function () { handle.moveFocus(handle.menuSize() - 1, true); },
            Home: function () { handle.setFocus(0); },
            End: function () { handle.setFocus(handle.length - 1); },
            Enter: handle.pick,
            Tab: handle.pick,
            Esc: handle.close
        };
        var custom = completion.options.customKeys;
        var ourMap = custom ? {} : baseMap;
        function addBinding(key, val) {
            var bound;
            if (typeof val != "string")
                bound = function (cm) { return val(cm, handle); };
                // This mechanism is deprecated
            else if (baseMap.hasOwnProperty(val))
                bound = baseMap[val];
            else
                bound = val;
            ourMap[key] = bound;
        }
        if (custom)
            for (var key in custom) if (custom.hasOwnProperty(key))
                addBinding(key, custom[key]);
        var extra = completion.options.extraKeys;
        if (extra)
            for (var key in extra) if (extra.hasOwnProperty(key))
                addBinding(key, extra[key]);
        return ourMap;
    }

    function getHintElement(hintsElement, el) {
        while (el && el != hintsElement) {
            if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el;
            el = el.parentNode;
        }
    }

    function Widget(completion, data) {
        this.completion = completion;
        this.data = data;
        this.picked = false;
        var widget = this, cm = completion.cm;

        var hints = this.hints = document.createElement("ul");
        hints.className = "CodeMirror-hints";
        this.selectedHint = data.selectedHint || 0;

        var completions = data.list;
        for (var i = 0; i < completions.length; ++i) {
            var elt = hints.appendChild(document.createElement("li")), cur = completions[i];
            var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS);
            if (cur.className != null) className = cur.className + " " + className;
            elt.className = className;
            if (cur.render) cur.render(elt, data, cur);
            else elt.appendChild(document.createTextNode(cur.displayText || getText(cur)));
            elt.hintId = i;
        }

        var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null);
        var left = pos.left, top = pos.bottom, below = true;
        hints.style.left = left + "px";
        hints.style.top = top + "px";
        // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
        var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth);
        var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight);
        (completion.options.container || document.body).appendChild(hints);
        var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH;
        if (overlapY > 0) {
            var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top);
            if (curTop - height > 0) { // Fits above cursor
                hints.style.top = (top = pos.top - height) + "px";
                below = false;
            } else if (height > winH) {
                hints.style.height = (winH - 5) + "px";
                hints.style.top = (top = pos.bottom - box.top) + "px";
                var cursor = cm.getCursor();
                if (data.from.ch != cursor.ch) {
                    pos = cm.cursorCoords(cursor);
                    hints.style.left = (left = pos.left) + "px";
                    box = hints.getBoundingClientRect();
                }
            }
        }
        var overlapX = box.right - winW;
        if (overlapX > 0) {
            if (box.right - box.left > winW) {
                hints.style.width = (winW - 5) + "px";
                overlapX -= (box.right - box.left) - winW;
            }
            hints.style.left = (left = pos.left - overlapX) + "px";
        }

        cm.addKeyMap(this.keyMap = buildKeyMap(completion, {
            moveFocus: function (n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); },
            setFocus: function (n) { widget.changeActive(n); },
            menuSize: function () { return widget.screenAmount(); },
            length: completions.length,
            close: function () { completion.close(); },
            pick: function () { widget.pick(); },
            data: data
        }));

        if (completion.options.closeOnUnfocus) {
            var closingOnBlur;
            cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); });
            cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); });
        }

        var startScroll = cm.getScrollInfo();
        cm.on("scroll", this.onScroll = function () {
            var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect();
            var newTop = top + startScroll.top - curScroll.top;
            var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop);
            if (!below) point += hints.offsetHeight;
            if (point <= editor.top || point >= editor.bottom) return completion.close();
            hints.style.top = newTop + "px";
            hints.style.left = (left + startScroll.left - curScroll.left) + "px";
        });

        CodeMirror.on(hints, "dblclick", function (e) {
            var t = getHintElement(hints, e.target || e.srcElement);
            if (t && t.hintId != null) { widget.changeActive(t.hintId); widget.pick(); }
        });

        CodeMirror.on(hints, "click", function (e) {
            var t = getHintElement(hints, e.target || e.srcElement);
            if (t && t.hintId != null) {
                widget.changeActive(t.hintId);
                if (completion.options.completeOnSingleClick) widget.pick();
            }
        });

        CodeMirror.on(hints, "mousedown", function () {
            setTimeout(function () { cm.focus(); }, 20);
        });

        CodeMirror.signal(data, "select", completions[0], hints.firstChild);
        return true;
    }

    Widget.prototype = {
        close: function () {
            if (this.completion.widget != this) return;
            this.completion.widget = null;
            this.hints.parentNode.removeChild(this.hints);
            this.completion.cm.removeKeyMap(this.keyMap);

            var cm = this.completion.cm;
            if (this.completion.options.closeOnUnfocus) {
                cm.off("blur", this.onBlur);
                cm.off("focus", this.onFocus);
            }
            cm.off("scroll", this.onScroll);
        },

        disable: function () {
            this.completion.cm.removeKeyMap(this.keyMap);
            var widget = this;
            this.keyMap = { Enter: function () { widget.picked = true; } };
            this.completion.cm.addKeyMap(this.keyMap);
        },

        pick: function () {
            this.completion.pick(this.data, this.selectedHint);
        },

        changeActive: function (i, avoidWrap) {
            if (i >= this.data.list.length)
                i = avoidWrap ? this.data.list.length - 1 : 0;
            else if (i < 0)
                i = avoidWrap ? 0 : this.data.list.length - 1;
            if (this.selectedHint == i) return;
            var node = this.hints.childNodes[this.selectedHint];
            node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, "");
            node = this.hints.childNodes[this.selectedHint = i];
            node.className += " " + ACTIVE_HINT_ELEMENT_CLASS;
            if (node.offsetTop < this.hints.scrollTop)
                this.hints.scrollTop = node.offsetTop - 3;
            else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight)
                this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3;
            CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node);
        },

        screenAmount: function () {
            return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1;
        }
    };

    function applicableHelpers(cm, helpers) {
        if (!cm.somethingSelected()) return helpers
        var result = []
        for (var i = 0; i < helpers.length; i++)
            if (helpers[i].supportsSelection) result.push(helpers[i])
        return result
    }

    function resolveAutoHints(cm, pos) {
        var helpers = cm.getHelpers(pos, "hint"), words
        if (helpers.length) {
            var async = false, resolved
            for (var i = 0; i < helpers.length; i++) if (helpers[i].async) async = true
            if (async) {
                resolved = function (cm, callback, options) {
                    var app = applicableHelpers(cm, helpers)
                    function run(i, result) {
                        if (i == app.length) return callback(null)
                        var helper = app[i]
                        if (helper.async) {
                            helper(cm, function (result) {
                                if (result) callback(result)
                                else run(i + 1)
                            }, options)
                        } else {
                            var result = helper(cm, options)
                            if (result) callback(result)
                            else run(i + 1)
                        }
                    }
                    run(0)
                }
                resolved.async = true
            } else {
                resolved = function (cm, options) {
                    var app = applicableHelpers(cm, helpers)
                    for (var i = 0; i < app.length; i++) {
                        var cur = app[i](cm, options)
                        if (cur && cur.list.length) return cur
                    }
                }
            }
            resolved.supportsSelection = true
            return resolved
        } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) {
            return function (cm) { return CodeMirror.hint.fromList(cm, { words: words }) }
        } else if (CodeMirror.hint.anyword) {
            return function (cm, options) { return CodeMirror.hint.anyword(cm, options) }
        } else {
            return function () { }
        }
    }

    CodeMirror.registerHelper("hint", "auto", {
        resolve: resolveAutoHints
    });

    CodeMirror.registerHelper("hint", "fromList", function (cm, options) {
        var cur = cm.getCursor(), token = cm.getTokenAt(cur);
        var to = CodeMirror.Pos(cur.line, token.end);
        if (token.string && /\w/.test(token.string[token.string.length - 1])) {
            var term = token.string, from = CodeMirror.Pos(cur.line, token.start);
        } else {
            var term = "", from = to;
        }
        var found = [];
        for (var i = 0; i < options.words.length; i++) {
            var word = options.words[i];
            if (word.slice(0, term.length) == term)
                found.push(word);
        }

        if (found.length) return { list: found, from: from, to: to };
    });

    CodeMirror.commands.autocomplete = CodeMirror.showHint;

    var defaultOptions = {
        hint: CodeMirror.hint.auto,
        completeSingle: true,
        alignWithWord: true,
        closeCharacters: /[\s()\[\]{};:>,]/,
        closeOnUnfocus: true,
        completeOnSingleClick: false,
        container: null,
        customKeys: null,
        extraKeys: null
    };

    CodeMirror.defineOption("hintOptions", null);
});

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    var Pos = CodeMirror.Pos;

    function forEach(arr, f) {
        for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]);
    }

    function arrayContains(arr, item) {
        if (!Array.prototype.indexOf) {
            var i = arr.length;
            while (i--) {
                if (arr[i] === item) {
                    return true;
                }
            }
            return false;
        }
        return arr.indexOf(item) != -1;
    }

    function scriptHint(editor, keywords, getToken, options) {
        // Find the token at the cursor
        var cur = editor.getCursor(), token = getToken(editor, cur);
        if (/\b(?:string|comment)\b/.test(token.type)) return;
        token.state = CodeMirror.innerMode(editor.getMode(), token.state).state;

        // If it's not a 'word-style' token, ignore the token.
        if (!/^[\w$_]*$/.test(token.string)) {
            token = {
                start: cur.ch, end: cur.ch, string: "", state: token.state,
                type: token.string == "." ? "property" : null
            };
        } else if (token.end > cur.ch) {
            token.end = cur.ch;
            token.string = token.string.slice(0, cur.ch - token.start);
        }

        var tprop = token;
        // If it is a property, find out what it is a property of.
        while (tprop.type == "property") {
            tprop = getToken(editor, Pos(cur.line, tprop.start));
            if (tprop.string != ".") return;
            tprop = getToken(editor, Pos(cur.line, tprop.start));
            if (!context) var context = [];
            context.push(tprop);
        }
        return {
            list: getCompletions(token, context, keywords, options),
            from: Pos(cur.line, token.start),
            to: Pos(cur.line, token.end)
        };
    }

    function javascriptHint(editor, options) {
        return scriptHint(editor, javascriptKeywords,
                          function (e, cur) { return e.getTokenAt(cur); },
                          options);
    };
    CodeMirror.registerHelper("hint", "javascript", javascriptHint);

    function getCoffeeScriptToken(editor, cur) {
        // This getToken, it is for coffeescript, imitates the behavior of
        // getTokenAt method in javascript.js, that is, returning "property"
        // type and treat "." as indepenent token.
        var token = editor.getTokenAt(cur);
        if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') {
            token.end = token.start;
            token.string = '.';
            token.type = "property";
        }
        else if (/^\.[\w$_]*$/.test(token.string)) {
            token.type = "property";
            token.start++;
            token.string = token.string.replace(/\./, '');
        }
        return token;
    }

    function coffeescriptHint(editor, options) {
        return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options);
    }
    CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint);

    var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " +
                       "toUpperCase toLowerCase split concat match replace search").split(" ");
    var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " +
                      "lastIndexOf every some filter forEach map reduce reduceRight ").split(" ");
    var funcProps = "prototype apply call bind".split(" ");
    var javascriptKeywords = ("break case catch continue debugger default delete do else false finally for function " +
                    "if in instanceof new null return switch throw true try typeof var void while with").split(" ");
    var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " +
                    "if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" ");

    function getCompletions(token, context, keywords, options) {
        var found = [], start = token.string, global = options && options.globalScope || window;
        function maybeAdd(str) {
            if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str);
        }
        function gatherCompletions(obj) {
            if (typeof obj == "string") forEach(stringProps, maybeAdd);
            else if (obj instanceof Array) forEach(arrayProps, maybeAdd);
            else if (obj instanceof Function) forEach(funcProps, maybeAdd);
            for (var name in obj) maybeAdd(name);
        }

        if (context && context.length) {
            // If this is a property, see if it belongs to some object we can
            // find in the current environment.
            var obj = context.pop(), base;
            if (obj.type && obj.type.indexOf("variable") === 0) {
                if (options && options.additionalContext)
                    base = options.additionalContext[obj.string];
                if (!options || options.useGlobalScope !== false)
                    base = base || global[obj.string];
            } else if (obj.type == "string") {
                base = "";
            } else if (obj.type == "atom") {
                base = 1;
            } else if (obj.type == "function") {
                if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') &&
                    (typeof global.jQuery == 'function'))
                    base = global.jQuery();
                else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function'))
                    base = global._();
            }
            while (base != null && context.length)
                base = base[context.pop().string];
            if (base != null) gatherCompletions(base);
        } else {
            // If not, just look in the global object and any local scope
            // (reading into JS mode internals to get at the local and global variables)
            for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name);
            for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name);
            if (!options || options.useGlobalScope !== false)
                gatherCompletions(global);
            forEach(keywords, maybeAdd);
        }
        return found;
    }
});

/*!
 * JSHint, by JSHint Community.
 *
 * Licensed under the same slightly modified MIT license that JSLint is.
 * It stops evil-doers everywhere.
 *
 * JSHint is a derivative work of JSLint:
 *
 *   Copyright (c) 2002 Douglas Crockford  (www.JSLint.com)
 *
 *   Permission is hereby granted, free of charge, to any person obtaining
 *   a copy of this software and associated documentation files (the "Software"),
 *   to deal in the Software without restriction, including without limitation
 *   the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *   and/or sell copies of the Software, and to permit persons to whom
 *   the Software is furnished to do so, subject to the following conditions:
 *
 *   The above copyright notice and this permission notice shall be included
 *   in all copies or substantial portions of the Software.
 *
 *   The Software shall be used for Good, not Evil.
 *
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *   DEALINGS IN THE SOFTWARE.
 *
 * JSHint was forked from 2010-12-16 edition of JSLint.
 *
 */

/*
 JSHINT is a global function. It takes two parameters.

     var myResult = JSHINT(source, option);

 The first parameter is either a string or an array of strings. If it is a
 string, it will be split on '\n' or '\r'. If it is an array of strings, it
 is assumed that each string represents one line. The source can be a
 JavaScript text or a JSON text.

 The second parameter is an optional object of options which control the
 operation of JSHINT. Most of the options are booleans: They are all
 optional and have a default value of false. One of the options, predef,
 can be an array of names, which will be used to declare global variables,
 or an object whose keys are used as global names, with a boolean value
 that determines if they are assignable.

 If it checks out, JSHINT returns true. Otherwise, it returns false.

 If false, you can inspect JSHINT.errors to find out the problems.
 JSHINT.errors is an array of objects containing these members:

 {
     line      : The line (relative to 0) at which the lint was found
     character : The character (relative to 0) at which the lint was found
     reason    : The problem
     evidence  : The text line in which the problem occurred
     raw       : The raw message before the details were inserted
     a         : The first detail
     b         : The second detail
     c         : The third detail
     d         : The fourth detail
 }

 If a fatal error was found, a null will be the last element of the
 JSHINT.errors array.

 You can request a Function Report, which shows all of the functions
 and the parameters and vars that they use. This can be used to find
 implied global variables and other problems. The report is in HTML and
 can be inserted in an HTML <body>.

     var myReport = JSHINT.report(limited);

 If limited is true, then the report will be limited to only errors.

 You can request a data structure which contains JSHint's results.

     var myData = JSHINT.data();

 It returns a structure with this form:

 {
     errors: [
         {
             line: NUMBER,
             character: NUMBER,
             reason: STRING,
             evidence: STRING
         }
     ],
     functions: [
         name: STRING,
         line: NUMBER,
         last: NUMBER,
         param: [
             STRING
         ],
         closure: [
             STRING
         ],
         var: [
             STRING
         ],
         exception: [
             STRING
         ],
         outer: [
             STRING
         ],
         unused: [
             STRING
         ],
         global: [
             STRING
         ],
         label: [
             STRING
         ]
     ],
     globals: [
         STRING
     ],
     member: {
         STRING: NUMBER
     },
     unused: [
         {
             name: STRING,
             line: NUMBER
         }
     ],
     implieds: [
         {
             name: STRING,
             line: NUMBER
         }
     ],
     urls: [
         STRING
     ],
     json: BOOLEAN
 }

 Empty arrays will not be included.

*/

/*jshint
 evil: true, nomen: false, onevar: false, regexp: false, strict: true, boss: true,
 undef: true, maxlen: 100, indent:4
*/

/*members "\b", "\t", "\n", "\f", "\r", "!=", "!==", "\"", "%", "(begin)",
 "(breakage)", "(context)", "(error)", "(global)", "(identifier)", "(last)",
 "(line)", "(loopage)", "(name)", "(onevar)", "(params)", "(scope)",
 "(statement)", "(verb)", "*", "+", "++", "-", "--", "\/", "<", "<=", "==",
 "===", ">", ">=", $, $$, $A, $F, $H, $R, $break, $continue, $w, Abstract, Ajax,
 __filename, __dirname, ActiveXObject, Array, ArrayBuffer, ArrayBufferView, Audio,
 Autocompleter, Assets, Boolean, Builder, Buffer, Browser, COM, CScript, Canvas,
 CustomAnimation, Class, Control, Chain, Color, Cookie, Core, DataView, Date,
 Debug, Draggable, Draggables, Droppables, Document, DomReady, DOMReady, DOMParser, Drag,
 E, Enumerator, Enumerable, Element, Elements, Error, Effect, EvalError, Event,
 Events, FadeAnimation, Field, Flash, Float32Array, Float64Array, Form,
 FormField, Frame, FormData, Function, Fx, GetObject, Group, Hash, HotKey,
 HTMLElement, HTMLAnchorElement, HTMLBaseElement, HTMLBlockquoteElement,
 HTMLBodyElement, HTMLBRElement, HTMLButtonElement, HTMLCanvasElement, HTMLDirectoryElement,
 HTMLDivElement, HTMLDListElement, HTMLFieldSetElement,
 HTMLFontElement, HTMLFormElement, HTMLFrameElement, HTMLFrameSetElement,
 HTMLHeadElement, HTMLHeadingElement, HTMLHRElement, HTMLHtmlElement,
 HTMLIFrameElement, HTMLImageElement, HTMLInputElement, HTMLIsIndexElement,
 HTMLLabelElement, HTMLLayerElement, HTMLLegendElement, HTMLLIElement,
 HTMLLinkElement, HTMLMapElement, HTMLMenuElement, HTMLMetaElement,
 HTMLModElement, HTMLObjectElement, HTMLOListElement, HTMLOptGroupElement,
 HTMLOptionElement, HTMLParagraphElement, HTMLParamElement, HTMLPreElement,
 HTMLQuoteElement, HTMLScriptElement, HTMLSelectElement, HTMLStyleElement,
 HtmlTable, HTMLTableCaptionElement, HTMLTableCellElement, HTMLTableColElement,
 HTMLTableElement, HTMLTableRowElement, HTMLTableSectionElement,
 HTMLTextAreaElement, HTMLTitleElement, HTMLUListElement, HTMLVideoElement,
 Iframe, IframeShim, Image, Int16Array, Int32Array, Int8Array,
 Insertion, InputValidator, JSON, Keyboard, Locale, LN10, LN2, LOG10E, LOG2E,
 MAX_VALUE, MIN_VALUE, Mask, Math, MenuItem, MessageChannel, MessageEvent, MessagePort,
 MoveAnimation, MooTools, Native, NEGATIVE_INFINITY, Number, Object, ObjectRange, Option,
 Options, OverText, PI, POSITIVE_INFINITY, PeriodicalExecuter, Point, Position, Prototype,
 RangeError, Rectangle, ReferenceError, RegExp, ResizeAnimation, Request, RotateAnimation,
 SQRT1_2, SQRT2, ScrollBar, ScriptEngine, ScriptEngineBuildVersion,
 ScriptEngineMajorVersion, ScriptEngineMinorVersion, Scriptaculous, Scroller,
 Slick, Slider, Selector, SharedWorker, String, Style, SyntaxError, Sortable, Sortables,
 SortableObserver, Sound, Spinner, System, Swiff, Text, TextArea, Template,
 Timer, Tips, Type, TypeError, Toggle, Try, "use strict", unescape, URI, URIError, URL,
 VBArray, WSH, WScript, XDomainRequest, Web, Window, XMLDOM, XMLHttpRequest, XMLSerializer,
 XPathEvaluator, XPathException, XPathExpression, XPathNamespace, XPathNSResolver, XPathResult,
 "\\", a, addEventListener, address, alert, apply, applicationCache, arguments, arity, asi, atob,
 b, basic, basicToken, bitwise, block, blur, boolOptions, boss, browser, btoa, c, call, callee,
 caller, cases, charAt, charCodeAt, character, clearInterval, clearTimeout,
 close, closed, closure, comment, condition, confirm, console, constructor,
 content, couch, create, css, curly, d, data, datalist, dd, debug, decodeURI,
 decodeURIComponent, defaultStatus, defineClass, deserialize, devel, document,
 dojo, dijit, dojox, define, else, emit, encodeURI, encodeURIComponent,
 entityify, eqeq, eqeqeq, eqnull, errors, es5, escape, esnext, eval, event, evidence, evil,
 ex, exception, exec, exps, expr, exports, FileReader, first, floor, focus,
 forin, fragment, frames, from, fromCharCode, fud, funcscope, funct, function, functions,
 g, gc, getComputedStyle, getRow, getter, getterToken, GLOBAL, global, globals, globalstrict,
 hasOwnProperty, help, history, i, id, identifier, immed, implieds, importPackage, include,
 indent, indexOf, init, ins, instanceOf, isAlpha, isApplicationRunning, isArray,
 isDigit, isFinite, isNaN, iterator, java, join, jshint,
 JSHINT, json, jquery, jQuery, keys, label, labelled, last, lastsemic, laxbreak, laxcomma,
 latedef, lbp, led, left, length, line, load, loadClass, localStorage, location,
 log, loopfunc, m, match, maxerr, maxlen, member,message, meta, module, moveBy,
 moveTo, mootools, multistr, name, navigator, new, newcap, noarg, node, noempty, nomen,
 nonew, nonstandard, nud, onbeforeunload, onblur, onerror, onevar, onecase, onfocus,
 onload, onresize, onunload, open, openDatabase, openURL, opener, opera, options, outer, param,
 parent, parseFloat, parseInt, passfail, plusplus, predef, print, process, prompt,
 proto, prototype, prototypejs, provides, push, quit, range, raw, reach, reason, regexp,
 readFile, readUrl, regexdash, removeEventListener, replace, report, require,
 reserved, resizeBy, resizeTo, resolvePath, resumeUpdates, respond, rhino, right,
 runCommand, scroll, screen, scripturl, scrollBy, scrollTo, scrollbar, search, seal,
 send, serialize, sessionStorage, setInterval, setTimeout, setter, setterToken, shift, slice,
 smarttabs, sort, spawn, split, stack, status, start, strict, sub, substr, supernew, shadow,
 supplant, sum, sync, test, toLowerCase, toString, toUpperCase, toint32, token, top, trailing,
 type, typeOf, Uint16Array, Uint32Array, Uint8Array, undef, undefs, unused, urls, validthis,
 value, valueOf, var, vars, version, WebSocket, withstmt, white, window, windows, Worker, wsh*/

/*global exports: false */

// We build the application inside a function so that we produce only a single
// global variable. That function will be invoked immediately, and its return
// value is the JSHINT function itself.

var JSHINT = (function () {
    "use strict";

    var anonname,       // The guessed name for anonymous functions.

// These are operators that should not be used with the ! operator.

        bang = {
            '<': true,
            '<=': true,
            '==': true,
            '===': true,
            '!==': true,
            '!=': true,
            '>': true,
            '>=': true,
            '+': true,
            '-': true,
            '*': true,
            '/': true,
            '%': true
        },

        // These are the JSHint boolean options.
        boolOptions = {
            asi: true, // if automatic semicolon insertion should be tolerated
            bitwise: true, // if bitwise operators should not be allowed
            boss: true, // if advanced usage of assignments should be allowed
            browser: true, // if the standard browser globals should be predefined
            couch: true, // if CouchDB globals should be predefined
            curly: true, // if curly braces around all blocks should be required
            debug: true, // if debugger statements should be allowed
            devel: true, // if logging globals should be predefined (console,
            // alert, etc.)
            dojo: true, // if Dojo Toolkit globals should be predefined
            eqeqeq: true, // if === should be required
            eqnull: true, // if == null comparisons should be tolerated
            es5: true, // if ES5 syntax should be allowed
            esnext: true, // if es.next specific syntax should be allowed
            evil: true, // if eval should be allowed
            expr: true, // if ExpressionStatement should be allowed as Programs
            forin: true, // if for in statements must filter
            funcscope: true, // if only function scope should be used for scope tests
            globalstrict: true, // if global "use strict"; should be allowed (also
            // enables 'strict')
            immed: true, // if immediate invocations must be wrapped in parens
            iterator: true, // if the `__iterator__` property should be allowed
            jquery: true, // if jQuery globals should be predefined
            lastsemic: true, // if semicolons may be ommitted for the trailing
            // statements inside of a one-line blocks.
            latedef: true, // if the use before definition should not be tolerated
            laxbreak: true, // if line breaks should not be checked
            laxcomma: true, // if line breaks should not be checked around commas
            loopfunc: true, // if functions should be allowed to be defined within
            // loops
            mootools: true, // if MooTools globals should be predefined
            multistr: true, // allow multiline strings
            newcap: true, // if constructor names must be capitalized
            noarg: true, // if arguments.caller and arguments.callee should be
            // disallowed
            node: true, // if the Node.js environment globals should be
            // predefined
            noempty: true, // if empty blocks should be disallowed
            nonew: true, // if using `new` for side-effects should be disallowed
            nonstandard: true, // if non-standard (but widely adopted) globals should
            // be predefined
            nomen: true, // if names should be checked
            onevar: true, // if only one var statement per function should be
            // allowed
            onecase: true, // if one case switch statements should be allowed
            passfail: true, // if the scan should stop on first error
            plusplus: true, // if increment/decrement should not be allowed
            proto: true, // if the `__proto__` property should be allowed
            prototypejs: true, // if Prototype and Scriptaculous globals should be
            // predefined
            regexdash: true, // if unescaped first/last dash (-) inside brackets
            // should be tolerated
            regexp: true, // if the . should not be allowed in regexp literals
            rhino: true, // if the Rhino environment globals should be predefined
            undef: true, // if variables should be declared before used
            scripturl: true, // if script-targeted URLs should be tolerated
            shadow: true, // if variable shadowing should be tolerated
            smarttabs: true, // if smarttabs should be tolerated
            // (http://www.emacswiki.org/emacs/SmartTabs)
            strict: true, // require the "use strict"; pragma
            sub: true, // if all forms of subscript notation are tolerated
            supernew: true, // if `new function () { ... };` and `new Object;`
            // should be tolerated
            trailing: true, // if trailing whitespace rules apply
            validthis: true, // if 'this' inside a non-constructor function is valid.
            // This is a function scoped option only.
            withstmt: true, // if with statements should be allowed
            white: true, // if strict whitespace rules apply
            wsh: true  // if the Windows Scripting Host environment globals
            // should be predefined
        },

        // These are the JSHint options that can take any value
        // (we use this object to detect invalid options)
        valOptions = {
            maxlen: false,
            indent: false,
            maxerr: false,
            predef: false
        },

        // These are JSHint boolean options which are shared with JSLint
        // where the definition in JSHint is opposite JSLint
        invertedOptions = {
            bitwise: true,
            forin: true,
            newcap: true,
            nomen: true,
            plusplus: true,
            regexp: true,
            undef: true,
            white: true,

            // Inverted and renamed, use JSHint name here
            eqeqeq: true,
            onevar: true
        },

        // These are JSHint boolean options which are shared with JSLint
        // where the name has been changed but the effect is unchanged
        renamedOptions = {
            eqeq: "eqeqeq",
            vars: "onevar",
            windows: "wsh"
        },


        // browser contains a set of global names which are commonly provided by a
        // web browser environment.
        browser = {
            ArrayBuffer: false,
            ArrayBufferView: false,
            Audio: false,
            addEventListener: false,
            applicationCache: false,
            atob: false,
            blur: false,
            btoa: false,
            clearInterval: false,
            clearTimeout: false,
            close: false,
            closed: false,
            DataView: false,
            DOMParser: false,
            defaultStatus: false,
            document: false,
            event: false,
            FileReader: false,
            Float32Array: false,
            Float64Array: false,
            FormData: false,
            focus: false,
            frames: false,
            getComputedStyle: false,
            HTMLElement: false,
            HTMLAnchorElement: false,
            HTMLBaseElement: false,
            HTMLBlockquoteElement: false,
            HTMLBodyElement: false,
            HTMLBRElement: false,
            HTMLButtonElement: false,
            HTMLCanvasElement: false,
            HTMLDirectoryElement: false,
            HTMLDivElement: false,
            HTMLDListElement: false,
            HTMLFieldSetElement: false,
            HTMLFontElement: false,
            HTMLFormElement: false,
            HTMLFrameElement: false,
            HTMLFrameSetElement: false,
            HTMLHeadElement: false,
            HTMLHeadingElement: false,
            HTMLHRElement: false,
            HTMLHtmlElement: false,
            HTMLIFrameElement: false,
            HTMLImageElement: false,
            HTMLInputElement: false,
            HTMLIsIndexElement: false,
            HTMLLabelElement: false,
            HTMLLayerElement: false,
            HTMLLegendElement: false,
            HTMLLIElement: false,
            HTMLLinkElement: false,
            HTMLMapElement: false,
            HTMLMenuElement: false,
            HTMLMetaElement: false,
            HTMLModElement: false,
            HTMLObjectElement: false,
            HTMLOListElement: false,
            HTMLOptGroupElement: false,
            HTMLOptionElement: false,
            HTMLParagraphElement: false,
            HTMLParamElement: false,
            HTMLPreElement: false,
            HTMLQuoteElement: false,
            HTMLScriptElement: false,
            HTMLSelectElement: false,
            HTMLStyleElement: false,
            HTMLTableCaptionElement: false,
            HTMLTableCellElement: false,
            HTMLTableColElement: false,
            HTMLTableElement: false,
            HTMLTableRowElement: false,
            HTMLTableSectionElement: false,
            HTMLTextAreaElement: false,
            HTMLTitleElement: false,
            HTMLUListElement: false,
            HTMLVideoElement: false,
            history: false,
            Int16Array: false,
            Int32Array: false,
            Int8Array: false,
            Image: false,
            length: false,
            localStorage: false,
            location: false,
            MessageChannel: false,
            MessageEvent: false,
            MessagePort: false,
            moveBy: false,
            moveTo: false,
            name: false,
            navigator: false,
            onbeforeunload: true,
            onblur: true,
            onerror: true,
            onfocus: true,
            onload: true,
            onresize: true,
            onunload: true,
            open: false,
            openDatabase: false,
            opener: false,
            Option: false,
            parent: false,
            print: false,
            removeEventListener: false,
            resizeBy: false,
            resizeTo: false,
            screen: false,
            scroll: false,
            scrollBy: false,
            scrollTo: false,
            sessionStorage: false,
            setInterval: false,
            setTimeout: false,
            SharedWorker: false,
            status: false,
            top: false,
            Uint16Array: false,
            Uint32Array: false,
            Uint8Array: false,
            WebSocket: false,
            window: false,
            Worker: false,
            XMLHttpRequest: false,
            XMLSerializer: false,
            XPathEvaluator: false,
            XPathException: false,
            XPathExpression: false,
            XPathNamespace: false,
            XPathNSResolver: false,
            XPathResult: false
        },

        couch = {
            "require": false,
            respond: false,
            getRow: false,
            emit: false,
            send: false,
            start: false,
            sum: false,
            log: false,
            exports: false,
            module: false,
            provides: false
        },

        devel = {
            alert: false,
            confirm: false,
            console: false,
            Debug: false,
            opera: false,
            prompt: false
        },

        dojo = {
            dojo: false,
            dijit: false,
            dojox: false,
            define: false,
            "require": false
        },

        escapes = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"': '\\"',
            '/': '\\/',
            '\\': '\\\\'
        },

        funct,          // The current function

        functionicity = [
            'closure', 'exception', 'global', 'label',
            'outer', 'unused', 'var'
        ],

        functions,      // All of the functions

        global,         // The global scope
        implied,        // Implied globals
        inblock,
        indent,
        jsonmode,

        jquery = {
            '$': false,
            jQuery: false
        },

        lines,
        lookahead,
        member,
        membersOnly,

        mootools = {
            '$': false,
            '$$': false,
            Assets: false,
            Browser: false,
            Chain: false,
            Class: false,
            Color: false,
            Cookie: false,
            Core: false,
            Document: false,
            DomReady: false,
            DOMReady: false,
            Drag: false,
            Element: false,
            Elements: false,
            Event: false,
            Events: false,
            Fx: false,
            Group: false,
            Hash: false,
            HtmlTable: false,
            Iframe: false,
            IframeShim: false,
            InputValidator: false,
            instanceOf: false,
            Keyboard: false,
            Locale: false,
            Mask: false,
            MooTools: false,
            Native: false,
            Options: false,
            OverText: false,
            Request: false,
            Scroller: false,
            Slick: false,
            Slider: false,
            Sortables: false,
            Spinner: false,
            Swiff: false,
            Tips: false,
            Type: false,
            typeOf: false,
            URI: false,
            Window: false
        },

        nexttoken,

        node = {
            __filename: false,
            __dirname: false,
            Buffer: false,
            console: false,
            exports: false,
            GLOBAL: false,
            global: false,
            module: false,
            process: false,
            require: false,
            setTimeout: false,
            clearTimeout: false,
            setInterval: false,
            clearInterval: false
        },

        noreach,
        option,
        predefined,     // Global variables defined by option
        prereg,
        prevtoken,

        prototypejs = {
            '$': false,
            '$$': false,
            '$A': false,
            '$F': false,
            '$H': false,
            '$R': false,
            '$break': false,
            '$continue': false,
            '$w': false,
            Abstract: false,
            Ajax: false,
            Class: false,
            Enumerable: false,
            Element: false,
            Event: false,
            Field: false,
            Form: false,
            Hash: false,
            Insertion: false,
            ObjectRange: false,
            PeriodicalExecuter: false,
            Position: false,
            Prototype: false,
            Selector: false,
            Template: false,
            Toggle: false,
            Try: false,
            Autocompleter: false,
            Builder: false,
            Control: false,
            Draggable: false,
            Draggables: false,
            Droppables: false,
            Effect: false,
            Sortable: false,
            SortableObserver: false,
            Sound: false,
            Scriptaculous: false
        },

        rhino = {
            defineClass: false,
            deserialize: false,
            gc: false,
            help: false,
            importPackage: false,
            "java": false,
            load: false,
            loadClass: false,
            print: false,
            quit: false,
            readFile: false,
            readUrl: false,
            runCommand: false,
            seal: false,
            serialize: false,
            spawn: false,
            sync: false,
            toint32: false,
            version: false
        },

        scope,      // The current scope
        stack,

        // standard contains the global names that are provided by the
        // ECMAScript standard.
        standard = {
            Array: false,
            Boolean: false,
            Date: false,
            decodeURI: false,
            decodeURIComponent: false,
            encodeURI: false,
            encodeURIComponent: false,
            Error: false,
            'eval': false,
            EvalError: false,
            Function: false,
            hasOwnProperty: false,
            isFinite: false,
            isNaN: false,
            JSON: false,
            Math: false,
            Number: false,
            Object: false,
            parseInt: false,
            parseFloat: false,
            RangeError: false,
            ReferenceError: false,
            RegExp: false,
            String: false,
            SyntaxError: false,
            TypeError: false,
            URIError: false
        },

        // widely adopted global names that are not part of ECMAScript standard
        nonstandard = {
            escape: false,
            unescape: false
        },

        standard_member = {
            E: true,
            LN2: true,
            LN10: true,
            LOG2E: true,
            LOG10E: true,
            MAX_VALUE: true,
            MIN_VALUE: true,
            NEGATIVE_INFINITY: true,
            PI: true,
            POSITIVE_INFINITY: true,
            SQRT1_2: true,
            SQRT2: true
        },

        directive,
        syntax = {},
        tab,
        token,
        urls,
        useESNextSyntax,
        warnings,

        wsh = {
            ActiveXObject: true,
            Enumerator: true,
            GetObject: true,
            ScriptEngine: true,
            ScriptEngineBuildVersion: true,
            ScriptEngineMajorVersion: true,
            ScriptEngineMinorVersion: true,
            VBArray: true,
            WSH: true,
            WScript: true,
            XDomainRequest: true
        };

    // Regular expressions. Some of these are stupidly long.
    var ax, cx, tx, nx, nxg, lx, ix, jx, ft;
    (function () {
        /*jshint maxlen:300 */

        // unsafe comment or string
        ax = /@cc|<\/?|script|\]\s*\]|<\s*!|&lt/i;

        // unsafe characters that are silently deleted by one or more browsers
        cx = /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;

        // token
        tx = /^\s*([(){}\[.,:;'"~\?\]#@]|==?=?|\/(\*(jshint|jslint|members?|global)?|=|\/)?|\*[\/=]?|\+(?:=|\++)?|-(?:=|-+)?|%=?|&[&=]?|\|[|=]?|>>?>?=?|<([\/=!]|\!(\[|--)?|<=?)?|\^=?|\!=?=?|[a-zA-Z_$][a-zA-Z0-9_$]*|[0-9]+([xX][0-9a-fA-F]+|\.[0-9]*)?([eE][+\-]?[0-9]+)?)/;

        // characters in strings that need escapement
        nx = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/;
        nxg = /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

        // star slash
        lx = /\*\/|\/\*/;

        // identifier
        ix = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/;

        // javascript url
        jx = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i;

        // catches /* falls through */ comments
        ft = /^\s*\/\*\s*falls\sthrough\s*\*\/\s*$/;
    }());

    function F() { }     // Used by Object.create

    function is_own(object, name) {

        // The object.hasOwnProperty method fails when the property under consideration
        // is named 'hasOwnProperty'. So we have to use this more convoluted form.

        return Object.prototype.hasOwnProperty.call(object, name);
    }

    function checkOption(name, t) {
        if (valOptions[name] === undefined && boolOptions[name] === undefined) {
            warning("Bad option: '" + name + "'.", t);
        }
    }

    // Provide critical ES5 functions to ES3.

    if (typeof Array.isArray !== 'function') {
        Array.isArray = function (o) {
            return Object.prototype.toString.apply(o) === '[object Array]';
        };
    }

    if (typeof Object.create !== 'function') {
        Object.create = function (o) {
            F.prototype = o;
            return new F();
        };
    }

    if (typeof Object.keys !== 'function') {
        Object.keys = function (o) {
            var a = [], k;
            for (k in o) {
                if (is_own(o, k)) {
                    a.push(k);
                }
            }
            return a;
        };
    }

    // Non standard methods

    if (typeof String.prototype.entityify !== 'function') {
        String.prototype.entityify = function () {
            return this
                .replace(/&/g, '&amp;')
                .replace(/</g, '&lt;')
                .replace(/>/g, '&gt;');
        };
    }

    if (typeof String.prototype.isAlpha !== 'function') {
        String.prototype.isAlpha = function () {
            return (this >= 'a' && this <= 'z\uffff') ||
                (this >= 'A' && this <= 'Z\uffff');
        };
    }

    if (typeof String.prototype.isDigit !== 'function') {
        String.prototype.isDigit = function () {
            return (this >= '0' && this <= '9');
        };
    }

    if (typeof String.prototype.supplant !== 'function') {
        String.prototype.supplant = function (o) {
            return this.replace(/\{([^{}]*)\}/g, function (a, b) {
                var r = o[b];
                return typeof r === 'string' || typeof r === 'number' ? r : a;
            });
        };
    }

    if (typeof String.prototype.name !== 'function') {
        String.prototype.name = function () {

            // If the string looks like an identifier, then we can return it as is.
            // If the string contains no control characters, no quote characters, and no
            // backslash characters, then we can simply slap some quotes around it.
            // Otherwise we must also replace the offending characters with safe
            // sequences.

            if (ix.test(this)) {
                return this;
            }
            if (nx.test(this)) {
                return '"' + this.replace(nxg, function (a) {
                    var c = escapes[a];
                    if (c) {
                        return c;
                    }
                    return '\\u' + ('0000' + a.charCodeAt().toString(16)).slice(-4);
                }) + '"';
            }
            return '"' + this + '"';
        };
    }


    function combine(t, o) {
        var n;
        for (n in o) {
            if (is_own(o, n)) {
                t[n] = o[n];
            }
        }
    }

    function assume() {
        if (option.couch) {
            combine(predefined, couch);
        }

        if (option.rhino) {
            combine(predefined, rhino);
        }

        if (option.prototypejs) {
            combine(predefined, prototypejs);
        }

        if (option.node) {
            combine(predefined, node);
            option.globalstrict = true;
        }

        if (option.devel) {
            combine(predefined, devel);
        }

        if (option.dojo) {
            combine(predefined, dojo);
        }

        if (option.browser) {
            combine(predefined, browser);
        }

        if (option.nonstandard) {
            combine(predefined, nonstandard);
        }

        if (option.jquery) {
            combine(predefined, jquery);
        }

        if (option.mootools) {
            combine(predefined, mootools);
        }

        if (option.wsh) {
            combine(predefined, wsh);
        }

        if (option.esnext) {
            useESNextSyntax();
        }

        if (option.globalstrict && option.strict !== false) {
            option.strict = true;
        }
    }


    // Produce an error warning.
    function quit(message, line, chr) {
        var percentage = Math.floor((line / lines.length) * 100);

        throw {
            name: 'JSHintError',
            line: line,
            character: chr,
            message: message + " (" + percentage + "% scanned).",
            raw: message
        };
    }

    function isundef(scope, m, t, a) {
        return JSHINT.undefs.push([scope, m, t, a]);
    }

    function warning(m, t, a, b, c, d) {
        var ch, l, w;
        t = t || nexttoken;
        if (t.id === '(end)') {  // `~
            t = token;
        }
        l = t.line || 0;
        ch = t.from || 0;
        w = {
            id: '(error)',
            raw: m,
            evidence: lines[l - 1] || '',
            line: l,
            character: ch,
            a: a,
            b: b,
            c: c,
            d: d
        };
        w.reason = m.supplant(w);
        JSHINT.errors.push(w);
        if (option.passfail) {
            quit('Stopping. ', l, ch);
        }
        warnings += 1;
        if (warnings >= option.maxerr) {
            quit("Too many errors.", l, ch);
        }
        return w;
    }

    function warningAt(m, l, ch, a, b, c, d) {
        return warning(m, {
            line: l,
            from: ch
        }, a, b, c, d);
    }

    function error(m, t, a, b, c, d) {
        var w = warning(m, t, a, b, c, d);
    }

    function errorAt(m, l, ch, a, b, c, d) {
        return error(m, {
            line: l,
            from: ch
        }, a, b, c, d);
    }



    // lexical analysis and token construction

    var lex = (function lex() {
        var character, from, line, s;

        // Private lex methods

        function nextLine() {
            var at,
                tw; // trailing whitespace check

            if (line >= lines.length)
                return false;

            character = 1;
            s = lines[line];
            line += 1;

            // If smarttabs option is used check for spaces followed by tabs only.
            // Otherwise check for any occurence of mixed tabs and spaces.
            if (option.smarttabs)
                at = s.search(/ \t/);
            else
                at = s.search(/ \t|\t /);

            if (at >= 0)
                warningAt("Mixed spaces and tabs.", line, at + 1);

            s = s.replace(/\t/g, tab);
            at = s.search(cx);

            if (at >= 0)
                warningAt("Unsafe character.", line, at);

            if (option.maxlen && option.maxlen < s.length)
                warningAt("Line too long.", line, s.length);

            // Check for trailing whitespaces
            tw = option.trailing && s.match(/^(.*?)\s+$/);
            if (tw && !/^\s+$/.test(s)) {
                warningAt("Trailing whitespace.", line, tw[1].length + 1);
            }
            return true;
        }

        // Produce a token object.  The token inherits from a syntax symbol.

        function it(type, value) {
            var i, t;
            if (type === '(color)' || type === '(range)') {
                t = { type: type };
            } else if (type === '(punctuator)' ||
                    (type === '(identifier)' && is_own(syntax, value))) {
                t = syntax[value] || syntax['(error)'];
            } else {
                t = syntax[type];
            }
            t = Object.create(t);
            if (type === '(string)' || type === '(range)') {
                if (!option.scripturl && jx.test(value)) {
                    warningAt("Script URL.", line, from);
                }
            }
            if (type === '(identifier)') {
                t.identifier = true;
                if (value === '__proto__' && !option.proto) {
                    warningAt("The '{a}' property is deprecated.",
                        line, from, value);
                } else if (value === '__iterator__' && !option.iterator) {
                    warningAt("'{a}' is only available in JavaScript 1.7.",
                        line, from, value);
                } else if (option.nomen && (value.charAt(0) === '_' ||
                         value.charAt(value.length - 1) === '_')) {
                    if (!option.node || token.id === '.' ||
                            (value !== '__dirname' && value !== '__filename')) {
                        warningAt("Unexpected {a} in '{b}'.", line, from, "dangling '_'", value);
                    }
                }
            }
            t.value = value;
            t.line = line;
            t.character = character;
            t.from = from;
            i = t.id;
            if (i !== '(endline)') {
                prereg = i &&
                    (('(,=:[!&|?{};'.indexOf(i.charAt(i.length - 1)) >= 0) ||
                    i === 'return' ||
                    i === 'case');
            }
            return t;
        }

        // Public lex methods
        return {
            init: function (source) {
                if (typeof source === 'string') {
                    lines = source
                        .replace(/\r\n/g, '\n')
                        .replace(/\r/g, '\n')
                        .split('\n');
                } else {
                    lines = source;
                }

                // If the first line is a shebang (#!), make it a blank and move on.
                // Shebangs are used by Node scripts.
                if (lines[0] && lines[0].substr(0, 2) === '#!')
                    lines[0] = '';

                line = 0;
                nextLine();
                from = 1;
            },

            range: function (begin, end) {
                var c, value = '';
                from = character;
                if (s.charAt(0) !== begin) {
                    errorAt("Expected '{a}' and instead saw '{b}'.",
                            line, character, begin, s.charAt(0));
                }
                for (; ;) {
                    s = s.slice(1);
                    character += 1;
                    c = s.charAt(0);
                    switch (c) {
                        case '':
                            errorAt("Missing '{a}'.", line, character, c);
                            break;
                        case end:
                            s = s.slice(1);
                            character += 1;
                            return it('(range)', value);
                        case '\\':
                            warningAt("Unexpected '{a}'.", line, character, c);
                    }
                    value += c;
                }

            },


            // token -- this is called by advance to get the next token
            token: function () {
                var b, c, captures, d, depth, high, i, l, low, q, t, isLiteral, isInRange, n;

                function match(x) {
                    var r = x.exec(s), r1;
                    if (r) {
                        l = r[0].length;
                        r1 = r[1];
                        c = r1.charAt(0);
                        s = s.substr(l);
                        from = character + l - r1.length;
                        character += l;
                        return r1;
                    }
                }

                function string(x) {
                    var c, j, r = '', allowNewLine = false;

                    if (jsonmode && x !== '"') {
                        warningAt("Strings must use doublequote.",
                                line, character);
                    }

                    function esc(n) {
                        var i = parseInt(s.substr(j + 1, n), 16);
                        j += n;
                        if (i >= 32 && i <= 126 &&
                                i !== 34 && i !== 92 && i !== 39) {
                            warningAt("Unnecessary escapement.", line, character);
                        }
                        character += n;
                        c = String.fromCharCode(i);
                    }
                    j = 0;
                    unclosedString: for (; ;) {
                        while (j >= s.length) {
                            j = 0;

                            var cl = line, cf = from;
                            if (!nextLine()) {
                                errorAt("Unclosed string.", cl, cf);
                                break unclosedString;
                            }

                            if (allowNewLine) {
                                allowNewLine = false;
                            } else {
                                warningAt("Unclosed string.", cl, cf);
                            }
                        }
                        c = s.charAt(j);
                        if (c === x) {
                            character += 1;
                            s = s.substr(j + 1);
                            return it('(string)', r, x);
                        }
                        if (c < ' ') {
                            if (c === '\n' || c === '\r') {
                                break;
                            }
                            warningAt("Control character in string: {a}.",
                                    line, character + j, s.slice(0, j));
                        } else if (c === '\\') {
                            j += 1;
                            character += 1;
                            c = s.charAt(j);
                            n = s.charAt(j + 1);
                            switch (c) {
                                case '\\':
                                case '"':
                                case '/':
                                    break;
                                case '\'':
                                    if (jsonmode) {
                                        warningAt("Avoid \\'.", line, character);
                                    }
                                    break;
                                case 'b':
                                    c = '\b';
                                    break;
                                case 'f':
                                    c = '\f';
                                    break;
                                case 'n':
                                    c = '\n';
                                    break;
                                case 'r':
                                    c = '\r';
                                    break;
                                case 't':
                                    c = '\t';
                                    break;
                                case '0':
                                    c = '\0';
                                    // Octal literals fail in strict mode
                                    // check if the number is between 00 and 07
                                    // where 'n' is the token next to 'c'
                                    if (n >= 0 && n <= 7 && directive["use strict"]) {
                                        warningAt(
                                        "Octal literals are not allowed in strict mode.",
                                        line, character);
                                    }
                                    break;
                                case 'u':
                                    esc(4);
                                    break;
                                case 'v':
                                    if (jsonmode) {
                                        warningAt("Avoid \\v.", line, character);
                                    }
                                    c = '\v';
                                    break;
                                case 'x':
                                    if (jsonmode) {
                                        warningAt("Avoid \\x-.", line, character);
                                    }
                                    esc(2);
                                    break;
                                case '':
                                    // last character is escape character
                                    // always allow new line if escaped, but show
                                    // warning if option is not set
                                    allowNewLine = true;
                                    if (option.multistr) {
                                        if (jsonmode) {
                                            warningAt("Avoid EOL escapement.", line, character);
                                        }
                                        c = '';
                                        character -= 1;
                                        break;
                                    }
                                    warningAt("Bad escapement of EOL. Use option multistr if needed.",
                                        line, character);
                                    break;
                                default:
                                    warningAt("Bad escapement.", line, character);
                            }
                        }
                        r += c;
                        character += 1;
                        j += 1;
                    }
                }

                for (; ;) {
                    if (!s) {
                        return it(nextLine() ? '(endline)' : '(end)', '');
                    }
                    t = match(tx);
                    if (!t) {
                        t = '';
                        c = '';
                        while (s && s < '!') {
                            s = s.substr(1);
                        }
                        if (s) {
                            errorAt("Unexpected '{a}'.", line, character, s.substr(0, 1));
                            s = '';
                        }
                    } else {

                        //      identifier

                        if (c.isAlpha() || c === '_' || c === '$') {
                            return it('(identifier)', t);
                        }

                        //      number

                        if (c.isDigit()) {
                            if (!isFinite(Number(t))) {
                                warningAt("Bad number '{a}'.",
                                    line, character, t);
                            }
                            if (s.substr(0, 1).isAlpha()) {
                                warningAt("Missing space after '{a}'.",
                                        line, character, t);
                            }
                            if (c === '0') {
                                d = t.substr(1, 1);
                                if (d.isDigit()) {
                                    if (token.id !== '.') {
                                        warningAt("Don't use extra leading zeros '{a}'.",
                                            line, character, t);
                                    }
                                } else if (jsonmode && (d === 'x' || d === 'X')) {
                                    warningAt("Avoid 0x-. '{a}'.",
                                            line, character, t);
                                }
                            }
                            if (t.substr(t.length - 1) === '.') {
                                warningAt(
"A trailing decimal point can be confused with a dot '{a}'.", line, character, t);
                            }
                            return it('(number)', t);
                        }
                        switch (t) {

                            //      string

                            case '"':
                            case "'":
                                return string(t);

                                //      // comment

                            case '//':
                                s = '';
                                token.comment = true;
                                break;

                                //      /* comment

                            case '/*':
                                for (; ;) {
                                    i = s.search(lx);
                                    if (i >= 0) {
                                        break;
                                    }
                                    if (!nextLine()) {
                                        errorAt("Unclosed comment.", line, character);
                                    }
                                }
                                character += i + 2;
                                if (s.substr(i, 1) === '/') {
                                    errorAt("Nested comment.", line, character);
                                }
                                s = s.substr(i + 2);
                                token.comment = true;
                                break;

                                //      /*members /*jshint /*global

                            case '/*members':
                            case '/*member':
                            case '/*jshint':
                            case '/*jslint':
                            case '/*global':
                            case '*/':
                                return {
                                    value: t,
                                    type: 'special',
                                    line: line,
                                    character: character,
                                    from: from
                                };

                            case '':
                                break;
                                //      /
                            case '/':
                                if (token.id === '/=') {
                                    errorAt("A regular expression literal can be confused with '/='.",
                                        line, from);
                                }
                                if (prereg) {
                                    depth = 0;
                                    captures = 0;
                                    l = 0;
                                    for (; ;) {
                                        b = true;
                                        c = s.charAt(l);
                                        l += 1;
                                        switch (c) {
                                            case '':
                                                errorAt("Unclosed regular expression.", line, from);
                                                return quit('Stopping.', line, from);
                                            case '/':
                                                if (depth > 0) {
                                                    warningAt("{a} unterminated regular expression " +
                                                        "group(s).", line, from + l, depth);
                                                }
                                                c = s.substr(0, l - 1);
                                                q = {
                                                    g: true,
                                                    i: true,
                                                    m: true
                                                };
                                                while (q[s.charAt(l)] === true) {
                                                    q[s.charAt(l)] = false;
                                                    l += 1;
                                                }
                                                character += l;
                                                s = s.substr(l);
                                                q = s.charAt(0);
                                                if (q === '/' || q === '*') {
                                                    errorAt("Confusing regular expression.",
                                                            line, from);
                                                }
                                                return it('(regexp)', c);
                                            case '\\':
                                                c = s.charAt(l);
                                                if (c < ' ') {
                                                    warningAt(
        "Unexpected control character in regular expression.", line, from + l);
                                                } else if (c === '<') {
                                                    warningAt(
        "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
                                                }
                                                l += 1;
                                                break;
                                            case '(':
                                                depth += 1;
                                                b = false;
                                                if (s.charAt(l) === '?') {
                                                    l += 1;
                                                    switch (s.charAt(l)) {
                                                        case ':':
                                                        case '=':
                                                        case '!':
                                                            l += 1;
                                                            break;
                                                        default:
                                                            warningAt(
            "Expected '{a}' and instead saw '{b}'.", line, from + l, ':', s.charAt(l));
                                                    }
                                                } else {
                                                    captures += 1;
                                                }
                                                break;
                                            case '|':
                                                b = false;
                                                break;
                                            case ')':
                                                if (depth === 0) {
                                                    warningAt("Unescaped '{a}'.",
                                                            line, from + l, ')');
                                                } else {
                                                    depth -= 1;
                                                }
                                                break;
                                            case ' ':
                                                q = 1;
                                                while (s.charAt(l) === ' ') {
                                                    l += 1;
                                                    q += 1;
                                                }
                                                if (q > 1) {
                                                    warningAt(
        "Spaces are hard to count. Use {{a}}.", line, from + l, q);
                                                }
                                                break;
                                            case '[':
                                                c = s.charAt(l);
                                                if (c === '^') {
                                                    l += 1;
                                                    if (option.regexp) {
                                                        warningAt("Insecure '{a}'.",
                                                                line, from + l, c);
                                                    } else if (s.charAt(l) === ']') {
                                                        errorAt("Unescaped '{a}'.",
                                                            line, from + l, '^');
                                                    }
                                                }
                                                if (c === ']') {
                                                    warningAt("Empty class.", line,
                                                            from + l - 1);
                                                }
                                                isLiteral = false;
                                                isInRange = false;
                                                klass: do {
                                                    c = s.charAt(l);
                                                    l += 1;
                                                    switch (c) {
                                                        case '[':
                                                        case '^':
                                                            warningAt("Unescaped '{a}'.",
                                                                    line, from + l, c);
                                                            if (isInRange) {
                                                                isInRange = false;
                                                            } else {
                                                                isLiteral = true;
                                                            }
                                                            break;
                                                        case '-':
                                                            if (isLiteral && !isInRange) {
                                                                isLiteral = false;
                                                                isInRange = true;
                                                            } else if (isInRange) {
                                                                isInRange = false;
                                                            } else if (s.charAt(l) === ']') {
                                                                isInRange = true;
                                                            } else {
                                                                if (option.regexdash !== (l === 2 || (l === 3 &&
                                                                    s.charAt(1) === '^'))) {
                                                                    warningAt("Unescaped '{a}'.",
                                                                        line, from + l - 1, '-');
                                                                }
                                                                isLiteral = true;
                                                            }
                                                            break;
                                                        case ']':
                                                            if (isInRange && !option.regexdash) {
                                                                warningAt("Unescaped '{a}'.",
                                                                        line, from + l - 1, '-');
                                                            }
                                                            break klass;
                                                        case '\\':
                                                            c = s.charAt(l);
                                                            if (c < ' ') {
                                                                warningAt(
            "Unexpected control character in regular expression.", line, from + l);
                                                            } else if (c === '<') {
                                                                warningAt(
            "Unexpected escaped character '{a}' in regular expression.", line, from + l, c);
                                                            }
                                                            l += 1;

                                                            // \w, \s and \d are never part of a character range
                                                            if (/[wsd]/i.test(c)) {
                                                                if (isInRange) {
                                                                    warningAt("Unescaped '{a}'.",
                                                                        line, from + l, '-');
                                                                    isInRange = false;
                                                                }
                                                                isLiteral = false;
                                                            } else if (isInRange) {
                                                                isInRange = false;
                                                            } else {
                                                                isLiteral = true;
                                                            }
                                                            break;
                                                        case '/':
                                                            warningAt("Unescaped '{a}'.",
                                                                    line, from + l - 1, '/');

                                                            if (isInRange) {
                                                                isInRange = false;
                                                            } else {
                                                                isLiteral = true;
                                                            }
                                                            break;
                                                        case '<':
                                                            if (isInRange) {
                                                                isInRange = false;
                                                            } else {
                                                                isLiteral = true;
                                                            }
                                                            break;
                                                        default:
                                                            if (isInRange) {
                                                                isInRange = false;
                                                            } else {
                                                                isLiteral = true;
                                                            }
                                                    }
                                                } while (c);
                                                break;
                                            case '.':
                                                if (option.regexp) {
                                                    warningAt("Insecure '{a}'.", line,
                                                            from + l, c);
                                                }
                                                break;
                                            case ']':
                                            case '?':
                                            case '{':
                                            case '}':
                                            case '+':
                                            case '*':
                                                warningAt("Unescaped '{a}'.", line,
                                                        from + l, c);
                                        }
                                        if (b) {
                                            switch (s.charAt(l)) {
                                                case '?':
                                                case '+':
                                                case '*':
                                                    l += 1;
                                                    if (s.charAt(l) === '?') {
                                                        l += 1;
                                                    }
                                                    break;
                                                case '{':
                                                    l += 1;
                                                    c = s.charAt(l);
                                                    if (c < '0' || c > '9') {
                                                        warningAt(
        "Expected a number and instead saw '{a}'.", line, from + l, c);
                                                    }
                                                    l += 1;
                                                    low = +c;
                                                    for (; ;) {
                                                        c = s.charAt(l);
                                                        if (c < '0' || c > '9') {
                                                            break;
                                                        }
                                                        l += 1;
                                                        low = +c + (low * 10);
                                                    }
                                                    high = low;
                                                    if (c === ',') {
                                                        l += 1;
                                                        high = Infinity;
                                                        c = s.charAt(l);
                                                        if (c >= '0' && c <= '9') {
                                                            l += 1;
                                                            high = +c;
                                                            for (; ;) {
                                                                c = s.charAt(l);
                                                                if (c < '0' || c > '9') {
                                                                    break;
                                                                }
                                                                l += 1;
                                                                high = +c + (high * 10);
                                                            }
                                                        }
                                                    }
                                                    if (s.charAt(l) !== '}') {
                                                        warningAt(
        "Expected '{a}' and instead saw '{b}'.", line, from + l, '}', c);
                                                    } else {
                                                        l += 1;
                                                    }
                                                    if (s.charAt(l) === '?') {
                                                        l += 1;
                                                    }
                                                    if (low > high) {
                                                        warningAt(
        "'{a}' should not be greater than '{b}'.", line, from + l, low, high);
                                                    }
                                            }
                                        }
                                    }
                                    c = s.substr(0, l - 1);
                                    character += l;
                                    s = s.substr(l);
                                    return it('(regexp)', c);
                                }
                                return it('(punctuator)', t);

                                //      punctuator

                            case '#':
                                return it('(punctuator)', t);
                            default:
                                return it('(punctuator)', t);
                        }
                    }
                }
            }
        };
    }());


    function addlabel(t, type) {

        if (t === 'hasOwnProperty') {
            warning("'hasOwnProperty' is a really bad name.");
        }

        // Define t in the current function in the current scope.
        if (is_own(funct, t) && !funct['(global)']) {
            if (funct[t] === true) {
                if (option.latedef)
                    warning("'{a}' was used before it was defined.", nexttoken, t);
            } else {
                if (!option.shadow && type !== "exception")
                    warning("'{a}' is already defined.", nexttoken, t);
            }
        }

        funct[t] = type;
        if (funct['(global)']) {
            global[t] = funct;
            if (is_own(implied, t)) {
                if (option.latedef)
                    warning("'{a}' was used before it was defined.", nexttoken, t);
                delete implied[t];
            }
        } else {
            scope[t] = funct;
        }
    }


    function doOption() {
        var b, obj, filter, o = nexttoken.value, t, tn, v;

        switch (o) {
            case '*/':
                error("Unbegun comment.");
                break;
            case '/*members':
            case '/*member':
                o = '/*members';
                if (!membersOnly) {
                    membersOnly = {};
                }
                obj = membersOnly;
                break;
            case '/*jshint':
            case '/*jslint':
                obj = option;
                filter = boolOptions;
                break;
            case '/*global':
                obj = predefined;
                break;
            default:
                error("What?");
        }

        t = lex.token();
        loop: for (; ;) {
            for (; ;) {
                if (t.type === 'special' && t.value === '*/') {
                    break loop;
                }
                if (t.id !== '(endline)' && t.id !== ',') {
                    break;
                }
                t = lex.token();
            }
            if (t.type !== '(string)' && t.type !== '(identifier)' &&
                    o !== '/*members') {
                error("Bad option.", t);
            }

            v = lex.token();
            if (v.id === ':') {
                v = lex.token();

                if (obj === membersOnly) {
                    error("Expected '{a}' and instead saw '{b}'.",
                            t, '*/', ':');
                }

                if (o === '/*jshint') {
                    checkOption(t.value, t);
                }

                if (t.value === 'indent' && (o === '/*jshint' || o === '/*jslint')) {
                    b = +v.value;
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
                            Math.floor(b) !== b) {
                        error("Expected a small integer and instead saw '{a}'.",
                                v, v.value);
                    }
                    obj.white = true;
                    obj.indent = b;
                } else if (t.value === 'maxerr' && (o === '/*jshint' || o === '/*jslint')) {
                    b = +v.value;
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
                            Math.floor(b) !== b) {
                        error("Expected a small integer and instead saw '{a}'.",
                                v, v.value);
                    }
                    obj.maxerr = b;
                } else if (t.value === 'maxlen' && (o === '/*jshint' || o === '/*jslint')) {
                    b = +v.value;
                    if (typeof b !== 'number' || !isFinite(b) || b <= 0 ||
                            Math.floor(b) !== b) {
                        error("Expected a small integer and instead saw '{a}'.",
                                v, v.value);
                    }
                    obj.maxlen = b;
                } else if (t.value === 'validthis') {
                    if (funct['(global)']) {
                        error("Option 'validthis' can't be used in a global scope.");
                    } else {
                        if (v.value === 'true' || v.value === 'false')
                            obj[t.value] = v.value === 'true';
                        else
                            error("Bad option value.", v);
                    }
                } else if (v.value === 'true' || v.value === 'false') {
                    if (o === '/*jslint') {
                        tn = renamedOptions[t.value] || t.value;
                        obj[tn] = v.value === 'true';
                        if (invertedOptions[tn] !== undefined) {
                            obj[tn] = !obj[tn];
                        }
                    } else {
                        obj[t.value] = v.value === 'true';
                    }
                } else {
                    error("Bad option value.", v);
                }
                t = lex.token();
            } else {
                if (o === '/*jshint' || o === '/*jslint') {
                    error("Missing option value.", t);
                }
                obj[t.value] = false;
                t = v;
            }
        }
        if (filter) {
            assume();
        }
    }


    // We need a peek function. If it has an argument, it peeks that much farther
    // ahead. It is used to distinguish
    //     for ( var i in ...
    // from
    //     for ( var i = ...

    function peek(p) {
        var i = p || 0, j = 0, t;

        while (j <= i) {
            t = lookahead[j];
            if (!t) {
                t = lookahead[j] = lex.token();
            }
            j += 1;
        }
        return t;
    }



    // Produce the next token. It looks for programming errors.

    function advance(id, t) {
        switch (token.id) {
            case '(number)':
                if (nexttoken.id === '.') {
                    warning("A dot following a number can be confused with a decimal point.", token);
                }
                break;
            case '-':
                if (nexttoken.id === '-' || nexttoken.id === '--') {
                    warning("Confusing minusses.");
                }
                break;
            case '+':
                if (nexttoken.id === '+' || nexttoken.id === '++') {
                    warning("Confusing plusses.");
                }
                break;
        }

        if (token.type === '(string)' || token.identifier) {
            anonname = token.value;
        }

        if (id && nexttoken.id !== id) {
            if (t) {
                if (nexttoken.id === '(end)') {
                    warning("Unmatched '{a}'.", t, t.id);
                } else {
                    warning("Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.",
                            nexttoken, id, t.id, t.line, nexttoken.value);
                }
            } else if (nexttoken.type !== '(identifier)' ||
                            nexttoken.value !== id) {
                warning("Expected '{a}' and instead saw '{b}'.",
                        nexttoken, id, nexttoken.value);
            }
        }

        prevtoken = token;
        token = nexttoken;
        for (; ;) {
            nexttoken = lookahead.shift() || lex.token();
            if (nexttoken.id === '(end)' || nexttoken.id === '(error)') {
                return;
            }
            if (nexttoken.type === 'special') {
                doOption();
            } else {
                if (nexttoken.id !== '(endline)') {
                    break;
                }
            }
        }
    }


    // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it
    // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
    // like .nud except that it is only used on the first token of a statement.
    // Having .fud makes it much easier to define statement-oriented languages like
    // JavaScript. I retained Pratt's nomenclature.

    // .nud     Null denotation
    // .fud     First null denotation
    // .led     Left denotation
    //  lbp     Left binding power
    //  rbp     Right binding power

    // They are elements of the parsing method called Top Down Operator Precedence.

    function expression(rbp, initial) {
        var left, isArray = false, isObject = false;

        if (nexttoken.id === '(end)')
            error("Unexpected early end of program.", token);

        advance();
        if (initial) {
            anonname = 'anonymous';
            funct['(verb)'] = token.value;
        }
        if (initial === true && token.fud) {
            left = token.fud();
        } else {
            if (token.nud) {
                left = token.nud();
            } else {
                if (nexttoken.type === '(number)' && token.id === '.') {
                    warning("A leading decimal point can be confused with a dot: '.{a}'.",
                            token, nexttoken.value);
                    advance();
                    return token;
                } else {
                    error("Expected an identifier and instead saw '{a}'.",
                            token, token.id);
                }
            }
            while (rbp < nexttoken.lbp) {
                isArray = token.value === 'Array';
                isObject = token.value === 'Object';

                // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object()
                // Line breaks in IfStatement heads exist to satisfy the checkJSHint
                // "Line too long." error.
                if (left && (left.value || (left.first && left.first.value))) {
                    // If the left.value is not "new", or the left.first.value is a "."
                    // then safely assume that this is not "new Array()" and possibly
                    // not "new Object()"...
                    if (left.value !== 'new' ||
                      (left.first && left.first.value && left.first.value === '.')) {
                        isArray = false;
                        // ...In the case of Object, if the left.value and token.value
                        // are not equal, then safely assume that this not "new Object()"
                        if (left.value !== token.value) {
                            isObject = false;
                        }
                    }
                }

                advance();
                if (isArray && token.id === '(' && nexttoken.id === ')')
                    warning("Use the array literal notation [].", token);
                if (isObject && token.id === '(' && nexttoken.id === ')')
                    warning("Use the object literal notation {}.", token);
                if (token.led) {
                    left = token.led(left);
                } else {
                    error("Expected an operator and instead saw '{a}'.",
                        token, token.id);
                }
            }
        }
        return left;
    }


    // Functions for conformance of style.

    function adjacent(left, right) {
        left = left || token;
        right = right || nexttoken;
        if (option.white) {
            if (left.character !== right.from && left.line === right.line) {
                left.from += (left.character - left.from);
                warning("Unexpected space after '{a}'.", left, left.value);
            }
        }
    }

    function nobreak(left, right) {
        left = left || token;
        right = right || nexttoken;
        if (option.white && (left.character !== right.from || left.line !== right.line)) {
            warning("Unexpected space before '{a}'.", right, right.value);
        }
    }

    function nospace(left, right) {
        left = left || token;
        right = right || nexttoken;
        if (option.white && !left.comment) {
            if (left.line === right.line) {
                adjacent(left, right);
            }
        }
    }

    function nonadjacent(left, right) {
        if (option.white) {
            left = left || token;
            right = right || nexttoken;
            if (left.line === right.line && left.character === right.from) {
                left.from += (left.character - left.from);
                warning("Missing space after '{a}'.",
                        left, left.value);
            }
        }
    }

    function nobreaknonadjacent(left, right) {
        left = left || token;
        right = right || nexttoken;
        if (!option.laxbreak && left.line !== right.line) {
            warning("Bad line breaking before '{a}'.", right, right.id);
        } else if (option.white) {
            left = left || token;
            right = right || nexttoken;
            if (left.character === right.from) {
                left.from += (left.character - left.from);
                warning("Missing space after '{a}'.",
                        left, left.value);
            }
        }
    }

    function indentation(bias) {
        var i;
        if (option.white && nexttoken.id !== '(end)') {
            i = indent + (bias || 0);
            if (nexttoken.from !== i) {
                warning(
"Expected '{a}' to have an indentation at {b} instead at {c}.",
                        nexttoken, nexttoken.value, i, nexttoken.from);
            }
        }
    }

    function nolinebreak(t) {
        t = t || token;
        if (t.line !== nexttoken.line) {
            warning("Line breaking error '{a}'.", t, t.value);
        }
    }


    function comma() {
        if (token.line !== nexttoken.line) {
            if (!option.laxcomma) {
                if (comma.first) {
                    warning("Comma warnings can be turned off with 'laxcomma'");
                    comma.first = false;
                }
                warning("Bad line breaking before '{a}'.", token, nexttoken.id);
            }
        } else if (!token.comment && token.character !== nexttoken.from && option.white) {
            token.from += (token.character - token.from);
            warning("Unexpected space after '{a}'.", token, token.value);
        }
        advance(',');
        nonadjacent(token, nexttoken);
    }


    // Functional constructors for making the symbols that will be inherited by
    // tokens.

    function symbol(s, p) {
        var x = syntax[s];
        if (!x || typeof x !== 'object') {
            syntax[s] = x = {
                id: s,
                lbp: p,
                value: s
            };
        }
        return x;
    }


    function delim(s) {
        return symbol(s, 0);
    }


    function stmt(s, f) {
        var x = delim(s);
        x.identifier = x.reserved = true;
        x.fud = f;
        return x;
    }


    function blockstmt(s, f) {
        var x = stmt(s, f);
        x.block = true;
        return x;
    }


    function reserveName(x) {
        var c = x.id.charAt(0);
        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
            x.identifier = x.reserved = true;
        }
        return x;
    }


    function prefix(s, f) {
        var x = symbol(s, 150);
        reserveName(x);
        x.nud = (typeof f === 'function') ? f : function () {
            this.right = expression(150);
            this.arity = 'unary';
            if (this.id === '++' || this.id === '--') {
                if (option.plusplus) {
                    warning("Unexpected use of '{a}'.", this, this.id);
                } else if ((!this.right.identifier || this.right.reserved) &&
                        this.right.id !== '.' && this.right.id !== '[') {
                    warning("Bad operand.", this);
                }
            }
            return this;
        };
        return x;
    }


    function type(s, f) {
        var x = delim(s);
        x.type = s;
        x.nud = f;
        return x;
    }


    function reserve(s, f) {
        var x = type(s, f);
        x.identifier = x.reserved = true;
        return x;
    }


    function reservevar(s, v) {
        return reserve(s, function () {
            if (typeof v === 'function') {
                v(this);
            }
            return this;
        });
    }


    function infix(s, f, p, w) {
        var x = symbol(s, p);
        reserveName(x);
        x.led = function (left) {
            if (!w) {
                nobreaknonadjacent(prevtoken, token);
                nonadjacent(token, nexttoken);
            }
            if (s === "in" && left.id === "!") {
                warning("Confusing use of '{a}'.", left, '!');
            }
            if (typeof f === 'function') {
                return f(left, this);
            } else {
                this.left = left;
                this.right = expression(p);
                return this;
            }
        };
        return x;
    }


    function relation(s, f) {
        var x = symbol(s, 100);
        x.led = function (left) {
            nobreaknonadjacent(prevtoken, token);
            nonadjacent(token, nexttoken);
            var right = expression(100);
            if ((left && left.id === 'NaN') || (right && right.id === 'NaN')) {
                warning("Use the isNaN function to compare with NaN.", this);
            } else if (f) {
                f.apply(this, [left, right]);
            }
            if (left.id === '!') {
                warning("Confusing use of '{a}'.", left, '!');
            }
            if (right.id === '!') {
                warning("Confusing use of '{a}'.", right, '!');
            }
            this.left = left;
            this.right = right;
            return this;
        };
        return x;
    }


    function isPoorRelation(node) {
        return node &&
              ((node.type === '(number)' && +node.value === 0) ||
               (node.type === '(string)' && node.value === '') ||
               (node.type === 'null' && !option.eqnull) ||
                node.type === 'true' ||
                node.type === 'false' ||
                node.type === 'undefined');
    }


    function assignop(s, f) {
        symbol(s, 20).exps = true;
        return infix(s, function (left, that) {
            var l;
            that.left = left;
            if (predefined[left.value] === false &&
                    scope[left.value]['(global)'] === true) {
                warning("Read only.", left);
            } else if (left['function']) {
                warning("'{a}' is a function.", left, left.value);
            }
            if (left) {
                if (option.esnext && funct[left.value] === 'const') {
                    warning("Attempting to override '{a}' which is a constant", left, left.value);
                }
                if (left.id === '.' || left.id === '[') {
                    if (!left.left || left.left.value === 'arguments') {
                        warning('Bad assignment.', that);
                    }
                    that.right = expression(19);
                    return that;
                } else if (left.identifier && !left.reserved) {
                    if (funct[left.value] === 'exception') {
                        warning("Do not assign to the exception parameter.", left);
                    }
                    that.right = expression(19);
                    return that;
                }
                if (left === syntax['function']) {
                    warning(
"Expected an identifier in an assignment and instead saw a function invocation.",
                                token);
                }
            }
            error("Bad assignment.", that);
        }, 20);
    }


    function bitwise(s, f, p) {
        var x = symbol(s, p);
        reserveName(x);
        x.led = (typeof f === 'function') ? f : function (left) {
            if (option.bitwise) {
                warning("Unexpected use of '{a}'.", this, this.id);
            }
            this.left = left;
            this.right = expression(p);
            return this;
        };
        return x;
    }


    function bitwiseassignop(s) {
        symbol(s, 20).exps = true;
        return infix(s, function (left, that) {
            if (option.bitwise) {
                warning("Unexpected use of '{a}'.", that, that.id);
            }
            nonadjacent(prevtoken, token);
            nonadjacent(token, nexttoken);
            if (left) {
                if (left.id === '.' || left.id === '[' ||
                        (left.identifier && !left.reserved)) {
                    expression(19);
                    return that;
                }
                if (left === syntax['function']) {
                    warning(
"Expected an identifier in an assignment, and instead saw a function invocation.",
                                token);
                }
                return that;
            }
            error("Bad assignment.", that);
        }, 20);
    }


    function suffix(s, f) {
        var x = symbol(s, 150);
        x.led = function (left) {
            if (option.plusplus) {
                warning("Unexpected use of '{a}'.", this, this.id);
            } else if ((!left.identifier || left.reserved) &&
                    left.id !== '.' && left.id !== '[') {
                warning("Bad operand.", this);
            }
            this.left = left;
            return this;
        };
        return x;
    }


    // fnparam means that this identifier is being defined as a function
    // argument (see identifier())
    function optionalidentifier(fnparam) {
        if (nexttoken.identifier) {
            advance();
            if (token.reserved && !option.es5) {
                // `undefined` as a function param is a common pattern to protect
                // against the case when somebody does `undefined = true` and
                // help with minification. More info: https://gist.github.com/315916
                if (!fnparam || token.value !== 'undefined') {
                    warning("Expected an identifier and instead saw '{a}' (a reserved word).",
                            token, token.id);
                }
            }
            return token.value;
        }
    }

    // fnparam means that this identifier is being defined as a function
    // argument
    function identifier(fnparam) {
        var i = optionalidentifier(fnparam);
        if (i) {
            return i;
        }
        if (token.id === 'function' && nexttoken.id === '(') {
            warning("Missing name in function declaration.");
        } else {
            error("Expected an identifier and instead saw '{a}'.",
                    nexttoken, nexttoken.value);
        }
    }


    function reachable(s) {
        var i = 0, t;
        if (nexttoken.id !== ';' || noreach) {
            return;
        }
        for (; ;) {
            t = peek(i);
            if (t.reach) {
                return;
            }
            if (t.id !== '(endline)') {
                if (t.id === 'function') {
                    if (!option.latedef) {
                        break;
                    }
                    warning(
"Inner functions should be listed at the top of the outer function.", t);
                    break;
                }
                warning("Unreachable '{a}' after '{b}'.", t, t.value, s);
                break;
            }
            i += 1;
        }
    }


    function statement(noindent) {
        var i = indent, r, s = scope, t = nexttoken;

        if (t.id === ";") {
            advance(";");
            return;
        }

        // Is this a labelled statement?

        if (t.identifier && !t.reserved && peek().id === ':') {
            advance();
            advance(':');
            scope = Object.create(s);
            addlabel(t.value, 'label');
            if (!nexttoken.labelled) {
                warning("Label '{a}' on {b} statement.",
                        nexttoken, t.value, nexttoken.value);
            }
            if (jx.test(t.value + ':')) {
                warning("Label '{a}' looks like a javascript url.",
                        t, t.value);
            }
            nexttoken.label = t.value;
            t = nexttoken;
        }

        // Parse the statement.

        if (!noindent) {
            indentation();
        }
        r = expression(0, true);

        // Look for the final semicolon.
        if (!t.block) {
            if (!option.expr && (!r || !r.exps)) {
                warning("Expected an assignment or function call and instead saw an expression.",
                    token);
            } else if (option.nonew && r.id === '(' && r.left.id === 'new') {
                warning("Do not use 'new' for side effects.");
            }

            if (nexttoken.id === ',') {
                return comma();
            }

            if (nexttoken.id !== ';') {
                if (!option.asi) {
                    // If this is the last statement in a block that ends on
                    // the same line *and* option lastsemic is on, ignore the warning.
                    // Otherwise, complain about missing semicolon.
                    if (!option.lastsemic || nexttoken.id !== '}' ||
                            nexttoken.line !== token.line) {
                        warningAt("Missing semicolon.", token.line, token.character);
                    }
                }
            } else {
                adjacent(token, nexttoken);
                advance(';');
                nonadjacent(token, nexttoken);
            }
        }

        // Restore the indentation.

        indent = i;
        scope = s;
        return r;
    }


    function statements(startLine) {
        var a = [], f, p;

        while (!nexttoken.reach && nexttoken.id !== '(end)') {
            if (nexttoken.id === ';') {
                p = peek();
                if (!p || p.id !== "(") {
                    warning("Unnecessary semicolon.");
                }
                advance(';');
            } else {
                a.push(statement(startLine === nexttoken.line));
            }
        }
        return a;
    }


    /*
     * read all directives
     * recognizes a simple form of asi, but always
     * warns, if it is used
     */
    function directives() {
        var i, p, pn;

        for (; ;) {
            if (nexttoken.id === "(string)") {
                p = peek(0);
                if (p.id === "(endline)") {
                    i = 1;
                    do {
                        pn = peek(i);
                        i = i + 1;
                    } while (pn.id === "(endline)");

                    if (pn.id !== ";") {
                        if (pn.id !== "(string)" && pn.id !== "(number)" &&
                            pn.id !== "(regexp)" && pn.identifier !== true &&
                            pn.id !== "}") {
                            break;
                        }
                        warning("Missing semicolon.", nexttoken);
                    } else {
                        p = pn;
                    }
                } else if (p.id === "}") {
                    // directive with no other statements, warn about missing semicolon
                    warning("Missing semicolon.", p);
                } else if (p.id !== ";") {
                    break;
                }

                indentation();
                advance();
                if (directive[token.value]) {
                    warning("Unnecessary directive \"{a}\".", token, token.value);
                }

                if (token.value === "use strict") {
                    option.newcap = true;
                    option.undef = true;
                }

                // there's no directive negation, so always set to true
                directive[token.value] = true;

                if (p.id === ";") {
                    advance(";");
                }
                continue;
            }
            break;
        }
    }


    /*
     * Parses a single block. A block is a sequence of statements wrapped in
     * braces.
     *
     * ordinary - true for everything but function bodies and try blocks.
     * stmt     - true if block can be a single statement (e.g. in if/for/while).
     * isfunc   - true if block is a function body
     */
    function block(ordinary, stmt, isfunc) {
        var a,
            b = inblock,
            old_indent = indent,
            m,
            s = scope,
            t,
            line,
            d;

        inblock = ordinary;
        if (!ordinary || !option.funcscope) scope = Object.create(scope);
        nonadjacent(token, nexttoken);
        t = nexttoken;

        if (nexttoken.id === '{') {
            advance('{');
            line = token.line;
            if (nexttoken.id !== '}') {
                indent += option.indent;
                while (!ordinary && nexttoken.from > indent) {
                    indent += option.indent;
                }

                if (isfunc) {
                    m = {};
                    for (d in directive) {
                        if (is_own(directive, d)) {
                            m[d] = directive[d];
                        }
                    }
                    directives();

                    if (option.strict && funct['(context)']['(global)']) {
                        if (!m["use strict"] && !directive["use strict"]) {
                            warning("Missing \"use strict\" statement.");
                        }
                    }
                }

                a = statements(line);

                if (isfunc) {
                    directive = m;
                }

                indent -= option.indent;
                if (line !== nexttoken.line) {
                    indentation();
                }
            } else if (line !== nexttoken.line) {
                indentation();
            }
            advance('}', t);
            indent = old_indent;
        } else if (!ordinary) {
            error("Expected '{a}' and instead saw '{b}'.",
                  nexttoken, '{', nexttoken.value);
        } else {
            if (!stmt || option.curly)
                warning("Expected '{a}' and instead saw '{b}'.",
                        nexttoken, '{', nexttoken.value);

            noreach = true;
            indent += option.indent;
            // test indentation only if statement is in new line
            a = [statement(nexttoken.line === token.line)];
            indent -= option.indent;
            noreach = false;
        }
        funct['(verb)'] = null;
        if (!ordinary || !option.funcscope) scope = s;
        inblock = b;
        if (ordinary && option.noempty && (!a || a.length === 0)) {
            warning("Empty block.");
        }
        return a;
    }


    function countMember(m) {
        if (membersOnly && typeof membersOnly[m] !== 'boolean') {
            warning("Unexpected /*member '{a}'.", token, m);
        }
        if (typeof member[m] === 'number') {
            member[m] += 1;
        } else {
            member[m] = 1;
        }
    }


    function note_implied(token) {
        var name = token.value, line = token.line, a = implied[name];
        if (typeof a === 'function') {
            a = false;
        }

        if (!a) {
            a = [line];
            implied[name] = a;
        } else if (a[a.length - 1] !== line) {
            a.push(line);
        }
    }


    // Build the syntax table by declaring the syntactic elements of the language.

    type('(number)', function () {
        return this;
    });

    type('(string)', function () {
        return this;
    });

    syntax['(identifier)'] = {
        type: '(identifier)',
        lbp: 0,
        identifier: true,
        nud: function () {
            var v = this.value,
                s = scope[v],
                f;

            if (typeof s === 'function') {
                // Protection against accidental inheritance.
                s = undefined;
            } else if (typeof s === 'boolean') {
                f = funct;
                funct = functions[0];
                addlabel(v, 'var');
                s = funct;
                funct = f;
            }

            // The name is in scope and defined in the current function.
            if (funct === s) {
                // Change 'unused' to 'var', and reject labels.
                switch (funct[v]) {
                    case 'unused':
                        funct[v] = 'var';
                        break;
                    case 'unction':
                        funct[v] = 'function';
                        this['function'] = true;
                        break;
                    case 'function':
                        this['function'] = true;
                        break;
                    case 'label':
                        warning("'{a}' is a statement label.", token, v);
                        break;
                }
            } else if (funct['(global)']) {
                // The name is not defined in the function.  If we are in the global
                // scope, then we have an undefined variable.
                //
                // Operators typeof and delete do not raise runtime errors even if
                // the base object of a reference is null so no need to display warning
                // if we're inside of typeof or delete.

                if (option.undef && typeof predefined[v] !== 'boolean') {
                    // Attempting to subscript a null reference will throw an
                    // error, even within the typeof and delete operators
                    if (!(anonname === 'typeof' || anonname === 'delete') ||
                        (nexttoken && (nexttoken.value === '.' || nexttoken.value === '['))) {

                        isundef(funct, "'{a}' is not defined.", token, v);
                    }
                }
                note_implied(token);
            } else {
                // If the name is already defined in the current
                // function, but not as outer, then there is a scope error.

                switch (funct[v]) {
                    case 'closure':
                    case 'function':
                    case 'var':
                    case 'unused':
                        warning("'{a}' used out of scope.", token, v);
                        break;
                    case 'label':
                        warning("'{a}' is a statement label.", token, v);
                        break;
                    case 'outer':
                    case 'global':
                        break;
                    default:
                        // If the name is defined in an outer function, make an outer entry,
                        // and if it was unused, make it var.
                        if (s === true) {
                            funct[v] = true;
                        } else if (s === null) {
                            warning("'{a}' is not allowed.", token, v);
                            note_implied(token);
                        } else if (typeof s !== 'object') {
                            // Operators typeof and delete do not raise runtime errors even
                            // if the base object of a reference is null so no need to
                            // display warning if we're inside of typeof or delete.
                            if (option.undef) {
                                // Attempting to subscript a null reference will throw an
                                // error, even within the typeof and delete operators
                                if (!(anonname === 'typeof' || anonname === 'delete') ||
                                    (nexttoken &&
                                        (nexttoken.value === '.' || nexttoken.value === '['))) {

                                    isundef(funct, "'{a}' is not defined.", token, v);
                                }
                            }
                            funct[v] = true;
                            note_implied(token);
                        } else {
                            switch (s[v]) {
                                case 'function':
                                case 'unction':
                                    this['function'] = true;
                                    s[v] = 'closure';
                                    funct[v] = s['(global)'] ? 'global' : 'outer';
                                    break;
                                case 'var':
                                case 'unused':
                                    s[v] = 'closure';
                                    funct[v] = s['(global)'] ? 'global' : 'outer';
                                    break;
                                case 'closure':
                                case 'parameter':
                                    funct[v] = s['(global)'] ? 'global' : 'outer';
                                    break;
                                case 'label':
                                    warning("'{a}' is a statement label.", token, v);
                            }
                        }
                }
            }
            return this;
        },
        led: function () {
            error("Expected an operator and instead saw '{a}'.",
                nexttoken, nexttoken.value);
        }
    };

    type('(regexp)', function () {
        return this;
    });


    // ECMAScript parser

    delim('(endline)');
    delim('(begin)');
    delim('(end)').reach = true;
    delim('</').reach = true;
    delim('<!');
    delim('<!--');
    delim('-->');
    delim('(error)').reach = true;
    delim('}').reach = true;
    delim(')');
    delim(']');
    delim('"').reach = true;
    delim("'").reach = true;
    delim(';');
    delim(':').reach = true;
    delim(',');
    delim('#');
    delim('@');
    reserve('else');
    reserve('case').reach = true;
    reserve('catch');
    reserve('default').reach = true;
    reserve('finally');
    reservevar('arguments', function (x) {
        if (directive['use strict'] && funct['(global)']) {
            warning("Strict violation.", x);
        }
    });
    reservevar('eval');
    reservevar('false');
    reservevar('Infinity');
    reservevar('NaN');
    reservevar('null');
    reservevar('this', function (x) {
        if (directive['use strict'] && !option.validthis && ((funct['(statement)'] &&
                funct['(name)'].charAt(0) > 'Z') || funct['(global)'])) {
            warning("Possible strict violation.", x);
        }
    });
    reservevar('true');
    reservevar('undefined');
    assignop('=', 'assign', 20);
    assignop('+=', 'assignadd', 20);
    assignop('-=', 'assignsub', 20);
    assignop('*=', 'assignmult', 20);
    assignop('/=', 'assigndiv', 20).nud = function () {
        error("A regular expression literal can be confused with '/='.");
    };
    assignop('%=', 'assignmod', 20);
    bitwiseassignop('&=', 'assignbitand', 20);
    bitwiseassignop('|=', 'assignbitor', 20);
    bitwiseassignop('^=', 'assignbitxor', 20);
    bitwiseassignop('<<=', 'assignshiftleft', 20);
    bitwiseassignop('>>=', 'assignshiftright', 20);
    bitwiseassignop('>>>=', 'assignshiftrightunsigned', 20);
    infix('?', function (left, that) {
        that.left = left;
        that.right = expression(10);
        advance(':');
        that['else'] = expression(10);
        return that;
    }, 30);

    infix('||', 'or', 40);
    infix('&&', 'and', 50);
    bitwise('|', 'bitor', 70);
    bitwise('^', 'bitxor', 80);
    bitwise('&', 'bitand', 90);
    relation('==', function (left, right) {
        var eqnull = option.eqnull && (left.value === 'null' || right.value === 'null');

        if (!eqnull && option.eqeqeq)
            warning("Expected '{a}' and instead saw '{b}'.", this, '===', '==');
        else if (isPoorRelation(left))
            warning("Use '{a}' to compare with '{b}'.", this, '===', left.value);
        else if (isPoorRelation(right))
            warning("Use '{a}' to compare with '{b}'.", this, '===', right.value);

        return this;
    });
    relation('===');
    relation('!=', function (left, right) {
        var eqnull = option.eqnull &&
                (left.value === 'null' || right.value === 'null');

        if (!eqnull && option.eqeqeq) {
            warning("Expected '{a}' and instead saw '{b}'.",
                    this, '!==', '!=');
        } else if (isPoorRelation(left)) {
            warning("Use '{a}' to compare with '{b}'.",
                    this, '!==', left.value);
        } else if (isPoorRelation(right)) {
            warning("Use '{a}' to compare with '{b}'.",
                    this, '!==', right.value);
        }
        return this;
    });
    relation('!==');
    relation('<');
    relation('>');
    relation('<=');
    relation('>=');
    bitwise('<<', 'shiftleft', 120);
    bitwise('>>', 'shiftright', 120);
    bitwise('>>>', 'shiftrightunsigned', 120);
    infix('in', 'in', 120);
    infix('instanceof', 'instanceof', 120);
    infix('+', function (left, that) {
        var right = expression(130);
        if (left && right && left.id === '(string)' && right.id === '(string)') {
            left.value += right.value;
            left.character = right.character;
            if (!option.scripturl && jx.test(left.value)) {
                warning("JavaScript URL.", left);
            }
            return left;
        }
        that.left = left;
        that.right = right;
        return that;
    }, 130);
    prefix('+', 'num');
    prefix('+++', function () {
        warning("Confusing pluses.");
        this.right = expression(150);
        this.arity = 'unary';
        return this;
    });
    infix('+++', function (left) {
        warning("Confusing pluses.");
        this.left = left;
        this.right = expression(130);
        return this;
    }, 130);
    infix('-', 'sub', 130);
    prefix('-', 'neg');
    prefix('---', function () {
        warning("Confusing minuses.");
        this.right = expression(150);
        this.arity = 'unary';
        return this;
    });
    infix('---', function (left) {
        warning("Confusing minuses.");
        this.left = left;
        this.right = expression(130);
        return this;
    }, 130);
    infix('*', 'mult', 140);
    infix('/', 'div', 140);
    infix('%', 'mod', 140);

    suffix('++', 'postinc');
    prefix('++', 'preinc');
    syntax['++'].exps = true;

    suffix('--', 'postdec');
    prefix('--', 'predec');
    syntax['--'].exps = true;
    prefix('delete', function () {
        var p = expression(0);
        if (!p || (p.id !== '.' && p.id !== '[')) {
            warning("Variables should not be deleted.");
        }
        this.first = p;
        return this;
    }).exps = true;

    prefix('~', function () {
        if (option.bitwise) {
            warning("Unexpected '{a}'.", this, '~');
        }
        expression(150);
        return this;
    });

    prefix('!', function () {
        this.right = expression(150);
        this.arity = 'unary';
        if (bang[this.right.id] === true) {
            warning("Confusing use of '{a}'.", this, '!');
        }
        return this;
    });
    prefix('typeof', 'typeof');
    prefix('new', function () {
        var c = expression(155), i;
        if (c && c.id !== 'function') {
            if (c.identifier) {
                c['new'] = true;
                switch (c.value) {
                    case 'Number':
                    case 'String':
                    case 'Boolean':
                    case 'Math':
                    case 'JSON':
                        warning("Do not use {a} as a constructor.", token, c.value);
                        break;
                    case 'Function':
                        if (!option.evil) {
                            warning("The Function constructor is eval.");
                        }
                        break;
                    case 'Date':
                    case 'RegExp':
                        break;
                    default:
                        if (c.id !== 'function') {
                            i = c.value.substr(0, 1);
                            if (option.newcap && (i < 'A' || i > 'Z')) {
                                warning("A constructor name should start with an uppercase letter.",
                                    token);
                            }
                        }
                }
            } else {
                if (c.id !== '.' && c.id !== '[' && c.id !== '(') {
                    warning("Bad constructor.", token);
                }
            }
        } else {
            if (!option.supernew)
                warning("Weird construction. Delete 'new'.", this);
        }
        adjacent(token, nexttoken);
        if (nexttoken.id !== '(' && !option.supernew) {
            warning("Missing '()' invoking a constructor.");
        }
        this.first = c;
        return this;
    });
    syntax['new'].exps = true;

    prefix('void').exps = true;

    infix('.', function (left, that) {
        adjacent(prevtoken, token);
        nobreak();
        var m = identifier();
        if (typeof m === 'string') {
            countMember(m);
        }
        that.left = left;
        that.right = m;
        if (left && left.value === 'arguments' && (m === 'callee' || m === 'caller')) {
            if (option.noarg)
                warning("Avoid arguments.{a}.", left, m);
            else if (directive['use strict'])
                error('Strict violation.');
        } else if (!option.evil && left && left.value === 'document' &&
                (m === 'write' || m === 'writeln')) {
            warning("document.write can be a form of eval.", left);
        }
        if (!option.evil && (m === 'eval' || m === 'execScript')) {
            warning('eval is evil.');
        }
        return that;
    }, 160, true);

    infix('(', function (left, that) {
        if (prevtoken.id !== '}' && prevtoken.id !== ')') {
            nobreak(prevtoken, token);
        }
        nospace();
        if (option.immed && !left.immed && left.id === 'function') {
            warning("Wrap an immediate function invocation in parentheses " +
                "to assist the reader in understanding that the expression " +
                "is the result of a function, and not the function itself.");
        }
        var n = 0,
            p = [];
        if (left) {
            if (left.type === '(identifier)') {
                if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) {
                    if (left.value !== 'Number' && left.value !== 'String' &&
                            left.value !== 'Boolean' &&
                            left.value !== 'Date') {
                        if (left.value === 'Math') {
                            warning("Math is not a function.", left);
                        } else if (option.newcap) {
                            warning(
"Missing 'new' prefix when invoking a constructor.", left);
                        }
                    }
                }
            }
        }
        if (nexttoken.id !== ')') {
            for (; ;) {
                p[p.length] = expression(10);
                n += 1;
                if (nexttoken.id !== ',') {
                    break;
                }
                comma();
            }
        }
        advance(')');
        nospace(prevtoken, token);
        if (typeof left === 'object') {
            if (left.value === 'parseInt' && n === 1) {
                warning("Missing radix parameter.", left);
            }
            if (!option.evil) {
                if (left.value === 'eval' || left.value === 'Function' ||
                        left.value === 'execScript') {
                    warning("eval is evil.", left);
                } else if (p[0] && p[0].id === '(string)' &&
                       (left.value === 'setTimeout' ||
                        left.value === 'setInterval')) {
                    warning(
    "Implied eval is evil. Pass a function instead of a string.", left);
                }
            }
            if (!left.identifier && left.id !== '.' && left.id !== '[' &&
                    left.id !== '(' && left.id !== '&&' && left.id !== '||' &&
                    left.id !== '?') {
                warning("Bad invocation.", left);
            }
        }
        that.left = left;
        return that;
    }, 155, true).exps = true;

    prefix('(', function () {
        nospace();
        if (nexttoken.id === 'function') {
            nexttoken.immed = true;
        }
        var v = expression(0);
        advance(')', this);
        nospace(prevtoken, token);
        if (option.immed && v.id === 'function') {
            if (nexttoken.id === '(' ||
              (nexttoken.id === '.' && (peek().value === 'call' || peek().value === 'apply'))) {
                warning(
"Move the invocation into the parens that contain the function.", nexttoken);
            } else {
                warning(
"Do not wrap function literals in parens unless they are to be immediately invoked.",
                        this);
            }
        }
        return v;
    });

    infix('[', function (left, that) {
        nobreak(prevtoken, token);
        nospace();
        var e = expression(0), s;
        if (e && e.type === '(string)') {
            if (!option.evil && (e.value === 'eval' || e.value === 'execScript')) {
                warning("eval is evil.", that);
            }
            countMember(e.value);
            if (!option.sub && ix.test(e.value)) {
                s = syntax[e.value];
                if (!s || !s.reserved) {
                    warning("['{a}'] is better written in dot notation.",
                            e, e.value);
                }
            }
        }
        advance(']', that);
        nospace(prevtoken, token);
        that.left = left;
        that.right = e;
        return that;
    }, 160, true);

    prefix('[', function () {
        var b = token.line !== nexttoken.line;
        this.first = [];
        if (b) {
            indent += option.indent;
            if (nexttoken.from === indent + option.indent) {
                indent += option.indent;
            }
        }
        while (nexttoken.id !== '(end)') {
            while (nexttoken.id === ',') {
                warning("Extra comma.");
                advance(',');
            }
            if (nexttoken.id === ']') {
                break;
            }
            if (b && token.line !== nexttoken.line) {
                indentation();
            }
            this.first.push(expression(10));
            if (nexttoken.id === ',') {
                comma();
                if (nexttoken.id === ']' && !option.es5) {
                    warning("Extra comma.", token);
                    break;
                }
            } else {
                break;
            }
        }
        if (b) {
            indent -= option.indent;
            indentation();
        }
        advance(']', this);
        return this;
    }, 160);


    function property_name() {
        var id = optionalidentifier(true);
        if (!id) {
            if (nexttoken.id === '(string)') {
                id = nexttoken.value;
                advance();
            } else if (nexttoken.id === '(number)') {
                id = nexttoken.value.toString();
                advance();
            }
        }
        return id;
    }


    function functionparams() {
        var i, t = nexttoken, p = [];
        advance('(');
        nospace();
        if (nexttoken.id === ')') {
            advance(')');
            return;
        }
        for (; ;) {
            i = identifier(true);
            p.push(i);
            addlabel(i, 'parameter');
            if (nexttoken.id === ',') {
                comma();
            } else {
                advance(')', t);
                nospace(prevtoken, token);
                return p;
            }
        }
    }


    function doFunction(i, statement) {
        var f,
            oldOption = option,
            oldScope = scope;

        option = Object.create(option);
        scope = Object.create(scope);

        funct = {
            '(name)': i || '"' + anonname + '"',
            '(line)': nexttoken.line,
            '(context)': funct,
            '(breakage)': 0,
            '(loopage)': 0,
            '(scope)': scope,
            '(statement)': statement
        };
        f = funct;
        token.funct = funct;
        functions.push(funct);
        if (i) {
            addlabel(i, 'function');
        }
        funct['(params)'] = functionparams();

        block(false, false, true);
        scope = oldScope;
        option = oldOption;
        funct['(last)'] = token.line;
        funct = funct['(context)'];
        return f;
    }


    (function (x) {
        x.nud = function () {
            var b, f, i, j, p, t;
            var props = {}; // All properties, including accessors

            function saveProperty(name, token) {
                if (props[name] && is_own(props, name))
                    warning("Duplicate member '{a}'.", nexttoken, i);
                else
                    props[name] = {};

                props[name].basic = true;
                props[name].basicToken = token;
            }

            function saveSetter(name, token) {
                if (props[name] && is_own(props, name)) {
                    if (props[name].basic || props[name].setter)
                        warning("Duplicate member '{a}'.", nexttoken, i);
                } else {
                    props[name] = {};
                }

                props[name].setter = true;
                props[name].setterToken = token;
            }

            function saveGetter(name) {
                if (props[name] && is_own(props, name)) {
                    if (props[name].basic || props[name].getter)
                        warning("Duplicate member '{a}'.", nexttoken, i);
                } else {
                    props[name] = {};
                }

                props[name].getter = true;
                props[name].getterToken = token;
            }

            b = token.line !== nexttoken.line;
            if (b) {
                indent += option.indent;
                if (nexttoken.from === indent + option.indent) {
                    indent += option.indent;
                }
            }
            for (; ;) {
                if (nexttoken.id === '}') {
                    break;
                }
                if (b) {
                    indentation();
                }
                if (nexttoken.value === 'get' && peek().id !== ':') {
                    advance('get');
                    if (!option.es5) {
                        error("get/set are ES5 features.");
                    }
                    i = property_name();
                    if (!i) {
                        error("Missing property name.");
                    }
                    saveGetter(i);
                    t = nexttoken;
                    adjacent(token, nexttoken);
                    f = doFunction();
                    p = f['(params)'];
                    if (p) {
                        warning("Unexpected parameter '{a}' in get {b} function.", t, p[0], i);
                    }
                    adjacent(token, nexttoken);
                } else if (nexttoken.value === 'set' && peek().id !== ':') {
                    advance('set');
                    if (!option.es5) {
                        error("get/set are ES5 features.");
                    }
                    i = property_name();
                    if (!i) {
                        error("Missing property name.");
                    }
                    saveSetter(i, nexttoken);
                    t = nexttoken;
                    adjacent(token, nexttoken);
                    f = doFunction();
                    p = f['(params)'];
                    if (!p || p.length !== 1) {
                        warning("Expected a single parameter in set {a} function.", t, i);
                    }
                } else {
                    i = property_name();
                    saveProperty(i, nexttoken);
                    if (typeof i !== 'string') {
                        break;
                    }
                    advance(':');
                    nonadjacent(token, nexttoken);
                    expression(10);
                }

                countMember(i);
                if (nexttoken.id === ',') {
                    comma();
                    if (nexttoken.id === ',') {
                        warning("Extra comma.", token);
                    } else if (nexttoken.id === '}' && !option.es5) {
                        warning("Extra comma.", token);
                    }
                } else {
                    break;
                }
            }
            if (b) {
                indent -= option.indent;
                indentation();
            }
            advance('}', this);

            // Check for lonely setters if in the ES5 mode.
            if (option.es5) {
                for (var name in props) {
                    if (is_own(props, name) && props[name].setter && !props[name].getter) {
                        warning("Setter is defined without getter.", props[name].setterToken);
                    }
                }
            }
            return this;
        };
        x.fud = function () {
            error("Expected to see a statement and instead saw a block.", token);
        };
    }(delim('{')));

    // This Function is called when esnext option is set to true
    // it adds the `const` statement to JSHINT

    useESNextSyntax = function () {
        var conststatement = stmt('const', function (prefix) {
            var id, name, value;

            this.first = [];
            for (; ;) {
                nonadjacent(token, nexttoken);
                id = identifier();
                if (funct[id] === "const") {
                    warning("const '" + id + "' has already been declared");
                }
                if (funct['(global)'] && predefined[id] === false) {
                    warning("Redefinition of '{a}'.", token, id);
                }
                addlabel(id, 'const');
                if (prefix) {
                    break;
                }
                name = token;
                this.first.push(token);

                if (nexttoken.id !== "=") {
                    warning("const " +
                      "'{a}' is initialized to 'undefined'.", token, id);
                }

                if (nexttoken.id === '=') {
                    nonadjacent(token, nexttoken);
                    advance('=');
                    nonadjacent(token, nexttoken);
                    if (nexttoken.id === 'undefined') {
                        warning("It is not necessary to initialize " +
                          "'{a}' to 'undefined'.", token, id);
                    }
                    if (peek(0).id === '=' && nexttoken.identifier) {
                        error("Constant {a} was not declared correctly.",
                                nexttoken, nexttoken.value);
                    }
                    value = expression(0);
                    name.first = value;
                }

                if (nexttoken.id !== ',') {
                    break;
                }
                comma();
            }
            return this;
        });
        conststatement.exps = true;
    };

    var varstatement = stmt('var', function (prefix) {
        // JavaScript does not have block scope. It only has function scope. So,
        // declaring a variable in a block can have unexpected consequences.
        var id, name, value;

        if (funct['(onevar)'] && option.onevar) {
            warning("Too many var statements.");
        } else if (!funct['(global)']) {
            funct['(onevar)'] = true;
        }
        this.first = [];
        for (; ;) {
            nonadjacent(token, nexttoken);
            id = identifier();
            if (option.esnext && funct[id] === "const") {
                warning("const '" + id + "' has already been declared");
            }
            if (funct['(global)'] && predefined[id] === false) {
                warning("Redefinition of '{a}'.", token, id);
            }
            addlabel(id, 'unused');
            if (prefix) {
                break;
            }
            name = token;
            this.first.push(token);
            if (nexttoken.id === '=') {
                nonadjacent(token, nexttoken);
                advance('=');
                nonadjacent(token, nexttoken);
                if (nexttoken.id === 'undefined') {
                    warning("It is not necessary to initialize '{a}' to 'undefined'.", token, id);
                }
                if (peek(0).id === '=' && nexttoken.identifier) {
                    error("Variable {a} was not declared correctly.",
                            nexttoken, nexttoken.value);
                }
                value = expression(0);
                name.first = value;
            }
            if (nexttoken.id !== ',') {
                break;
            }
            comma();
        }
        return this;
    });
    varstatement.exps = true;

    blockstmt('function', function () {
        if (inblock) {
            warning("Function declarations should not be placed in blocks. " +
                "Use a function expression or move the statement to the top of " +
                "the outer function.", token);

        }
        var i = identifier();
        if (option.esnext && funct[i] === "const") {
            warning("const '" + i + "' has already been declared");
        }
        adjacent(token, nexttoken);
        addlabel(i, 'unction');
        doFunction(i, true);
        if (nexttoken.id === '(' && nexttoken.line === token.line) {
            error(
"Function declarations are not invocable. Wrap the whole function invocation in parens.");
        }
        return this;
    });

    prefix('function', function () {
        var i = optionalidentifier();
        if (i) {
            adjacent(token, nexttoken);
        } else {
            nonadjacent(token, nexttoken);
        }
        doFunction(i);
        if (!option.loopfunc && funct['(loopage)']) {
            warning("Don't make functions within a loop.");
        }
        return this;
    });

    blockstmt('if', function () {
        var t = nexttoken;
        advance('(');
        nonadjacent(this, t);
        nospace();
        expression(20);
        if (nexttoken.id === '=') {
            if (!option.boss)
                warning("Expected a conditional expression and instead saw an assignment.");
            advance('=');
            expression(20);
        }
        advance(')', t);
        nospace(prevtoken, token);
        block(true, true);
        if (nexttoken.id === 'else') {
            nonadjacent(token, nexttoken);
            advance('else');
            if (nexttoken.id === 'if' || nexttoken.id === 'switch') {
                statement(true);
            } else {
                block(true, true);
            }
        }
        return this;
    });

    blockstmt('try', function () {
        var b, e, s;

        block(false);
        if (nexttoken.id === 'catch') {
            advance('catch');
            nonadjacent(token, nexttoken);
            advance('(');
            s = scope;
            scope = Object.create(s);
            e = nexttoken.value;
            if (nexttoken.type !== '(identifier)') {
                warning("Expected an identifier and instead saw '{a}'.",
                    nexttoken, e);
            } else {
                addlabel(e, 'exception');
            }
            advance();
            advance(')');
            block(false);
            b = true;
            scope = s;
        }
        if (nexttoken.id === 'finally') {
            advance('finally');
            block(false);
            return;
        } else if (!b) {
            error("Expected '{a}' and instead saw '{b}'.",
                    nexttoken, 'catch', nexttoken.value);
        }
        return this;
    });

    blockstmt('while', function () {
        var t = nexttoken;
        funct['(breakage)'] += 1;
        funct['(loopage)'] += 1;
        advance('(');
        nonadjacent(this, t);
        nospace();
        expression(20);
        if (nexttoken.id === '=') {
            if (!option.boss)
                warning("Expected a conditional expression and instead saw an assignment.");
            advance('=');
            expression(20);
        }
        advance(')', t);
        nospace(prevtoken, token);
        block(true, true);
        funct['(breakage)'] -= 1;
        funct['(loopage)'] -= 1;
        return this;
    }).labelled = true;

    blockstmt('with', function () {
        var t = nexttoken;
        if (directive['use strict']) {
            error("'with' is not allowed in strict mode.", token);
        } else if (!option.withstmt) {
            warning("Don't use 'with'.", token);
        }

        advance('(');
        nonadjacent(this, t);
        nospace();
        expression(0);
        advance(')', t);
        nospace(prevtoken, token);
        block(true, true);

        return this;
    });

    blockstmt('switch', function () {
        var t = nexttoken,
            g = false;
        funct['(breakage)'] += 1;
        advance('(');
        nonadjacent(this, t);
        nospace();
        this.condition = expression(20);
        advance(')', t);
        nospace(prevtoken, token);
        nonadjacent(token, nexttoken);
        t = nexttoken;
        advance('{');
        nonadjacent(token, nexttoken);
        indent += option.indent;
        this.cases = [];
        for (; ;) {
            switch (nexttoken.id) {
                case 'case':
                    switch (funct['(verb)']) {
                        case 'break':
                        case 'case':
                        case 'continue':
                        case 'return':
                        case 'switch':
                        case 'throw':
                            break;
                        default:
                            // You can tell JSHint that you don't use break intentionally by
                            // adding a comment /* falls through */ on a line just before
                            // the next `case`.
                            if (!ft.test(lines[nexttoken.line - 2])) {
                                warning(
                                    "Expected a 'break' statement before 'case'.",
                                    token);
                            }
                    }
                    indentation(-option.indent);
                    advance('case');
                    this.cases.push(expression(20));
                    g = true;
                    advance(':');
                    funct['(verb)'] = 'case';
                    break;
                case 'default':
                    switch (funct['(verb)']) {
                        case 'break':
                        case 'continue':
                        case 'return':
                        case 'throw':
                            break;
                        default:
                            if (!ft.test(lines[nexttoken.line - 2])) {
                                warning(
                                    "Expected a 'break' statement before 'default'.",
                                    token);
                            }
                    }
                    indentation(-option.indent);
                    advance('default');
                    g = true;
                    advance(':');
                    break;
                case '}':
                    indent -= option.indent;
                    indentation();
                    advance('}', t);
                    if (this.cases.length === 1 || this.condition.id === 'true' ||
                            this.condition.id === 'false') {
                        if (!option.onecase)
                            warning("This 'switch' should be an 'if'.", this);
                    }
                    funct['(breakage)'] -= 1;
                    funct['(verb)'] = undefined;
                    return;
                case '(end)':
                    error("Missing '{a}'.", nexttoken, '}');
                    return;
                default:
                    if (g) {
                        switch (token.id) {
                            case ',':
                                error("Each value should have its own case label.");
                                return;
                            case ':':
                                g = false;
                                statements();
                                break;
                            default:
                                error("Missing ':' on a case clause.", token);
                                return;
                        }
                    } else {
                        if (token.id === ':') {
                            advance(':');
                            error("Unexpected '{a}'.", token, ':');
                            statements();
                        } else {
                            error("Expected '{a}' and instead saw '{b}'.",
                                nexttoken, 'case', nexttoken.value);
                            return;
                        }
                    }
            }
        }
    }).labelled = true;

    stmt('debugger', function () {
        if (!option.debug) {
            warning("All 'debugger' statements should be removed.");
        }
        return this;
    }).exps = true;

    (function () {
        var x = stmt('do', function () {
            funct['(breakage)'] += 1;
            funct['(loopage)'] += 1;
            this.first = block(true);
            advance('while');
            var t = nexttoken;
            nonadjacent(token, t);
            advance('(');
            nospace();
            expression(20);
            if (nexttoken.id === '=') {
                if (!option.boss)
                    warning("Expected a conditional expression and instead saw an assignment.");
                advance('=');
                expression(20);
            }
            advance(')', t);
            nospace(prevtoken, token);
            funct['(breakage)'] -= 1;
            funct['(loopage)'] -= 1;
            return this;
        });
        x.labelled = true;
        x.exps = true;
    }());

    blockstmt('for', function () {
        var s, t = nexttoken;
        funct['(breakage)'] += 1;
        funct['(loopage)'] += 1;
        advance('(');
        nonadjacent(this, t);
        nospace();
        if (peek(nexttoken.id === 'var' ? 1 : 0).id === 'in') {
            if (nexttoken.id === 'var') {
                advance('var');
                varstatement.fud.call(varstatement, true);
            } else {
                switch (funct[nexttoken.value]) {
                    case 'unused':
                        funct[nexttoken.value] = 'var';
                        break;
                    case 'var':
                        break;
                    default:
                        warning("Bad for in variable '{a}'.",
                                nexttoken, nexttoken.value);
                }
                advance();
            }
            advance('in');
            expression(20);
            advance(')', t);
            s = block(true, true);
            if (option.forin && s && (s.length > 1 || typeof s[0] !== 'object' ||
                    s[0].value !== 'if')) {
                warning("The body of a for in should be wrapped in an if statement to filter " +
                        "unwanted properties from the prototype.", this);
            }
            funct['(breakage)'] -= 1;
            funct['(loopage)'] -= 1;
            return this;
        } else {
            if (nexttoken.id !== ';') {
                if (nexttoken.id === 'var') {
                    advance('var');
                    varstatement.fud.call(varstatement);
                } else {
                    for (; ;) {
                        expression(0, 'for');
                        if (nexttoken.id !== ',') {
                            break;
                        }
                        comma();
                    }
                }
            }
            nolinebreak(token);
            advance(';');
            if (nexttoken.id !== ';') {
                expression(20);
                if (nexttoken.id === '=') {
                    if (!option.boss)
                        warning("Expected a conditional expression and instead saw an assignment.");
                    advance('=');
                    expression(20);
                }
            }
            nolinebreak(token);
            advance(';');
            if (nexttoken.id === ';') {
                error("Expected '{a}' and instead saw '{b}'.",
                        nexttoken, ')', ';');
            }
            if (nexttoken.id !== ')') {
                for (; ;) {
                    expression(0, 'for');
                    if (nexttoken.id !== ',') {
                        break;
                    }
                    comma();
                }
            }
            advance(')', t);
            nospace(prevtoken, token);
            block(true, true);
            funct['(breakage)'] -= 1;
            funct['(loopage)'] -= 1;
            return this;
        }
    }).labelled = true;


    stmt('break', function () {
        var v = nexttoken.value;

        if (funct['(breakage)'] === 0)
            warning("Unexpected '{a}'.", nexttoken, this.value);

        if (!option.asi)
            nolinebreak(this);

        if (nexttoken.id !== ';') {
            if (token.line === nexttoken.line) {
                if (funct[v] !== 'label') {
                    warning("'{a}' is not a statement label.", nexttoken, v);
                } else if (scope[v] !== funct) {
                    warning("'{a}' is out of scope.", nexttoken, v);
                }
                this.first = nexttoken;
                advance();
            }
        }
        reachable('break');
        return this;
    }).exps = true;


    stmt('continue', function () {
        var v = nexttoken.value;

        if (funct['(breakage)'] === 0)
            warning("Unexpected '{a}'.", nexttoken, this.value);

        if (!option.asi)
            nolinebreak(this);

        if (nexttoken.id !== ';') {
            if (token.line === nexttoken.line) {
                if (funct[v] !== 'label') {
                    warning("'{a}' is not a statement label.", nexttoken, v);
                } else if (scope[v] !== funct) {
                    warning("'{a}' is out of scope.", nexttoken, v);
                }
                this.first = nexttoken;
                advance();
            }
        } else if (!funct['(loopage)']) {
            warning("Unexpected '{a}'.", nexttoken, this.value);
        }
        reachable('continue');
        return this;
    }).exps = true;


    stmt('return', function () {
        if (this.line === nexttoken.line) {
            if (nexttoken.id === '(regexp)')
                warning("Wrap the /regexp/ literal in parens to disambiguate the slash operator.");

            if (nexttoken.id !== ';' && !nexttoken.reach) {
                nonadjacent(token, nexttoken);
                if (peek().value === "=" && !option.boss) {
                    warningAt("Did you mean to return a conditional instead of an assignment?",
                              token.line, token.character + 1);
                }
                this.first = expression(0);
            }
        } else if (!option.asi) {
            nolinebreak(this); // always warn (Line breaking error)
        }
        reachable('return');
        return this;
    }).exps = true;


    stmt('throw', function () {
        nolinebreak(this);
        nonadjacent(token, nexttoken);
        this.first = expression(20);
        reachable('throw');
        return this;
    }).exps = true;

    //  Superfluous reserved words

    reserve('class');
    reserve('const');
    reserve('enum');
    reserve('export');
    reserve('extends');
    reserve('import');
    reserve('super');

    reserve('let');
    reserve('yield');
    reserve('implements');
    reserve('interface');
    reserve('package');
    reserve('private');
    reserve('protected');
    reserve('public');
    reserve('static');


    // Parse JSON

    function jsonValue() {

        function jsonObject() {
            var o = {}, t = nexttoken;
            advance('{');
            if (nexttoken.id !== '}') {
                for (; ;) {
                    if (nexttoken.id === '(end)') {
                        error("Missing '}' to match '{' from line {a}.",
                                nexttoken, t.line);
                    } else if (nexttoken.id === '}') {
                        warning("Unexpected comma.", token);
                        break;
                    } else if (nexttoken.id === ',') {
                        error("Unexpected comma.", nexttoken);
                    } else if (nexttoken.id !== '(string)') {
                        warning("Expected a string and instead saw {a}.",
                                nexttoken, nexttoken.value);
                    }
                    if (o[nexttoken.value] === true) {
                        warning("Duplicate key '{a}'.",
                                nexttoken, nexttoken.value);
                    } else if ((nexttoken.value === '__proto__' &&
                        !option.proto) || (nexttoken.value === '__iterator__' &&
                        !option.iterator)) {
                        warning("The '{a}' key may produce unexpected results.",
                            nexttoken, nexttoken.value);
                    } else {
                        o[nexttoken.value] = true;
                    }
                    advance();
                    advance(':');
                    jsonValue();
                    if (nexttoken.id !== ',') {
                        break;
                    }
                    advance(',');
                }
            }
            advance('}');
        }

        function jsonArray() {
            var t = nexttoken;
            advance('[');
            if (nexttoken.id !== ']') {
                for (; ;) {
                    if (nexttoken.id === '(end)') {
                        error("Missing ']' to match '[' from line {a}.",
                                nexttoken, t.line);
                    } else if (nexttoken.id === ']') {
                        warning("Unexpected comma.", token);
                        break;
                    } else if (nexttoken.id === ',') {
                        error("Unexpected comma.", nexttoken);
                    }
                    jsonValue();
                    if (nexttoken.id !== ',') {
                        break;
                    }
                    advance(',');
                }
            }
            advance(']');
        }

        switch (nexttoken.id) {
            case '{':
                jsonObject();
                break;
            case '[':
                jsonArray();
                break;
            case 'true':
            case 'false':
            case 'null':
            case '(number)':
            case '(string)':
                advance();
                break;
            case '-':
                advance('-');
                if (token.character !== nexttoken.from) {
                    warning("Unexpected space after '-'.", token);
                }
                adjacent(token, nexttoken);
                advance('(number)');
                break;
            default:
                error("Expected a JSON value.", nexttoken);
        }
    }


    // The actual JSHINT function itself.

    var itself = function (s, o, g) {
        var a, i, k, x,
            optionKeys,
            newOptionObj = {};

        JSHINT.errors = [];
        JSHINT.undefs = [];
        predefined = Object.create(standard);
        combine(predefined, g || {});
        if (o) {
            a = o.predef;
            if (a) {
                if (Array.isArray(a)) {
                    for (i = 0; i < a.length; i += 1) {
                        predefined[a[i]] = true;
                    }
                } else if (typeof a === 'object') {
                    k = Object.keys(a);
                    for (i = 0; i < k.length; i += 1) {
                        predefined[k[i]] = !!a[k[i]];
                    }
                }
            }
            optionKeys = Object.keys(o);
            for (x = 0; x < optionKeys.length; x++) {
                newOptionObj[optionKeys[x]] = o[optionKeys[x]];
            }
        }

        option = newOptionObj;

        option.indent = option.indent || 4;
        option.maxerr = option.maxerr || 50;

        tab = '';
        for (i = 0; i < option.indent; i += 1) {
            tab += ' ';
        }
        indent = 1;
        global = Object.create(predefined);
        scope = global;
        funct = {
            '(global)': true,
            '(name)': '(global)',
            '(scope)': scope,
            '(breakage)': 0,
            '(loopage)': 0
        };
        functions = [funct];
        urls = [];
        stack = null;
        member = {};
        membersOnly = null;
        implied = {};
        inblock = false;
        lookahead = [];
        jsonmode = false;
        warnings = 0;
        lex.init(s);
        prereg = true;
        directive = {};

        prevtoken = token = nexttoken = syntax['(begin)'];

        // Check options
        for (var name in o) {
            if (is_own(o, name)) {
                checkOption(name, token);
            }
        }

        assume();

        // combine the passed globals after we've assumed all our options
        combine(predefined, g || {});

        //reset values
        comma.first = true;

        try {
            advance();
            switch (nexttoken.id) {
                case '{':
                case '[':
                    option.laxbreak = true;
                    jsonmode = true;
                    jsonValue();
                    break;
                default:
                    directives();
                    if (directive["use strict"] && !option.globalstrict) {
                        warning("Use the function form of \"use strict\".", prevtoken);
                    }

                    statements();
            }
            advance('(end)');

            var markDefined = function (name, context) {
                do {
                    if (typeof context[name] === 'string') {
                        // JSHINT marks unused variables as 'unused' and
                        // unused function declaration as 'unction'. This
                        // code changes such instances back 'var' and
                        // 'closure' so that the code in JSHINT.data()
                        // doesn't think they're unused.

                        if (context[name] === 'unused')
                            context[name] = 'var';
                        else if (context[name] === 'unction')
                            context[name] = 'closure';

                        return true;
                    }

                    context = context['(context)'];
                } while (context);

                return false;
            };

            var clearImplied = function (name, line) {
                if (!implied[name])
                    return;

                var newImplied = [];
                for (var i = 0; i < implied[name].length; i += 1) {
                    if (implied[name][i] !== line)
                        newImplied.push(implied[name][i]);
                }

                if (newImplied.length === 0)
                    delete implied[name];
                else
                    implied[name] = newImplied;
            };

            // Check queued 'x is not defined' instances to see if they're still undefined.
            for (i = 0; i < JSHINT.undefs.length; i += 1) {
                k = JSHINT.undefs[i].slice(0);

                if (markDefined(k[2].value, k[0])) {
                    clearImplied(k[2].value, k[2].line);
                } else {
                    warning.apply(warning, k.slice(1));
                }
            }
        } catch (e) {
            if (e) {
                var nt = nexttoken || {};
                JSHINT.errors.push({
                    raw: e.raw,
                    reason: e.message,
                    line: e.line || nt.line,
                    character: e.character || nt.from
                }, null);
            }
        }

        return JSHINT.errors.length === 0;
    };

    // Data summary.
    itself.data = function () {

        var data = { functions: [], options: option }, fu, globals, implieds = [], f, i, j,
            members = [], n, unused = [], v;
        if (itself.errors.length) {
            data.errors = itself.errors;
        }

        if (jsonmode) {
            data.json = true;
        }

        for (n in implied) {
            if (is_own(implied, n)) {
                implieds.push({
                    name: n,
                    line: implied[n]
                });
            }
        }
        if (implieds.length > 0) {
            data.implieds = implieds;
        }

        if (urls.length > 0) {
            data.urls = urls;
        }

        globals = Object.keys(scope);
        if (globals.length > 0) {
            data.globals = globals;
        }
        for (i = 1; i < functions.length; i += 1) {
            f = functions[i];
            fu = {};
            for (j = 0; j < functionicity.length; j += 1) {
                fu[functionicity[j]] = [];
            }
            for (n in f) {
                if (is_own(f, n) && n.charAt(0) !== '(') {
                    v = f[n];
                    if (v === 'unction') {
                        v = 'unused';
                    }
                    if (Array.isArray(fu[v])) {
                        fu[v].push(n);
                        if (v === 'unused') {
                            unused.push({
                                name: n,
                                line: f['(line)'],
                                'function': f['(name)']
                            });
                        }
                    }
                }
            }
            for (j = 0; j < functionicity.length; j += 1) {
                if (fu[functionicity[j]].length === 0) {
                    delete fu[functionicity[j]];
                }
            }
            fu.name = f['(name)'];
            fu.param = f['(params)'];
            fu.line = f['(line)'];
            fu.last = f['(last)'];
            data.functions.push(fu);
        }

        if (unused.length > 0) {
            data.unused = unused;
        }

        members = [];
        for (n in member) {
            if (typeof member[n] === 'number') {
                data.member = member;
                break;
            }
        }

        return data;
    };

    itself.report = function (option) {
        var data = itself.data();

        var a = [], c, e, err, f, i, k, l, m = '', n, o = [], s;

        function detail(h, array) {
            var b, i, singularity;
            if (array) {
                o.push('<div><i>' + h + '</i> ');
                array = array.sort();
                for (i = 0; i < array.length; i += 1) {
                    if (array[i] !== singularity) {
                        singularity = array[i];
                        o.push((b ? ', ' : '') + singularity);
                        b = true;
                    }
                }
                o.push('</div>');
            }
        }


        if (data.errors || data.implieds || data.unused) {
            err = true;
            o.push('<div id=errors><i>Error:</i>');
            if (data.errors) {
                for (i = 0; i < data.errors.length; i += 1) {
                    c = data.errors[i];
                    if (c) {
                        e = c.evidence || '';
                        o.push('<p>Problem' + (isFinite(c.line) ? ' at line ' +
                                c.line + ' character ' + c.character : '') +
                                ': ' + c.reason.entityify() +
                                '</p><p class=evidence>' +
                                (e && (e.length > 80 ? e.slice(0, 77) + '...' :
                                e).entityify()) + '</p>');
                    }
                }
            }

            if (data.implieds) {
                s = [];
                for (i = 0; i < data.implieds.length; i += 1) {
                    s[i] = '<code>' + data.implieds[i].name + '</code>&nbsp;<i>' +
                        data.implieds[i].line + '</i>';
                }
                o.push('<p><i>Implied global:</i> ' + s.join(', ') + '</p>');
            }

            if (data.unused) {
                s = [];
                for (i = 0; i < data.unused.length; i += 1) {
                    s[i] = '<code><u>' + data.unused[i].name + '</u></code>&nbsp;<i>' +
                        data.unused[i].line + '</i> <code>' +
                        data.unused[i]['function'] + '</code>';
                }
                o.push('<p><i>Unused variable:</i> ' + s.join(', ') + '</p>');
            }
            if (data.json) {
                o.push('<p>JSON: bad.</p>');
            }
            o.push('</div>');
        }

        if (!option) {

            o.push('<br><div id=functions>');

            if (data.urls) {
                detail("URLs<br>", data.urls, '<br>');
            }

            if (data.json && !err) {
                o.push('<p>JSON: good.</p>');
            } else if (data.globals) {
                o.push('<div><i>Global</i> ' +
                        data.globals.sort().join(', ') + '</div>');
            } else {
                o.push('<div><i>No new global variables introduced.</i></div>');
            }

            for (i = 0; i < data.functions.length; i += 1) {
                f = data.functions[i];

                o.push('<br><div class=function><i>' + f.line + '-' +
                        f.last + '</i> ' + (f.name || '') + '(' +
                        (f.param ? f.param.join(', ') : '') + ')</div>');
                detail('<big><b>Unused</b></big>', f.unused);
                detail('Closure', f.closure);
                detail('Variable', f['var']);
                detail('Exception', f.exception);
                detail('Outer', f.outer);
                detail('Global', f.global);
                detail('Label', f.label);
            }

            if (data.member) {
                a = Object.keys(data.member);
                if (a.length) {
                    a = a.sort();
                    m = '<br><pre id=members>/*members ';
                    l = 10;
                    for (i = 0; i < a.length; i += 1) {
                        k = a[i];
                        n = k.name();
                        if (l + n.length > 72) {
                            o.push(m + '<br>');
                            m = '    ';
                            l = 1;
                        }
                        l += n.length + 2;
                        if (data.member[k] === 1) {
                            n = '<i>' + n + '</i>';
                        }
                        if (i < a.length - 1) {
                            n += ', ';
                        }
                        m += n;
                    }
                    o.push(m + '<br>*/</pre>');
                }
                o.push('</div>');
            }
        }
        return o.join('');
    };

    itself.jshint = itself;

    return itself;
}());

// Make JSHINT a Node module, if possible.
if (typeof exports === 'object' && exports)
    exports.JSHINT = JSHINT;

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    "use strict";
    var GUTTER_ID = "CodeMirror-lint-markers";

    function showTooltip(e, content) {
        var tt = document.createElement("div");
        tt.className = "CodeMirror-lint-tooltip";
        tt.appendChild(content.cloneNode(true));
        document.body.appendChild(tt);

        function position(e) {
            if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position);
            tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px";
            tt.style.left = (e.clientX + 5) + "px";
        }
        CodeMirror.on(document, "mousemove", position);
        position(e);
        if (tt.style.opacity != null) tt.style.opacity = 1;
        return tt;
    }
    function rm(elt) {
        if (elt.parentNode) elt.parentNode.removeChild(elt);
    }
    function hideTooltip(tt) {
        if (!tt.parentNode) return;
        if (tt.style.opacity == null) rm(tt);
        tt.style.opacity = 0;
        setTimeout(function () { rm(tt); }, 600);
    }

    function showTooltipFor(e, content, node) {
        var tooltip = showTooltip(e, content);
        function hide() {
            CodeMirror.off(node, "mouseout", hide);
            if (tooltip) { hideTooltip(tooltip); tooltip = null; }
        }
        var poll = setInterval(function () {
            if (tooltip) for (var n = node; ; n = n.parentNode) {
                if (n && n.nodeType == 11) n = n.host;
                if (n == document.body) return;
                if (!n) { hide(); break; }
            }
            if (!tooltip) return clearInterval(poll);
        }, 400);
        CodeMirror.on(node, "mouseout", hide);
    }

    function LintState(cm, options, hasGutter) {
        this.marked = [];
        this.options = options;
        this.timeout = null;
        this.hasGutter = hasGutter;
        this.onMouseOver = function (e) { onMouseOver(cm, e); };
        this.waitingFor = 0
    }

    function parseOptions(_cm, options) {
        if (options instanceof Function) return { getAnnotations: options };
        if (!options || options === true) options = {};
        return options;
    }

    function clearMarks(cm) {
        var state = cm.state.lint;
        if (state.hasGutter) cm.clearGutter(GUTTER_ID);
        for (var i = 0; i < state.marked.length; ++i)
            state.marked[i].clear();
        state.marked.length = 0;
    }

    function makeMarker(labels, severity, multiple, tooltips) {
        var marker = document.createElement("div"), inner = marker;
        marker.className = "CodeMirror-lint-marker-" + severity;
        if (multiple) {
            inner = marker.appendChild(document.createElement("div"));
            inner.className = "CodeMirror-lint-marker-multiple";
        }

        if (tooltips != false) CodeMirror.on(inner, "mouseover", function (e) {
            showTooltipFor(e, labels, inner);
        });

        return marker;
    }

    function getMaxSeverity(a, b) {
        if (a == "error") return a;
        else return b;
    }

    function groupByLine(annotations) {
        var lines = [];
        for (var i = 0; i < annotations.length; ++i) {
            var ann = annotations[i], line = ann.from.line;
            (lines[line] || (lines[line] = [])).push(ann);
        }
        return lines;
    }

    function annotationTooltip(ann) {
        var severity = ann.severity;
        if (!severity) severity = "error";
        var tip = document.createElement("div");
        tip.className = "CodeMirror-lint-message-" + severity;
        tip.appendChild(document.createTextNode(ann.message));
        return tip;
    }

    function lintAsync(cm, getAnnotations, passOptions) {
        var state = cm.state.lint
        var id = ++state.waitingFor
        function abort() {
            id = -1
            cm.off("change", abort)
        }
        cm.on("change", abort)
        getAnnotations(cm.getValue(), function (annotations, arg2) {
            cm.off("change", abort)
            if (state.waitingFor != id) return
            if (arg2 && annotations instanceof CodeMirror) annotations = arg2
            updateLinting(cm, annotations)
        }, passOptions, cm);
    }

    function startLinting(cm) {
        var state = cm.state.lint, options = state.options;
        var passOptions = options.options || options; // Support deprecated passing of `options` property in options
        var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint");
        if (!getAnnotations) return;
        if (options.async || getAnnotations.async) {
            lintAsync(cm, getAnnotations, passOptions)
        } else {
            updateLinting(cm, getAnnotations(cm.getValue(), passOptions, cm));
        }
    }

    function updateLinting(cm, annotationsNotSorted) {
        clearMarks(cm);
        var state = cm.state.lint, options = state.options;

        var annotations = groupByLine(annotationsNotSorted);

        for (var line = 0; line < annotations.length; ++line) {
            var anns = annotations[line];
            if (!anns) continue;

            var maxSeverity = null;
            var tipLabel = state.hasGutter && document.createDocumentFragment();

            for (var i = 0; i < anns.length; ++i) {
                var ann = anns[i];
                var severity = ann.severity;
                if (!severity) severity = "error";
                maxSeverity = getMaxSeverity(maxSeverity, severity);

                if (options.formatAnnotation) ann = options.formatAnnotation(ann);
                if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann));

                if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, {
                    className: "CodeMirror-lint-mark-" + severity,
                    __annotation: ann
                }));
            }

            if (state.hasGutter)
                cm.setGutterMarker(line, GUTTER_ID, makeMarker(tipLabel, maxSeverity, anns.length > 1,
                                                               state.options.tooltips));
        }
        if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm);
    }

    function onChange(cm) {
        var state = cm.state.lint;
        if (!state) return;
        clearTimeout(state.timeout);
        state.timeout = setTimeout(function () { startLinting(cm); }, state.options.delay || 500);
    }

    function popupSpanTooltip(ann, e) {
        var target = e.target || e.srcElement;
        showTooltipFor(e, annotationTooltip(ann), target);
    }

    function onMouseOver(cm, e) {
        var target = e.target || e.srcElement;
        if (!/\bCodeMirror-lint-mark-/.test(target.className)) return;
        var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2;
        var spans = cm.findMarksAt(cm.coordsChar({ left: x, top: y }, "client"));
        for (var i = 0; i < spans.length; ++i) {
            var ann = spans[i].__annotation;
            if (ann) return popupSpanTooltip(ann, e);
        }
    }

    CodeMirror.defineOption("lint", false, function (cm, val, old) {
        if (old && old != CodeMirror.Init) {
            clearMarks(cm);
            if (cm.state.lint.options.lintOnChange !== false)
                cm.off("change", onChange);
            CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver);
            clearTimeout(cm.state.lint.timeout);
            delete cm.state.lint;
        }

        if (val) {
            var gutters = cm.getOption("gutters"), hasLintGutter = false;
            for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true;
            var state = cm.state.lint = new LintState(cm, parseOptions(cm, val), hasLintGutter);
            if (state.options.lintOnChange !== false)
                cm.on("change", onChange);
            if (state.options.tooltips != false)
                CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver);

            startLinting(cm);
        }
    });

    CodeMirror.defineExtension("performLint", function () {
        if (this.state.lint) startLinting(this);
    });
});

// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE

(function (mod) {
    if (typeof exports == "object" && typeof module == "object") // CommonJS
        mod(require("../../lib/codemirror"));
    else if (typeof define == "function" && define.amd) // AMD
        define(["../../lib/codemirror"], mod);
    else // Plain browser env
        mod(CodeMirror);
})(function (CodeMirror) {
    "use strict";
    // declare global: JSHINT

    var bogus = ["Dangerous comment"];

    var warnings = [["Expected '{'",
                       "Statement body should be inside '{ }' braces."]];

    var errors = ["Missing semicolon", "Extra comma", "Missing property name",
                   "Unmatched ", " and instead saw", " is not defined",
                   "Unclosed string", "Stopping, unable to continue"];

    function validator(text, options) {
        if (!window.JSHINT) return [];
        JSHINT(text, options, options.globals);
        var errors = JSHINT.data().errors, result = [];
        if (errors) parseErrors(errors, result);
        return result;
    }

    CodeMirror.registerHelper("lint", "javascript", validator);

    function cleanup(error) {
        // All problems are warnings by default
        fixWith(error, warnings, "warning", true);
        fixWith(error, errors, "error");

        return isBogus(error) ? null : error;
    }

    function fixWith(error, fixes, severity, force) {
        var description, fix, find, replace, found;

        description = error.description;

        for (var i = 0; i < fixes.length; i++) {
            fix = fixes[i];
            find = (typeof fix === "string" ? fix : fix[0]);
            replace = (typeof fix === "string" ? null : fix[1]);
            found = description.indexOf(find) !== -1;

            if (force || found) {
                error.severity = severity;
            }
            if (found && replace) {
                error.description = replace;
            }
        }
    }

    function isBogus(error) {
        var description = error.description;
        for (var i = 0; i < bogus.length; i++) {
            if (description.indexOf(bogus[i]) !== -1) {
                return true;
            }
        }
        return false;
    }

    function parseErrors(errors, output) {
        for (var i = 0; i < errors.length; i++) {
            var error = errors[i];
            if (error) {
                var linetabpositions, index;

                linetabpositions = [];

                // This next block is to fix a problem in jshint. Jshint
                // replaces
                // all tabs with spaces then performs some checks. The error
                // positions (character/space) are then reported incorrectly,
                // not taking the replacement step into account. Here we look
                // at the evidence line and try to adjust the character position
                // to the correct value.
                if (error.evidence) {
                    // Tab positions are computed once per line and cached
                    var tabpositions = linetabpositions[error.line];
                    if (!tabpositions) {
                        var evidence = error.evidence;
                        tabpositions = [];
                        // ugggh phantomjs does not like this
                        // forEachChar(evidence, function(item, index) {
                        Array.prototype.forEach.call(evidence, function (item,
                                                                        index) {
                            if (item === '\t') {
                                // First col is 1 (not 0) to match error
                                // positions
                                tabpositions.push(index + 1);
                            }
                        });
                        linetabpositions[error.line] = tabpositions;
                    }
                    if (tabpositions.length > 0) {
                        var pos = error.character;
                        tabpositions.forEach(function (tabposition) {
                            if (pos > tabposition) pos -= 1;
                        });
                        error.character = pos;
                    }
                }

                var start = error.character - 1, end = start + 1;
                if (error.evidence) {
                    index = error.evidence.substring(start).search(/.\b/);
                    if (index > -1) {
                        end += index;
                    }
                }

                // Convert to format expected by validation service
                error.description = error.reason;// + "(jshint)";
                error.start = error.character;
                error.end = end;
                error = cleanup(error);

                if (error)
                    output.push({
                        message: error.description,
                        severity: error.severity,
                        from: CodeMirror.Pos(error.line - 1, start),
                        to: CodeMirror.Pos(error.line - 1, end)
                    });
            }
        }
    }
});


/// <reference path="../Application.js" />

Define("PageViewer",

    function (options_) {
        return new Window();
    },

    function (options_) {

        //#region Members

        var _self = this;
        var _base = null;
        var m_id = null;
        var m_uid = "";
        var m_loaded = false;
        var m_view = "";
        var m_parent = null; //PageViewer
        var m_openedFrom = null; //PageViewer
        var m_form = null; //Page
        var m_table = null; //Table
        var m_record = null; //Record    
        var m_controls = new Array();
        var m_filterToolbar = null; //FilterToolbar
        var m_tabs = new Array();
        var m_subPages = new Array(); //PageViewer
        var m_closeFunc = null;
        var m_closeAction = null;
        var m_disableKeys = false;
        var m_col = null;
        var m_row = null;
        var m_lastValue = null;
        var m_focusControl = null;
        var m_xFocusControl = null;
        var m_layout = null;
        var m_options = null;
        var m_okClicked = false;
        var m_actionsQueue = 0;
        var m_delete = null;
        var m_customControl = null; //Control
        var m_temp = false;
        var m_tempChanged = false;
        var m_nextPageOptions = null;
        var m_lineEditor = null; //PageViewer
        var m_enableEditMode = false;
        var m_changed = false; //Change tracking.
        var m_designerPages = ["VP$TableDesigner", "VP$PageDesigner", "VP$CodeModuleDesigner"];
        var m_designerPages2 = ["VP$ColumnDesigner", "VP$TableKeysDesigner", "VP$PageFieldsDesigner"];
        var m_designerPages3 = ["VP$PageActionsDesigner", "VP$PageTabsDesigner"];
        var m_comboSelected = false;
		var m_buttons = new Object();
		var m_causedUpdate = null;	
		var m_lineActions = [];
		var m_lastView = null;

        //#endregion

        //#region Public Functions

        this.Constructor = function (options_) {

            if (Application.testMode && arguments[0] == null) return;

            //Set the base and get the options.
            _base = Base("PageViewer");
            m_options = options_;

            m_id = Default(m_options.id, null);
            m_view = Default(m_options.view, "");
            m_parent = m_options.parent;
            m_options.caption = Default(m_options.caption, null);
            m_options.tableid = Default(m_options.tableid, null);
        };

        this.Open = function () {

            Application.LogDebug("Opening PageViewer: " + m_id);

            //Check if window is already open.
            var winid = UI.WindowManager.GetWindowByUID(m_id + m_view);
            if (winid != -1 && m_options.dialog != true) { //&& !Application.IsInMobile()) {
                Application.LogDebug("Opening Previous PageViewer: " + winid);
                var win = UI.WindowManager.Open(winid);
                Application.RunNext(win.Update);
                return win;
            }

            var w = $wait();

            $code(

            function () {
                if (m_options.page != null)
                    return m_options.page;
                if (m_id != null)
                    return new Page(m_id);
            },

            function (obj) {

                //Create the window.
                if (obj == null && m_id != null) {
                    Application.Error(Application.StrSubstitute("Form $1 does not exist.", m_id));
                }

                //Save the application form.
                m_form = obj;

                //Table viewer mode.
                if (m_form == null && m_options.tableid != null) {
                    m_id = "VIEWER" + m_options.tableid;
                    m_form = new Page();
                    m_form.SourceID = m_options.tableid;
                    m_form.Icon = "table_sql_run";
                    m_form.ShowFilters = true;
                    m_form.ShowSorting = true;
                    m_form.Type = "List";
                    m_form.InsertAllowed = true;
                    m_form.DeleteAllowed = true;

                    var act1 = Application.Objects.PageActionInfo();
                    act1.Name = "New";
                    act1.Type = "New";
                    m_form.Actions.push(act1);

                    var act2 = Application.Objects.PageActionInfo();
                    act2.Name = "Delete";
                    act2.Type = "Delete";
                    m_form.Actions.push(act2);

                    var act3 = Application.Objects.PageActionInfo();
                    act3.Name = "Design Table";
                    act3.Type = "Open Page";
                    act3.Image = "table_sql_select";
                    act3.ReferencePage = "VP$TableDesigner";
                    act3.ActionView = "WHERE(Name=CONST(" + m_options.tableid + "))";
                    m_form.Actions.push(act3);
                }

                if (m_options.table != null)
                    return m_options.table;

                return new Table(m_form.SourceID);
            },

            function (tbl) {

                //Save the table.
                m_table = tbl;

                //Table viewer mode.
                if (m_options.tableid != null) {
                    for (var i = 0; i < m_table.Columns.length; i++) {
                        var field = Application.Objects.PageFieldInfo();
                        //field.ID = i + 1;
                        field.Name = m_table.Columns[i].Name;
                        field.Caption = m_table.Columns[i].Caption;
                        if (m_table.Columns[i].FlowField == "" && m_table.Columns[i].Formula == "" && m_table.Columns[i].Identity == false) {
                            field.Editable = true;
                            //field.Validate = true;
                        }
                        field.Type = m_table.Columns[i].Type;
                        field.Width = 100;
                        m_form.Fields.push(field);
                    }
                }

                //Merge fields.
                for (var i = 0; i < m_table.Columns.length; i++) {
                    for (var j = 0; j < m_form.Fields.length; j++) {
                        if (m_form.Fields[j].Name == m_table.Columns[i].Name) {
                            m_form.Fields[j].LookupTable = m_table.Columns[i].LookupTable;
                            m_form.Fields[j].LookupField = m_table.Columns[i].LookupField;
                            m_form.Fields[j].LookupDisplayField = m_table.Columns[i].LookupDisplayField;
                            m_form.Fields[j].LookupCategoryField = m_table.Columns[i].LookupCategoryField;
                            m_form.Fields[j].LookupFilters = m_table.Columns[i].LookupFilters;
                            m_form.Fields[j].LookupColumns = m_table.Columns[i].LookupColumns;
                            m_form.Fields[j].LookupColumnCaptions = m_table.Columns[i].LookupColumnCaptions;
                            m_form.Fields[j].LookupAdvanced = m_table.Columns[i].LookupAdvanced;
                            m_form.Fields[j].OptionCaption = m_table.Columns[i].OptionCaption;
                            m_form.Fields[j].OptionString = m_table.Columns[i].OptionString;
                            m_form.Fields[j].Size = m_table.Columns[i].Size;
                            if (m_form.Fields[j].Size == 0)
                                m_form.Fields[j].Size = 1000000;
                            if (m_form.Fields[j].OptionCaption != "" && m_form.Fields[j].OptionString == "") {
                                var capts = m_form.Fields[j].OptionCaption.split(",");
                                for (var k = 0; k < capts.length; k++) {
                                    if (m_form.Fields[j].OptionString == "") {
                                        m_form.Fields[j].OptionString = k + "";
                                    } else {
                                        m_form.Fields[j].OptionString += "," + k;
                                    }
                                }
                            }

                            m_form.Fields[j].FlowField = m_table.Columns[i].FlowField;

                            if (m_table.Columns[i].Options != null && m_table.Columns[i].Options != '') {
                                if (m_form.Fields[j].Options == null || m_form.Fields[j].Options == "") {
                                    m_form.Fields[j].Options = m_table.Columns[i].Options;
                                } else {
                                    m_form.Fields[j].Options += ";" + m_table.Columns[i].Options;
                                }
                            }
                            break;
                        }
                    }
                }
				
				//Bug fix.
				for (var j = 0; j < m_form.Fields.length; j++) {
					
					m_form.Fields[j].Caption = Application.ProcessCaption(m_form.Fields[j].Caption);
					
					if(typeof m_form.Fields[j].LookupTable == "undefined"){
						m_form.Fields[j].LookupTable = "";
						m_form.Fields[j].LookupField = "";
						m_form.Fields[j].LookupDisplayField = "";
						m_form.Fields[j].LookupCategoryField = "";
						m_form.Fields[j].LookupFilters = "";
						m_form.Fields[j].LookupColumns = "";
						m_form.Fields[j].LookupColumnCaptions = "";
						m_form.Fields[j].LookupAdvanced = "";
						m_form.Fields[j].OptionCaption = "";
						m_form.Fields[j].OptionString = "";
						m_form.Fields[j].Size = 1000000;
					}
                }
                
                if(Application.IsInMobile() && !m_options.homepage)
                    return $codeblock(
                        function(){
                            if(m_form.TabList.length > 0)
                                return $loop(function(i){
                                    return $codeblock(
                                        function(){
                                            var tab = m_form.TabList[i];
                                            if (tab.ID != "" && !Application.HasOption(tab.Options, "desktoponly")) {
                                                return $codeblock(
                                                    function(){
                                                        return new Page(tab.ID);
                                                    },
                                                    function(pge){
                                                        var act = new Application.Objects.PageActionInfo();
                                                        act.Name = tab.Name;
                                                        act.Type = "Open Page";
                                                        act.ReferencePage = tab.ID;
                                                        act.ActionView = tab.View;
                                                        act.Image = pge.Icon;
                                                        act.Sort = 2;
                                                        if(m_form.Type == "List")
                                                            act.Options = "lineaction";
                                                        m_form.Actions.push(act);
                                                    }
                                                );
                                            }
                                        },
                                        function(){
                                            if(i < m_form.TabList.length - 1)
                                                return $next;
                                            for(var j = 0; j < m_form.TabList.length; j++){
                                                if(m_form.TabList[j].ID != ''){
                                                    m_form.TabList.splice(j, 1);
                                                    j -= 1;
                                                }
                                            }
                                            for(var j = 0; j < m_form.Actions.length; j++){
                                                if(m_form.Actions[j].Type == "New")
                                                    m_form.Actions[j].Sort = 1;
                                                if(m_form.Actions[j].Type == "Delete")
                                                    m_form.Actions[j].Sort = 4;
                                                if(!m_form.Actions[j].Sort)
                                                    m_form.Actions[j].Sort = 3;
                                            }
                                            m_form.Actions.sort(function (a, b) {
                                                if (a.Sort == b.Sort)
                                                    return 0;
                                                if (a.Sort > b.Sort) {
                                                    return 1;
                                                } else {
                                                    return -1;
                                                }
                                            });
                                        }
                                    );
                                });
                        },
                        function(){
                            return Application.FireWait("PageFetch", m_form);
                        }
                    );

                return Application.FireWait("PageFetch", m_form); //Issue #83 - Add event to manipulate page before load.
            },

            function () {

                if (m_form.Icon == "") {
                    m_form.Icon = "window";
                }                

                m_uid = m_id + m_view;

                //Initialize the form view.
                if (m_view == null || m_view == "") {
                    m_view = m_form.View;
                }
                m_form.View = Default(m_form.View, "");
                m_view = Default(m_view, "");

                //Load the layout.
                return _self.LoadLayout();
            },

            function () {

                //#100 - Check fields on open.
				if(Application.HasOption(m_form.Options,"skipfieldcheck") == false)
					for (var i = 0; i < m_form.Fields.length; i++) {
						var c = m_table.Column(m_form.Fields[i].Name);
						if (!c)
							Application.Error("Field " + m_form.Fields[i].Name + " does not exist in Table "+m_table.Name);
                }
			
                m_form.View = Application.CombineViews(m_form.View, m_view);
                m_view = m_form.View;

                if (
                    (m_form.Type == "Card" && Application.IsInMobile()) ||
                    (m_options.mobilegrideditor != null) ||
                    m_options.dialog == true ||
                    m_form.CloseAction != null ||
                    Application.HasOption(m_form.Options, "temp")
                )
                    m_temp = true;

				if(Application.HasOption(m_form.Options, "nottemp"))
					m_temp = false;
					
                if (m_options.record != null)
                    m_options.record.Temp = m_temp;

                if (m_options.caption != null) {
                    m_form.Caption = m_options.caption;
                }
                m_options.caption = m_form.Caption;
                m_form.Caption = "Loading...";

                var clsebtn = true;
                if (m_options.closebutton == false) clsebtn = false;

                var pos = Application.position.normal;
                if (m_options.factbox && !Application.IsInMobile())
                    pos = Application.position.right;
                if (m_options.block == true)
					if (!Application.IsInMobile())
						pos = Application.position.block;
                if (m_options.position != null) {
                    pos = m_options.position;
                }

                var diag = false;
                if(m_form.Option("dialog"))
                    m_options.dialog = true;
                //if (Application.IsInMobile())
                //    m_options.dialog = false;
                if (m_options.dialog == true)
                    diag = true;

                //Apply form options.
                if (m_form.Option("singleColumn") || Application.IsMobileDisplay())
                    m_options.singleColumn = true;

                //Tabname
                if (m_options.tabname == null && Application.IsInMobile())
                    m_options.tabname = "";

                var editpage = null;
                if (m_form.GetAction("Design Page") != null)
                    editpage = { type: "Page", name: m_form.Name };
                if (m_form.GetAction("Design Table") != null)
                    editpage = { type: "Table", name: m_options.tableid };
				if (m_form.GetAction("Customize Page") != null)
                    editpage = { type: "PageCustom", name: m_form.Name };
		    
                //Create the window.
                if (m_options.workspace != null) {
                    _base.Create(UI.IconImage(m_form.Icon) + ' ' + m_form.Caption, {
                        closebutton: clsebtn,
                        workspace: m_options.workspace,
                        shortcutWorkspace: null,
                        hidden: m_form.Fields.length == 0,
                        position: pos,
                        dialog: diag,
                        editpage: editpage,
                        editormode: m_options.editlinemode,
						removetitle: m_options.removetitle,
                        type: m_form.Type,
                        homepage: m_options.homepage
                    });
                } else if (m_parent == null) {
                    _base.Create(UI.IconImage(m_form.Icon) + ' ' + m_form.Caption, {
                        closebutton: clsebtn,
                        workspace: $("#AppWorkspace"),
                        shortcutWorkspace: $("#AppWindows"),
                        hidden: m_form.Fields.length == 0,
                        position: pos,
                        dialog: diag,
                        editpage: editpage,
                        editormode: m_options.editlinemode,
						removetitle: m_options.removetitle,
                        type: m_form.Type,
                        homepage: m_options.homepage
                    });
                } else {

                    var workspace = "#AppWorkspace";
                    if (m_options && m_options.factbox == true && !Application.IsInMobile())
                        workspace = "#AppSideWorkspace";

                    _base.Create(UI.IconImage(m_form.Icon) + ' ' + m_form.Caption, {
                        closebutton: false,
                        workspace: $(workspace),
                        shortcutWorkspace: null,
                        hidden: m_form.Fields.length == 0,
                        position: pos,
                        dialog: diag,
                        editpage: editpage,
                        editormode: m_options.editlinemode,
						removetitle: m_options.removetitle,
                        type: m_form.Type,
                        homepage: m_options.homepage
                    });
                }
				
				//Removed as jquery widgets trigger this
				if(Application.IsInMobile() && window.history && window.history.pushState && (diag || m_parent == null))
				    window.history.pushState({ windowid: _base.ID() }, window.title);
				
                if (m_form.Type == "List" && Default(m_form.CustomControl,"") == "")
                    _base.ShowExportCSV(_self.ExportCSV);

				_base.OnToggle = _self.OnToggle;

                _self.UpdateCaption();

                //Set close action.                
                if (m_form.CloseAction && !m_form.CustomControl && (m_options.dialog != true || Application.IsInMobile()))
                    _self.CreateOKButton();
                m_closeAction = function () {
                    return $codeblock(
                        function () {

                            if (!Application.HasOption(m_form.Options, "temp")) {

                                if (m_loaded && !_base.Visible()) //Show window (incase close all is called)
                                    UI.WindowManager.Open(_base.ID());

                                var w = $wait();
								
								var unsaved = false;
								if((m_record && m_record.UnsavedChanges() && m_record.Count > 0) || m_changed == true)
									unsaved = true;
								for(var i = 0; i < m_subPages.length; i++){
									var rec = m_subPages[i].Record();
									if((rec && rec.UnsavedChanges() && rec.Count > 0) || m_subPages[i].Changed() == true)
										unsaved = true;
								}

                                if (m_tempChanged == true) {

                                    //Changes need saving.
                                    Application.Confirm("You have unsaved changes. Do you wish to save?", function (r) {

                                        if (r) {

                                            //Save the page and close.
                                            Application.RunNext(function () {
                                                if (_base.Dialog()) {
                                                    _base.HideDialog(true);
                                                } else {
                                                    m_okClicked = true;
                                                    return _self.OnSave(true);
                                                }
                                            });

                                            //Cancel this close.
                                            _base.CancelClose(true);
                                            _self.HideLoad();
                                            w.resolve(false);

                                        } else {

                                            //Continue with the close.
                                            w.resolve(true);

                                        }
                                    }, "Save changes?","Yes","No");

                                } else if (unsaved) {

                                    //Record not filled out yet...
                                    Application.Confirm("Your changes have not been saved. Close anyway?", function (r) {
                                        if (!r) {
                                            _base.CancelClose(true);
                                            _self.HideLoad();
                                        }
                                        w.resolve(r);
                                    }, (m_changed ? "Don't leave yet..." : "Mandatory Fields Required"));
                                } else {
                                    return true;
                                }

                                return w.promise();
                            }
                            return true;
                        },
                        function (r) {
                            if (!m_okClicked && !m_form.RunFunctionOnCancel)
                                return;
                            if (r && m_form.CloseAction)
                                return _self.RunAction(m_form.CloseAction.Name, true);
                        }
                    );
                };

                //Add the window to the manager and open it.                
                if (m_parent == null) {
                    UI.WindowManager.Add(_self);
                    UI.WindowManager.PreLoad(_base.ID());
                } else {
                    if (m_options.mobilegrideditor == null)
                        m_parent.AddSubpage(_self);
                    _base.Hide();
                }

                //Set the window UID.
                _base.UID(m_uid);

                if (m_options.parentwin != null) {
                    m_openedFrom = m_options.parentwin;
                    m_openedFrom.AddChildWindow(_base);
                }

                //Show filters?
                if (m_form.Type != "List")
                    m_form.ShowFilters = false;
                if (m_form.ShowFilters && m_form.Fields.length > 0) {
                    m_filterToolbar = new FilterToolbar(_self);
                    m_filterToolbar.Create(_base, m_form, m_table);
                }

                _base.ShowLoad();

                _base.Progress(0);

                //Form actions.                
                var added = false;
                for (var i = 0; i < m_form.Actions.length; i++) {

                    var action = m_form.Actions[i];

                    var skip = false;
                    if (_self.ReadOnly() && (action.Type == "New" || action.Type == "Delete"))
                        skip = true;

                    if (Application.HasOption(action.Options, "desktoponly") && Application.IsInMobile())
                        skip = true;

                    if (Application.HasOption(action.Options, "mobileonly") && !Application.IsInMobile())
                        skip = true;

                    if (m_options.tabname != null && m_options.tabname != "")
                        skip = true;

                    if (m_options.mobilegrideditor != null)
                        skip = true;

                    if (action.Name.within(["Design Page", "Design Table", "Customize Page"]) && (!Application.IsInMobile() || Application.IsMobileDisplay()))
                        skip = true;

                    if (action.Name != "" && !skip) {

                        var func;
                        eval("func = function () {Application.RunNext(function () {return _self.RunAction('" + action.Name + "',true);},null,'ACTION" + action.Name + "');}");

                        if (action.Type == "New")
                            action.Image = "document_new";
                        if (action.Type == "Delete")
                            action.Image = "delete";
                        if (action.Type == "Filters")
                            action.Image = "row_add";
                        if (action.Type == "Refresh")
                            action.Image = "refresh";
                        if (action.Image == "")
                            action.Image = "nav_plain_blue";

						if(Application.IsInMobile() && Application.HasOption(action.Options,"lineaction")){
							
							m_lineActions.push(action);
							
						}else{
						
							var btn = _base.AddButton(action.Name, action.Image, Application.ProcessCaption(action.Name), func);
							m_buttons[action.Name] = btn;
							added = true;
						
						}
                    }
                }

                if (Application.IsInMobile()) {
                    _base.LoadedActions();
                }

                //Add special mobile actions.
                if (!m_form.CustomControl || m_form.CustomControl == "") {

                    if (Application.IsInMobile() && m_form.Type == "List" && !m_form.Option("noedit")) {
                        for (var i = 0; i < m_form.Fields.length; i++) {
                            if (m_form.Fields[i].Editable == true && (!Application.HasOption(m_form.Fields[i].Options,"desktoponly") || !Application.IsInMobile()) && (!Application.HasOption(m_form.Fields[i].Options,"mobileonly") || Application.IsInMobile())) {
                                m_enableEditMode = true;
                                break;
                            }
                        }
                    }
                }

                if (!added)
                    _base.HideActions();
            },

            function () {

                //Readonly?
                if (_self.ReadOnly()) {
                    for (var i = 0; i < m_form.Fields.length; i++) {
                        m_form.Fields[i].Editable = false;
                    }
                }

                //Load the page.
                return _self.Load();
            },
			
			function(){
				return Application.TourManager.CheckTour(_self);
			},
			
			function(ret){
				if(ret){
					var win = _base;
					if(m_form.Fields.length == 0 && m_subPages.length > 0)
						win = m_subPages[0];
					win.ShowHelp(function(){
						Application.RunNext(function(){
							Application.TourManager.RunTour(_self);
						});
					});				
				}else{
					_base.HideHelp();
				}
				
				//Load toggle state
				if((m_layout && m_layout.state && m_layout.state > 0) || m_options.minimized)
					_base.ToggleState(true);
				
				return _self;
			}

        );

            return w.promise();

        };

        this.Load = function () {

            Application.LogDebug("Loading PageViewer: " + m_id);

            var w = $wait();

            $code(

                function () {

                    if (m_options.record != null)
                        return m_options.record;

                    //Create a record set for this page.
                    return new Record(m_form.SourceID);
                },

                function (r) {

                    m_record = r;
                    m_record.Temp = m_temp;

                    //Add mandatory fields.
                    for (var i = 0; i < m_form.Fields.length; i++) {
                        if (m_form.Fields[i].Mandatory)
                            m_record.AddMandatoryField(m_form.Fields[i].Name);
                        if (m_form.Option("loadColumnsOnly"))
                            m_record.AddLookupField(m_form.Fields[i].Name);
                    }

                    //Set the view.                                
                    m_record.View = m_view;

                    //Retrieve filters.
                    if (m_form.ShowFilters && m_layout && m_layout.Filters && !Application.IsInMobile() && !Application.HasOption(m_form.Options,"clearfilters") && !m_options.searchmode) {
                        for (var i in m_layout.Filters) {
							if(m_layout.Filters[i] != null)
								m_record.Filter(i, m_layout.Filters[i]);
                        }
                    }                                           

                    //Load the form.
                    if (m_form.CustomControl && m_form.CustomControl != "") {

                        eval("m_customControl = new " + m_form.CustomControl + "(null, _self);");
                        m_controls.push(m_customControl);

                        m_customControl.View = _self.View;
                        m_customControl.MergeView = _self.MergeView;
                        m_customControl.FocusControl = _self.FocusControl;
                        m_customControl.XFocusControl = _self.XFocusControl;
                        m_customControl.Page = _self.Page;
                        m_customControl.Type = _self.Type;
                        m_customControl.AddChildWindow = _self.AddChildWindow;

                        if (Application.IsInMobile()) {
                            return m_customControl.CreateMobile(_base, m_form);
                        } else {
                            return m_customControl.CreateDesktop(_base, m_form);
                        }
                    }
                    if (m_form.Type == "Card") {
                        return _self.LoadCardForm();
                    } else {
                        return _self.LoadListForm();
                    }
                },

                function () {

                    //Hide additional fields.
                    _self.HideAdditonal(true);

                    //Resize window (mobile only)
                    if (Application.IsInMobile()) {

                        $(".placeholder").css("height", '800px');
                        $.mobile.resetActivePageHeight();
                        $(".placeholder").css("height", '1px');
                        $.mobile.resetActivePageHeight();

                        //Hide child tabs.
                        //if (Application.IsMobileDisplay() && m_parent && m_options.mobilegrideditor != true && m_options.promoted != true)
                        //    _base.ToggleState();
                    }

                    //Update the page.
                    if (m_parent == null || m_options.record != null)
                        return _self.Update(true,null,false);
                },

                function () {

                    //Open the window.
                    if (m_parent == null) {
                        UI.WindowManager.Open(_base.ID());
                    } else if (m_options.dialog == true) {
                        _base.Show();
                    }

                    if (m_customControl)
                        $("#saveBtn,#saveCloseBtn,#saveNewBtn,#closeBtn").hide();					
					
					_self.Resize();
					
                    //_self.HideLoad();
                    if(m_parent == null)
                    	Application.Fire("PageLoad", _self);

                    return _self;
                }

            );

            return w.promise();

        };
		
		this.SkipPageRefresh = function(){
			
			var skipupdate = false;
			if(m_causedUpdate && m_record){
				
				skipupdate = true;														

				if(Application.HasOption(m_form.Options,"skiprefresh"))				
					return true;
				
				//Check page options.
				if(Application.HasOption(m_form.Options,"refresh"))
					skipupdate = false;
				
				//Check field options.
				var field = m_form.GetField(m_causedUpdate);
				if(field && (Application.HasOption(field.Options,"refresh") || field.CustomControl == "ImageLookup"))
					skipupdate = false;
				
				if(field && Application.HasOption(field.Options,"skiprefresh"))				
					return true;
				
				//Check the view.
				if(m_record.View && (m_record.View.indexOf(m_causedUpdate+'=')!=-1 || m_record.View.indexOf('('+m_causedUpdate+')') != -1))
					skipupdate = false;				
				
				//Check code;
				if(skipupdate){
					var col = m_table.Column(m_causedUpdate);
					if(col){																						
						if(col.PrimaryKey)
							skipupdate = false;
					}
				}
				
				//Check flowfields.
				if(skipupdate){
					for (var i = 0; i < m_table.Columns.length; i++) {
						var col = m_table.Columns[i];
						if(col.LookupFilters && (col.LookupFilters.indexOf(m_causedUpdate+'=')!=-1 || col.LookupFilters.indexOf('('+m_causedUpdate+')') != -1))
							skipupdate = false;				
					}
				}
				
				//Check record validate.
				if(skipupdate){
					for (var i = 0; i < m_record.Functions.length; i++) {
						if (m_record.Functions[i][0] == m_causedUpdate) {
							if(m_record.Functions[i][1].indexOf("rec") != -1)
								skipupdate = false;
							break;
						}
					}
				}
				
			}
			return skipupdate;
			
		};		
		
        this.Update = function (first_, showProgress_, skipOpenFunc_) {

			if(m_form && Application.HasOption(m_form.Options,"norefresh") && first_ && skipOpenFunc_){
				return;
			}
					
            first_ = Default(first_, false);
            showProgress_ = Default(showProgress_, true);		
			skipOpenFunc_ = Default(skipOpenFunc_, true);

			//Partial refresh.
			var skipupdate = _self.SkipPageRefresh();
					
			
            //_self.SaveLayout();

            var w2 = $wait();

            $code(

            Application.BeginTransaction,

            function () {

				if(!_self || skipupdate)return;
			
                if (!m_temp)
                    _self.ShowLoad();
                _self.LoadControls(false);

                if (showProgress_)
                    _base.Progress(20);

                //Set the view.                
                m_record.View = Application.ViewSubstitute(m_record.View);

                //On open action.
                if (first_ && m_form.OpenAction && !skipOpenFunc_) {		
					Application.Fire("OpenPage");				
                    return _self.RunIndividualAction(m_form.OpenAction.Name, false, false);
                }
            },

			function(){
				var maxrows = Default(Application.OptionValue(m_form.Options,"maxrows"),0);
				if(maxrows > 0){
					
					var skip = true;
					if (m_form.SkipRecordLoad) {						
						var filters = _self.Filters();
						for (var i = 0; i < filters.length; i++) {
							var pagefield = m_form.GetField(filters[i].Name.replace("FF$", ""));
							if (pagefield)
								skip = false;
						}
					}else{
						skip = false;
					}
					
					if(!skip)
						COUNT(m_record.Table, m_record.View.replace(Application.GetSorting(m_record.View),""), function(c){
							if(c.Count > maxrows){
								var w = $wait();
								Application.Confirm("There are more than "+maxrows+" records. Do you wish to continue?",function(b){								
									if(b){									
										w.resolve();
									}else{
										setTimeout(function(){
											Application.Error("Cancelled");
										},10);
									}
								});
								return w.promise();
							}
						});
				}
			},
			
            function () {

				if(!_self || skipupdate)return m_record;
			
                if (m_form.SkipRecordLoad) {

                    var clear = true;
                    var filters = _self.Filters();
                    for (var i = 0; i < filters.length; i++) {
                        var pagefield = m_form.GetField(filters[i].Name.replace("FF$", ""));
                        if (pagefield)
                            clear = false;
                    }

                    var g = _self.GetPageGrid();

                    if (clear) {
                        if (g)
                            Application.Loading.ShowOverlay("gbox_" + g.ID() + "table", "Please apply a filter to continue");
                        m_record.Clear();
                        return m_record;
                    } else {
                        if (g)
                            Application.Loading.HideOverlay("gbox_" + g.ID() + "table");
                    }
                }

				var isnew = true;
				if(m_record.Record)
					isnew = m_record.Record.NewRecord;
                if (m_options.mode && m_options.mode == "New" && first_ && isnew)
                    return m_record.New();

                if (m_form.Fields.length == 0)
                    return m_record;

                if (m_options.record != null)
                    return m_record;

                if (first_ || m_form.Type == "List" || (!Application.restrictedMode && m_options.homepage) || (!m_tempChanged && m_temp))
                    if (!Application.HasOption(m_form.Options, "temp"))
                        return m_record.FindFirst();

				if (!Application.HasOption(m_form.Options, "skipfirst"))
					m_record.First();
				
                return m_record;
            },

            //Liveapp #75 - Offline flowfield
           function (r) {			  			  

               if (!_self || skipupdate) return r;

			   if(m_options.pos && first_)
					r.SetPosition(m_options.pos);
			   
               if (!Application.IsOffline() && !Application.HasOption(m_form.Options, "calcclientfields"))
                   return r.CalcClientSideFields();
			   
			   if(m_form.Type == "Card")
				    return r.CalcClientSideFields();

               //Loop records in offline mode.
               if (r.Count > 0) {
                   r.First();
                   return $loop(function () {
                       return $codeblock(
                           function () {
                               return r.CalcClientSideFields();
                           },
                           function () {
                               if (r.Next())
                                   return $next;
                               r.First();
                               return r;
                           }
                       );
                   });
               }

               return r;
           },

            function (r) {

                if (!_self || skipupdate) return;

                if (showProgress_)
                    _base.Progress(30);

                if (r == null)
                    Application.Error("Invalid record");			
				
                m_record = r;
                m_record.Temp = m_temp;

                //No records found.
                if (m_record.Count == 0) {

                    _self.EnableControls(false);

                } else { //Records found.                    

                    _self.EnableControls(true);

                }

                _self.UpdateCaption();

                //Update filters.
                if (m_form.ShowFilters && m_filterToolbar)
                    m_filterToolbar.SetFilters(null, first_ && !skipOpenFunc_);

                return _self.UpdateControls(first_, showProgress_);
            },

            function () {

				if(!_self)return;
			
                //Focus on first row                
                var grd = _self.GetPageGrid();
                if (grd) {
                    if (first_) {
                        if (m_record.Count > 0) {
                            grd.SelectRow(1);							
                            grd.ScrollToRow(1);
                            _self.GetRecordByRowId(1);
                        }
                    } else {
                        if (grd.SelectedRow()) {
							grd.SelectRow(grd.SelectedRow());
                            grd.ScrollToRow(grd.SelectedRow());
                            _self.GetRecordByRowId(grd.SelectedRow());
                        }
                    }
                }

                return _self.UpdateSubPages(true, showProgress_,skipOpenFunc_);
            },

            Application.CommitTransaction,

            function () {
				
				if(!_self)return;
				
                if (!Application.IsInMobile())
                    _self.LoadControls(true);

                _self.HideLoad();

                if (m_focusControl != null && m_form.Type == "Card" && !Application.IsInMobile())
                    m_focusControl.select();

                //Focus on first editable field.                
                if (first_ && m_form.Type == "Card" && !Application.IsInMobile() && !Application.HasOption(m_form.Options,"skipfocus")) {                    
					for (var i = 0; i < m_form.Fields.length; i++) {
                        var c = _self.GetControl(m_form.Fields[i].Name);
                        if (m_form.Fields[i].Editable && c && !c.NoFocus) {
                            Application.RunNext(_self.GetControl(m_form.Fields[i].Name).Focus);
                            break;
                        }
                    }
                }

                if (m_form.Type == "Card")
                    _self.DisableKeys(false);

                if (m_options.editlinemode != null) {
                    $('#' + _base.ID() + "LeftColumn").css("padding-bottom", "0px");
                    $('#' + _base.ID() + "RightColumn").css("padding-bottom", "0px");
                }

                if (showProgress_)
                    _base.Progress(100);

				if (_base.Dialog())
					Application.RunNext(_base.CenterDialog);
					
                if (m_options.homepage != true && m_options.mobilegrideditor != true && m_parent && m_parent.Record()) {
                    if (m_parent.Record().NewRecord && !Application.HasOption(m_parent.Page().Options, "temp")) {
                        _base.ShowOverlay();
                    } else {
                        _base.HideOverlay();
                    }
                }
				
				//_self.ResizeParent();

				m_lastView = m_record.View;
				
                m_loaded = true;
            }
        );

            return w2.promise();
        };

        this.UpdateSubPages = function (first_, showProgress_, skipOpenFunc_) {

			first_ = Default(first_, true);
		
            Application.LogDebug("Updating Subpages");

            if (m_subPages.length > 0)
                return $loop(function (i) {

                    if (showProgress_)
                        _base.Progress(_base.Progress() + ((i + 1) / m_subPages.length * 25));

                    Application.LogDebug("Updating Subpage: " + i);

                    var w = $wait();

                    $code(

                            function (v) {

								var page = m_subPages[i];
							
								var skipupdate = false;
								if(m_causedUpdate){
									
									skipupdate = true;
									
									//Check page options.
									if(Application.HasOption(m_form.Options,"refresh"))
										skipupdate = false;
									
									//Check field options.
									var field = m_form.GetField(m_causedUpdate);
									if(field && Application.HasOption(field.Options,"refresh"))
										skipupdate = false;
									
									//Check view.
									var view = page.FormView();
									if(view && (view.indexOf(m_causedUpdate+'=')!=-1 || view.indexOf('('+m_causedUpdate+')') != -1))
										skipupdate = false;
								}
								
								if(skipupdate)
									return;
							                                
                                var v = Application.MergeView(page.FormView(), m_record);
                                page.View(v);
                                	return page.Update(first_, showProgress_, skipOpenFunc_);
                            },

                            function () {
                                //Continue?
                                if (i < m_subPages.length - 1)
                                    return $next;
                            }
                        );

                    return w.promise();

                });
        };

        this.OnShow = function () {

            var grd = _self.GetPageGrid();
            if (grd && grd.SelectedRow())
                grd.ScrollToRow(grd.SelectedRow());

            if (m_parent == null) //Only run this on parent
                $("#lnkInfo").hide();

            try {
                for (var i = 0; i < m_form.TabList.length; i++) {
                    if (m_form.TabOption(m_form.TabList[i], "factbox")) {
                        if (Application.IsInMobile()) {
                            $("#lnkInfo").show();
                        } else {
                            if (!Application.App.SideVisible())
                                Application.App.ToggleSide();
                        }
                    }
                }
            } catch (e) {
            }

            if (Application.IsInMobile() && (m_parent == null || _base.Dialog()) && !Application.HasOption(m_form.Options,"hidesave")) {

                $("#saveBtn,#saveCloseBtn").show();
                if (Application.HasOption("savenew", m_form.Options))
                    $("#saveNewBtn").show();
                $("#divMobileFooter,#okBtn,#customBtn1,#customBtn2,#closeBtn").hide();

                function ShowTick(){
                    $("#"+_base.ID()+"containertitle").css("width","calc(100vw - 100px)");
                    if(!$("#"+_base.ID()+"containerok").is(":visible")){
                        $("#"+_base.ID()+"containerok").click(function () { 
                            setTimeout(function(){
                                Application.RunNext(function(){                    
                                    return UI.WindowManager.OnSave(true);
                                });
                            },500); //Delay here to wait for field validation
                            return false;
                        }).show().ripple(); 
                    }
                }
                if (m_form.Type == "Card" && !m_options.homepage && (m_parent == null || _base.Dialog())){
                    ShowTick();
                }else if (m_form.CloseAction && !m_customControl) {
                    $("#okBtn").show();
                    $("#saveBtn,#saveCloseBtn,#saveNewBtn").hide();
                    ShowTick();
                }

            }					

            if (m_customControl && m_customControl.OnShow)
                m_customControl.OnShow();

        };

        this.OpenPageTab = function (tabname_) {

            return $codeblock(
            function () {

                var rec = new Record();
                rec.Copy(m_record);

                var page = new PageViewer({ id: m_id, view: m_view, record: rec, tabname: tabname_ });

                page.CloseFunction(function () {
                    var w = $wait();
                    $code(_self.Update);
                    return w.promise();
                });

                return page.Open();
            }
        );
        };

        this.GetInfo = function () {

            if (m_form == null) {
                return
            }

			var view = "";
			if(m_record)
				view = Application.MergeView(m_record.View, m_record);
			
            return {
                ID: m_form.Name,
                View: view
            };
        };

        this.Caption = function (caption) {
            m_options.caption = caption;
            _self.UpdateCaption();
        };

        this.UpdateCaption = function (extra) {

            extra = Default(extra, "");
            var caption = m_options.caption;
            caption = Default(caption, "New Window");

            if (caption.indexOf("{") != -1) {

                //Update caption from record.
                var check = new RegExp('(\{)(.*?)(\})', 'g');
                var consts = caption.match(check);
                if (consts) {
                    for (j = 0; j < consts.length; j++) {
                        var name = consts[j].replace(check, '$2');
                        if (m_record && name != "" && m_record[name] != null) {
                            caption = caption.replace("{" + consts[j].replace(check, '$2') + "}", m_record[name]);
                        }
                    }
                }

                //Update caption from filters.
                var filters = Application.GetFilters(m_view);
                for (var i = 0; i < filters.length; i++) {
                    var filter = filters[i];
                    caption = caption.replace("{" + filter[0] + "}", filter[1].replace(">", "").replace("<", "").replace("=", "").replace(".", ""));
                }

                //Hide unmerged fields. 
                var check = new RegExp('(\{)(.*?)(\})', 'g');
                var consts = caption.match(check);
                if (consts)
                    for (j = 0; j < consts.length; j++)
                        caption = caption.replace("{" + consts[j].replace(check, '$2') + "}", "");

            }

            caption = caption + extra;
            if (caption.indexOf(" - ") == caption.length - 3)
                caption = caption.substr(0, caption.indexOf(" - "));

            //Update caption.
            if (m_options.mobilegrideditor != true) {
                _base.SetTitle(UI.IconImage(m_form.Icon) + ' ' + caption);
            } else {
                _base.SetTitle(caption);
            }
        };

        this.UpdateControls = function (first_, showProgress_) {

            Application.LogDebug("Updating Controls.");

            if (m_controls.length > 0)
                return $loop(function (i) {

                    if (showProgress_)
                        _base.Progress(_base.Progress() + ((i + 1) / m_controls.length * 25));

                    Application.LogDebug("Updating Control: " + i);

                    var w = $wait();

                    $code(

                    function () {

                        var cont = m_controls[i];

                        //Grid control.
                        if (cont.ObjectType() == "Grid") {

                            //Set Selected.
                            var selectedrec = cont.DataSourceById(cont.SelectedRow());
                            if (selectedrec != null)
                                selectedrec = selectedrec.Record.RecID;

                            return _self.UpdateGrid(cont, selectedrec);

                        } else {
                            return cont.Update(m_record);
                        }

                    },

                    function () {
                        //Continue?
                        if (i < m_controls.length - 1)
                            return $next;
                    }
                );

                    return w.promise();

                });

        };

        this.LoadControls = function (loaded_) {

            for (var i = 0; i < m_controls.length; i++) {
                m_controls[i].Loaded(loaded_);
            }
        };

        this.HideAdditonal = function (hide_, tab_) {

            tab_ = Default(tab_, null);

            for (var i = 0; i < m_controls.length; i++) {
                if (m_controls[i].Field().Importance == "Additional" && (tab_ == null || m_controls[i].Field().TabName == tab_)) {
                    if (hide_) {
                        m_controls[i].Hide();
                    } else {
                        m_controls[i].Show();
                    }
                }
            }
        };

        this.EnableControls = function (enable_) {

            for (var i = 0; i < m_controls.length; i++) {
                m_controls[i].Enabled(enable_, false);
            }
        };

        this.HideDropdowns = function () {

            for (var i = 0; i < m_controls.length; i++) {
                if (m_controls[i].HideDropdown) {
                    m_controls[i].HideDropdown();
                }
            }
        };

        this.DisableKeys = function (value) {

            if (Application.IsInMobile())
                return;

            m_disableKeys = value;
            if (m_parent) {
                m_parent.DisableKeys(value);
            }
        };

        this.ShowLoad = function () {

            _base.ShowLoad();

            if (m_options.homepage == true)
                return;

            for (var i = 0; i < m_tabs.length; i++) {
                m_tabs[i].ShowLoad();
            }
            for (var i = 0; i < m_subPages.length; i++) {
                m_subPages[i].ShowLoad();
            }					
        };

        this.HideLoad = function (all) {

            _base.HideLoad(all);
            for (var i = 0; i < m_tabs.length; i++) {
                m_tabs[i].HideLoad(all);
            }
            for (var i = 0; i < m_subPages.length; i++) {
                m_subPages[i].HideLoad(all);
            }
        };

        this.ResizeParent = function () {
            if (m_parent) {
                m_parent.Resize();
            } else {
                _self.Resize();
            }
        };

        this.SetOuterHeight = function (height) {
            _base.SetOuterHeight(height);
        };

        this.Close = function () {
            if (m_options.closebutton == false) return;
            return UI.WindowManager.Close(_base.ID());
        };
		
		this.CloseSilent = function () {
            if (m_options.closebutton == false) return;
            return UI.WindowManager.Close(_base.ID(), true, true);
        };

        this.LoadLayout = function () {

            m_layout = null;

			if (Application.IsInMobile() || Application.HasOption(m_form.Options,"nolayout"))
                return;
			
            return $codeblock(

                function () {
                    return Application.GetUserLayout(Application.auth.Username, m_id);
                },

                function (layout) {

                    if (layout != "") {
                        m_layout = $.parseJSON(layout);
                        m_layout.Filters = Default(m_layout.Filters, null);
                    }

                }

            );

        };

        this.SaveLayout = function () {

            if (Application.IsInMobile() || Application.HasOption(m_form.Options,"nolayout"))
                return;

            Application.RunNext(function () {

				if(!_self) return;
				
                var filters = null;
                if (m_layout)
                    filters = m_layout.Filters;

                m_layout = new Object();
                m_layout.columns = null;

                var grd = _self.GetPageGrid();
                if (grd) {
                    m_layout.columns = new Array();
                    var cols = grd.GetColumns();
                    for (var i = 0; i < cols.length; i++) {
                        var col = new Object();
                        col.name = cols[i].name;
                        col.width = cols[i].width;
                        col.hidden = cols[i].hidden;
                        m_layout.columns.push(col);
                    }
                }

                if (m_form.ShowFilters)
                    m_layout.Filters = filters;

				m_layout.state = _base.State();	

				m_layout.tabs = [];
				for(var i = 0; i < m_tabs.length; i++){
					m_layout.tabs.push(m_tabs[i].State());
				}
				
                return Application.SaveUserLayout(Application.auth.Username, m_id, $.toJSON(m_layout));                 

            },null,null,true);
        };

        this.ClearLayout = function () {

            m_layout = null;

            Application.RunNext(function () {

                return $codeblock(

                    Application.BeginTransaction,

                    function () {
                        return Application.DeleteUserLayout(Application.auth.Username, m_id)
                    },

                    Application.CommitTransaction,

                    function () {
                        Application.Message("You must re-open the form for the changes to take effect.");
                    }

                );

            });

        };

        this.CreateOKButton = function () {

            if (!Application.IsInMobile()) {

                var toolbar = _base.Toolbar3();
                toolbar.addClass("ui-widget ui-state-default");
                toolbar.css("display", "inline-block");
                toolbar.css("width", "100%");
                toolbar.css("text-align", "right");

                var btn = $("<button id='" + $id() + "' style='width: 100px; margin: 10px;'><b>OK</b></button>");
                btn.button().click(function () {
                    Application.RunNext(function () {
                        m_okClicked = true;
                        return _self.OnSave(true);
                    });
                });
                toolbar.append(btn);

            } else {

                // $("#okBtn").unbind("tap");
                // $("#okBtn").on("tap", function () {
                    // Application.RunNext(function () {
                        // m_okClicked = true;
                        // return _self.OnSave(true);
                    // });
                // });

            }
        };

        this.OnSave = function (close, skipcheck, okclicked) {

            close = Default(close, false);

            if (!skipcheck)
                if (!_self.OnBeforeClose(true))
                    return false;

            if (okclicked)
                m_okClicked = okclicked;

            //m_okClicked = true;
            _self.Save();

            return $codeblock(

                Application.BeginTransaction,

                function () {

                    _self.ShowLoad();				
					
                    //Don't save temp records.
                    if (Application.HasOption(m_form.Options, "temp") || m_okClicked == false)
                        if (!Application.HasOption(m_form.Options, "savetemp"))
                            return false;

					if(_self.ReadOnly())
						return false;
						
                    //Allow for temp list pages.
                    if (m_form.Type == "List") {
                        m_record.First();
                        if (m_record.Count > 0)
                            return $loop(function (i) {
                                return $codeblock(
                                    function () {
                                        m_record.Temp = false;
                                        //m_record.ClearXRec(false, m_table.TableKeys[0].Columns.split(",")); //Issue #78 - Xrec issue in mobile
                                        if (m_record.NewRecord == true) {
                                            return m_record.Insert(true, null, _self);
                                        } else {
                                            return m_record.Modify(true, _self);
                                        }
                                    },
                                    function () {
                                        if (m_record.Next())
                                            return $next;
                                        return m_record;
                                    }
                                );
                            });
                    }

                    m_record.Temp = false;
                    //m_record.ClearXRec(false, m_table.TableKeys[0].Columns.split(",")); //Issue #78 - Xrec issue in mobile
                    if (m_record.NewRecord == true) {
                        return m_record.Insert(true, null, _self);
                    } else {
                        return m_record.Modify(true, _self);
                    }
                },
                function (r) {

                    _self.HideLoad();

                    if (r != false) {

                        m_record = r;
                        m_record.Temp = m_temp;

                        //Update filters.
                        var filters = Application.GetFilters(m_view);
                        for (var i = 0; i < filters.length; i++) {
                            var f = m_record.GetField(filters[i][0]);
                            if (f && filters[i][1] != f.Value) {
                                m_record.Filter(filters[i][0], f.Value);
                            }
                        }

                        m_tempChanged = false;

                    }

                    return Application.CommitTransaction();
                },

                function () {

                    if (close && m_options.dialog != true)
                        if (!m_parent) {
                            return _self.Close();
                        } else {
                            return m_parent.Close();
                        }

                    if (close)
                        return _self.OnClose(m_okClicked);

                    m_okClicked = true;
                    //if (!m_form.CloseAction)
                    //    $("#divMobileFooter").hide();

                    if (m_options.mobilegrideditor == null) {
                        return _self.Update();
                    } else {
                        return _self.UpdateControls();
                    }
                }
            );

            return true;
        };

        this.Save = function () {

            var grd = _self.GetPageGrid();
            if (grd)
                grd.Save();

        };

        this.ClearCache = function () {
            m_form.ClearCache();
            Application.Message("You must re-open the form for the changes to take effect.");
        };

        this.MergeView = function (view) {
            return Application.MergeView(view, m_record);
        };

        this.ChangeMade = function () {
            if (m_form.Name.within(m_designerPages))
                m_changed = true;
            if (m_form.Name.within(m_designerPages2))
                m_parent.Changed(true);
            if (m_form.Name.within(m_designerPages3) && !Application.IsInMobile())				
				m_openedFrom.Changed(true);				             
        };

        this.GetControl = function (id) {
            for (var j = 0; j < m_controls.length; j++) {
                if (m_controls[j].Field().Name == id) {
                    return m_controls[j];
                }
            }
            return null;
        };

        this.MandatoryCheck = function () {
            //Check mandatory.
            for (var j = 0; j < m_form.Fields.length; j++) {
                var field = m_form.Fields[j];
                if (field.Mandatory) {
                    if ((m_record[field.Name] == 0 || m_record[field.Name] == null || m_record[field.Name] == "null") && field.OptionCaption == "") {
                        var cont = _self.GetControl(field.Name);
                        if (cont)
                            _self.XFocusControl(cont.Control());
                        Application.Error(field.Caption + " must have a value.");
                    }
                }
            }
        };

        this.ValidCheck = function () {
            //Check valid.
            for (var j = 0; j < m_form.Fields.length; j++) {
                var field = m_form.Fields[j];
                var cont = _self.GetControl(field.Name);
                if (cont) {
                    if (cont.Invalid()) {
                        _self.XFocusControl(cont.Control());
                        Application.Error(field.Caption + " has an invalid value.");
                    }
                }
            }
        };

        //#endregion

        //#region Record Functions

        this.OnNew = function () {

            var grd = _self.GetPageGrid();

            return $codeblock(

            function () {

                _self.ShowLoad();

                //New record.                
                return m_record.New();
            },

            function (r) {

                if (r == null)
                    Application.Error("Invalid record");

                m_record = r;
                m_record.Temp = m_temp;

                var action = m_form.OnNewAction();
                if (action) {
                    return $codeblock(
                        Application.BeginTransaction,
                        function () {
                            return m_form.RunActionCode(m_record, action, _self);
                        },
                        Application.CommitTransaction
                    );
                }
            },

            function () {

                if (m_form.Type == "Card") {

                    //Update the form.
                    return _self.Update();

                } else {

                    if (m_customControl)
                        return m_customControl.OnNew(m_record);

                    if (grd) {
                        //Add the grid row.
                        var data = _self.ConvertRecordToData();
                        return grd.AddRow(data.RowId, data);
                    }
                }
            },

            function () {

                //Edit first cell.
                if (grd) {
                    grd.EditFirstCell();
                    if (!Application.IsInMobile()) {
                        grd.ScrollToRow(m_record.Count);
                        return _self.UpdateSubPages(true, false);
                    }
                }

            },

            function () {

                _self.HideLoad();

                //Change was made.
                _self.ChangeMade();

                if (m_enableEditMode) {
                    var data = _self.ConvertRecordToData();
                    return _self.GridDoubleClick(data.RowId);
                }

                //Run the double click action.
                if (m_form.DoubleClickAction() && m_form.RunDblClickOnNew) {
                    if (m_record.Blank == true)
                        m_nextPageOptions = { mode: 'New' };
                    return _self.RunAction(m_form.DoubleClickAction().Name, true);
                }
            }

        );
        };

        this.OnDelete = function () {

            return $codeblock(
            function () {

                var msg = "Are you sure you wish to delete this record?";
                if (m_actionsQueue > 1)
                    msg = "Do you wish to delete these records?";

                if (m_delete == null) {

                    var w2 = $wait();

                    Application.Confirm(msg, function (r) {
                        m_delete = r;
                        w2.resolve(r);
                    }, "Are you sure?");

                    return w2.promise();

                } else {
                    return m_delete;
                }
            },
            function (r) {
                if (r == true)
                    return _self.DeleteRecord();
            }
        );
        };

        this.DeleteRecord = function () {

            var w = $wait();

            $code(

                    Application.BeginTransaction,

                    function () {

                        _self.ShowLoad();

                        //Get the record (List form only).
                        //if (m_form.Type == "List") {
                        //    var grd = _self.GetPageGrid();
                        //    _self.GetRecordByRowId(grd.SelectedRow());
                        //}

                        return m_record.Delete(true, _self);
                    },

                    function (r) {

                        if (r == null)
                            Application.Error("Invalid record");

                        m_record = r;
                        m_record.Temp = m_temp;

                        var action = m_form.OnDeleteAction();
                        if (action)
                            return m_form.RunActionCode(m_record, action, _self);
                    },

					Application.CommitTransaction,

					function () {

					    m_actionsQueue -= 1;
					    if (!_self.ActionsFinished())
					        return;

					    _self.HideLoad();

					    //Change was made.
					    _self.ChangeMade();

					    if (m_form.Type == "Card") {

					        //Close the form.
					        _self.Save();
					        return _self.Close();

					    } else {

					        //Select previous row.                            
					        var grd = _self.GetPageGrid();																			
					        if (grd) {
								
								//Clear selected rows.
								grd.ClearSelected();
								
					            var prevrow = grd.SelectedRow(-1);
					            if (prevrow != null)
					                grd.SelectRow(prevrow);
					        }
					        //Update the form.
					        return _self.Update();
					    }
					}
                );

            return w.promise();

        };

        this.FixValue = function (field, value_) {

            //Check for nulls
            if (value_ == "" || value_ == "null" || (value_ && value_.trim && value_.trim() == ""))
                value_ = null;

            if (value_ != null && field.OptionCaption == "") {

                if (field.Type == "Date") {

                    var dte = Application.ParseDate(value_);
                    if (dte == null)
                        Application.Error("Invalid date: " + value_);
                    value_ = dte;

                } else if (field.Type == "Time") {

                    value_ = Application.ParseTime(value_);

                } else if (field.Type == "DateTime") {

                    var dte = Application.ParseDateTime(value_);
                    if (dte == null)
                        Application.Error("Invalid date time: " + value_);
                    value_ = dte;

                } else if (field.Type == "Integer") {

                    var i = parseInt(value_);
                    if (isNaN(i))
                        Application.Error("Invalid integer: " + value_);
                    value_ = i;

                } else if (field.Type == "Decimal") {

                    var i = parseFloat(value_);
                    if (isNaN(i))
                        Application.Error("Invalid decimal: " + value_);
                    value_ = i;

                } else if (field.Type == "Code") {

                    value_ = value_.toString().toUpperCase();

                } else if (field.Type == "Boolean") {

                    if (value_ == "Yes" || value_ == true || value_ == "true") {
                        value_ = true;
                    } else {
                        value_ = false;
                    }
                }
            }

            if (field.OptionCaption != "" && value_ != null && field.Type != "BigText") {

                var found = false;
                var vals = field.OptionString.split(",");
                var captions = field.OptionCaption.split(",");
                for (var i = 0; i < vals.length; i++) {
                    if (value_ == captions[i]) {
                        if (field.Type == "Integer") {
                            value_ = parseInt(vals[i]);
                        } else {
                            value_ = vals[i];
                        }
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    for (var i = 0; i < vals.length; i++) {
                        if (captions[i].toLowerCase().indexOf(value_.toLowerCase()) != -1) {
                            value_ = vals[i];
                            found = true;
                            break;
                        }
                    }
                    if (!found)
                        Application.Error("Invalid value: " + value_);
                }
            }

            if (!Application.IsInMobile() && field.LookupDisplayField != "" && value_ == null)
                m_record["FF$" + field.Name] = null;		

            return value_;
        };

        this.RecordValidate = function (name_, value_, rowid_, showLoad_) {

			//Partial refresh.
			m_causedUpdate = null;			
		
            var field = m_form.GetField(name_);
            if (field == null) {
                Application.Error("Field not found: " + name_);
            }

            //#85 - Sanitize value.			
            if (!Application.HasOption(field.Options, "SkipSanitze") && !Application.HasOption(field.Options, "skipsanitize"))
                value_ = Application.SanitizeString(value_);		    
			
			if (value_ == "" || value_ == "null")
                value_ = null;
			
			//Partial refresh.
			if(m_record.NewRecord == false || m_record.Temp)
				m_causedUpdate = name_;
			var skipupdate = _self.SkipPageRefresh();
			
            //Show load?
            showLoad_ = Default(showLoad_, true);
            if (showLoad_ && !skipupdate)
                _self.ShowLoad();

            _self.DisableKeys(true);
            _self.HideDropdowns();

            m_col = name_;
            m_row = rowid_;

            //Check lookup value.			
            if (field.LookupTable != "" && !m_form.FieldOption(field, "anyvalue") && value_ != null && value_ != "") {
                Application.RunNext(function () {
                    return $codeblock(
                        function () {
                            return Application.LookupRecord(field, _self, value_, function () { });
                        },
                        function (vals) {

                            //if (m_form.Type == "List")
                            //    _self.GetRecordByRowId(rowid_);

                            var f = field.LookupField;
                            if (field.LookupDisplayField != "")
                                f = field.LookupDisplayField;

                            for (var i = 0; i < vals.length; i++) {
                                if (vals[i][f] == value_) {
                                    if (field.LookupDisplayField != "") {
                                        m_record["FF$" + field.Name] = vals[i][field.LookupDisplayField];
                                        m_record.SaveCurrent(null, true);
                                        m_record[field.Name] = vals[i][field.LookupField];
                                        m_comboSelected = true;
                                    }
                                    return vals[i][f];
                                }
                            }

                            for (var i = 0; i < vals.length; i++) {
                                if (vals[i][f].toLowerCase().indexOf(value_.toLowerCase()) != -1) {
                                    if (field.LookupDisplayField != "") {
                                        m_record["FF$" + field.Name] = vals[i][field.LookupDisplayField];
                                        m_record.SaveCurrent(null, true);
                                        m_record[field.Name] = vals[i][field.LookupField];
                                        m_comboSelected = true;
                                    }
                                    return vals[i][f];
                                }
                            }

                            return null;
                        },
                        function (ret) {
                            if (ret == null)
                                Application.Error("Invalid value: " + value_);
                            value_ = ret;
                        },
                        function () {
                            return _self.FinishValidate(name_, value_, rowid_, showLoad_, field);
                        }
                    );
                });
                return;
            }

            Application.RunNext(function () {                
                return _self.FinishValidate(name_, value_, rowid_, showLoad_, field);
            });

        };

        this.FinishValidate = function (name_, value_, rowid_, showLoad_, field_) {            

			//Partial refresh.			
			var skipupdate = _self.SkipPageRefresh();
			
            if (field_.LookupDisplayField != "" && value_ != "" && value_ != null && field_.CustomControl == "" && m_comboSelected) {
                value_ = m_record[name_];
            }			

            m_comboSelected = false;

            return $codeblock(

            Application.BeginTransaction,

            function () {
                //Get the record (List form only).                    
                if (m_form.Type == "List") {
                    _self.GetRecordByRowId(rowid_);
                }
                return _self.Validate(name_, value_, rowid_, field_);
            },

            Application.CommitTransaction,

            function () {

                m_col = null;
					m_row = null;									

					if (m_form.Type == "List")
						_self.DisableKeys(false);

					//A change has been made.
					_self.ChangeMade();

                //Reload page?
                if (field_.ReloadOnValidate || (m_form.Type == "Card" && !Application.HasOption(field_.Options,"skipupdate"))) {
                    return _self.Update(false, false);
					} else {
						if(!skipupdate)
							_self.HideLoad();
					}
				},
				
				function(){
					
					//Partial refresh.
					m_causedUpdate = null;	
				}

			);
        };

        this.Validate = function (name_, value_, rowid_, field_) {

            if (!m_form.FieldOption(field_, "anyvalue"))
                value_ = _self.FixValue(field_, value_);

            return $codeblock(

            function () {

                if (m_temp) {
                    if (!field_.Mandatory || (value_ != null && value_ != "null" && value_ != 0 && value_ != "") || field_.OptionCaption != "") {
                        _self.TempChanged(true, true);
                    }
                }

                //Validate field.
                return m_record.Validate(name_, value_, _self);
            },

            function (r) {

                if (r == false)
                    return false;

                //OK Button handles modify.
                if (m_temp)
                    return r;

                if (r.NewRecord == true) {
                    return r.Insert(true, null, _self);
                } else {
                    return r.Modify(true, _self);
                }

                return r;
            },

            function (r) {

                if (r == false)
                    return;

                if (m_temp) {
                } else {
                    _self.TempChanged(false, false);
                }

                //Save the record.
                if (r == null)
                    Application.Error("Invalid record");

                m_record = r;
                m_record.Temp = m_temp;

				//Update filters.
				if(!Application.HasOption(m_form.Options,"skipupdatefilters")){
					var filters = Application.GetFilters(m_view);
					for (var i = 0; i < filters.length; i++) {
                        var f = m_record.GetField(filters[i][0]);
                        if(f){
                            var field = m_table.Column(f.Name);
                            if (f && field && filters[i][1] != f.Value && field.PrimaryKey){
                                m_record.Filter(filters[i][0], f.Value);
                            }
                        }
					}
				}
				
				//Update UID
				if(!m_record.UnsavedChanges()){
					m_uid = m_id + m_record.View;
					_base.UID(m_uid);
				}
				
                //Update xrec. 
                if (!m_temp && !m_record.UnsavedChanges()) //Issue #78 - Xrec issue in mobile
                    m_record.UpdateXRec();

				var skipupdate = _self.SkipPageRefresh();
					
                //Refresh the row.								
                if (m_form.Type == "List" && !skipupdate) {

                    m_record.RowId = rowid_;
                    var grd = _self.GetPageGrid();
                    grd.SetDataRow(rowid_, _self.ConvertRecordToData());

                    //Refresh totals.
                    if (grd.Footer() == true)
                        _self.GridLoadFooter(grd);

					return _self.UpdateSubPages(true, false);
                }
            }
        );

        };

        this.ClearFilters = function () {

            //m_record.Filters = new Array();
            //m_record.View = m_view;

            for (var i = 0; i < m_form.Fields.length; i++) {
                m_record.Filter(m_form.Fields[i].Name);
                m_record.Filter("FF$" + m_form.Fields[i].Name);
                if (m_layout) {                    
                    m_layout.Filters[m_form.Fields[i].Name] = null;
                    m_layout.Filters["FF$"+m_form.Fields[i].Name] = null;
                }
            }

            if (!Application.IsInMobile()) 
                _self.SaveLayout();            
                
            Application.RunNext(_self.Update);
        };

        this.Filter = function (col, value, update, applywildcard) {

            update = Default(update, true);
            applywildcard = Default(applywildcard, false);

            //#42 - Add wildcard to filter
            var field = m_record.GetField(col);
            if (field && applywildcard) {
                if (field.Type.within(["Code", "Char", "Text", "BigText"]) || col.indexOf("FF$") == 0) {
                    if (value && !Application.HasFilterChar(value)) {
                        if (value.indexOf("*") != 0)
                            value = "*" + value;
                        if (value[value.length - 1] != "*")
                            value += "*";
                    }
                }
            }

            m_record.Filter(col, value);

            if (!Application.IsInMobile()) {
                if (!m_layout) {
                    m_layout = new Object();                    
                }
                m_layout.Filters = Default(m_layout.Filters,new Object());
                m_layout.Filters[col] = value;
                _self.SaveLayout();
            }

            if (update)
                return _self.Update();
        };

        //#endregion

        //#region Temp Record Functions

        this.TempChanged = function (value, showSave) {

            if (typeof value != "undefined") {

                m_tempChanged = value;
                m_okClicked = false;
                showSave = Default(showSave, false);
                if (m_customControl != null)
                    showSave = false;

                //if (showSave && m_temp && m_options.mobilegrideditor == null && value)
                //    $("#divMobileFooter").show();

            } else {

                return m_tempChanged;
            }
        };

        //#endregion

        //#region Card Form Functions

        this.LoadCardForm = function () {

            var w = $wait();

            $code(

            _self.LoadTabs,

            function () {

                //Add padding to the top.
                if(!Application.IsInMobile()){
                    $('#' + _base.ID() + "main").css("padding-top", "10px");
                    $('#' + _base.ID() + "main").css("padding-bottom", "10px");
                }
        
                _base.AddColumns();

                $('#' + _base.ID() + "LeftColumn").css("display", "none");
                $('#' + _base.ID() + "RightColumn").css("display", "none");

                if (m_options.factbox || m_options.dialog == true || m_options.singleColumn == true)
                    _base.SingleColumn(true);

                var tabindex = 10;
                var tabs = m_form.GetTabs();

                //Apply field options.
                for (var j = 0; j < m_form.Fields.length; j++) {

                    if (m_form.FieldOption(m_form.Fields[j], "mobileonly") && !Application.IsInMobile())
                        m_form.Fields[j].Hidden = true;
                    if (m_form.FieldOption(m_form.Fields[j], "desktoponly") && Application.IsInMobile())
                        m_form.Fields[j].Hidden = true;
					
					if (m_form.FieldOption(m_form.Fields[j], "offlineonly") && !Application.IsOffline())
                        m_form.Fields[j].Hidden = true;
                    if (m_form.FieldOption(m_form.Fields[j], "onlineonly") && Application.IsOffline())
                        m_form.Fields[j].Hidden = true;

                    if (Application.IsInMobile()) {
                        if (m_form.Fields[j].Importance == "Additional" && m_options.mobilegrideditor != null) {
                            m_form.Fields[j].Importance = "Standard";
                        }
                        if (m_form.Fields[j].Type == "BigText" && m_options.mobilegrideditor != null && m_form.Fields[j].LookupTable == "")
                            m_form.Fields[j].CustomControl = "NotesBox";
                    }
                }

                for (var j = 0; j < tabs.length; j++) { //Tab Loop

                    var skiptab = false;
                    if (!skiptab) {
                        for (var add = 0; add < 2; add++) { //Additonal Fields Loop

                            if (add == 1 && Application.IsInMobile())
                                break;

                            var fields = m_form.GetFieldsByTab(tabs[j].Name, add, (Application.IsInMobile() && m_options.mobilegrideditor));

                            //Used for tab index calclulation.
                            var half = Math.round(fields.length / 2);
                            var left = false;
                            var hasAdditonal = false;

                            for (var k = 0; k < fields.length; k++) { //Field Loop

                                //Get the field.
                                var field = fields[k];

                                if (field.Hidden == false) {

                                    if (field.Importance == "Additional")
                                        hasAdditonal = true;

                                    field.TabIndex = tabindex;
                                    tabindex += 1;

                                    left = false;
                                    if (k + 1 <= half || m_form.FieldOption(field, "leftcolumn") == true)
                                        left = true;
                                    if (m_form.FieldOption(field, "rightcolumn") == true)
                                        left = false;

                                    if (field.CustomControl && field.CustomControl != "") {
                                        _self.AddCustomControl(field, left);
                                    } else if (field.LookupTable != '' || field.OptionCaption != "") {
                                        _self.AddComboField(field, left);
                                    } else if (field.IncrementDelta != 0 && !Application.IsInMobile()) {
                                        _self.AddSpinnerField(field, left);
                                    } else if (field.Type == "Date") {
                                        _self.AddDateField(field, left);
                                    } else if (field.Type == "DateTime" && !Application.IsInMobile()) {
                                        _self.AddDateTimeField(field, left);
                                    } else if (field.Type == "Boolean") {
                                        _self.AddCheckboxField(field, left);
                                    } else if (field.Type == "Time") {
                                        _self.AddTimeField(field, left);
                                    } else {
                                        _self.AddTextField(field, left);
                                    }
                                }
                            }

                            if (hasAdditonal) {
                                var tab = _self.GetTab(tabs[j].Name);
                                var tabname = tabs[j].Name;
                                if (tabname == "")
                                    tabname = "General";
                                tab.Main().append("<div id='additional" + _base.ID() + tabname + "' style='cursor: pointer; padding: 5px; width: 200px;'><table><tr><td><img src='https://go.scrubit.com.au/Images/Icons/icon-arrowright.png' /></td><td id='addtext" + _base.ID() + tabname + "'> Show more fields</td></tr></table></div>");
                                $("#additional" + _base.ID() + tabname).on("click", function () {
                                    var tabname = $(this).attr("id").replace("additional" + _base.ID(), "");
                                    if ($("#addtext" + _base.ID() + tabname).text() == " Show more fields") {
                                        _self.HideAdditonal(false, tabname);
                                        $("#addtext" + _base.ID() + tabname).text(" Hide additional fields");
                                    } else {
                                        _self.HideAdditonal(true, tabname);
                                        $("#addtext" + _base.ID() + tabname).text(" Show more fields");
                                    }
                                    _self.Resize();
                                });
                            }
                        }
                    }
                }
            }
        );

            return w.promise();

        };

        this.LoadTabs = function () {

			if(m_options.mobilegrideditor)
				return;
		
            var w2 = $wait();

            var subpages = 0;

            $code(

            function () {

                if (m_form.TabList.length > 0)
                    return $loop(function (i) {

                        var w = $wait();

                        $code(

                            function () {

                                var tab = m_form.TabList[i];

                                if (Application.IsInMobile() && m_form.TabOption(tab, "desktoponly"))
                                    return;

                                if (!Application.IsInMobile() && m_form.TabOption(tab, "mobileonly"))
                                    return;

                                if (tab.ID != "") {

                                    _self.OnShow();
                                    var block = false;
                                    subpages += 1;

                                    if (m_form.TabOption(tab, "block"))
                                        block = true;

                                    var pos = null;
                                    if (m_options.homepage == true) {

										if (m_form.SubPages() == 1) {
											pos = Application.position.rolefull;
                                        }else if (m_form.SubPages() <= 2) {
                                            pos = Application.position.rolehalf;
                                        } else if (m_form.SubPages() == 3) {
                                            if (subpages <= 2) {
                                                pos = Application.position.rolequarter;
                                            } else {
                                                pos = Application.position.rolehalf;
                                            }
                                        } else {
                                            pos = Application.position.rolequarter;
                                        }

                                    }

                                    var subpage = new PageViewer({ 
										id: tab.ID, 
										parent: _self, 
										factbox: m_form.TabOption(tab, "factbox"), 
										caption: tab.Name, 
										block: block, 
										view: tab.View, 
										position: pos, 
										homepage: m_options.homepage, 
										promoted: m_form.TabOption(tab, "promoted"), 
										height: Application.OptionValue(tab.Options, "height"),
										minimized: Application.OptionValue(tab.Options, "minimized"),
										removetitle: m_form.TabOption(tab,"removetitle")										
									});
									subpage.TabName(tab.Name);
                                    return subpage.Open();

                                } else {
                                    _self.CreateTab(tab);
                                }
                            },

                            function (pge) {

                                //if (pge && Application.IsMobileDisplay() && m_options.homepage == true && subpages == 1) {
                                //    pge.ToggleState();
                                //}
																
                                //Continue?
                                if (i < m_form.TabList.length - 1)
                                    return $next;															
                            }
                        );

                        return w.promise();

                    });

            }
        );

            return w2.promise();

        };

        this.CreateTab = function (tab_) {

            //var icon = Default(Application.OptionValue(tab_.Options, "icon"), m_form.Icon);

            var pos = Application.position.normal;
            var workspace = "#AppWorkspace";
            if (m_form.TabOption(tab_, "factbox") && !Application.IsInMobile()) {
                workspace = "#AppSideWorkspace";
                pos = Application.position.right;
            } else if (m_form.TabOption(tab_, "block")) {
                pos = Application.position.block;
            }

			var title = tab_.Name;
            //var title = UI.IconImage(icon) + ' ' + tab_.Name;
            //title = title.replace('ActionIcon', 'Icon').replace('width:15px;height:15px', 'width:30px;height:30px');
            var win = new Window();
            win.Create(title, {
                closebutton: false,
                workspace: $(workspace),
                shortcutWorkspace: null,
                position: pos,
                removetitle: m_form.TabOption(tab_,"removetitle"),
                type: "Card"
            });

            //Add padding to the top.
            if(!Application.IsInMobile()){
                $('#' + win.ID() + "main").css("padding-top", "10px");
                $('#' + win.ID() + "main").css("padding-bottom", "10px");
            }

            win.Caption = tab_.Name;
            win.AddColumns();
            if (m_form.TabOption(tab_, "factbox") || Application.IsMobileDisplay())
                win.SingleColumn(true);
            win.HideActions();
            win.ShowLoad();

            if (Application.IsInMobile()) {
                win.Hide();
                //if (Application.IsMobileDisplay())
                    //win.ToggleState();
            }
			
			//Load toggle state
			if((m_layout && m_layout.tabs && m_layout.tabs.length >= m_tabs.length && m_layout.tabs[m_tabs.length] > 0) || Application.HasOption(tab_.Options,"minimized"))
				win.ToggleState(true);


            //Override window methods.       
            win.OnError = _self.OnError;
            win.GetInfo = _self.GetInfo;
            win.ClearLayout = _self.ClearLayout;
            win.ClearCache = _self.ClearCache;
            win.OnKeyPress = _self.OnKeyPress;
			win.OnToggle = _self.OnToggle;
			
			win.TabName(tab_.Name);

            m_tabs.push(win);
            _base.AddSubWindow(win);
        };

        this.GetTab = function (name_) {
            if (name_ != "General") {
                for (var i = 0; i < m_tabs.length; i++) {
                    if (m_tabs[i].Caption == name_) {
                        return m_tabs[i];
                    }
                }
            }
            return _base;
        };

        this.GetTabColumn = function (tab_, cont_, left_) {
			
			var ignore = cont_.IgnoreColumns();
			if(!ignore && cont_.Field() && Application.HasOption(cont_.Field().Options,"ignorecolumns"))
                ignore = true;
			
            if (ignore) {
                $('#' + tab_.ID() + "LeftColumn").css("padding-bottom", "0px");
                $('#' + tab_.ID() + "RightColumn").css("padding-bottom", "0px");
                return tab_.Main();
            } else {
                $('#' + tab_.ID() + "LeftColumn").css("display", "inline-block");
                $('#' + tab_.ID() + "RightColumn").css("display", "inline-block");
                return tab_.GetColumn(left_);
            }
        };

        this.AddCustomControl = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var cont = null;
            eval("cont = new " + field_.CustomControl + "(field_, _self);");
            cont.OnValueChange = this.RecordValidate;
            if (Application.IsInMobile()) {
                cont.CreateMobile(this.GetTabColumn(tab, cont, left_));
            } else {
                cont.CreateDesktop(this.GetTabColumn(tab, cont, left_));
            }

            m_controls.push(cont);
        };

        this.AddTextField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var txt = new Textbox(field_, _self);
            txt.OnValueChange = this.RecordValidate;
            txt.Create(this.GetTabColumn(tab, txt, left_));

            m_controls.push(txt);
        };

        this.AddTimeField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var txt = new TimePicker(field_, _self);
            txt.OnValueChange = this.RecordValidate;
            txt.Create(this.GetTabColumn(tab, txt, left_));

            m_controls.push(txt);
        };

        this.AddSpinnerField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var txt = new Spinner(field_, _self);
            txt.OnValueChange = this.RecordValidate;
            txt.Create(this.GetTabColumn(tab, txt, left_));

            m_controls.push(txt);
        };

        this.AddDateField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var dte = new DatePicker(field_, _self);
            dte.OnValueChange = this.RecordValidate;
            dte.Create(this.GetTabColumn(tab, dte, left_));

            m_controls.push(dte);
        };

        this.AddDateTimeField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var dte = new DateTimePicker(field_, _self);
            dte.OnValueChange = this.RecordValidate;
            dte.Create(this.GetTabColumn(tab, dte, left_));

            m_controls.push(dte);
        };

        this.AddComboField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var cmb = new Combobox(field_, _self);
            cmb.OnValueChange = this.RecordValidate;
            cmb.Create(this.GetTabColumn(tab, cmb, left_));

            m_controls.push(cmb);
        };

        this.AddCheckboxField = function (field_, left_) {

            var tab = _self.GetTab(field_.TabName);

            var chk = new Checkbox(field_, _self);
            chk.OnValueChange = this.RecordValidate;
            chk.Create(this.GetTabColumn(tab, chk, left_));

            m_controls.push(chk);
        };

        this.AddSubpage = function (page_) {
            m_subPages.push(page_);
            _base.AddSubWindow(page_);
        };
		
		this.RemoveSubpage = function (index_) {
            for(var i = 0; i < m_subPages.length; i++){
				if(i == index_){
					m_subPages[i].Remove();
					_base.RemoveSubWindow(m_subPages[i].ID());					
					m_subPages.splice(i,1);
					return;
				}
			}            
        };
		
		this.RemoveTab = function (index_) {
            for(var i = 0; i < m_tabs.length; i++){
				if(i == index_){
					m_tabs[i].Remove();
					_base.RemoveSubWindow(m_tabs[i].ID());					
					m_tabs.splice(i,1);
					return;
				}
			}            
        };

        //#endregion

        //#region List Form Functions

        this.LoadListForm = function () {

            return $codeblock(

                _self.LoadTabs,

                function () {
                    //Load the page grid.
                    _self.LoadPageGrid();
                }
            );

        };

        this.GenerateGridData = function () {

            var recs = new Array();
            if (m_record.Count > 0){
				m_record.First();
                do {
                    recs.push(_self.ConvertRecordToData());
                }
                while (m_record.Next())
			}
            return recs;
        };

        this.ConvertRecordToData = function () {

            var r = new Record();
            r.Copy(m_record);
            r.RowId = r.Position;
            r.RowId++;
            return r;
        };

        //#endregion

        //#region Grid Functions

        this.ExportCSV = function () {

            var data = _self.GetPageGrid().DataSource();
            var csv_data = _self.GenerateCSVData(data);
            Application.FileDownload.DownloadText(m_id+".csv", csv_data, "text/csv;charset=utf-8;");
        };

        this.GenerateCSVData = function (data_) {

            var csvFile = '';

            var hdrrow = [];
            for (var j = 0; j < m_form.Fields.length; j++) {
                hdrrow.push(m_form.Fields[j].Caption);
            }
            csvFile += ProcessCSVRow(hdrrow);

            for (var i = 0; i < data_.length; i++) {
                var row = [];
                for (var j = 0; j < m_form.Fields.length; j++) {
                    var val = Default(data_[i]["FF$" + m_form.Fields[j].Name], data_[i][m_form.Fields[j].Name]);                    
                    row.push(FormatData(val, m_form.Fields[j].Type));
                }
                csvFile += ProcessCSVRow(row);
            }
            return csvFile;
        };

        function FormatData(value_, type_) {

            if (value_ == null || typeof value_ == "undefined")
                return "";

            //Dates and times
            if (type_ == "Date") {
                return $.format.date(value_, "dd/MM/yyyy");
            } else if (type_ == "DateTime") {
                return $.format.date(value_, "dd/MM/yyyy hh:mm a");
            } else if (type_ == "Time") {
                return $.format.date(value_, "hh:mm a");
            }

            return value_;
        };

        function ProcessCSVRow(row) {
            var finalVal = '';
            for (var j = 0; j < row.length; j++) {
                var innerValue = row[j] === null ? '' : row[j].toString();
                if (row[j] instanceof Date) {
                    innerValue = row[j].toLocaleString();
                };
                var result = innerValue.replace(/"/g, '""');
				result = result.replace(/\<br\>/g,'\n');
				result = result.replace(/\<br\/\>/g,'\n');
				
				result = Application.SanitizeString(result);
				
                if (result.search(/("|,|\n)/g) >= 0)
                    result = '"' + result + '"';
                if (j > 0)
                    finalVal += ',';
                finalVal += result;
            }
            return finalVal + '\r\n';
        };

        this.LoadPageGrid = function () {

            var grd = new Grid(null, _self);

            //Add fields.        
            var totals = false;
            for (var i = 0; i < m_form.Fields.length; i++) {

                //Get the field.
                var field = m_form.Fields[i];

                var skip = false;
                if (Application.IsInMobile() && field.Importance == "Additional")
                    skip = true;

                if (m_form.FieldOption(field, "mobileonly") && !Application.IsInMobile())
                    skip = true;
                if (m_form.FieldOption(field, "desktoponly") && Application.IsInMobile())
                    skip = true;

                if (m_form.FieldOption(field, "cardonly") && Application.IsInMobile())
                    skip = true;

                if (!skip) {

                    //Check totals.
                    if (field.Totals == true)
                        totals = true;

                    //Get width from layout.
                    if (m_layout && m_layout.columns) {
                        for (var j = 0; j < m_layout.columns.length; j++) {
                            if (m_layout.columns[j].name == field.Name) {
                                field.Width = m_layout.columns[j].width;
                                break;
                            }
                        }
                    }

                    //Add the field to the grid.
                    grd.AddColumn(field);
                }
            }
            
            grd.Create(_base, totals);            

            //Load layout.
            if (m_layout && m_layout.columns) {
                for (var i = 0; i < m_layout.columns.length; i++) {
                    try {
                        grd.SetColumnHidden(m_layout.columns[i].name, m_layout.columns[i].hidden);
                    } catch (e) {
                    }
                }
            }

            //Overrides.
            grd.OnCellSubmit = _self.GridCellSubmit;
            grd.OnDoubleClick = _self.GridDoubleClick;
            grd.OnLoadFooter = _self.GridLoadFooter;
            grd.OnResizeCol = _self.SaveLayout;
            grd.OnColumnChooserDone = _self.SaveLayout;
            grd.OnRowSelect = _self.GridRowSelect;

            //Add the grid to controls.
            m_controls.push(grd);
        };

        this.GridRowSelect = function (rowid) {
            setTimeout(function () {
                Application.RunNext(function () {
                    _self.GetRecordByRowId(rowid);
                    if (m_subPages.length > 0) {
                        return _self.UpdateSubPages(true, false);
                    }
                });
            }, 500);
        };

        this.GetPageGrid = function () {

            for (var i = 0; i < m_controls.length; i++) {

                if (m_controls[i].ObjectType() == "Grid")
                    return m_controls[i];

            }

            return null;
        };

        this.GetRecordByRowId = function (rowid) {

            if (m_record.Count == 0 || rowid == null)
                return;

            m_record.First();
            do {
                if (rowid == (m_record.Position + 1))
                    break;
            } while (m_record.Next());

        };

        this.GetRecordByRecId = function (recid) {

            if (m_record.Count == 0 || recid == null)
                return;

            m_record.First();
            do {
                if (m_record.Record.RecID == recid)
                    break;
            } while (m_record.Next());

        };

        this.UpdateGrid = function (cont, selectedrec) {

            var w = $wait();

            $code(

                _self.GenerateGridData,

                function (data) {

                    if (data == null)
                        data = new Array();
                    cont.DataSource(data);
                    return cont.Bind(selectedrec);
                }

            );

            return w.promise();
        };

        this.SelectRowByRec = function (cont, selectedrec) {
            var data = cont.DataSource();
            for (var i = 0; i < data.length; i++) {
                if (data[i].Record.RecID == selectedrec) {
                    cont.SelectRow(data[i].RowId);
                    return i;
                }
            }
            return 0;
        };

        this.GridResizeCol = function () {
            _self.SaveLayout();
        };

        this.GridDoubleClick = function (rowid, iRow, iCol, e) {

            if (!m_form.DoubleClickAction() && !m_enableEditMode)
                return;

			_self.ShowLoad();
			
            $thread(function () {

                var w = $wait();

                $code(

                function () {

                    _self.GetRecordByRowId(rowid);

                    if (Application.IsInMobile() && m_enableEditMode) {
                        return $codeblock(
                            function () {
                                
                                var p = new Page();
                                p.Name = m_id;
                                p.Copy(m_form);
                                p.Type = "Card";
								
                                var rec = new Record();
                                rec.Copy(m_record);
                                rec.Count = 1;
                                rec.Position = 0;
								
								var t = new Object();
								app_deepTransferObjectProperties.call(t, m_table);
								
                                var pv = new PageViewer({ id: m_id, caption: _base.Title(), page: p, table: t, dialog: true, record: rec, view: m_record.View, mobilegrideditor: true, parentviewer: _self });
                                pv.CloseFunction(function(){
									
									if (Application.HasOption(m_form.Options, "temp") && !Application.HasOption(m_form.Options, "savetemp")){
										m_record.TransferFields(pv.Record());
										m_record.SaveCurrent();
									}
									
									return _self.Update();
								});
                                return pv.Open();
                            }
                        );
                    }

                    return _self.RunAction(m_form.DoubleClickAction().Name, true);
                },
				
				_self.HideLoad
            );

                return w.promise();

            });

        };

        this.GridCellSubmit = function (rowid, cellname, value, iRow, iCol) {

            _self.RecordValidate(cellname, value, rowid);

            return value; //Must return the value.
        };

        this.GridLoadFooter = function (grd) {
            var data = new Object();
            for (var i = 0; i < m_form.Fields.length; i++) {
                var field = m_form.Fields[i];
                if (field.Totals == true) {
                    var d = Application.Fire("SumColumn", field.Name, m_record);
                    d = Default(d, null);
                    if (d != null) {
						if(d.toFixed){
							data[field.Name] = d.toFixed(2);
						}else{
							data[field.Name] = d;
						}
                    } else {
                        
						data[field.Name] = grd.SumColumn(field.Name);
						
						//Decimal fix.
						if(field.Type == "Integer")
							data[field.Name] = parseInt(data[field.Name]);
						if(field.Type == "Decimal")
							data[field.Name] = +parseFloat(data[field.Name]).toFixed(2);
                    }
                }
            }
            grd.Footer(data);
        };

        //#endregion

        //#region Action Functions

        this.RunAction = function (name_, trans_) {

            _self.Save();
            m_delete = null;

            var action = m_form.GetAction(name_);
            if (action == null)
                Application.Error("Action not found. Action: " + name_);

            m_actionsQueue = 1;

            if (m_form.Type == "Card") {

                return _self.RunIndividualAction(name_, trans_, false);

            } else {

                if (m_customControl != null)
                    return _self.RunIndividualAction(name_, trans_, false);

                var grd = _self.GetPageGrid();
                var id = grd.SelectedRow();
                _self.GetRecordByRowId(id);

                if (grd.SelectedRows().length == 0 || action.Type == "New" || Application.HasOption(action.Options, "singleaction"))
                    return _self.RunIndividualAction(name_, trans_, false);

                m_actionsQueue = 1 + grd.SelectedRows().length;

                var w = $wait();

                $code(

                function () {
                    _self.GetRecordByRowId(id);
                    return _self.RunIndividualAction(name_, trans_, false);
                },

                function () {
                    return $loop(function (i) {

                        var w2 = $wait();

                        $code(

                            function () {
                                _self.GetRecordByRecId(grd.SelectedRows()[i]);
                                return _self.RunIndividualAction(name_, trans_, false);
                            },

                            function () {
                                //Continue?
                                if (i < grd.SelectedRows().length - 1)
                                    return $next;
                            }
                        );

                        return w2.promise();

                    });
                }
            );

                return w.promise();
            }
        };

        this.RunIndividualAction = function (name_, trans_, hideLoad_) {

            if (name_ == null || name_ == "")
                return;

            trans_ = Default(trans_, false);
            hideLoad_ = Default(hideLoad_, true);

            //Refresh?
            if (name_ == "Refresh") {
                return _self.Update();
            }

            var action = m_form.GetAction(name_);
            if (action == null)
                Application.Error("Action not found. Action: " + name_);

            //Reset action view.
            action.View = "";

            //Built in actions.
            if (action.Type == "New") {
                var grd = _self.GetPageGrid();
                if (grd && grd.Loading())
                    Application.Error("Please wait for all the records to load.");
                return _self.OnNew();
            } else if (action.Type == "Delete") {
                return _self.OnDelete();
            } else if (action.Type == "Refresh") {
                return _self.Update();
            }

            if (action.RecordRequired == true && (m_record.Count == 0 || m_record.Record.NewRecord) && !m_nextPageOptions) {
                if (m_record.Count == 0) {
                    Application.Error("Please select a record.");
                } else {
                    Application.Error("The current record must be saved before you can run this action.");
                }
            }

            var w = $wait();

            $code(

            function () {

                if (!hideLoad_)
                    _self.ShowLoad();

                if (trans_)
                    return Application.BeginTransaction();
            },

            function () {

                if (Application.IsInMobile() && action.Type == "Open Page") {
                    window.scrollTo(0, 0);
                    document.body.scrollTop = 0;
                }

                //Get View.
                action.View = m_form.GetActionView(m_record, action);
                action.View = action.View.replace('\\', '\\\\');
				action.View = action.View.replace(/\'/g, '\\\'');

                //Run action code.
                return m_form.RunActionCode(m_record, action, _self);
            },

            function (msg) {

                if (m_form.Name.within(m_designerPages)) {
                    if (action.Name.indexOf("Save") != -1) {
                        m_changed = false;
                    }
                }

                m_actionsQueue -= 1;

                //Show the return message (if any).
                if (msg && msg != "" && _self.ActionsFinished())
                    Application.Message(msg);

                //Open Page action.
                if (action.Type == "Open Page") {
                    eval("Application.RunNext(function () { return _self.OpenPageAction(action, action.ReferencePage, '" + action.View + "');});");
                }
            },

            function () {
                if (trans_)
                    return Application.CommitTransaction();
            },

            function () {

                if (!_self.ActionsFinished())
                    return;

                _self.HideLoad();

                if (action.Type != "Open Page") {
                    if (action.Reload == true) {
                        return _self.Update();
                    } else if (action.ReloadParent == true) {
                        if (m_parent != null) {
                            return m_parent.Update();
                        }
                    }
                }
            }
        );

            return w.promise();
        };

        this.ActionsFinished = function () {
            return (m_actionsQueue <= 0);
        };

        this.OpenPageAction = function (action, id, view) {

            if (Application.IsInMobile())
                $("#divSideMenu,#divFactbox").panel("close");

			//Remove search.
			$(".searchdropdown").remove();
		
            return $codeblock(
                function () {

                    var opts = { id: id, view: view, readonly: action.OpenFormReadOnly };
                    if (m_form.ActionOption(action, "dialog") || _base.Dialog())
                        opts.dialog = true;
                    if (_self.ParentWindow() && _self.ParentWindow().Dialog())
                        opts.dialog = true;
                    if (m_nextPageOptions != null && m_nextPageOptions.mode != null)
                        opts.mode = m_nextPageOptions.mode;
                    opts.parentwin = _self.ParentWindow();

                    m_nextPageOptions = null;

                    var page = new PageViewer(opts);

                    //Setup the close function.
                    if (action.Reload == true) {
                        page.CloseFunction(function () {
                            var w = $wait();
                            $code(_self.Update);
                            return w.promise();
                        });
                    } else if (action.ReloadParent == true) {
                        page.CloseFunction(function () {
                            var w = $wait();
                            $code(
                                function () {
                                    if (m_parent != null) {
                                        return m_parent.Update();
                                    }
                                }
                            );
                            return w.promise();
                        });
                    }

                    return page.Open();
                }
            );
        };

		this.ShowLineActions = function(row,rowid){
			
			$(".lineactions,.lineactionsoverlay").remove();	
			
			var dd = $("<div class='lineactions'>");
			$("body").append(dd);						
            
            var fieldname = Application.OptionValue(m_form.Options,"hyperlink");
            var field = m_form.GetField(fieldname);
            dd.append("<div class='lineactions-title cut-text'>" +
            FormatData((row["FF$"+fieldname] ? row["FF$"+fieldname] : row[fieldname]),field.Type) + 
            "</div>");

			if(_self.EnableEditMode()){
				var func;
				eval("func = function () {$('.lineactions,.lineactionsoverlay').remove();_self.GridDoubleClick("+rowid+");}");
				_self.AddLineAction("EditRow", "redo", "Edit", func);
			}
			
			var j = 0;
			for(var i = 0; i < m_lineActions.length; i++){
				
				var action = m_lineActions[i];
				
				if(!action.Hide){
					
					var func;
					eval("func = function () {$('.lineactions,.lineactionsoverlay').remove();Application.RunNext(function () {return _self.RunAction('" + action.Name + "',true);},null,'ACTION" + action.Name + "');}");

					var pos = j;
					if(_self.EnableEditMode())
						pos += 1;
					j += 1;
					
					_self.AddLineAction(action.Name, action.Image, Application.ProcessCaption(Default(action.HTML,action.Name)), func, pos);
					
				}
			}
            
            var h = (j * 50) + 50 + (_self.EnableEditMode() ? 50 : 0);
			dd.css("left","0").css("top","100vh").animate({
                top: $(window).height() - h
            });
			
			var o = $('<div class="ui-widget-overlay app-overlay lineactionsoverlay"></div>');
			$("body").append(o);		
			o.width('100%').height('100%');
            o.show();
			
			o.on("click",function(){	
                $(".lineactions").animate({
                    top: $(window).height()
                },null,null,function(){
                    $(".lineactions,.lineactionsoverlay").remove();
                });	
			});
		};
		
		 this.AddLineAction = function (name, image, text, func, i) {

			var id = $id();

			var imgcode = ""
			if (image != "") {
                imgcode = "<i class='mdi "+UI.MapMDIcon(UI.MapIcon(image))+"' style='font-size: 20px'></i>&nbsp;";
			}
			var $action = $("<div id='" + id + "' data-ripple class='lineactions-btn'>" + imgcode + text + "</div>");

			$action.ripple({ color: 'gainsboro' }).click(func);

			$(".lineactions").append($action);
			
			return $action;
		};
	
        //#endregion       

        //#region Public Properties

        this.CustomControl = function () {
            return m_customControl;
        };

        this.Options = function () {
            return m_options;
        };

        this.AddOption = function (name, value) {
            m_options[name] = value;
        };

        this.Type = function () {
            return m_form.Type;
        };

        this.Window = function () {
            return _base;
        };

        this.ParentWindow = function () {
            if (m_parent != null)
                return m_parent; //.Window();
            return _self;
        };

        this.OpenedFrom = function () {
            return m_openedFrom;
        };

        this.Record = function (value) {
            if (typeof value == "undefined") {
                //Get the record (List form only).
                if (m_form.Type == "List") {
                    var grd = _self.GetPageGrid();
					if(grd){
						_self.GetRecordByRowId(grd.SelectedRow());
					}
                }
                return m_record;
            } else {
                m_record = value;
            }
        };

        this.FormView = function () {
            return m_form.View;
        };
		
		this.Loaded = function(value_) {

            if (value_ !== undefined) { //SET                
				m_loaded = value_;
            } else { //GET                
                return m_loaded;
            }
        };

        this.View = function (value_) {

            if (value_ !== undefined) { //SET
                if (m_record)
                    m_record.View = value_;
            } else { //GET
                if (m_record)
                    return m_record.View;
                return m_view;
            }
        };

        this.CancelClose = function (value_) {

            if (value_ !== undefined) {
                _base.CancelClose(value_);
            } else {
                return _base.CancelClose();
            }
        };
		
		this.GridEditMode = function(){
			return m_options.mobilegrideditor != null;
		};

        this.Filters = function () {
            return m_record.Filters();
        };

        this.LineEditor = function () {
            return m_lineEditor;
        };

        this.FocusControl = function (cont) {
            m_focusControl = cont;
        };

        this.XFocusControl = function (cont) {
            m_xFocusControl = cont;
        };

		this.CloseAction = function (func_) {
            m_closeAction = func_;
        };
		
        this.CloseFunction = function (func_) {
            m_closeFunc = func_;
        };

        this.ReadOnly = function () {

            if (m_options && m_options.readonly && m_options.readonly == true)
                return true;
			
			if(Application.HasOption(m_form.Options,"mobilereadonly") && Application.IsInMobile())
				return true;

			var editable = false;
			for (var i = 0; i < m_form.Fields.length; i++) {
				if(m_form.Fields[i].Editable)
					editable = true;
			}
			
			if(m_form.Actions.length > 0)
				editable = true;			
			
            return !editable;
        };

        this.Position = function () {
            return _base.Position();
        };

        this.Page = function () {
            return m_form;
        };

		this.Table = function () {
            return m_table;
        };
		
        this.FilterToolbar = function () {
            return m_filterToolbar;
        };

        this.Control = function (name_) {

            if (m_customControl && m_customControl.Control)
                return m_customControl.Control(name_);

            for (var i = 0; i < m_controls.length; i++) {
                if (m_controls[i].Field().Name == name_)
                    return m_controls[i];
            }			
			for (var i = 0; i < m_subPages.length; i++) {
				var cont = m_subPages[i].Control(name_);
				if(cont != null)
					return cont
			}		    
            return null;
        };

		this.Button = function(name){			
		    var btn = Default(m_buttons[name],null);
		    if (!btn) {
		        for (var i = 0; i < m_subPages.length; i++) {
		            var btn2 = m_subPages[i].Button(name);
		            if(btn2 != null)
                        return btn2
		        }
		    }
			if(!btn){
				for(var i = 0; i < m_lineActions.length; i++){				
					var action = m_lineActions[i];
					if(action.Name == name)
						return {
							hide: function(){
								m_lineActions[i].Hide = true;
							},
							show: function(){
								m_lineActions[i].Hide = false;
							},
							html: function(val){
								m_lineActions[i].Image = "";
								m_lineActions[i].HTML = val;
							}
						};
				}			
			}
			return btn;
		};

        this.ValidValue = function (name, valid, msg) {

            var cont = _self.Control(name);
            if (cont) {
                if (cont.Valid)
                    cont.Valid(valid, msg);
            }
        };

        this.Col = function (value_) {
            m_col = value_;
        };

        this.Row = function (value_) {
            m_row = value_;
        };

        this.CheckLayout = function (pge) {
            if (m_layout && m_layout.Filters) {
                Application.Confirm("One or more filters may have caused an error. Do you wish to clear them?", function (r) {
                    if (r == true) {
                        m_record.Filters = null;
                        _self.SaveLayout();
                    }
                    Application.RunNext(pge.Close);
                }, "Bad filters");
                return true;
            }
            return false;
        };

        this.ParentPage = function () {
            return m_parent;
        };

        this.SubPages = function () {
            return m_subPages;
        };

		this.Tabs = function () {
            return m_tabs;
        };
		
		this.GetTabByName = function(name){
			for(var i = 0; i < m_subPages.length; i++){
				if(m_subPages[i].TabName() == name)
				    return m_subPages[i];
				var nme = m_subPages[i].GetTabByName(name);
				if (nme)
				    return nme;
			}
			for(var i = 0; i < m_tabs.length; i++){
				if(m_tabs[i].TabName() == name)
					return m_tabs[i];
			}
			return null;
		};
		
		this.GetTabByID = function(id){
			for(var i = 0; i < m_subPages.length; i++){
				if(m_subPages[i].ID() == id)
					return m_subPages[i];
			}
			for(var i = 0; i < m_tabs.length; i++){
				if(m_tabs[i].ID() == id)
					return m_tabs[i];
			}
			return null;
		};
		
        this.OKClicked = function () {
            return m_okClicked;
        };

        this.Changed = function (value_) {

            if (value_ !== undefined) {
                m_changed = value_;
            } else {
                return m_changed;
            }

        };

        this.EnableEditMode = function () {
            return m_enableEditMode;
        };

        this.ComboSelected = function (value_) {
            if (typeof value_ == "undefined") {
                return m_comboSelected;
            } else {
                m_comboSelected = value_;
            }
        };
		
		this.LineActions = function () {
            return m_lineActions;
        };

        //#endregion          

        //#region Events

        this.OnError = function (e) {

            m_record.Temp = m_temp; //Reset this if the error occurs on save.            			

            //Partial refresh.            
            m_causedUpdate = null;

            if(Application.transactionStarted > 0)
                Application.RunNext(function () {
                    return $codeblock(
                        function () {
                            if (Application.auth.SessionID != "") { 
                                Application.supressServiceErrors = true;
                                return Application.RollbackTransaction();
                            }
                        },
                        function () {
                            Application.supressServiceErrors = false;
                        }
                    );
                });

            _self.LoadControls(true);
            m_okClicked = false;
            _self.HideLoad(true);
            _self.DisableKeys(false);

            if (Application.restrictedMode && m_loaded == false) {
                Application.ShowError(e, function () {
					window.location = Application.url + Application.auth.Instance;
				});
            } else {

                if (m_loaded && !_base.Visible()) //Show window (incase close all is called)
                    UI.WindowManager.Open(_base.ID());

                Application.ShowError(e, function () {
					
					//Update filters.
					m_view = m_lastView;
					m_record.View = m_view;
					if (m_form.ShowFilters && m_filterToolbar)
						m_filterToolbar.SetFilters(true);

					if (!Application.IsInMobile()) {
						if (!m_layout) {
							m_layout = new Object();                    
						}
						var filters = Application.GetFilters(m_view);
						m_layout.Filters = {};
						for (var i = 0; i < filters.length; i++) {
						    m_layout.Filters[filters[0]] = filters[1];
						}
						_self.SaveLayout();
					}					
					
                    if (m_loaded == false) {
                        if (_self.CheckLayout(_self))
                            return;
                        for (var i = 0; i < m_subPages.length; i++) {
                            if (m_subPages[i].CheckLayout(_self))
                                return;
                        }
                        Application.RunNext(_self.Close);
                        return;
                    }

                    if (m_form.Type == "List" && m_col == null) return;
                    if (m_form.Type == "Card" && m_xFocusControl == null) return;

                    //Rollback record.
                    m_record.RollBack();

                    if (m_form.Type == "List") {

                        var grd = _self.GetPageGrid();

                        if (grd) {

                            grd.SetDataRow(m_row, _self.ConvertRecordToData()); //Error record.

                            //Rollback current row (if the user moved).
                            var curr_row = grd.SelectedRow();
                            if (curr_row != m_row) {
                                _self.GetRecordByRowId(curr_row);
                                m_record.RollBack();
                                grd.SetDataRow(curr_row, _self.ConvertRecordToData());
                            }

                            //Go back to the error cell.
                            grd.SelectRow(m_row);
                            grd.EditCellByName(m_col);
                        }
                        m_col = null;
                        m_row = null;

                    } else {
                        m_focusControl = m_xFocusControl;
                        try {
                            m_focusControl.select();
                        } catch (e) {
                        }
                        Application.RunNext(_self.UpdateControls);
                    }
					
                });
            }
        };

        this.OnKeyPress = function (ev) {

            try {

                //F2.
                if (ev.which == 113) {
                    if (m_form.Type == "List") {
                        var grd = _self.GetPageGrid();
                        if (grd != null) {
                            grd.EditCurrentCell();
                        }
                    }
                    ev.preventDefault();
                    return false;
                }

                //F3.
                if (ev.which == 114 && m_form.InsertAllowed) {
                    Application.RunNext(function () { return _self.OnNew(); });
                    ev.preventDefault();
                    return false;
                }

                //F4.
                if (ev.which == 115 && m_form.DeleteAllowed) {
                    Application.RunNext(function () { return _self.OnDelete(); });
                    ev.preventDefault();
                    return false;
                }

                //F5.
                if (ev.which == 116 && !ev.ctrlKey) {					
                    Application.RunNext(function () { return _self.Update(true,true,true); }); //Issue #37 - Refresh flowfields.
                    ev.preventDefault();
                    return false;
                }

                //F7
                if (ev.which == 118) {
                    var grd = _self.GetPageGrid();
                    if (grd) {
                        var col = grd.CurrentColumn();
                        if (col) {
                            var frmfield = m_form.GetField(col.name);
                            var fld = $("#" + _base.ID() + "filterfields");
                            if (frmfield) {
                                fld.val(frmfield.Name);
                                m_filterToolbar.GetFilter(fld.val());
                            }
                        }
                    }
                    var input = $("#" + _base.ID() + "filterinput");
                    input.select();
                    ev.preventDefault();
                    return false;
                }

                //F8
                if (ev.which == 119) {

                    if (m_form.Type == "List") {
                        var grd = _self.GetPageGrid();
                        if (grd) {
                            var col = grd.CurrentColumn();
                            var rw = grd.SelectedRow(-1);
                            if (rw && col) {
                                var data = grd.DataSourceById(rw);
                                if (data) {
                                    var editor = grd.CurrentEditor(parseInt(rw) + 1);
                                    if (editor) {
                                        var val = data[col.name];
                                        var field = m_table.Column(col.name);
                                        if (field.Type == "DateTime")
                                            val = $.format.date(val, 'dd/MM/yyyy HH:mm');
                                        if (field.Type == "Time")
                                            val = $.format.date(val, 'HH:mm');
                                        if (field.Type == "Date")
                                            val = $.format.date(val, 'dd/MM/yyyy');
                                        if (field.LookupDisplayField != "")
                                            val = data["FF$" + col.name];
                                        editor.val(val);
                                        editor.change();
                                        if (editor.attr("skipSelect") != "true")
                                            setTimeout(function () { editor.select(); }, 10);
                                    }
                                }
                            }
                        }
                    }

                    ev.preventDefault();
                    return false;
                }

            } catch (e) {
                _self.OnError(e);
            }

        };

        this.OnBeforeClose = function (okclicked) {

            if (okclicked != null)
                m_okClicked = okclicked;

            this.Save();

            if (!okclicked)
                return true;

            try {
                _self.MandatoryCheck();
                _self.ValidCheck();
            } catch (e) {
                return false;
            }

            return true;
        };

        this.OnClose = function (okclicked) {

			if(m_options.homepage && Application.IsInMobile())
				Application.Error("You cannot close the dashboard");
		
            _self.Save();

            if (okclicked != null)
                m_okClicked = okclicked;

            _self.ShowLoad();

            var w = $wait();

            $code(

                function () {

                    if (m_closeAction != null && !_base.CancelClose()) {
                        return m_closeAction();
                    }
                },

                function () {
                    if (m_closeFunc != null && !_base.CancelClose()) {
                        return m_closeFunc(m_okClicked);
                    }
                },

                function () {

                    //Stop grid load.
                    var grd = _self.GetPageGrid();
                    if (grd)
                        grd.StopLoad();

                    _self.HideLoad();
                }
            );

            return w.promise();
        };

        this.OnResize = function (width) {

                var j = 0;
                var totalheight = _base.Height();
                if (_base.Hidden() == true)
                    totalheight = 0;

                for (var i = 0; i < m_tabs.length; i++) {
                    if (m_tabs[i].Position() == Application.position.normal || m_tabs[i].Position() == Application.position.rolefull) {
                        j += 1;
                        totalheight += m_tabs[i].Height();
                    }
                }

                for (var i = 0; i < m_subPages.length; i++) {
                    m_subPages[i].ResizeList(10);
                    if (m_subPages[i].Position() == Application.position.normal || m_subPages[i].Position() == Application.position.block || m_subPages[i].Position() == Application.position.rolefull) {
                        j += 1;
                    }
                }

                if (m_form.Type == "List") {
                    if (j == 0) {
                        totalheight = UI.Height();
                    } else {
                        totalheight = 300;
                    }
                }

                var uiheight = UI.Height();

                if (j <= 0)
                    j = 1;

                var minheight = 300;
                if (Application.IsInMobile())
                    minheight = 400;

                for (var i = 0; i < m_subPages.length; i++) {

                    var optionheight = Application.OptionValue(m_subPages[i].Page().Options, "height");
                    if (optionheight) {

                        m_subPages[i].ResizeList(optionheight);

                    } else {

                        if (m_subPages[i].Position() == Application.position.normal ||m_subPages[i].Position() == Application.position.rolefull) {
                            m_subPages[i].ResizeList(10);
                            var subheight = (uiheight - totalheight) / j;
                            if (subheight < minheight)
                                subheight = minheight;
                            m_subPages[i].ResizeList(subheight - 8);
                        } else if (m_subPages[i].Position() == Application.position.right) {
                            m_subPages[i].ResizeList(uiheight / 2);
                        } else if (m_subPages[i].Position() == Application.position.block) {
                            m_subPages[i].ResizeList(300);
                        } else if (m_subPages[i].Position() == Application.position.rolequarter || m_subPages[i].Position() == Application.position.rolehalf) {
                            if(Application.IsMobileDisplay()){
								m_subPages[i].ResizeList(uiheight);
							}else if (m_form.SubPages() <= 4) {
                                m_subPages[i].ResizeList(uiheight / 2);
                            } else {
                                m_subPages[i].ResizeList(500);
                            }
                        }
                    }
                }

                if (m_parent == null && m_form.Type == "List") {
                    this.ResizeList(10);
                    var height = totalheight;
                    if (height < minheight)
                        height = minheight;
                    if (m_options.dialog)
                        height = (UI.Height() / 2) - _base.HeaderHeight();
                    this.ResizeList(height);
                }

            for (var i = 0; i < m_controls.length; i++) {

                var cont = m_controls[i];

                if (m_customControl && m_customControl.ObjectType() == cont.ObjectType()) {

                    cont.Width(width);

                } else if (cont.ObjectType() == "Grid") {

                    cont.Width(width);

                } else {

                    var w = width / 2 - 5;

                    if (_base.GetSingleColumn())
                        w = width - 10;

                    if (m_form.Type == "Card") {
                        var tab = _self.GetTab(cont.Field().TabName);
                        if (tab.GetSingleColumn())
                            w = tab.InnerWidth() - 10;
                    }

                    cont.SetSize(w, height);
                }

            }
        };

        //#endregion        

        //#region Window Functions

        this.Show = function (w) {

            w = _base.Show(w);				
				
			_self.OnShow();
				
			setTimeout(function(){
                    
                if(_self){
                    
                    _self.Resize();				
                    
                    for (var i = 0; i < m_tabs.length; i++) {
                        m_tabs[i].OnShow();								
                    }
                    
                    for (var i = 0; i < m_subPages.length; i++) {
                        m_subPages[i].OnShow();					
                    }	
                }
				
			},100);
			
            return w;
        };
		
		this.Remove = function(){
			
			for(var i = 0; i < m_controls.length; i++){
				var cont = m_controls[i];
				cont.Dispose();
				cont = null;				
			}
			m_controls = null;
			
			if(m_filterToolbar){
				m_filterToolbar.Dispose();
				m_filterToolbar = null;
			}
			
			if(m_openedFrom)
				m_openedFrom.RemoveChildWindow(_base.ID());
			
			//if(m_parent)
			//		m_parent.RemoveSubpage(_base.ID());							
			
			_base.Remove();		
			if(m_table) m_table.Dispose();	
			if(m_record) m_record.Dispose();
			
			//Remove references.
			m_closeAction = null;			
			m_record = null;
			m_table = null;
			m_form = null;
			m_layout = null;
			m_options = null;
			m_designerPages = null;
			m_designerPages2 = null;
			m_designerPages3 = null;
			m_subPages = null;
			m_tabs = null;
			
			_base = null;
			_self = null;
		};

        this.Resize = function () {
			
            _base.Resize();
            _self.OnResize(_base.InnerWidth());			
        };

        this.ResizeList = function (height) {

            var h = m_options.height;
            if (h)
                height = h;

            var grd = _self.GetPageGrid();
            if (grd != null) {
				
                grd.Height(height - _base.HeaderHeight());
				
            } else {

                if (m_form && (_self.Position() == Application.position.block || _self.Position() == Application.position.rolehalf || _self.Position() == Application.position.rolequarter || _self.Position() == Application.position.rolefull))
					_base.SetHeight(height, true); //Set height and max
            }

            if (m_customControl)
                m_customControl.Height(height - _base.HeaderHeight());

            if (_base.Dialog())
                _base.CenterDialog();
        };

        this.Pin = function () {
        };	

		this.OnToggle = function(skipevent){
			if(!skipevent)
			_self.SaveLayout();
			_self.ResizeParent();
		};

        //#endregion

        this.Constructor(options_);
    });
/// <reference path="../Application.js" />

Define("CodeViewer", null, function (options_) {

    //#region Members

    var _self = this;
    var m_type = '';
    var m_id = null;
    var m_loaded = false;
    var m_window = null; //Window
    var m_openedFrom = null; //PageViewer
    var m_obj = null;
    var m_options = null;
    var m_closeFunc = null;
    var m_container = null;
    var m_groups = [];
    var m_changed = false;

    //#endregion

    //#region Public Functions

    this.Constructor = function (options_) {

        if (Application.testMode && arguments[0] == null) return;

        m_id = options_.id;
        m_type = options_.type;
        m_options = options_;
    };

    this.Open = function (parent_) {

        //Check if window is already open.
        var winid = UI.WindowManager.GetWindowByUID(m_type + m_id);
        if (winid != -1) {
            var win = UI.WindowManager.Open(winid);
            Application.RunNext(win.Update);
            return;
        }

        return $codeblock(

            function () {
                if (m_type == "TABL") {
                    Application.Cache.Remove("TableFetch", m_id);
                    return new Table(m_id);
                }
                if (m_type == "PAGE") {
                    Application.Cache.Remove("PageFetch", m_id);
                    return new Page(m_id);
                }
                if (m_type == "CODE")
                    return new CodeModule(m_id, true);
            },

            function (obj) {

                //Save the object.
                m_obj = obj;

                if (!m_options.icon) {
                    m_options.icon = "window";
                }

                var uid = m_type + m_id;

                //Create the window.
                m_window = new Window();
                m_window.Create(UI.IconImage(m_options.icon) + ' ' + m_options.caption, {
                    closebutton: true,
                    workspace: $("#AppWorkspace"),
                    shortcutWorkspace: $("#AppWindows")
                });

                //Override window methods.
                m_window.OnError = _self.OnError;
                m_window.OnResize = _self.OnResize;
                m_window.OnKeyPress = _self.OnKeyPress;
                m_window.OnClose = _self.OnClose;
                m_window.Update = _self.Update;

                m_window.AddButton('Save', 'disk_blue', 'Save', _self.SaveCode);
                m_window.AddButton('Save and Close', 'disk_blue_ok', 'Save and Close', function () { _self.SaveCode(true); });

                //Add the window to the manager and open it.
                UI.WindowManager.Add(m_window);
                UI.WindowManager.Open(m_window.ID());

                m_window.Viewer = function () {
                    return _self;
                };

                //Set the window UID.
                m_window.UID(uid);

                m_window.ShowLoad();

                if (!Application.IsInMobile()) {
                    $('#' + m_window.ID() + 'main').css('max-height', UI.Height() - m_window.HeaderHeight() - 10);
                    $('#' + m_window.ID() + 'main').css('overflow-y', 'scroll');
                }

                if (parent_) {
                    m_openedFrom = parent_;
                    parent_.AddChildWindow(m_window);
                }

                //Load the page.
                return _self.Load();
            }

        );
    };

    this.SaveCode = function (closethis_) {

        Application.RunNext(function () {

            return $codeblock(

                function () {
                    _self.ShowLoad();

                    var code = new Application.Objects.ArrayList();
                    for (var i = 0; i < m_groups.length; i++) {
                        code[i] = m_groups[i].editor.Value();
                    }

                    return Application.SaveSource(m_type, m_id, code);
                },

                function () {

                    m_changed = false;

                    _self.HideLoad();
                    if (closethis_ == true)
                        Application.RunNext(_self.Close);
                }

            );

        });
    }

    this.Load = function () {

        Application.LogInfo('Loading Code Viewer: ' + m_id);

        return $codeblock(

            function () {

                //Create the container.
                m_container = $('<div style="width: 100%; padding: 4px; box-sizing: border-box;"></div>');
                m_window.AddControl(m_container);

                //Update the page.           
                return _self.Update(true);
            },
            function () {
                _self.HideLoad();
            }

        );
    };

    this.AddGroup = function (name_, caption_, code_) {

        var id = 'grp' + $id();
        var mnu = $('<div class="ui-widget ui-state-default unselectable" style="border-width: 4px; padding: 4px; width: 100%; box-sizing: border-box; margin: 0px; text-align: left;">' + caption_ + '</div><textarea id="' + id + 'txt"></textarea>');
        m_container.append(mnu);

        $("#" + id + "txt").val(code_);

        var editor = new CodeEditor($("#" + id + "txt")[0], _self.Changed);
        m_groups.push({ name: name_, id: id, editor: editor });

        return $("#" + id);
    };

    this.Changed = function () {
        m_changed = true;
        if (m_openedFrom)
            m_openedFrom.Changed(true);
    };

    this.Update = function (first_) {

        Application.LogInfo('Updating Code Viewer: ' + m_id);

        if (first_ == null) first_ = false;

        return $codeblock(

            function () {

                _self.ShowLoad();

                m_container.html('');
                m_groups = [];

                if (m_type == "TABL") {

                    _self.AddGroup("Insert", "OnInsert", m_obj.InsertCode);
                    _self.AddGroup("Modify", "OnModify", m_obj.ModifyCode);
                    _self.AddGroup("Delete", "OnDelete", m_obj.DeleteCode);

                    for (var i = 0; i < m_obj.Columns.length; i++) {
                        _self.AddGroup(m_obj.Columns[i].Name, m_obj.Columns[i].Name + " - OnValidate", m_obj.Columns[i].ValidateCode);
                    }
                }

                if (m_type == "PAGE") {

                    if (m_obj.OpenAction)
                        _self.AddGroup(m_obj.OpenAction.Name, m_obj.OpenAction.Name + "(rec)", m_obj.OpenAction.ActionCode);

                    if (m_obj.CloseAction)
                        _self.AddGroup(m_obj.CloseAction.Name, m_obj.CloseAction.Name + "(rec)", m_obj.CloseAction.ActionCode);

                    for (var i = 0; i < m_obj.Actions.length; i++) {
                        if (m_obj.Actions[i].Name != "Design Page" && m_obj.Actions[i].Name != "Design Table")
                            _self.AddGroup(m_obj.Actions[i].Name, m_obj.Actions[i].Name + " - OnClick(rec)", m_obj.Actions[i].ActionCode);
                    }
                }

                if (m_type == "CODE") {

                    _self.AddGroup("Code", "Code", m_obj.Code);
                }

                m_loaded = true;
                _self.HideLoad();

                m_window.Resize();
            }
        );
    };

    this.ShowLoad = function () {
        m_window.ShowLoad();
    };

    this.HideLoad = function () {
        m_window.HideLoad();
    };

    this.Resize = function () {
        m_window.Resize();
    };

    this.Close = function () {
        if (m_options.closeButton == false) return;
        return UI.WindowManager.Close(m_window.ID());
    };

    this.CloseFunction = function (func_) {
        m_closeFunc = func_;
    };

    this.OpenedFrom = function () {
        return m_openedFrom;
    };

    //#endregion

    //#region Public Properties

    this.ID = function () {
        return m_id;
    };

    this.Type = function () {
        return m_type;
    };

    this.Window = function () {
        return m_window;
    };

    //#endregion          

    //#region Events

    this.OnError = function (e) {

        _self.HideLoad();

        try {

            if (Application.auth.SessionID != "")
                Application.Rollback();

        } catch (e) {
        }

        Application.ShowError(e, function () {



        });

        if (m_loaded == false)
            return _self.Close();
    };

    this.OnResize = function (width, height) {

    };

    this.OnKeyPress = function (ev) {

        try {

        } catch (e) {
            _self.OnError(e);
        }

    };

    this.OnClose = function () {

        _self.ShowLoad();

        return $codeblock(

            function () {
                if (m_changed == true) {
                    if (m_loaded && !m_window.Visible()) //Show window (incase close all is called)
                        UI.WindowManager.Open(m_window.ID());
                    var w = $wait();
                    Application.Confirm("You have unsaved changes. Close anyway?", function (r) {
                        if (!r) {
                            m_window.CancelClose(true);
                            _self.HideLoad();
                        }
                        w.resolve(r);
                    }, "Don't leave yet...");
                    return w.promise();
                }
                return true;
            },

            function (r) {
                if (m_closeFunc != null && r) {
                    return m_closeFunc();
                }
            }
        );
    };

    //#endregion        

    this.Constructor(options_);

});

/// <reference path="../Application.js" />

Define("OptionsWindow", null, function (options_) {

    //#region Members

    var _self = this;
    var m_loaded = false;
    var m_window = null; //Window
    var m_openedFrom = null; //PageViewer
	var m_closeFunc = null;
    var m_okClicked = false;
	var m_options = null; //Options
	
	//Option Members
	var m_record = new Object();
	var m_xRecord = new Object();
    var m_controls = []; 
	var m_fields = [];
	
	//Filter Members
	var m_filterContainer = null;
	var m_filters = new Object();
	var m_page = null; //Page
    var m_table = null; //Table
    var m_view = null;
	var m_editors = []; //Controls
	var m_filterControls = []; //Controls

    //#endregion

    //#region Public Functions

    this.Constructor = function (options_) {
        
		if (Application.testMode && arguments[0] == null) return;
        
		m_options = options_;
		
		//Filtering
		m_page = options_.page;
        m_view = options_.view;
		
    };

    this.Open = function (parent_) {

        return $codeblock(

            function (obj) {

                if (!m_options.icon) {
                    m_options.icon = "window";
                }

                var uid = $id();

                //Create the window.
                m_window = new Window();
                m_window.Create('', {
                    closebutton: true,
                    workspace: $("#AppWorkspace"),
                    shortcutWorkspace: $("#AppWindows"),
                    dialog: true
                });

                m_options.caption = Default(m_options.caption, "Options");
				m_options.showclose = Default(m_options.showclose,false);
                m_window.SetTitle(m_options.caption);

                //Override window methods.
                m_window.OnError = _self.OnError;
                m_window.OnKeyPress = _self.OnKeyPress;
                m_window.OnClose = _self.OnClose;
                m_window.Update = _self.Update;
                m_window.OnBeforeClose = _self.OnBeforeClose;
                m_window.OnSave = null;
				m_window.OnShow = _self.OnShow;

                //Add the window to the manager and open it.
                UI.WindowManager.Add(m_window);
                m_window.Show();
				UI.WindowManager.SelectedWindow(m_window);
				UI.WindowManager.FocusWindow(m_window.ID());

                m_window.Viewer = function () {
                    return _self;
                };

                //Set the window UID.
                m_window.UID(uid);

                m_window.ShowLoad();
				
				if(Application.IsInMobile())
					m_window.Main().css("margin-bottom","100px");

                if (parent_) {
                    m_openedFrom = parent_;
                    parent_.AddChildWindow(m_window);
                }

                //Load the page.
                return _self.Load();
            },

            function () {
                return _self.Update(true, true);
            },

            function () {
                m_loaded = true;
				_self.OnShow();
			}
        );
    };

    this.Load = function () {

        Application.LogInfo('Loading Options Window');

        return $codeblock(

			function () {
                //Get the table for filtering.
				if(m_page)
					return new Table(m_page.SourceID);
            },
			
            function (tbl) {

				if(tbl)
					m_table = tbl;
			
                //Create the container.
                m_container = $('<div style="width: 100%; padding: 4px; box-sizing: border-box;"></div>');
                m_window.AddControl(m_container);

				if(m_options.optionvalues)
					m_record = m_options.optionvalues;
				
				//Attach fake record functions.
				m_record.SaveCurrent = function(){};
				m_record.GetCurrent = function(){};
				
                //Add the options.
                if (m_options.fields) {
                    for (var i = 0; i < m_options.fields.length; i++) {

                        var f = m_options.fields[i];

                        var f2 = Extend(f, {
                            Name: "Option" + $id(),
                            Type: "Text",
                            Size: 1000000,
                            Editable: true,
                            Caption: "Option"
                        });											

						if(typeof m_record[f2.Name] == "undefined")
							m_record[f2.Name] = null;

						//Fix dates.
						if(m_record[f2.Name] && typeof m_record[f2.Name] == "string" && (f2.Type == "Date" || f2.Type == "Time" || f2.Type == "DateTime"))
							m_record[f2.Name] = Application.ConvertDate(m_record[f2.Name]);
						
                        var field = Extend(f2, Application.Objects.PageFieldInfo());

                        if (field.Hidden == false) {

                            if (field.CustomControl && field.CustomControl != "") {
                                _self.AddCustomControl(field);
                            } else if (field.LookupTable != '' || field.OptionCaption != "") {
                                _self.AddComboField(field);
                            } else if (field.IncrementDelta != 0 && !Application.IsInMobile()) {
                                _self.AddSpinnerField(field);
                            } else if (field.Type == "Date") {
                                _self.AddDateField(field);
                            } else if (field.Type == "DateTime" && !Application.IsInMobile()) {
                                _self.AddDateTimeField(field);
                            } else if (field.Type == "Boolean") {
                                _self.AddCheckboxField(field);
                            } else if (field.Type == "Time") {
                                _self.AddTimeField(field);
                            } else {
                                _self.AddTextField(field);
                            }
                            m_fields.push(field);
                        }
                    }
                }

				//Filtering.
				if(m_page){
					
					//Create the container.
					m_filterContainer = $('<div style="width: 100%; padding: 4px; box-sizing: border-box;"></div>');
					m_container.append(m_filterContainer);
					
					if(!m_options.hideaddnew){
											
						//Add filtering fields.				
						var cmbFields = $("<select id='" + m_window.ID() + "fields' class='ui-widget ui-widget-content ui-corner-left' style='width: auto; max-width: 200px; font-size: 16px; margin-left: 10px; margin-bottom: 20px;' />");
						m_container.append(cmbFields);
						cmbFields.append("<option value='ADDNEW'>Add new filter...</option>");
						for (var i = 0; i < m_table.Columns.length; i++) {
							var col = m_table.Columns[i];
							var name = col.Name;
							cmbFields.append("<option value='" + name + "'>" + col.Caption + "</option>");
						}

						cmbFields.change(function () {
							_self.AddFilter(this.value);
						});
						
					}
					
					//Add the filters.
					var filters = Application.GetFilters(m_view, true);

					if (m_options.filtercolumns) {
						var cols = m_options.filtercolumns.split(",");
						for (var i = 0; i < cols.length; i++) {						
							filters.push([cols[i], ""]);
						}
					}

					for (var i = 0; i < filters.length; i++) {

						filters[i][0] = filters[i][0].replace("FF$","");											
						
						var field = m_table.Column(filters[i][0]);																	
						if (field && typeof m_filters[filters[i][0]] == "undefined") {
							
							if(field.OptionCaption != ""){
								filters[i][1] = Application.GetOptionFilter(filters[i][1], field.OptionCaption);
							}
							
							m_filters[filters[i][0]] = filters[i][1];
							_self.AddFilter(filters[i][0],true);
						}						
					}
				}

				app_transferObjectProperties.call(m_xRecord, m_record);
				
                m_window.CenterDialog();

            },
            function () {
                _self.HideLoad();
            }

        );
    };
	
	this.Options = function(){
		return m_options;
	};
	
	this.OnShow = function(){
		
		if (Application.IsInMobile()) {
			
			$("#okBtn").show();
			$("#saveBtn,#saveCloseBtn,#saveNewBtn,#customBtn1,#customBtn2,#closeBtn").hide();
			$("#divMobileFooter").show();
			
			if (m_options.showclose) 				
				$("#closeBtn").show();
		}
		
	};

    this.Update = function (first_, showProgress_) {

        Application.LogInfo('Updating Options Window');

        if (first_ == null) first_ = false;

        return $codeblock(

            function () {

                _self.ShowLoad();

                return _self.UpdateControls(first_);
            },

            function () {

                if (!Application.IsInMobile())
                    _self.LoadControls(true);

                m_window.CenterDialog();

                _self.HideLoad();
            }
        );
    };	
	
    this.UpdateControls = function (first_, showProgress_) {

        Application.LogDebug("Updating Controls.");

        if (m_controls.length > 0)
            return $loop(function (i) {

                if (showProgress_)
                    _base.Progress(_base.Progress() + ((i + 1) / m_controls.length * 25));

                Application.LogDebug("Updating Control: " + i);

                var w = $wait();

                $code(

                    function () {
                        var cont = m_controls[i];
                        return cont.Update(m_record);
                    },

                    function () {
                        //Continue?
                        if (i < m_controls.length - 1)
                            return $next;
                    }
                );

                return w.promise();

            });

    };

    this.LoadControls = function (loaded_) {

        for (var i = 0; i < m_controls.length; i++) {
            m_controls[i].Loaded(loaded_);
			m_controls[i].SetSize(690, 730);
        }
    };

	this.Control = function (name_) {

		for (var i = 0; i < m_controls.length; i++) {
			if (m_controls[i].Field().Name == name_)
				return m_controls[i];
		}
		return null;
	};
	
	this.AddFilterData = function(name, data){
		if(m_options.addfilterdata)
			m_options.addfilterdata(name,data);
	};
	
    this.AddCustomControl = function (field_, onchange_, editor_) {

        var cont = null;
        eval("cont = new " + field_.CustomControl + "(field_, _self);");
        cont.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        if (Application.IsInMobile()) {
            cont.CreateMobile((editor_ ? m_filterContainer : m_container));
        } else {
            cont.CreateDesktop((editor_ ? m_filterContainer : m_container));
        }

		if(editor_){
			m_editors.push(cont);
		}else{
			m_controls.push(cont);
		}
    };

    this.AddTextField = function (field_, onchange_, editor_) {

        var txt = new Textbox(field_, _self);
        txt.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        txt.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(txt);
		}else{
			m_controls.push(txt);
		}
    };

    this.AddTimeField = function (field_, onchange_, editor_) {

        var txt = new TimePicker(field_, _self);
        txt.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        txt.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(txt);
		}else{
			m_controls.push(txt);
		}
    };

    this.AddSpinnerField = function (field_, onchange_, editor_) {

        var txt = new Spinner(field_, _self);
        txt.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        txt.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(txt);
		}else{
			m_controls.push(txt);
		}
    };

    this.AddDateField = function (field_, onchange_, editor_) {

        var dte = new DatePicker(field_, _self);
        dte.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        dte.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(dte);
		}else{
			m_controls.push(dte);
		}
    };

    this.AddDateTimeField = function (field_, onchange_, editor_) {

        var dte = new DateTimePicker(field_, _self);
        dte.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        dte.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(dte);
		}else{
			m_controls.push(dte);
		}
    };

    this.AddComboField = function (field_, onchange_, editor_) {

        var cmb = new Combobox(field_, _self);
        cmb.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        cmb.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(cmb);
		}else{
			m_controls.push(cmb);
		}
    };

    this.AddCheckboxField = function (field_, onchange_, editor_) {

        var chk = new Checkbox(field_, _self);
        chk.OnValueChange = (onchange_ ? onchange_ : _self.RecordValidate);
        chk.Create((editor_ ? m_filterContainer : m_container));

        if(editor_){
			m_editors.push(chk);
		}else{
			m_controls.push(chk);
		}
    };

	this.FixValue = function (field, value_) {

		//Check for nulls
		if (value_ == "" || value_ == "null" || (value_ && value_.trim && value_.trim() == ""))
			value_ = null;

		if (value_ != null && field.OptionCaption == "") {

			if (field.Type == "Date") {

				var dte = Application.ParseDate(value_);
				if (dte == null)
					Application.Error("Invalid date: " + value_);
				value_ = dte;

			} else if (field.Type == "Time") {

				value_ = Application.ParseTime(value_);

			} else if (field.Type == "DateTime") {

				var dte = Application.ParseDateTime(value_);
				if (dte == null)
					Application.Error("Invalid date time: " + value_);
				value_ = dte;

			} else if (field.Type == "Integer") {

				var i = parseInt(value_);
				if (isNaN(i))
					Application.Error("Invalid integer: " + value_);
				value_ = i;

			} else if (field.Type == "Decimal") {

				var i = parseFloat(value_);
				if (isNaN(i))
					Application.Error("Invalid decimal: " + value_);
				value_ = i;

			} else if (field.Type == "Code") {

				value_ = value_.toString().toUpperCase();

			} else if (field.Type == "Boolean") {

				if (value_ == "Yes" || value_ == true || value_ == "true") {
					value_ = true;
				} else {
					value_ = false;
				}
			}
		}

		if (field.OptionCaption != "" && value_ != null && field.Type != "BigText") {

			var found = false;
			var vals = field.OptionString.split(",");
			var captions = field.OptionCaption.split(",");
			for (var i = 0; i < vals.length; i++) {
				if (value_ == captions[i]) {
					if (field.Type == "Integer") {
						value_ = parseInt(vals[i]);
					} else {
						value_ = vals[i];
					}
					found = true;
					break;
				}
			}
			if (!found) {
				for (var i = 0; i < vals.length; i++) {
					if (captions[i].toLowerCase().indexOf(value_.toLowerCase()) != -1) {
						value_ = vals[i];
						found = true;
						break;
					}
				}
				if (!found)
					Application.Error("Invalid value: " + value_);
			}
		}

		if (!Application.IsInMobile() && field.LookupDisplayField != "" && value_ == null)
			m_record["FF$" + field.Name] = null;

		return value_;
	};
		
    this.RecordValidate = function (col, value) {
		
		var field = null;
		for(var i = 0; i < m_fields.length; i++){
			if(m_fields[i].Name == col){
				field = m_fields[i];
				break;
			}
		}
		
		if(field == null)
			Application.Error("Field not found: "+col);			
		
		if (field.LookupDisplayField != "" && value != "" && value != null && field.CustomControl == "") {
			value = m_record[col];
		}
				
		value = _self.FixValue(field,value);
        m_record[col] = value;
		
		if(field.OnValidate && field.OnValidate != ""){
			eval("var func = function(rec,viewer){" + field.OnValidate  + "};");
			Application.RunNext(function(){
				return $codeblock(					
					function(){
						_self.ShowLoad();
						return func(m_record,_self);
					},
					function () {
					    app_transferObjectProperties.call(m_xRecord, m_record);
						return _self.UpdateControls();
					},
					function(){
						_self.HideLoad();
					}
				);
			});
		} else {
		    app_transferObjectProperties.call(m_xRecord, m_record);
		}
				
		Application.RunNext(_self.Update);
    };       

    //#endregion

    //#region Filtering

    this.AddFilter = function (col, first) {

        if (typeof m_filters[col] == "undefined" || first) {
            var field = m_table.Column(col);
            if (field) {

                field.Size = 10000;

                if (typeof m_filters[col] == "undefined")
                    m_filters[col] = "";

                var txt = new Textbox(field, _self);
                txt.OnValueChange = _self.FilterChange;
                txt.Create(m_filterContainer);											
                txt.Update(m_filters);

                var del = $(UI.IconImage("delete"));
                del.css("cursor", "pointer").css("padding-left", "3px");

                var edit = $("<a style='padding:4px;font-weight:bold;cursor:pointer;'>...</a>");

                txt.Control().css("width", "60%").css("margin-right", "10px").after(del).after(edit);

                txt.Loaded(true);
                txt.Control().focus();

                m_filterControls.push(txt);

                var added = _self.AddAssistButton(field);
                if (added) {
                    eval('edit.button().click(function () {_self.ShowAssistEdit("' + field.Name + '");});');
                } else {
                    edit.remove();
                    txt.Control().css("width", "80%")
                }

                eval('del.click(function () {_self.RemoveFilter("' + field.Name + '");});');

                m_window.CenterDialog();
            }
        }
        $("#" + m_window.ID() + "fields").val("ADDNEW");
    };

    this.ShowAssistEdit = function (col) {

        var editor = _self.GetEditor(col);
        if (editor) {
            editor.Loaded(true);
            editor.Control().css("background-color", "#CCFF66").focus().trigger("click");
        }

        var cont = _self.GetFilterControl(col);
        if (cont) {
            cont.Container().hide();
        }
    };

    this.GetEditor = function (col) {
        for (var i = 0; i < m_editors.length; i++) {
            var cont = m_editors[i];
            if (cont.Field().Name == col) {
                return cont;
            }
        }
        return null;
    };

    this.GetFilterControl = function (col) {
        for (var i = 0; i < m_filterControls.length; i++) {
            var cont = m_filterControls[i];
            if (cont.Field().Name == col) {
                return cont;
            }
        }
        return null;
    };

    this.AssistChange = function (col, value) {

        var editor = _self.GetEditor(col);
        if (editor) {
            editor.Container().hide();
        }

        var cont = _self.GetFilterControl(col);
        if (cont) {
            cont.Control().val(value);
            _self.FilterChange(col, value);
            cont.Container().show();
        }
    };

    this.AddAssistButton = function (field) {

        var assistfield = Extend(field, Application.Objects.PageFieldInfo());
        assistfield.Editable = true;
        assistfield.Size = 10000;	
		
		if (assistfield.OptionCaption != "" && assistfield.OptionString == "") {
			var capts = assistfield.OptionCaption.split(",");
			for (var k = 0; k < capts.length; k++) {
				if (assistfield.OptionString == "") {
					assistfield.OptionString = k + "";
				} else {
					assistfield.OptionString += "," + k;
				}
			}
		}
		
        if (field.CustomControl && field.CustomControl != "") {
            _self.AddCustomControl(assistfield, _self.AssistChange, true);
        } else if (field.LookupTable != '' || field.OptionCaption != "") {
            _self.AddComboField(assistfield, _self.AssistChange, true);
        } else if (field.Type == "Date") {
            _self.AddDateField(assistfield, _self.AssistChange, true);
        } else if (field.Type == "DateTime" && !Application.IsInMobile()) {
            _self.AddDateTimeField(assistfield, _self.AssistChange, true);
        } else if (field.Type == "Time") {
            _self.AddTimeField(assistfield, _self.AssistChange, true);
        } else {
            return false;
        }

        return true;
    };

    this.FilterChange = function (col, value) {
        m_filters[col] = value;
    };

    this.RemoveFilter = function (col) {

        delete m_filters[col];

        var editor = _self.GetEditor(col);
        if (editor) {
            editor.Container().remove();
            for (var i = 0; i < m_editors.length; i++) {
                if (m_editors[i].Field().Name == col) {
                    m_editors.splice(i, 1);
                    break;
                }
            }
        }

        var cont = _self.GetFilterControl(col);
        if (cont) {
            cont.Container().remove();
            for (var i = 0; i < m_filterControls.length; i++) {
                if (m_filterControls[i].Field().Name == col) {
                    m_filterControls.splice(i, 1);
                    break;
                }
            }
        }

        m_window.CenterDialog();
    };

	this.CheckLayout = function (pge) {
		if (m_openedFrom && m_openedFrom.ReportOptions && m_openedFrom.ReportOptions() != null) {
			Application.Confirm("One or more options may have caused an error. Do you wish to clear them?", function (r) {
				if (r == true) {
					m_openedFrom.ReportOptions(null);
					_self.SaveReportOptions();
				}
				Application.RunNext(pge.Close);
			}, "Bad options");
			return true;
		}
		if (m_openedFrom && m_openedFrom.FilterOptions && m_openedFrom.FilterOptions() != '') {
			Application.Confirm("One or more filters may have caused an error. Do you wish to clear them?", function (r) {
				if (r == true) {
					m_openedFrom.FilterOptions('');
					_self.SaveReportOptions();
				}
				Application.RunNext(pge.Close);
			}, "Bad filters");
			return true;
		}
		return false;
	};
	
    //#endregion

    //#region Public Properties

    this.Window = function () {
        return m_window;
    };

    this.CloseFunction = function (func_) {		
        if (typeof func_ == "undefined") {
            return m_closeFunc;
        } else {
            m_closeFunc = func_;
        }
    };

    this.OpenedFrom = function () {
        return m_openedFrom;
    };

	this.AddField = function(field){
		if(!m_options)
			m_options = new Object();
		if(!m_options.fields)
			m_options.fields = [];
		m_options.fields.push(field);
	};
	
    this.SetOptions = function (val) {
        m_record = val;
    }

    this.GetOptions = function () {
        return m_record;
    };

    this.GetOption = function (col) {
        return m_record[col];
    };
	
	this.GetView = function () {

        if (!m_okClicked)
            return "";

        var filters = "";
        for (var c in m_filters) {
            var skip = false;
			var filter = m_filters[c];
            if (filter == "" || filter == null)
                skip = true;
            var col = m_table.Column(c);
            if (!skip && col) {
                var name = col.Name;
                if (col.LookupDisplayField != "") {
                    name = "FF$" + col.Name;
                }
				if(col.OptionCaption != ""){
					filter = Application.SetOptionFilter(filter,col.OptionCaption);
				}
                if (filters == "") {
                    filters = name + "=FILTER(" + filter + ")";
                } else {
                    filters += "," + name + "=FILTER(" + filter + ")";
                }
            }
        }

        if (filters.length == 0)
            return Application.GetSorting(m_view) + "";
        return Application.GetSorting(m_view) + " WHERE(" + filters + ")";
    };

    //#endregion          

    //#region Overloaded Methods

    this.FocusControl = function () {
    };

    this.XFocusControl = function () {
    };

    this.Type = function () {
        return "Card";
    };

    this.MergeView = function (view) {
		
		if(m_record){
			
			var rec = m_record;
			if(view == null) return "";

			var check = new RegExp('\=FIELD\\(((.*?))\\)', 'g');
			var consts = view.match(check);
			if (consts) {
				for (var j = 0; j < consts.length; j++) {
					var name = consts[j].replace(check, '$2');
					var cont = _self.Control(name);					
					var f = Default(rec[name], null);            										
					if(f == "null" || f == "" || f == 0)
						f = null;
					if(f && cont && (cont.ObjectType() == "MultiCombobox" || cont.ObjectType() == "MultiSelect"))
						f = f.replace(/,/g,'|');
					if(f && f.getMonth){           
						view = view.replace("=FIELD(" + consts[j].replace(check, '$1') + ")", "=CONST(" + $.format.date(f,"dd/MM/yyyy") + ")");
					}else{
						view = view.replace("=FIELD(" + consts[j].replace(check, '$1') + ")", "=CONST(" + f + ")");
					}					      
				}
			}

			view = Application.ViewSubstitute(view);

			return view;
		}
        return view;
    };

    this.View = function () {
        return null;
    };
	
	this.Record = function(){
		return m_record;
	};

    this.ShowLoad = function () {
        m_window.ShowLoad();
    };

    this.HideLoad = function () {
        m_window.HideLoad();
    };

    this.Close = function (save) {		
        if (m_options.closeButton == false) return;
        m_window.HideDialog(save);
    };

    //#endregion

    //#region Events

    this.OnError = function (e) {        

        if (Application.transactionStarted > 0)
            Application.RunNext(function () {
                return $codeblock(
				    function () {
				        if (Application.auth.SessionID != "") {
				            Application.supressServiceErrors = true;
				            return Application.RollbackTransaction();
				        }
				    },
				    function () {
				        Application.supressServiceErrors = false;
				    }
			    );
            });
            
		_self.HideLoad(true);
		m_okClicked = false;

		app_transferObjectProperties.call(m_record, m_xRecord);
		
        Application.ShowError(e, function () {
			 if(!m_loaded){
								
				if (_self.CheckLayout(_self))
					return;
				Application.RunNext(_self.Close);
				return;                
			 } else {
			     Application.RunNext(_self.UpdateControls);
			 }
        });        
    };

    this.OnResize = function (width, height) {

    };

    this.OnKeyPress = function (ev) {

        try {

        } catch (e) {
            _self.OnError(e);
        }

    };

    this.OnBeforeClose = function (okclicked) {

        //Check mandatory.
        if(okclicked)
            for (var j = 0; j < m_controls.length; j++) {
                var field = m_controls[j].Field();
                if (field.Mandatory) {
                    if ((m_record[field.Name] === 0 || m_record[field.Name] === null || m_record[field.Name] === "null") && field.OptionCaption === "") {
                        Application.Error(field.Caption + " must have a value.");
                        return false;
                    }
                }
            }

        m_okClicked = okclicked;

        return true;
    };

    this.OnClose = function () {

        _self.ShowLoad();

        return $codeblock(

            function () {
                if (m_closeFunc != null) {
                    return m_closeFunc(m_okClicked);
                }
            }
        );
    };

    //#endregion        

    this.Constructor(options_);

});

Define("Window",null,function(){var _self=this;var m_title="";var m_id=0;var m_uid="";var m_options=null;var m_window=null;var m_subWindows=[];var m_childWindows=[];var m_active=false;var m_lastFocus=0;var m_hidden=false;var m_visible=false;var m_singleColumn=false;var m_okClicked=false;var m_cancelClose=false;var m_spinner=null;var m_preLoading=true;var m_parentWindow=null;var m_state=0;var m_dialog=false;var m_boxy=null;var m_tabName="";this.Constructor=function(){};this.Create=function(title_,options_){if(Application.testMode&&arguments[0]==null)return;if(options_==null){options_=new Object();options_.closebutton=true;options_.workspace=null;options_.shortcutWorkspace=null;options_.position=Application.position.normal;}
if(options_.closebutton==null)
options_.closebutton=true;m_title=title_;m_options=options_;if(m_options.hidden&&m_options.hidden==true)
m_hidden=true;m_id=$id();if(m_options.workspace!=null){if(m_options.dialog!=true){var closebtn="";if(m_options.closebutton==true&&m_options.shortcutWorkspace&&m_options.shortcutWorkspace.length>0){closebtn="<i class='mdi mdi-close unselectable closebutton"+m_id+"' style='cursor: pointer;float:right; margin: 3px;'></i>";}
var pos=5;if(closebtn!="")
pos+=25;var maxbtn="";var editpge=GenerateIcon("editpge"+m_id,"mdi-pencil");if(!m_options.editpage)
editpge="";if(editpge!="")
pos+=25;var refreshpge=GenerateIcon("refreshpge"+m_id,"mdi-refresh");pos+=25;var export_csv=GenerateIcon("exportcsv"+m_id,"mdi-export");if(m_options.type=="List"){pos+=25;}else{export_csv="";}
var helppge=GenerateIcon("helppge"+m_id,"mdi-help");if(Application.restrictedMode){export_csv="";helppge="";refreshpge="";editpge="";maxbtn="";closebtn="";}
var alt=""
if(m_options.shortcutWorkspace==null&&!m_options.homepage)
alt="app-window-title-alt";m_window=$("<div id='"+m_id+"' class='ui-dialog ui-dialog-content ui-widget ui-widget-content ui-corner-all app-window'>"+"<div class='ui-dialog-titlebar ui-widget-header app-window-titlebar ui-helper-clearfix unselectable title"+m_id+" "+alt+"' style='"+(m_options.removetitle?'display: none; ':'')+"'>"+"<span class='ui-dialog-title app-window-title unselectable' id='title"+m_id+"' style='max-width: calc(98% - "+(pos+4)+"px);'>"+m_title+"</span>"+
closebtn+
refreshpge+
export_csv+
helppge+
editpge+"</div>"+"<div id='"+m_id+"actions' class='ui-widget ui-state-default unselectable' style='border-width: 0px;padding-bottom: 5px;'>"+"</div>"+"<div id='"+m_id+"toolbar2' style='display: none;'>"+"</div>"+"<div id='"+m_id+"main' class='ui-widget-content app-window-main'></div>"+"<div id='"+m_id+"toolbar3' style='display: none;' class='unselectable'>"+"</div></div>");m_options.workspace.append(m_window);if(m_options.position==Application.position.right){m_window.addClass("xpress-window-right");}else if(m_options.position==Application.position.block){m_window.addClass("xpress-window-block");}else if(m_options.position==Application.position.rolehalf){m_window.addClass("xpress-window-rolehalf");}else if(m_options.position==Application.position.rolequarter){m_window.addClass("xpress-window-rolequarter");}else{m_window.addClass("xpress-window-default");}}else{var win="<div id='"+m_id+"' class='app-dialog' style='max-height: "+($(window).height()-150)+"px;'><div id='"+m_id+"actions' class='ui-widget ui-state-default' style='border: 0px;'>"+"</div>"+"<div id='"+m_id+"toolbar2' style='display: none;'>"+"</div>"+"<div id='"+m_id+"main' class='ui-widget-content' style='border-width: 0px; height: 98%; width: 95%;'></div>"+"</div>";m_boxy=new Boxy(win,{title:"Loading...",closeText:"X",modal:true,unloadOnHide:true,show:false,beforeHide:function(closeclicked){if(closeclicked)
m_okClicked=false;var ret=UI.WindowManager.BeforeClose(m_id,m_okClicked);if(!ret){m_okClicked=false;return false}
Application.RunNext(function(){m_okClicked=false;return UI.WindowManager.Close(m_id);});return false;},toolbar:"<a id='okbtn"+m_id+"' style='float: right; font-size: 11pt; width: 100px; margin: 10px;'>OK</a>"});m_window=$("#"+m_id);$("#okbtn"+m_id).button().click(function(){m_okClicked=true;m_boxy.hide();});m_dialog=true;return this;}}
if(m_options.shortcutWorkspace!=null){var closebtn2="";if(m_options.closebutton==true){closebtn2="<a href='#' class='ui-dialog-titlebar-close ui-corner-all closebutton"+m_id+"'><span class='ui-icon ui-icon-closethick'>Close</span></a>";}
var winbtn=$("<div id='btn"+m_id+"' class='main-windowsbtn ui-widget ui-state-default app-window-button openbutton"+m_id+"' style='display: none;'><table><tr><td id='titleShortcut"+m_id+"' class='unselectable' style='font-weight: normal; font-size: 14px;'>"+m_title+"</td>"+"<td>"+closebtn2+"</td>"+"</tr></table></div>");m_options.shortcutWorkspace.append(winbtn);winbtn.slideDown(UI.WindowManager.Count()==0?0:300);}
if(!Application.restrictedMode){$('.closebutton'+m_id).on("click",function(){setTimeout(function(){Application.RunNext(function(){return UI.WindowManager.CloseClick(m_id)});},500);});$('.openbutton'+m_id).on("click",function(){UI.WindowManager.OpenClick(m_id);});$('.maxbutton'+m_id).on("click",function(){_self.ToggleState();});$('.title'+m_id).on("dblclick",function(){_self.ToggleState();});$('.maxbutton'+m_id).qtip({position:{at:'bottom right'},content:'Minimize/Maximize the Tab',style:{tip:{corner:false}}});$('#'+m_id).on("click",function(){UI.WindowManager.FocusWindow(m_id);});if(m_options.editpage){$('.editpge'+m_id).qtip({position:{at:'bottom right'},content:'Design '+m_options.editpage.type.replace("Custom",""),style:{tip:{corner:false}}});$('.editpge'+m_id).on("click",function(){if(m_options.editpage.type=="Page")
Application.App.LoadPage("VP$PageDesigner","WHERE(Name=CONST("+m_options.editpage.name+"))",null,m_id);if(m_options.editpage.type=="Table")
Application.App.LoadPage("VP$TableDesigner","WHERE(Name=CONST("+m_options.editpage.name+"))",null,m_id);if(m_options.editpage.type=="PageCustom")
Application.App.LoadPage("VP$PageDesignerCustomizer","WHERE(Name=CONST("+m_options.editpage.name+"))",null,m_id);});}
$('.refreshpge'+m_id).qtip({position:{at:'bottom right'},content:'Refresh Page',style:{tip:{corner:false}}});$('.refreshpge'+m_id).on("click",function(){UI.WindowManager.UpdateWindow(m_id);});_self.HideHelp();$('.helppge'+m_id).qtip({position:{at:'bottom right'},content:'Start a Page Tour',style:{tip:{corner:false}}});if(m_options.type=="List"){_self.HideExportCSV();$('.exportcsv'+m_id).qtip({position:{at:'bottom right'},content:'Export to CSV',style:{tip:{corner:false}}});}}
if(m_window){m_window.height('auto');}else{m_window=$('#nowindow');}
return this;};this.SetTitle=function(title_){title_=Default(title_,"");title_=Application.ProcessCaption(title_);m_title=title_;if(m_title.indexOf('> ')!=-1)
m_title=m_title.substr(m_title.indexOf('> ')+2);if(m_options.dialog==true){m_boxy.setTitle(m_title);return;}
$("#title"+m_id).html(m_title);$("#titleShortcut"+m_id).html(title_);};this.Hide=function(){if(m_options.dialog==true)
return;m_visible=false;$('#'+m_id).css("display","none");$('#btn'+m_id).removeClass("ui-state-hover").addClass("app-window-button-inactive").removeClass("app-window-button-active");$(".dhtmlXTooltip").remove();for(var i=0;i<m_subWindows.length;i++){m_subWindows[i].Hide();}};this.TogglePin=function(on_){};this.Pin=function(){return false;};this.PinMode=function(){return false;};this.Show=function(w){if(m_options.dialog==true){if(m_boxy.isVisible()==false){m_boxy.center();m_boxy.show();}
return;}
$("#"+m_id+"loader").remove();m_preLoading=false;m_visible=true;if(!m_hidden){$('#'+m_id).css("display","inline-block");}
$('#btn'+m_id).addClass("ui-state-hover").addClass("app-window-button-active").removeClass("app-window-button-inactive");if(this.Visible()){for(var i=0;i<m_subWindows.length;i++){w=m_subWindows[i].Show(w);}}
this.OnShow();if(!Application.IsInMobile())
$("#SideWindows").css("min-height",$("#AppWindows").height());};this.Remove=function(){if(m_options.dialog==true){m_boxy.unload();Application.Loading.Hide(m_id);m_parentWindow=null;_base=null;_self=null;return;}
$('#'+m_id).remove();$('#btn'+m_id).remove();$("#"+m_id+"loader").remove();for(var i=0;i<m_subWindows.length;i++){m_subWindows[i].Remove();}
m_subWindows=[];for(var i=0;i<m_childWindows.length;i++){UI.WindowManager.Remove(m_childWindows[i].ID());m_childWindows[i].Remove();}
m_childWindows=[];m_parentWindow=null;_base=null;_self=null;};this.Progress=function(value_){if(m_preLoading){return Application.Loading.Progress(m_id+"loader",value_);}else{return Application.Loading.Progress(m_id,value_);}};this.PreLoad=function(){if(m_options.dialog==true)
return;$('#btn'+m_id).addClass("ui-state-hover");var loader=$("<div id='"+m_id+"loader' class='ui-dialog ui-dialog-content ui-widget ui-widget-content ui-corner-all app-preloader'></div>");if(m_options.workspace)
m_options.workspace.append(loader);loader.height(UI.Height());loader.slideDown(300,function(){Application.Loading.Show(m_id+'loader');});};this.AddControl=function(cont){$('#'+m_id+'main').append(cont);};this.AddColumns=function(){$('#'+m_id+'main').append("<div id='"+m_id+"LeftColumn' style='width: 50%; display: inline-block; vertical-align: top;'></div>");$('#'+m_id+'main').append("<div id='"+m_id+"RightColumn' style='width: 50%; display: inline-block; vertical-align: top;'></div>");};this.GetColumn=function(left_){if(left_){return $("#"+m_id+"LeftColumn");}else{return $("#"+m_id+"RightColumn");}};this.SingleColumn=function(val){if(val==true){$("#"+m_id+"LeftColumn").css("width","100%");$("#"+m_id+"RightColumn").css("width","100%");}else{$("#"+m_id+"LeftColumn").css("width","50%");$("#"+m_id+"RightColumn").css("width","50%");}
m_singleColumn=val;};this.ShowLoad=function(){Application.Loading.Show(m_id);};this.HideLoad=function(){Application.Loading.Hide(m_id);Application.Loading.Hide("tdMain");};this.ShowOverlay=function(){Application.Loading.ShowOverlay(m_id);if(m_state!=0){var overlay=$('#'+m_id+'Overlay2').children();overlay.css("top","0%");}};this.HideOverlay=function(){Application.Loading.HideOverlay(m_id);Application.Loading.HideOverlay("tdMain");};this.Resize=function(w){if(m_options.dialog==true)
m_boxy.center();if(this.Visible()){for(var i=0;i<m_subWindows.length;i++){w=m_subWindows[i].Resize(w);}}
return w;};this.SetHeight=function(val,setmax){$('#'+m_id+'main').css('min-height',val-this.HeaderHeight());if(setmax){$('#'+m_id+'main').css('max-height',val-this.HeaderHeight());$('#'+m_id+'main').css('overflow-y','auto');}};this.ToggleState=function(skipevent){if(m_state==0){$('.maxbutton'+m_id).children(0).removeClass("ui-icon-carat-1-n");$('.maxbutton'+m_id).children(0).addClass("ui-icon-carat-1-s");$("#"+m_id+"main,#"+m_id+"actions,#"+m_id+"toolbar2,#"+m_id+"toolbar3").hide();m_state=1;}else{$('.maxbutton'+m_id).children(0).addClass("ui-icon-carat-1-n");$('.maxbutton'+m_id).children(0).removeClass("ui-icon-carat-1-s");$("#"+m_id+"main,#"+m_id+"actions,#"+m_id+"toolbar2,#"+m_id+"toolbar3").show();setTimeout(function(){var offset=$("#"+m_id).offset().top;$('html, body').scrollTop(offset-60);},50);m_state=0;}
_self.OnToggle(skipevent);};this.State=function(){return m_state;};this.ShowHelp=function(func){$(".helppge"+m_id).show();$(".helppge"+m_id).click(func);};this.HideHelp=function(){$(".helppge"+m_id).hide();};this.ShowExportCSV=function(func){$(".exportcsv"+m_id).show();$(".exportcsv"+m_id).click(func);};this.HideExportCSV=function(){$(".exportcsv"+m_id).hide();};this.AddSubWindow=function(win){if(win)
m_subWindows.push(win);};this.GetSubWindow=function(id_){for(var i=0;i<m_subWindows.length;i++){if(m_subWindows[i].ID()==id_){return m_subWindows[i];}else{var win=m_subWindows[i].GetSubWindow(id_);if(win)
return win;}}
return null;};this.RemoveSubWindow=function(id_){for(var i=0;i<m_subWindows.length;i++){if(m_subWindows[i].ID()==id_){m_subWindows.splice(i,1);return;}else{m_subWindows[i].RemoveSubWindow(id_);}}};this.AddChildWindow=function(win){if(win){m_childWindows.push(win);win.SetParentWindow(_self);}};this.RemoveChildWindow=function(id_){for(var i=0;i<m_childWindows.length;i++){if(m_childWindows[i].ID()==id_){UI.WindowManager.Remove(m_childWindows[i].ID());m_childWindows.splice(i,1);return;}}};this.GetChildWindow=function(id_){for(var i=0;i<m_childWindows.length;i++){if(m_childWindows[i].ID()==id_)
return m_childWindows[i];}
return null;};this.GetParentWindow=function(){return m_parentWindow;};this.SetParentWindow=function(win){m_parentWindow=win;};this.CenterDialog=function(){if(m_boxy)
m_boxy.center();};this.HideDialog=function(save_){if(save_)
m_okClicked=save_;if(m_boxy)
m_boxy.hide();};this.GetDialog=function(){return m_boxy;};this.AddButton=function(name,image,text,func){var id=m_id+"action"+$id();var imgcode=""
if(image!=""){imgcode=UI.IconImage(image)+"&nbsp;";}
var $action=$("<div id='"+id+"' class='unselectable app-button' style='border-width: 0px;'>"+imgcode+UI.InputManager.AddKeyBinding(text,id,m_id)+"</div>");$action.click(func);$("#"+m_id+"actions").append($action);return $action;};this.ShowActions=function(){$("#"+m_id+"actions").show();};this.HideActions=function(){$("#"+m_id+"actions").hide();};this.Focus=function(focus_){if(m_dialog)
return;if(focus_){m_window.addClass("ui-state-active");m_active=true;}else{m_window.removeClass("ui-state-active");m_active=false;}};this.FocusNext=function(){if(m_active){if(m_subWindows.length>0){UI.WindowManager.FocusWindow(m_subWindows[0].ID());}}else{for(var i=0;i<m_subWindows.length;i++){if(m_subWindows[i].Active()){if(i!=m_subWindows.length-1){UI.WindowManager.FocusWindow(m_subWindows[i+1].ID());}
break;}}}};this.FocusPrevious=function(){if(m_active){return;}else{for(var i=0;i<m_subWindows.length;i++){if(m_subWindows[i].Active()){if(i!=0){UI.WindowManager.FocusWindow(m_subWindows[i-1].ID());}else{UI.WindowManager.FocusWindow(this.ID());}
break;}}}};this.GetSingleColumn=function(){return m_singleColumn;};this.Dialog=function(){return m_dialog;};this.Width=function(){return m_window.width();};this.Height=function(){return m_window.outerHeight(true);};this.InnerWidth=function(){var main=this.Main();return main.innerWidth();};this.InnerHeight=function(){return this.Height()-this.HeaderHeight();};this.HeaderHeight=function(){return $("#"+m_id+"actions").outerHeight(true)+$("#"+m_id+"toolbar2").outerHeight(true)+$("#"+m_id+"toolbar3").outerHeight(true)+$(".title"+m_id).outerHeight(true)+$("#"+m_id+"maxrecs").outerHeight(true);};this.Active=function(){return m_active;};this.LastFocus=function(value_){if(value_!==undefined){m_lastFocus=value_;}else{return m_lastFocus;}};this.Pinned=function(value_){return false;};this.CancelClose=function(value_){if(value_!==undefined){m_cancelClose=value_;}else{return m_cancelClose;}};this.Title=function(){return m_title;};this.Visible=function(value_){if(value_!==undefined){m_visible=value_;}else{return m_visible;}};this.Hidden=function(){return m_hidden;};this.ID=function(){return m_id;};this.TabName=function(value_){if(value_!==undefined){m_tabName=value_;}else{return m_tabName;}};this.Position=function(){return m_options.position;};this.UID=function(value_){if(value_!==undefined){m_uid=value_;}else{return m_uid;}};this.Toolbar2=function(){return $("#"+m_id+"toolbar2");};this.Toolbar3=function(){return $("#"+m_id+"toolbar3");};this.Main=function(){return $('#'+m_id+'main');}
this.OnError=function(e){};this.OnResize=function(width,height){};this.OnKeyPress=function(ev){};this.Save=function(){};this.OnShow=function(){};this.OnBeforeClose=function(){};this.OnClose=function(){};this.ClearLayout=function(){};this.ClearCache=function(){};this.GetInfo=function(){return null;};this.Update=function(){};this.OnSave=function(){};this.OnToggle=function(){};function GenerateIcon(id,icon){return"<i class='mdi "+icon+" unselectable "+id+"' style='cursor: pointer;float: right; margin: 3px;'></i>";};this.Constructor();});

Define("Control",function(type_){return new AppObject(type_);},function(type_,field_,viewer_){var _self=this;var _base=null;var m_container=null;var m_label=null;var m_control=null;var m_id="";var m_enabled=false;var m_visible=true;var m_field=null;var m_loaded=false;var m_viewer=null;var m_invalid=false;var m_notSupported=false;this.Constructor=function(field_,viewer_){m_id=$id();m_field=field_;m_viewer=viewer_;if(m_field==null){m_field=new Object();m_field.Caption="";}
_base=Base("Control");Application.LogDebug("Created new control: "+m_id+", Caption: "+m_field.Caption);};this.CreateDesktop=function(window_){if(window_==null)return;var container=_self.CreateNoDesktop();_self.Create(window_,container,_self.OnValueChange,function(cont){});m_notSupported=true;};this.Create=function(window_,container_,onchange_,setupfunc_){m_container=container_;m_container.width(window_.width()-10);window_.append(m_container);m_control=$('#ctl'+m_id);m_label=$('#lbl'+m_id);m_control.attr("tabindex",m_field.TabIndex);m_control.addClass("app-control");if(m_field.Mandatory)
m_control.attr("placeholder","Mandatory").addClass("app-placeholder-mandatory");if(m_field.Editable==false){m_control.attr("disabled",true);}
m_label.html(m_field.Caption);m_label.addClass("app-label");m_label.css("display","inline-block");m_control.focus(function(){if(m_viewer)
m_viewer.FocusControl(m_control);});if(onchange_!=null){m_control.change(function(){if(m_loaded==false)
return;if(m_viewer)
m_viewer.XFocusControl(m_control);onchange_(m_field.Name,m_control.val());});}
if(setupfunc_)
setupfunc_(m_control);Application.Fire("ControlInit",m_control);Application.LogDebug("Finished control init: "+m_id+", Caption: "+m_field.Caption);};this.CreateList=function(container_,control_,value_){m_container=container_;m_control=control_;m_control.keydown(function(ev){return m_viewer.OnKeyPress(ev);});return m_container;};this.SetSize=function(width,height){m_container.width(width);m_control.width((width/2)-18);};this.Focus=function(){m_control.select();};this.Update=function(rec_){if(m_field==null||rec_==null||m_notSupported){m_loaded=true;return;}
Application.LogDebug("Updating control: "+m_id+", Caption: "+m_field.Caption);var value=rec_[m_field.Name];if(typeof value=='undefined'){m_loaded=true;return;}
m_control.val($.fn.fmatter(m_field.Mask,value));m_loaded=true;};this.CreateUnsupported=function(){return $('<div id="'+m_id+'" style="display: none; min-height: 30px;">&nbsp;&nbsp;&nbsp;<b>'+UI.IconImage('warning')+' This control is unsupported in your browser version. Please upgrade to the latest version.</b></div>');};this.CreateNoDesktop=function(){return $('<div id="'+m_id+'" style="display: none; min-height: 30px;">&nbsp;&nbsp;&nbsp;<b>'+UI.IconImage('warning')+' This control is unsupported in the desktop version.</b></div>');};this.Valid=function(valid,msg){valid=Default(valid,null);msg=Default(msg,"");var color="";if(valid==null){m_invalid=false;}else if(valid==true){color="#CCFF66";m_invalid=false;}else{color="#FFE6E6";m_invalid=true;m_control.select();}
m_control.css("background-color",color);if(msg==""){m_label.html(m_field.Caption);}else{m_label.html(m_field.Caption+"<br/><span style='font-size: 12px; background-color: "+color+"; padding: 4px;'>"+msg+"</span>");}};this.Dispose=function(){if(m_control)m_control.remove();if(m_label)m_label.remove();if(m_container)m_container.remove();m_viewer=null;_base=null;_self=null;};this.IsControl=function(){return true;};this.ID=function(){return m_id;};this.Field=function(){return m_field;};this.Label=function(){return m_label;};this.Viewer=function(){return m_viewer;};this.Control=function(){return m_control;};this.Container=function(){return m_container;};this.Loaded=function(value_){if(value_!==undefined){if(value_==true&&m_container&&m_field.Importance!="Additional"&&m_visible)
m_container.css("display","inline-block");m_loaded=value_;}else{return m_loaded;}};this.Enabled=function(value_,update_){if(value_!==undefined){update_=Default(update_,true);if(update_)
m_field.Editable=value_;if(value_){if(m_field.Editable)
m_control.attr("disabled",false);}else{m_control.attr("disabled",true);}
m_enabled=value_;}else{return m_enabled;}};this.Hide=function(){m_container.css("display","none");m_visible=false;};this.Show=function(){m_container.css("display","inline-block");m_visible=true;};this.Invalid=function(){return m_invalid;};this.OnRightClick=function(callback){m_control.mousedown(function(ev){if(ev.which!=3)return;if(callback)callback();});};this.HideDropdown=function(){};this.IgnoreColumns=function(){return false;};this.PageControl=function(){return false;};this.Constructor(field_,viewer_);});

Define("FilterToolbar",function(viewer_){return new Control("FilterToolbar",null,viewer_);},function(){var _self=this;var _base=null;var m_id=null;var m_filterInput=null;var m_filterText=null;var m_filterFields=null;var m_filterClear=null;var m_firstCol=null;this.Constructor=function(){_base=Base("FilterToolbar");};this.Create=function(window_,form_,table_){m_id=window_.ID();var toolbar=window_.Toolbar2();toolbar.addClass("ui-widget ui-state-default");toolbar.css("padding-top","10px");toolbar.css("padding-bottom","10px");toolbar.css("display","inline-block");toolbar.css("width","100%");toolbar.css("border-width","0px");toolbar.css("font-size","13px");toolbar.append("<select id='"+window_.ID()+"filterfields' class='ui-widget ui-widget-content ui-corner-left' style='width: auto; max-width: 100px; float: right; margin-right: 15px;' />");toolbar.append("<input type='text' id='"+window_.ID()+"filterinput' placeholder='Type to filter (F7)' class='ui-widget ui-widget-content ui-corner-left' style='width: 150px; float: right;' />");toolbar.append("<div id='"+window_.ID()+"filterclear' class='ui-state-hover' style='display: none; cursor: pointer; float: right; margin-right: 15px; padding: 1px; border: 0px; background: gainsboro;'>Clear All "+UI.IconImage('delete')+"</div>");toolbar.append("<label id='"+window_.ID()+"filtertxt' class='ui-state-hover' style='display: none; width: auto; float: right; margin-right: 3px; border: 0px;'></label>");m_filterFields=$("#"+window_.ID()+"filterfields");m_filterInput=$("#"+window_.ID()+"filterinput");m_filterClear=$("#"+window_.ID()+"filterclear");m_filterText=$("#"+window_.ID()+"filtertxt");for(var i=0;i<form_.Fields.length;i++){if(!form_.Fields[i].Hidden){var name=form_.Fields[i].Name;if(form_.Fields[i].LookupDisplayField!=""){name="FF$"+form_.Fields[i].Name;}
if(!m_firstCol)
m_firstCol=name;m_filterFields.append("<option value='"+name+"'>"+form_.Fields[i].Caption+"</option>");}}
HookPageEvents();};this.SetFilters=function(clear,first){var filtertxt="";m_filterClear.css("display","none");m_filterText.css("display","none").html("");var filters=_base.Viewer().Filters();$.each(filters,function(index,filter){var pagefield=_base.Viewer().Page().GetField(filter.Name.replace("FF$",""));if(pagefield){var filterbox=$("<div style='display: inline-block; background-color: gainsboro; margin-left: 4px; cursor: pointer; padding: 1px;'>"+pagefield.Name+"=FILTER("+filter.Value+")&nbsp;&nbsp;</div>");m_filterText.append(filterbox);filterbox.on("click",function(){_self.GetFilter(pagefield.Name);m_filterFields.val(pagefield.Name);});var delbox=$(UI.IconImage('delete'));delbox.on("click",function(){Application.RunNext(function(){return $codeblock(function(){return _base.Viewer().Filter(filter.Name,null,true);},function(){m_filterFields.val(pagefield.Name);m_filterInput.val('');});});});filterbox.append(delbox);m_filterText.css("display","");m_filterClear.css("display","");}});if(clear){m_filterInput.val("");}else if(m_firstCol&&first){m_filterFields.val(m_firstCol);_self.GetFilter(m_firstCol);}};this.GetFilter=function(col){var filters=_base.Viewer().Filters();for(var i=0;i<filters.length;i++){if(filters[i].Name==col||filters[i].Name=="FF$"+col){m_filterInput.val(filters[i].Value);m_filterInput.select();return;}}
m_filterInput.val('');m_filterInput.select();};this.RemoveField=function(name){$("#"+m_id+"filterfields option[value='"+name+"']").remove();$("#"+m_id+"filterfields option[value='FF$"+name+"']").remove();};this.Dispose=function(){if(m_filterClear)m_filterClear.remove();if(m_filterFields)m_filterFields.remove();if(m_filterInput)m_filterInput.remove();if(m_filterText)m_filterText.remove();_base.Dispose();this.prototype=null;_base=null;_self=null;};function HookPageEvents(){m_filterFields.keydown(function(ev){if(ev.which==13){ev.preventDefault();$(this).blur();m_filterInput.select();}else if(ev.which==27){ev.preventDefault();$(this).blur();}});m_filterFields.change(function(){_self.GetFilter(this.value);});m_filterInput.keydown(function(ev){var val=this.value;if(ev.which==13){ev.preventDefault();Application.RunNext(function(){return _base.Viewer().Filter(m_filterFields.val(),val,true,true);});$(this).blur();}else if(ev.which==27){ev.preventDefault();$(this).blur();}});m_filterInput.change(function(){var val=this.value;Application.RunNext(function(){return _base.Viewer().Filter(m_filterFields.val(),val,true,true);});});m_filterClear.click(function(){_base.Viewer().ClearFilters();m_filterInput.val("");});};this.Constructor();});

Define("Grid",function(field_,viewer_){return new Control("Grid",field_,viewer_);},function(){var _self=this;var _base=null;var m_grid=null;var m_colNames=new Array();var m_cols=new Array();var m_dataSource=null;var m_footer=false;var m_selected=new Array();var m_loading=false;var m_timeoutID=null;var m_grouping=null;var m_newSort=null;this.Constructor=function(){_base=Base("Grid");m_colNames.push(" ");m_cols.push({name:'RowId',index:'RowId',width:'20px',fixed:true,editable:false,sortable:true,search:false,align:'center',classes:'row-id',hidedlg:true,formatter:function(cellvalue,options,rowObject){var temp=false;if(_base.Viewer()&&Application.HasOption(_base.Viewer().Page().Options,"temp"))
temp=true;if(rowObject.Record&&!temp&&(rowObject.Record.NewRecord||rowObject.NoKeys())){return UI.IconImage("row_add_after");}
return cellvalue;}});};this.Create=function(window_,footer_){var gridid="#"+_base.ID()+"table";var grid=$('<div id="'+_base.ID()+'"><table id="'+_base.ID()+'table" style="border: none"></table></div>');window_.AddControl(grid);var width=$('#'+window_.ID()).width();var height='10px';m_footer=footer_;grid.on("click",function(e){if(e.target.className==="ui-jqgrid-bdiv"){_self.Save();}else{Application.RunSilent(function(){var parent=$(e.target).parent();if(parent.length>0&&parent[0].className==="ui-jqgrid-bdiv"){_self.Save();}});}});var options=_base.Viewer().Page().Options;var grpfields=Application.OptionValue(options,"groupfields");var grpfieldCaptions=Default(Application.OptionValue(options,"groupfieldcaptions"),grpfields);var grpclmshow=Default(Application.OptionValue(options,"groupcolumnshow"),false);if(grpclmshow=="true")grpclmshow=true;var grptext=Default(Application.OptionValue(options,"grouptext"),"{3}: {0}");var grpcoll=Default(Application.OptionValue(options,"groupcollapse"),null);if(grpcoll=="true")grpcoll=true;var grpsum=Default(Application.OptionValue(options,"groupsummary"),null);if(grpsum=="true")grpsum=true;var colspan=Default(Application.OptionValue(options,"footerspan"),4);m_grouping=null;if(grpfields){var gf=grpfields.split(",");m_grouping={groupField:gf,groupFieldCaption:grpfieldCaptions.split(","),groupColumnShow:Application.CreateArray(gf.length,grpclmshow),groupText:Application.CreateArray(gf.length,grptext),groupCollapse:grpcoll,groupSummary:Application.CreateArray(gf.length,grpsum),showSummaryOnHide:grpsum,colspan:colspan};}
jQuery(gridid).jqGrid({datatype:"local",data:new Array(),autowidth:false,height:height,width:1,colNames:m_colNames,colModel:m_cols,shrinkToFit:false,rowNum:50000,pginput:false,viewrecords:true,cellEdit:true,multiselect:false,cellsubmit:'clientArray',sortable:true,scrollrows:true,footerrow:footer_,autoencode:true,grouping:(m_grouping!=null),groupingView:m_grouping,beforeSubmitCell:function(rowid,cellname,value,iRow,iCol){return _self.OnCellSubmit(rowid,cellname,value,iRow,iCol);},ondblClickRow:function(rowid,iRow,iCol,e){_self.OnDoubleClick(rowid,iRow,iCol,e);},onRightClickRow:function(rowid,iRow,iCol,e){_self.SelectRow(rowid);_self.OnRightClick(rowid,iRow,iCol,e);e.preventDefault();return false;},loadComplete:function(){},resizeStop:function(){_self.OnResizeCol();},onColumnChooserDone:function(){_self.OnColumnChooserDone();},onSortCol:function(){_self.OnSortCol();},beforeSelectRow:function(rowid,e){if(!e.ctrlKey){for(var i=0;i<m_selected.length;i++){var rowid=_self.GetRowID(m_selected[i]);if(rowid){var ind=m_grid[0].rows.namedItem(rowid);$(ind).removeClass("ui-state-highlight");}}
m_selected=new Array();}else{if(rowid==_self.SelectedRow())
return;var ind=m_grid[0].rows.namedItem(rowid);var recid=_self.DataSourceById(rowid).Record.RecID;if($(ind).hasClass("ui-state-highlight")){for(var i=0;i<m_selected.length;i++){if(m_selected[i]==recid){m_selected.splice(i,1);break;}}
$(ind).removeClass("ui-state-highlight");}else{if(m_selected.indexOf(recid)==-1)
m_selected.push(recid);$(ind).addClass("ui-state-highlight");}
return false;}
if(rowid!=_self.SelectedRow()){_self.OnRowSelect(rowid,e);}
_self.OnRowClick(rowid,_self.DataSourceById(rowid),m_grid.getInd(rowid,true));return true;}});m_grid=$(gridid);};this.Dispose=function(){if(m_dataSource)
for(var i=0;i<m_dataSource.length;i++){m_dataSource[i].Dispose();}
$("#"+_base.ID()).remove();m_grid=null;_base.Dispose();this.prototype=null;_base=null;_self=null;};this.AddColumn=function(field){if(field.Hidden)return;var caption=field.Caption;if(field.Width=="999")
field.Width='200';m_colNames.push(caption);var sumtype=Application.OptionValue(field.Options,"summarytype");if(field.Type=="Integer"||field.Type=="Decimal")
sumtype="sum";if(!field.Totals)
sumtype=null;if(field.CustomControl!=""){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,edittype:'custom',summaryType:sumtype,skipsanitize:Application.HasOption(field.Options,"skipsanitize"),formatter:function(cellvalue,options,rowObject){var cont=null;eval("cont = new "+field.CustomControl+"(field, _base.Viewer());");if(typeof cont.FormatValue!="undefined"){return cont.FormatValue(cellvalue,rowObject);}
cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==null||cellvalue=="null")
return"";return cellvalue;},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var cont=null;eval("cont = new "+field.CustomControl+"(field, _base.Viewer());");var ele=cont.CreateList(value);setTimeout(function(){cont.Focus();},50);return ele;},custom_value:CustomValue}});}else if(field.Type=="Date"){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,edittype:'custom',align:'center',formatter:function(cellvalue,options,rowObject){cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==null||cellvalue=="null"||cellvalue=="")
return"";if(typeof cellvalue==="string")
cellvalue=Application.ParseDate(cellvalue);return $.format.date(cellvalue,"dd/MM/yyyy");},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var dte=new DatePicker(field,_base.Viewer());var ele=dte.CreateList(value);setTimeout(function(){dte.Focus();},50);return ele;},custom_value:CustomValue},sorttype:"date",datefmt:"ddmmyy"});}else if(field.Type=="DateTime"){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,edittype:'custom',align:'center',formatter:function(cellvalue,options,rowObject){cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==null||cellvalue=="null"||cellvalue=="")
return"";if(typeof cellvalue==="string")
return cellvalue;return $.format.date(cellvalue,"dd/MM/yyyy hh:mm a");},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var dte=new DateTimePicker(field,_base.Viewer());var ele=dte.CreateList(value);setTimeout(function(){dte.Focus();},50);return ele;},custom_value:CustomValue}});}else if(field.Type=="Time"){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,edittype:'custom',align:'center',formatter:function(cellvalue,options,rowObject){cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==null||cellvalue=="null"||cellvalue=="")
return"";if(typeof cellvalue==="string"&&cellvalue.indexOf("Mandatory")==-1)
cellvalue=Application.ParseTime(cellvalue);return $.format.date(cellvalue,"hh:mm a");},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var tm=new TimePicker(field,_base.Viewer());var ele=tm.CreateList(value);setTimeout(function(){tm.Focus();},50);return ele;},custom_value:CustomValue},formatoptions:{srcformat:'ShortTime',newformat:'ShortTime'}});}else if(field.LookupTable!=''||field.OptionCaption!=""){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,sorttype:function(cellvalue,rowObject){return UpdateComboCell(field,cellvalue,rowObject);},edittype:'custom',skipsanitize:Application.HasOption(field.Options,"skipsanitize"),formatter:function(cellvalue,options,rowObject){return UpdateComboCell(field,cellvalue,rowObject);},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var combo=new Combobox(field,_base.Viewer());var ele=combo.CreateList(value);setTimeout(function(){combo.Focus();},50);return ele;},custom_value:CustomValue}});}else if(field.IncrementDelta!=0){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,sorttype:function(cell,obj){if((field.Type=="Integer"||field.Type=="Decimal")&&cell&&cell!="")
return parseFloat(cell);return cell;},edittype:'custom',align:'right',summaryType:sumtype,editoptions:{custom_element:function(value,options){var txt=new Spinner(field,_base.Viewer());var ele=txt.CreateList(value);setTimeout(function(){txt.Focus();},50);return ele;},custom_value:CustomValue}});}else if(field.Type=="Boolean"){m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:false,hidden:false,sortable:true,edittype:'custom',align:'center',formatter:function(cellvalue,options,rowObject){var checked='';if(cellvalue==true||cellvalue=="Yes"||cellvalue=="True"){checked='checked';}
var disabled='';if(!field.Editable)
disabled='disabled=true';var id=$id();var input="<input type='checkbox' class='noinput' id='"+id+"' "+disabled+" "+checked+"  />";setTimeout(function(){$("#"+id).on('click',function(){_self.SelectRow(rowObject.RowId);_base.Viewer().RecordValidate(field.Name,this.checked,rowObject.RowId);});},10);return input;}});}else{var align="left";if(field.Type=="Integer"||field.Type=="Decimal")
align="right";m_cols.push({name:field.Name,index:field.Name,width:field.Width,editable:field.Editable,hidden:false,sortable:true,sorttype:function(cell,obj){if((field.Type=="Integer"||field.Type=="Decimal")&&cell&&cell!="")
return parseFloat(cell);return cell;},edittype:'custom',align:align,summaryType:sumtype,skipsanitize:Application.HasOption(field.Options,"skipsanitize"),formatter:function(cellvalue,options,rowObject){cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==null||cellvalue=="null")
return"";return cellvalue;},editoptions:{custom_element:function(value,options){value=MandatoryRevert(value,field);var txt=new Textbox(field,_base.Viewer());var ele=txt.CreateList(value);setTimeout(function(){txt.Focus();},50);return ele;},custom_value:CustomValue}});}};this.AddRow=function(rowid,data,skipselect){m_grid.addRowData('RowId',[data]);this.SetDataRow(rowid,data,skipselect);if(skipselect)
return;return this.SelectRow(rowid);};this.RemoveRow=function(rowid){m_grid.delRowData(rowid);m_dataSource.splice(rowid-1,1);};this.SetDataRow=function(rowid,data,skipfooter){for(var i=0;i<m_grid[0].p.data.length;i++){if(m_grid[0].p.data[i].RowId==rowid){m_grid[0].p.data[rowid-1]=data;break;}}
m_grid.setRowData(rowid,data);if(m_footer&&!skipfooter)
_self.OnLoadFooter(_self);_self.OnBindRow(rowid,data,m_grid.getInd(rowid,true));};this.Loading=function(){return m_loading;};this.StopLoad=function(){if(m_timeoutID!=null)
clearTimeout(m_timeoutID);m_timeoutID=null;};this.GetSort=function(){return m_grid.getGridParam("sortname")+";"+m_grid.getGridParam("sortorder");};this.SetSort=function(sort){try{m_grid.setGridParam({sortname:sort.split(";")[0],sortorder:sort.split(";")[1]});}catch(e){}};this.Bind=function(selected){var w=$wait();$code(function(){_self.StopLoad();m_loading=true;var load=Default(Application.OptionValue(_base.Viewer().Page().Options,"loadrows"),50);var srt=_self.GetSort();if(srt==";asc")srt=null;if(m_grouping!=null||srt)
load=99999999;var initdata=GetData(0,load);m_grid.clearGridData();m_grid.setGridParam({data:initdata});m_grid[0].refreshIndex();if(srt)
_self.SetSort(srt);m_grid.trigger('reloadGrid',{current:true});RenderSelected();OnBind(0,load);if(selected!=-1&&selected!=null){var rid=_self.GetRowID(selected);for(var j=0;j<initdata.length;j++){if(initdata[j].RowId==rid){_self.SelectRow(rid);_self.ScrollToRow(rid);_base.Viewer().GetRecordByRowId(rid);selected=-1;}}}
if(m_dataSource.length>load){LoadNextRecords(load,load,selected);}else{m_loading=false;if(selected!=null){var rid=_self.GetRowID(selected);_self.SelectRow(rid);}
if(m_footer)
_self.OnLoadFooter(_self);}
_base.Loaded(true);});return w.promise();};this.GetRowID=function(recid){for(var i=0;i<m_grid[0].p.data.length;i++){if(m_grid[0].p.data[i].Record.RecID==recid){return m_grid[0].p.data[i].RowId;}}
return null;};this.SelectRow=function(rid){var i=m_grid.getInd(rid);Application.RunSilent(function(){m_grid.jqGrid("editCell",i,1,false);});};this.EditCurrentCell=function(){if(m_grid[0].p.iCol!=0){m_grid.editCell(this.SelectedRow(),m_grid[0].p.iCol,true);}else{this.EditFirstCell();}};this.EditFirstCell=function(){var cols=_self.GetColumns();for(var j=0;j<cols.length;j++){if(cols[j].editable==true&&cols[j].hidden==false){m_grid.editCell(this.SelectedRow(),j,true);break;}}};this.EditCellByName=function(name_){for(var j=0;j<m_cols.length;j++){if(m_cols[j].name==name_){m_grid.editCell(this.SelectedRow(),j,true);break;}}};this.SelectedRow=function(factor){if(factor==null)
factor=0;var gridArr=m_grid.getDataIDs();var selrow=m_grid.getGridParam("selrow");for(var i=0;i<gridArr.length;i++){if(gridArr[i]==selrow){if(factor==1&&i==gridArr.length-1)
return null;if(factor==-1&&i==0)
return null;return gridArr[i+factor];}}
return null;};this.SumColumn=function(id_){return m_grid.getCol(id_,false,'sum');};this.DataSourceById=function(id_){for(var i=0;i<m_grid[0].p.data.length;i++){if(m_grid[0].p.data[i].RowId==id_){return m_grid[0].p.data[i];}}
return null;};this.GetColumns=function(){return m_grid.getGridParam("colModel");};this.SetColumnHidden=function(col,h){if(h){m_grid.hideCol(col);}else{m_grid.showCol(col);}};this.SetColumnCaption=function(col,val){m_grid.setLabel(col,val);};this.Save=function(){var savedrows=m_grid[0].p.savedRow;for(var i=0;i<savedrows.length;i++){m_grid.saveCell(savedrows[i].id,savedrows[i].ic);}};this.GridRowHeight=function(){var height=null;try{height=m_grid.find('tbody').find('tr:first').outerHeight();}
catch(e){}
return height;};this.ScrollToRow=function(rid){setTimeout(function(){var rowHeight=_self.GridRowHeight()||23;var index=m_grid.getInd(rid);m_grid.closest(".ui-jqgrid-bdiv").scrollTop(rowHeight*(index-1));},1);};this.HideColumn=function(column){m_grid.hideCol(column);};this.ShowColumn=function(column){m_grid.showCol(column);};this.Editable=function(column,editable){m_grid.setColProp(column,{editable:editable});var field=_base.Viewer().Page().GetField(column);if(field){field.Editable=editable;}};this.NewColumnOrder=function(value){if(typeof value=="undefined"){return m_newSort;}else{m_newSort=value;m_grid.remapColumns(value,true,false);}};this.Footer=function(value_){if(value_!==undefined){m_grid.footerData('set',value_);}else{return m_footer;}};this.DataSource=function(value_){if(value_!==undefined){m_dataSource=value_;}else{return m_dataSource;}};this.Width=function(value_){m_grid.setGridWidth(10,true);m_grid.setGridWidth(value_,false);};this.Height=function(value_){var h=value_;if(m_footer)
h-=30;h-=$("#"+_base.ID()).find("tr[role='rowheader']").height()+2;m_grid.setGridHeight(10,true);m_grid.setGridHeight(h,false);};this.SelectedRows=function(){return m_selected;};this.ClearSelected=function(){m_selected=[];};this.CurrentEditor=function(rid){try{var selector=$("td[role='gridcell']:eq("+m_grid[0].p.iCol+")",m_grid[0].rows.namedItem(rid));return UI.FindEditorInput(selector);}catch(e){}
return null;};this.CurrentColumn=function(){try{return m_grid.getGridParam("colModel")[m_grid[0].p.iCol];}catch(e){}
return null;};this.SelectAll=function(){m_selected=[];if(m_dataSource.length>0)
_self.SelectRow(1);if(m_dataSource.length>1)
for(var i=1;i<m_dataSource.length;i++){m_selected.push(m_dataSource[i].Record.RecID);var ind=m_grid[0].rows.namedItem(i+1);if(!$(ind).hasClass("ui-state-highlight")){$(ind).addClass("ui-state-highlight");};}};function MandatoryCheck(cellvalue,field){if(cellvalue==null||cellvalue=="null"||cellvalue==0)
if(field.Mandatory)
return"<span style='color: red; font-style: italic'>Mandatory</span>";return cellvalue;};function MandatoryRevert(value,field){if(value&&value.indexOf("Mandatory</span>")!=-1)
return"";return value;};function CustomValue(elem,op,value){var editor=UI.FindEditorInput($(elem));if(op=="set"&&editor){editor.val(value);}
if(!editor)
return null;return editor.val();};function GetData(offset,load){var ret=[];for(var i=offset;i<m_dataSource.length;i++){if(ret.length==load)
return ret;ret.push(m_dataSource[i]);}
return ret;};function LoadNextRecords(offset,load,selected){m_timeoutID=setTimeout(function(){var d=GetData(offset,load);for(var j=0;j<d.length;j++){_self.AddRow(d[j].RowId,d[j],true);if(selected!=-1){if(selected!=null){var rid=_self.GetRowID(selected);if(d[j].RowId==rid){_self.SelectRow(rid);_self.ScrollToRow(rid);_base.Viewer().GetRecordByRowId(rid);selected=-1;}}}}
offset+=load;RenderSelected();if(offset<m_dataSource.length){LoadNextRecords(offset,load,selected);}
else{m_loading=false;if(m_footer)
_self.OnLoadFooter(_self);}},0);};function RenderSelected(){for(var i=0;i<m_selected.length;i++){Application.RunSilent(function(){var rowid=_self.GetRowID(m_selected[i]);if(rowid){var ind=m_grid[0].rows.namedItem(rowid);$(ind).addClass("ui-state-highlight");}});}};function OnBind(offset,load){for(var i=offset;i<m_dataSource.length;i++){if(i>offset+load)
return;_self.OnBindRow((i+1),m_dataSource[i],m_grid.getInd(i+1,true));}};function UpdateComboCell(field,cellvalue,rowObject){if(field.OptionString!=""){var vals=field.OptionString.split(",");var captions=field.OptionCaption.split(",");for(var i=0;i<vals.length;i++){if(field.Type=="Integer"){if(parseInt(vals[i])==cellvalue||cellvalue==null)
return captions[i];}else{if(vals[i]==cellvalue)
return captions[i];}}}else{if(field.LookupDisplayField!=""){if(rowObject.Record){for(var i=0;i<rowObject.Record.Fields.length;i++){if(rowObject.Record.Fields[i].Name=="FF$"+field.Name){cellvalue=rowObject.Record.Fields[i].Value;}}}}
cellvalue=MandatoryCheck(cellvalue,field);if(cellvalue==0||cellvalue==null||cellvalue=="null"){return"";}}
return cellvalue;};this.Enabled=function(enabled_){};this.OnCellSubmit=function(rowid,cellname,value,iRow,iCol){return value;};this.OnDoubleClick=function(rowid,iRow,iCol,e){};this.OnRightClick=function(rowid,iRow,iCol,e){};this.OnLoadFooter=function(grd){};this.OnResizeCol=function(){};this.OnColumnChooserDone=function(){};this.OnRowSelect=function(){};this.OnBindRow=function(){};this.OnRowClick=function(){};this.OnSortCol=function(){};this.Constructor();});

Define("Textbox",function(field_,viewer_){return new Control("Textbox",field_,viewer_);},function(){var _self=this;var _base=null;this.Constructor=function(){_base=Base("Textbox");};this.Create=function(window_){var type="text";if(Application.HasOption(_base.Field().Options,"password"))
type="password";var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input type="'+type+'" id="ctl'+_base.ID()+'" style="width: 100%;"></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){cont.attr("maxlength",_base.Field().Size);if(type=="password")
cont.attr("autocomplete","new-password");});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').appendTo(container).val(value_).attr("maxlength",_base.Field().Size).addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 2px)");return _base.CreateList(container,cont,value_);};this.OnValueChange=function(name,value){return true;};this.Constructor();});

Define("DatePicker",function(field_,viewer_){return new Control("DatePicker",field_,viewer_);},function(){var _self=this;var _base=null;this.Constructor=function(){_base=Base("DatePicker");};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input type="text" id="ctl'+_base.ID()+'" style="width: 100%;"></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){var yearrange=Application.OptionValue(_base.Field().Options,'yearrange');if(yearrange)
yearrange=yearrange.replace('|',':');cont.datepicker({showOn:"none",showButtonPanel:true,changeMonth:true,changeYear:true,yearRange:Default(yearrange,'c-10:c+10')});cont.click(function(){cont.datepicker('show');});cont.datepicker("option","dateFormat",("dd/MM/yy").toLowerCase());$("#ui-datepicker-div").addClass("ui-custom-combo");});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').appendTo(container).datepicker({showButtonPanel:true,changeMonth:true,changeYear:true}).addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 2px)");cont.datepicker("option","dateFormat",("dd/MM/yy").toLowerCase());cont.val(value_);return _base.CreateList(container,cont,value_);};this.Update=function(rec_){var value=rec_[_base.Field().Name];if(typeof value=='undefined')
return;if(typeof value=="string")
value=Application.ParseDate(value);_base.Control().datepicker("setDate",value)};this.Loaded=function(value_){if(value_!==undefined){_base.Loaded(value_);this.HideDropdown();}else{return _base.Loaded();}};this.HideDropdown=function(){};this.OnValueChange=function(name,value){return true;};this.Constructor();});

Define("Combobox",function(field_,viewer_){return new Control("Combobox",field_,viewer_);},function(field_){var _self=this;var _base=null;var m_button=null;var m_cols=[];var m_values=null;var m_data=null;this.Constructor=function(field_){if(Application.testMode&&arguments[0]==null)return;_base=Base("Combobox");field_.OptionCaption=Default((field_.OptionCaption==''?null:field_.OptionCaption),field_.OptionString);if(field_.OptionString!=""){m_values=new Array();var vals=field_.OptionString.split(",");var captions=field_.OptionCaption.split(",");for(var i=0;i<vals.length;i++){var item=new Object();item.Display=captions[i];if(field_.Type=="Integer"){item.Value=parseInt(vals[i]);}else{item.Value=vals[i];}
m_values.push(item);}
m_cols.push({name:"Value",width:'230px',valueField:"Display"});return;}
field_.LookupColumns=Default((field_.LookupColumns==''?null:field_.LookupColumns),field_.LookupField);field_.LookupColumnCaptions=Default((field_.LookupColumnCaptions==''?null:field_.LookupColumnCaptions),field_.LookupColumns);var vals=field_.LookupColumns.split(",");var captions=field_.LookupColumnCaptions.split(",");for(var i=0;i<vals.length;i++){var w='100px';if(captions[i]=="City"||captions[i]=="Name"||captions[i]=="Description"){w='300px';}
var width=Application.OptionValue(field_.Options,vals[i]+"Width");if(width)
w=width;m_cols.push({name:Application.ProcessCaption(captions[i]),width:w,valueField:vals[i]});}};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctrl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; text-align: left; vertical-align: top;"><input type="text" id="ctl'+_base.ID()+'" style="width: 100%;"></input><button id="btn'+_base.ID()+'" type="button" style="display: none;">&nbsp;</button></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){cont.mcautocomplete(GenerateOptions());cont.on("click",function(){if(_base.Field().Editable==false)
return;if(_base.Control().mcautocomplete("widget").is(":visible")){_base.Control().mcautocomplete("close");return;}
_base.Control().mcautocomplete("search","");_base.Control().focus();});m_button=CreateDropdownButton($("#ctrl"+_base.ID()+"cont"));});};this.CreateList=function(value_,hidebutton_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').val(value_).appendTo(container).mcautocomplete(GenerateOptions()).addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 18px)");if(!hidebutton_){if(!Application.HasOption(_base.Field().Options,"menu")){m_button=CreateDropdownButton(container);}else{cont.mcautocomplete("search","");cont.css("visibility","hidden");container.append("<span id='mnu"+_base.ID()+"'>"+value_+"</span>");}}
return _base.CreateList(container,cont,value_);};function GenerateOptions(){var options=new Object();var viewer=_base.Viewer();var field=_base.Field();if(!viewer)
return;options.showHeader=true;options.autoFocus=true;options.columns=m_cols;options.minLength=0;options.delay=300;options.drilldown=field.LookupAdvanced;var filters=field.LookupFilters;if(typeof filters=="function")
filters=field.LookupFilters();options.drilldownview=filters;options.menu=Application.HasOption(_base.Field().Options,"menu");options.allowdelete=false;if(Application.HasOption(field.Options,"allowdelete"))
options.allowdelete=true;options.select=function(event,ui){if(viewer.Type()=="Card"&&_base.Loaded()==false)
return false;if(viewer.ComboSelected)
viewer.ComboSelected(true);if(m_values!=null){this.value=(ui.item?ui.item.Display:'');}else{if(typeof ui.item.DisplayCol=='undefined'){if(m_data){var f=field.LookupField;if(field.LookupDisplayField!="")
f=field.LookupDisplayField;var found=false;for(var i=0;i<m_data.length;i++){if(m_data[i][f]==this.value){ui.item[field.LookupField]=m_data[i][field.LookupField];if(field.LookupDisplayField!="")
ui.item[field.LookupDisplayField]=m_data[i][field.LookupDisplayField];found=true;break;}}
if(!found){for(var i=0;i<m_data.length;i++){if(m_data[i][f].toLowerCase().indexOf(this.value.toLowerCase())!=-1){ui.item[field.LookupField]=m_data[i][field.LookupField];if(field.LookupDisplayField!="")
ui.item[field.LookupDisplayField]=m_data[i][field.LookupDisplayField];break;}}}}}
if(field.LookupDisplayField!=""){this.value=(ui.item?ui.item[field.LookupDisplayField]:'');if(_base.Viewer().Record){var rec=_base.Viewer().Record();rec["FF$"+field.Name]=ui.item[field.LookupDisplayField];rec.SaveCurrent(null,true);rec[field.Name]=ui.item[field.LookupField];}else if(_base.Viewer().GetOptions){var rec=_base.Viewer().GetOptions();rec["FF$"+field.Name]=ui.item[field.LookupDisplayField];rec[field.Name]=ui.item[field.LookupField];_base.Viewer().SetOptions(rec);}}else{this.value=(ui.item?ui.item[field.LookupField]:'');}}
if(viewer.Type()=="Card"){viewer.XFocusControl(_base.Control());_self.OnValueChange(field.Name,this.value);}
if(Application.HasOption(_base.Field().Options,"menu")){$("#mnu"+_base.ID()).remove();_base.Container().append("<span id='mnu"+_base.ID()+"'>"+this.value+"</span>");if(viewer.Type()=="List"&&viewer.GetPageGrid())
viewer.GetPageGrid().Save();}
return false;}
options.source=function(request,response){if(request.term==""&&Application.HasOption(_base.Field().Options,"skipload"))
return;if(m_values!=null){var vals=new Array();for(var i=0;i<m_values.length;i++)
if(m_values[i].Display.toLowerCase().indexOf(request.term.toLowerCase())!=-1)
vals.push(m_values[i]);response(vals);return;}
var $this=$(this);var $element=$(this.element);var previous_request=$element.data("jqXHR");if(previous_request){previous_request.abort();}
var view=viewer.View();$thread(function(){return Application.LookupRecord(field,viewer,request.term,function(vals){m_data=vals;response(vals);});});}
return options;};function CreateDropdownButton(parent_){var btn=$("<a>").attr("tabIndex",-1).attr("title","Show All Items").appendTo(parent_).width(15).height('90%').button({icons:{primary:"ui-icon-triangle-1-s"},text:false}).removeClass("ui-corner-all").addClass("ui-corner-right ui-button-icon ui-combobox-button").click(function(){if(_base.Field().Editable==false)
return;if(_base.Control().mcautocomplete("widget").is(":visible")){_base.Control().mcautocomplete("close");return;}
$(this).blur();_base.Control().mcautocomplete("search","");_base.Control().focus();});return btn;};this.SetSize=function(width,height){_base.Container().width(width);if(_base.Viewer().Type=="List"){_base.Control().width((width/2)-m_button.width()-15);}else{_base.Control().width((width/2)-18);}};this.Update=function(rec_){var value=rec_[_base.Field().Name];if(typeof value=='undefined')
return;if(m_values!=null){var vals=_base.Field().OptionString.split(",");var captions=_base.Field().OptionCaption.split(",");for(var i=0;i<vals.length;i++){if(vals[i]==value)
_base.Control().val(captions[i]);}}else{if(_base.Field().LookupDisplayField!=""){if(rec_.Record){for(var i=0;i<rec_.Record.Fields.length;i++){if(rec_.Record.Fields[i].Name=="FF$"+_base.Field().Name){_base.Control().val(rec_.Record.Fields[i].Value);return;}}}else{_base.Control().val(rec_["FF$"+_base.Field().Name]);return;}}
_base.Control().val(value);}};this.Enabled=function(value_,update_){_base.Enabled(value_,update_);if(value_==false){m_button.hide();}else{m_button.show();}};this.OnValueChange=function(name,value){return true;};this.Constructor(field_);});

Define("Spinner",function(field_,viewer_){return new Control("Spinner",field_,viewer_);},function(){var _self=this;var _base=null;var m_val=null;this.Constructor=function(){_base=Base("Spinner");};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input type="text" id="ctl'+_base.ID()+'" style="width: 100%;"></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){var align="right";cont.spinner({step:_base.Field().IncrementDelta,numberFormat:_base.Field().Mask,alignment:align});cont.blur(function(){if(cont.val()!=m_val)
_self.OnValueChange(_base.Field().Name,cont.val());});cont.removeClass("app-control");$(".ui-spinner").addClass("app-control").addClass("app-spinner");});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').appendTo(container).val(value_).spinner({step:_base.Field().IncrementDelta,numberFormat:_base.Field().Mask}).addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 2px)");return _base.CreateList(container,cont,value_);};this.SetupTest=function(){_base.Field().IncrementDelta=1;};this.Update=function(rec){_base.Update(rec);m_val=_base.Control().val();};this.SetSize=function(width,height){_base.Container().width(width);_base.Control().width((width/2)-40);};this.OnValueChange=function(name,value){return true;};this.Constructor();});

Define("Checkbox",function(field_,viewer_){return new Control("Checkbox",field_,viewer_);},function(){var _self=this;var _base=null;this.Constructor=function(){_base=Base("Checkbox");};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 100%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50px; padding-right: 10px; text-align: right; vertical-align: top;"><input type="checkbox" id="ctl'+_base.ID()+'" style=""></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){cont.unbind("change");cont.change(function(){if(_base.Loaded()==false)
return;if(_base.Viewer())
_base.Viewer().XFocusControl(cont);_self.OnValueChange(_base.Field().Name,cont[0].checked);});});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input type="checkbox">').appendTo(container).val(value_)
return _base.CreateList(container,cont,value_);};this.SetSize=function(width,height){_base.Container().width(width);};this.Update=function(rec_){var value=rec_[_base.Field().Name];if(typeof value=='undefined')
return;_base.Control()[0].checked=value;};this.OnValueChange=function(name,value){return true;};this.Constructor();});

Define("TimePicker",function(field_,viewer_){return new Control("TimePicker",field_,viewer_);},function(){var _self=this;var _base=null;this.Constructor=function(){_base=Base("TimePicker");};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input type="text" id="ctl'+_base.ID()+'" style="width: 100%;"></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){cont.timepicker({showPeriod:true,showLeadingZero:true,showDeselectButton:true,showNowButton:true,deselectButtonText:"Clear"});});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').appendTo(container).timepicker({showPeriod:true,showLeadingZero:true,showDeselectButton:true,showNowButton:true}).addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 2px)");cont.val(value_);return _base.CreateList(container,cont,value_);};this.Update=function(rec_){var value=rec_[_base.Field().Name];if(typeof value=='undefined')
return;if(value!=null){_base.Control().timepicker("setTime",value,true);}else{_base.Control().timepicker("setTime",'',true);}};this.OnValueChange=function(name,value){return true;};this.Constructor();});

Define("DateTimePicker",function(field_,viewer_){return new Control("DateTimePicker",field_,viewer_);},function(){var _self=this;var _base=null;this.Constructor=function(){_base=Base("DateTimePicker");};this.Create=function(window_){var container=$('<div id="'+_base.ID()+'" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl'+_base.ID()+'" id= for="ctl'+_base.ID()+'" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input type="text" id="ctl'+_base.ID()+'" style="width: 100%;"></input></td></tr></table></div>');_base.Create(window_,container,_self.OnValueChange,function(cont){cont.datetimepicker();});};this.CreateList=function(value_){var container=$('<span>').addClass("ui-combobox").css("width","100%");var cont=$('<input>').appendTo(container).datetimepicker().addClass("ui-widget ui-widget-content ui-corner-left").css("width","80%").css("width","calc(100% - 2px)");cont.val(value_);return _base.CreateList(container,cont,value_);};this.Update=function(rec_){var value=rec_[_base.Field().Name];if(typeof value=='undefined')
return;_base.Control().val($.format.date(value,"dd/MM/yyyy hh:mm a"));};this.OnValueChange=function(name,value){return true;};this.Constructor();});
/// <reference path="../Application.js" />

DefineModule("App",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        depends: ['AppUI', 'CookieManager', 'CodeEngine', 'IDEngine', 'UpdateManager'],
        created: new Date(2013, 09, 03),
        version: '1.3',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.',
            '16/09/13   PF  Added main menu.',
            '26/09/13   PF  Updated language.',
            '10/10/13   PF  Added support for frame version',
            '20/11/13   PF  Added menu favorites.',
            '28/11/13   PF  Fixed login bug.',
            '11/03/14   PF  Removed Control Manager Module'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_params = [];
        var m_timer = null; //Timer
        var m_loaded = false;
        var m_serverInfo = null;
        var m_hideErrors = false;
        var m_sideVisible = true;
        var m_menuVisible = true;
        var m_sessionID = "";
        var m_favorites = new Array();
        var m_popular = new Array();
        var m_mainMenu = null;
        var m_skipHome = false;
        var m_currentMenu = 0;
        var m_lastMenu = null;
        var m_processing = false;
        var m_layout = new Object();
        var m_runningStartup = false;
        var m_maintenanceMode = false;		
        var m_searchQueue = [];
        var m_hideSearch = false;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            Application.App = this;

            //Backwards compatability
            Application.XpressApp = this;

            if (Application.testMode) return;

            $thread(function () {

                return $codeblock(
                    function () {

                        Application.On("ThreadFailed", function () {
                            Application.Loading.Hide("tdMain");
                        });

                        //Setup the title bar.
                        $("#divTop").css("width", $(window).width());
                        $("#divTop").css("display", "");

                        //Load footer.
                        $("#tdCopyright").text(Application.copyright + '. ' + Application.name + ' v' + Application.version);

                        _self.ToggleSide(false);

                        //Error handling.
                        Application.OnError = _self.Error;

                        //Load params.
                        m_params["title"] = '';
                        m_params["img"] = '';
                        m_params["instance"] = '';
                        m_params["pageid"] = null;
                        m_params["rid"] = null;
                        m_params["frame"] = "false";
                        m_params["initview"] = null;
                        m_params["updates"] = "false";
                        m_params["user"] = null;
                        m_params["pass"] = null;
                        m_params["debug"] = "false";
                        m_params["generate"] = "false";
                        m_params["auth"] = null;
                        m_params["windowsauth"] = "false";
                        m_params["custom"] = null;
                        Application.LoadParams(m_params, PAGE_PARAMETERS);

                        //Check if browser is supported.
                        if (Application.UnsupportedIE(true) && !Application.IsInFrame()) {
                            Application.NavigateToPage(Application.pages.ErrorBrowser);
                            return;
                        }

                        return Application.FireWait("Load", m_params);						
					},
					
					function(){

                        //Set logo.
                        m_params["img"] = decodeURIComponent(m_params["img"]).replace(/\+/g, ' ');
                        $("#imgLogo").attr("src", m_params["img"]);
                        $("#imgHeader").attr("src", m_params["img"]);

                        if (Application.IsInMobile())
                            $("#AppWindows").css("background-color", $("#divContent").parent().css("background-color"));

                        //Set title.
                        m_params["title"] = decodeURIComponent(m_params["title"]).replace(/\+/g, ' ');
                        parent.document.title = m_params["title"];
                        if (Application.IsInMobile() && m_params["img"].indexOf("Portrait") == -1)
                            m_params["title"] = '<img src="' + m_params["img"] + '" style="max-height: 20px;" />';
                        $("#windowTitle").html(m_params["title"]);

						//Setup icons.
						$("#menuToggle").attr("class","mdi mdi-arrow-left-drop-circle-outline");
						$("#sideToggle").attr("class","mdi mdi-arrow-right-drop-circle-outline");
						
                        if (Application.IsInMobile()) {

                            $('#lnkMenu .ui-btn-text').text("Menu");
                            $("#lnkMenu").buttonMarkup({ icon: "bars" });
                            $("#lnkMenu").unbind("click");
                            $("#lnkMenu").click(function () {
                                $("#divSideMenu").panel("toggle");
                            });
                            $("#lnkMenu").addClass("app-header-btn");
                        }

                        //Setup tips.
                        if (!Application.IsInMobile()) {
                            $("#menuToggle").qtip({ position: { at: 'bottom right' },
                                content: 'Hide/Show Main Menu',
                                style: { tip: { corner: false} }
                            });
                            $("#sideToggle").qtip({ position: { at: 'bottom left', my: 'bottom right' },
                                content: 'Hide/Show Factbox',
                                style: { tip: { corner: false} }
                            });
                        }

                        //Events.
                        Application.On("Connected", function () {
                            UI.StatusBar(false);
                            if (Application.IsOffline())
                                UI.StatusBar(true, "Offline mode", "#FF6666");
                            $(window).resize();
                        });
                        Application.On("ConnectionLost", function () {
                            if (m_loaded) {
                                UI.StatusBar(true);
                                $(window).resize();
                            }
                        });
                        Application.On("ExecutedWebservice", function (m, success) {
                            if (m == "GetServerInfo")
                                m_processing = false;
                        });

                        var search = $("#txtGlobalSearch");	
						search.on("keyup",function(ev){				
							if(ev.which == 13)
								_self.OnSearch($(this));
                        });						
                        search.on("keyup click",
							app_debouncer(function () {	
								if(arguments[0].which != 13)
									_self.OnSearch($(this));
							},1000)
                        );
						
						$("body").on("click",function(){
							$(".searchdropdown").remove();
							$(".lineactions").animate({
                                top: $(window).height()
                            },null,null,function(){
                                $(".lineactions,.lineactionsoverlay").remove();
                            });	
						});											

                        m_timer = new Timer(10000, _self.OnTimer);

                        if (m_params["debug"] == "true")
                            Application.debugMode = true;

						if (m_params["returnurl"] != null) {
							$("#lnkLogout").html("<i class='mdi mdi-logout'></i> Exit");							
						}
								
                        //Windows auth.
                        if (m_params["windowsauth"] == "true") {
                            return _self.LoginFromWindowsAuth();
                        }

                        //Auto login.
                        if (m_params["user"] != null && m_params["pass"] != null) {
                            $("#txtUsername").val(m_params["user"]);
                            $("#txtPassword").val(m_params["pass"]);
                            return _self.Login();
                        }

                        //Login from secret.
                        if (m_params["auth"] != null) {
                            return _self.LoginFromAppSecret(m_params["auth"].replace(/ /g,"+"));
                        }

						 //Login from token.
                        if (m_params["token"] != null && !Application.IsOffline()) {							
                            return _self.LoginFromToken(m_params["token"]);
                        }
						
                        //Attempt to login from cookie.
						return _self.LoginFromCookie();
                    }
                );
            });
        };

		this.OnSearch = function(search){
			m_searchQueue = [];			
			m_searchQueue.push(search.val());
			Application.RunNext(function () {
				if(m_searchQueue.length == 0)
					return;
				return $codeblock(
					function () {													
						$("#imgGlobalSearch").show();
						var s = m_searchQueue[0];
						m_searchQueue.splice(0,1);
						return Application.Search(s);
					},
					function (ret) {										
						$(".searchdropdown").remove();														
						if(ret.length != 0){											
							var dd = $("<div style='position:absolute; background-color: white; max-width: 400px; border: 1px solid gainsboro; max-height: 400px; overflow-y: auto; z-index: 1001;' class='searchdropdown'>");
							dd.css("width",UI.Width() - 5);
							$("body").append(dd);
							dd.css("top",search.offset().top+40).css("left",search.offset().left);
							for(var i = 0; i < ret.length; i++){
								var item = $("<div style='font-size: 10pt; padding: 5px; border-bottom: 1px solid gainsboro; cursor: pointer;'>"+UI.IconImage(ret[i][2])+" "+ret[i][0]+"</div>");
								dd.append(item);
							var code = 'Application.App.LoadPage("'+ret[i][3]+'","'+ret[i][1]+'",{searchmode:true});';
								if(Default(ret[i][4],"") != "")
									code = ret[i][4].replace(/\&quot\;/g,'"');
								eval('item.on("click",function(){'+code+'m_searchQueue=[];$(".searchdropdown").remove();});');
							}											
						}										
						$("#imgGlobalSearch").hide();
					}
				);
			});
		};
		
		this.UploadExtension = function () {

		    Application.FileDownload.ShowUploadDialog("Upload Extension", function (filename, data) {
		        Application.RunNext(function () {
		            return Application.FileDownload.UploadFile(filename, data, function (file) {

		                var callbacks = new Object();
		                callbacks.onerror = function (e) {
		                    setTimeout(function () {
		                        Application.Error(e);
		                    }, 1000);
		                };
		                callbacks.onsuccess = function (r) {
		                    
		                    setTimeout(function () {

		                        if (r && r.Message)
		                            Application.Error(r.Message);
		                        Application.Message(r);

		                        w.resolve();

		                    }, 1000);
		                };
		                callbacks.onsend = function () { };		                

		                var w = $wait();
		                Application.ExecuteWebService("UploadExtension", { auth: Application.auth, name_: file.Name }, null, true, null, true, callbacks);
		                return w.promise();
		            });
		        });
		    });

		};

        this.UploadObjects = function () {

            Application.FileDownload.ShowUploadDialog("Import Objects", function (filename, data) {
                Application.RunNext(function () {
                    return Application.FileDownload.UploadFile(filename, data, function (file) {

                        var callbacks = new Object();
                        callbacks.onerror = function (e) { 
							setTimeout(function () {                                
								Application.Error(e);
                            }, 1000);
						};
                        callbacks.onsuccess = function (r) {

                            UI.HideServerProgress();
                            setTimeout(function () {

                                if (r && r.Message)
                                    Application.Error(r.Message);
                                Application.Message(r);

                                w.resolve();

                            }, 1000);
                        };
                        callbacks.onsend = function () { };

                        UI.ShowServerProgress();

                        var w = $wait();
                        Application.ExecuteWebService("UploadObjects", { auth: Application.auth, name_: file.Name }, null, true, null, true, callbacks);
                        return w.promise();
                    });
                });
            });

        };

        this.MergeObjects = function () {

            Application.FileDownload.ShowUploadDialog("Upload Zip File", function (filename, data) {
                Application.RunNext(function () {
                    return Application.FileDownload.UploadFile(filename, data, function (file) {

                        Application.RunNext(function () {
                            return $codeblock(
                                function () {
                                    return Application.WebServiceWait("MergeObjects", { auth: Application.auth, name_: file.Name });
                                },
                                function (name) {
                                    window.open('https://go.scrubit.com.au/File/' + name);
                                }
                            );
                        });
                    });
                });
            });

        };

        this.SplitObjects = function () {

            Application.FileDownload.ShowUploadDialog("Split Objects", function (filename, data) {
                Application.RunNext(function () {
                    return Application.FileDownload.UploadFile(filename, data, function (file) {

                        var callbacks = new Object();
                        callbacks.onerror = function () { };
                        callbacks.onsuccess = function (r) {
                            Application.Message("Done. Please download from the File list");
                            w.resolve();
                        };
                        callbacks.onsend = function () { };

                        var w = $wait();
                        Application.ExecuteWebService("SplitObjects", { auth: Application.auth, name_: file.Name }, null, true, null, true, callbacks);
                        return w.promise();
                    });
                });
            });

        };

        this.StartMaintenanceMode = function () {

            Application.RunNext(function () {

                var options = new OptionsWindow({
                    caption: 'Start Maintenance',
                    fields: [
                        { Name: "Message", Caption: "Message", Type: "Text", Size: 1000, Mandatory: true },
                        { Name: "Time", Caption: "Time", Type: "DateTime", Mandatory: true }
                    ]
                });

                options.CloseFunction(function (okclicked) {
                    if (okclicked) {
                        return Application.StartMaintenanceMode(options.GetOption("Message"),options.GetOption("Time"));
                    }
                });
                return options.Open();

            });
        };

        this.EndMaintenanceMode = function () {
            Application.RunNext(Application.EndMaintenanceMode);
        };        

        this.ExportUserLayout = function (user_) {
            return $codeblock(
                function () {
                    return Application.ExportUserLayout(user_);
                },
                function (name) {
                    window.open('https://go.scrubit.com.au/File/' + name);
                }
            );
        };

        this.ImportUserLayout = function () {

            Application.FileDownload.ShowUploadDialog("Import User Layout", function (filename, data) {
                Application.RunNext(function () {

                    var options = new OptionsWindow({
                        caption: 'Select a User to Import to',
                        fields: [
                          {
                              Name: "User",
                              Caption: "Username",
                              Type: "Code",
                              LookupTable: "Xpress User",
                              LookupField: "Username",
                              LookupColumns: "Username",
                              LookupColumnCaptions: "Username",
                              Mandatory: true
                          }
                        ]
                    });

                    options.CloseFunction(function (okclicked) {
                        if (okclicked) {
                            return Application.FileDownload.UploadFile(filename, data, function (file) {

                                var callbacks = new Object();
                                callbacks.onerror = function () { };
                                callbacks.onsuccess = function (r) {

                                    UI.HideServerProgress();
                                    setTimeout(function () {

                                        if (r && r.Message)
                                            Application.Error(r.Message);
                                        Application.Message("Imported Successfully");
                                        w.resolve();

                                    }, 1000);
                                };
                                callbacks.onsend = function () { };

                                UI.ShowServerProgress();

                                var w = $wait();
                                Application.ExecuteWebService("ImportUserLayout", { auth: Application.auth, user_: options.GetOption("User"), name_: file.Name }, null, true, null, true, callbacks);
                                return w.promise();
                            });
                        }
                    });
                    return options.Open();
                });
            });

        };

        this.RefreshProfileImages = function () {
            $("#imgProfile").css("background-image","url("+_self.ProfileImageURL()+"?r="+(new Date()).getTime()+")");
        };

        this.LoadProfileImage = function(){

            if (Application.UnsupportedIE() || Application.IsOffline() || Application.restrictedMode)
                return;

            $("#imgProfile").css("background-image","url("+_self.ProfileImageURL()+"?r="+(new Date()).getTime()+")")
            .unbind("click")
            .on("click", function () {
                _self.ProfileImageOnClick();                    
            });

        };
		
		this.ProfileImageOnClick = function(){
			
			_self.LoadPage("Xpress User Card","WHERE(Username=CONST("+Application.auth.Username+"))",{dialog: true});
			
		};

        this.Authorize = function (options_) {

            var w = $wait();

            $code(

                function () {

                    //Show load.
                    Application.Loading.Show("tdMain");
                    m_hideErrors = false;

                    //Create a new auth object.
                    Application.auth = new Application.Objects.AuthInfo();
                    Application.auth.Instance = m_params["instance"];

                    if (options_ != null) {
                        if (options_.type == "Windows") { //Windows Auth.

                            Application.auth.Type = Application.authType.Login;
                            Application.auth.Username = "";
                            Application.auth.Password = "";
                            if (options_.remember == true)
                                Application.auth.Remember = true;

                        } else if (options_.type == "Login") { //Login form.

                            Application.auth.Type = Application.authType.Login;
                            Application.auth.Username = options_.username;
                            Application.auth.Password = options_.password;
                            if (options_.remember == true)
                                Application.auth.Remember = true;

                        } else if (options_.type == "AuthSecret") {

                            Application.auth.Type = Application.authType.Login;
                            Application.auth.AppSecret = options_.secret;
							
						} else if (options_.type == "Token") {

                            Application.auth.Type = Application.authType.Token;
                            Application.auth.AppSecret = options_.token;

						} else if (options_.type == "Tile") { //Login tile.

                            Application.auth.Type = 999;
                            Application.auth.Username = options_.username;
                            Application.auth.Password = options_.passcode;                            
							
                        } else { //Cookie.

                            Application.auth.Type = Application.authType.Cookie;
                            Application.auth.OfflineAuth = options_.offlineAuth;
                        }
                    }

                    return Application.Authorize();
                },

                function (a) {

                    // Liveware 04/03/14 3.2.9.10 AS
                    if (a.SessionID == null) {
                        parent.window.location.reload();
                    }
                    Application.auth = a;
                    m_sessionID = a.SessionID;

                    Application.Fire("Authorized");

                    _self.LoadProfileImage();

                    return Application.GetUserLayout(Application.auth.Username, "MAINMENU");
                },

                function (layout) {

                    if (layout != "") {
                        m_layout = $.parseJSON(layout);
                        m_layout.Favourites = Default(m_layout.Favourites, []);
                        m_layout.Popular = Default(m_layout.Popular, []);
                    }
                    
                }

            );

            return w.promise();

        };

        this.LoadPage = function (id_, view_, options_, parent_, singleThread_, callback_) {

			//Close search.
			m_searchQueue=[];
			$(".searchdropdown").remove();
		
            if (!Application.CheckOfflineObject("PAGE", id_))
                return;

            if (m_params["generate"] == "true")
                return;

            //Open the page viewer.
            Application.RunNext(function () {

                return $codeblock(
                    function () {

                        options_ = Default(options_, new Object());
                        options_.id = id_;
                        view_ = Default(view_, "");
                        if (view_ != "")
                            options_.view = view_;

                        if (parent_ != null) {
                            var win = UI.WindowManager.GetWindow(parent_);
                            if (win)
                                options_.parentwin = win;
                        }

                        var form = new PageViewer(options_);
                        if (parent_ != null) {
                            form.CloseFunction(function () {
                                Application.RunNext(function () {
                                    var win = UI.WindowManager.GetWindow(parent_);
                                    if (win) {
                                        return win.Update(true,true,true);
                                    }
                                }, false, "UPDATEPAGE" + parent_);
                            });
                        }
                        return form.Open();
                    },
					function(form){
						if(callback_)
							callback_(form);							
					}					
                );
            }, null, "LOADPAGE" + id_, null, !singleThread_);

            if (Application.IsInMobile()) {
                $("#divSideMenu,#divFactbox").panel("close");
            }
        };

        this.LoadExternalPage = function (id_, home_) {

            if (!Application.CheckOfflineObject("PAGE", id_))
                return;

            Application.RunNext(function () {

                return $codeblock(

                        function () {
                            return new Page(id_);
                        },

                        function (obj) {

                            if (obj == null) {
                                Application.Error(Application.StrSubstitute("Form $1 does not exist.", id_));
                            }

                            if (obj.AllowExternal == false) {
                                Application.Error(Application.StrSubstitute("Form $1 cannot be viewed from an external URL.", id_));
                            }

                            var form = new PageViewer({ id: id_, recid: m_params["rid"], view: m_params["initview"], closebutton: !Application.IsInFrame(), homepage: home_ });
                            return form.Open();
                        }
                );
            },null,null,null,true);
        };

        this.LoadFrame = function () {

            //Load external page or home page.
            if (m_params["pageid"] != null) {
                _self.LoadExternalPage(m_params["pageid"], true);
                UI.WindowManager.HasHome(true);
            }


            Application.Loading.Hide("tdMain");

            m_loaded = true;

        };

        this.Disconnect = function (clearcookie_) {

            Application.RunNext(function () {

                var w = $wait();

                $code(

                    function () {
                        m_sessionID = "";
                        Application.supressError = true;
                        //Application.auth.Layout = $.toJSON(m_layout); //Save layout.
                        if (!Application.IsOffline() && Application.connected)
                            return Application.Disconnect(true, clearcookie_);
                    },

                    function () {
                        Application.supressError = false;
                        _self.OnLogout();
                    }
                );

                return w.promise();
            });
        };

        this.SideVisible = function () {
            return m_sideVisible;
        };

        this.ToggleMainMenu = function (value_) {

            if (value_ != null)
                m_menuVisible = !value_;

            if (Application.IsInFrame())
                return;
            m_menuVisible = !m_menuVisible;
            SetWidths();
        };

        this.ToggleSide = function (value_) {

            if (Application.IsInMobile())
                return;

            if (value_ != null)
                m_sideVisible = !value_;

            m_sideVisible = !m_sideVisible;
            SetWidths();
        };

        function SetWidths() {

            if (Application.IsInMobile())
                return;

            //Set factbox width.
            if (!m_sideVisible) {
                $("#tdSide").css("min-width", "40px").width("1%").hide();
                $("#tdMain").css("max-width","100vw").width("100%");
                $("#AppSideWorkspace").hide();
            } else {
                $("#tdSide").css("max-width",$(window).width() * .24).css("min-width", "230px").width("24%").show();
                $("#tdMain").css("max-width",$(window).width() * .70).width("70%");
            }

            setTimeout(UI.WindowManager.OnResize, 100);
        };

        this.RememberOnClick = function () {
            if (RememberLogin())
                if (!_self.CheckCookie())
                    RememberLogin(false);
        };

        this.CheckCookie = function () {
            var check = true;
            if (!$moduleloaded('CookieManager'))
                check = false;
            if (check) {
                check = Application.CookieManager.Save('LIVEAPPTESTCOOKIE', 'test', 7);
                if (check) {
                    var cookie = Application.CookieManager.Get('LIVEAPPTESTCOOKIE');
                    check = (cookie != null);
                }
            }
            if (!check)
                Application.Message("Cookies need to be enabled on your browser in order to use this function. Please contact support.");
            return check;
        };

        this.SearchHidden = function(){
            return m_hideSearch;
        };

        this.Params = function () {
            return m_params;
        };

        this.ProfileImageURL = function (user) {
            var url = Application.Fire("GetProfileImageURL", user);
            if (url)
                return url;
            user = Default(user, Application.auth.Username);
            return 'https://go.scrubit.com.au/' + Application.auth.Instance + '/ProfileImage/' + user;
        };

        this.UpdateSolution = function (url_, force_) {
            Application.RunNext(function () {
                Application.Loading.Show("tdMain");
                return $codeblock(
                  function () {
                      Application.Loading.Hide("tdMain");
                      UI.ShowServerProgress();
                      return Application.WebServiceWait((force_ ? "SolutionUpdateForce" : "SolutionUpdate"), { auth: Application.auth, url_: url_ });
                  },
                  function (msg) {
                      Application.Cache.RemoveAll();
                      UI.HideServerProgress();
                      UI.WindowManager.RemoveAll();
                      UI.StatusBar(false);
                      setTimeout(function () {
                          Application.Message(msg);
                      }, 50);
                  }
                );
            });
        };

        this.ShowLoad = function () {
            Application.Loading.Show("tdMain");
        };

        this.HideLoad = function () {
            Application.Loading.Hide("tdMain");
        };

        this.Loaded = function () {
            return m_loaded;
        };

        this.GetInstance = function () {
            if (Application.auth.Instance == "")
                return m_params["instance"];
            return Application.auth.Instance;
        };

        //#endregion

        //#region Events

        this.Error = function (e) {

            try {

                if (m_hideErrors)
                    return;

                //Hide all throbbers.
                if ($moduleloaded("LoadingManager")) {
                    Application.Loading.Hide("divLogin");
                    Application.Loading.Hide("tdMain");
                }

                //Startup error.
                if (m_runningStartup) {
                    m_runningStartup = false;
                    Application.ShowError(e, function () {
                        Application.RunNext(function () {
                            if (Application.IsInFrame() || Application.restrictedMode) {
                                _self.LoadFrame();
                            } else {
                                return _self.LoadMainMenu();
                            }
                        });
                    });
                    return;
                }

                //Lost connection to server.
                if (typeof e.indexOf != 'undefined') {
                    if (e == "error" ||
                    e.toLowerCase() == "server too busy" ||
                    e.toLowerCase() == "internal server error" ||
                    e.toLowerCase() == "unknown" ||
                    e.toLowerCase() == "ok" ||
                    e.toLowerCase() == "not found") {
                        Application.connected = false;
                        return;
                    } else if (Application.HasDisconnected(e)) {					
						if (m_params["returnurl"] != null) 
							window.location = m_params["returnurl"]+(Application.IsInMobile() ? "?mobile=true" : "");
                        m_hideErrors = true;
                        if (Application.restrictedMode) {
                            window.location = Application.url + m_params["instance"];
                            return;
                        }
                        Application.ShowError(e, function () {
                            Application.RunSilent(function () {
                                if(Application.serviceWorkerReg){
                                    Application.serviceWorkerReg.update();
                                }else if (window.applicationCache)
                                    window.applicationCache.update();
                            });
                            if (e.indexOf("Invalid request. Please try again.") == -1) {
                                //Auto log in.
                                Application.RunNext(function () {
                                    return _self.LoginFromCookie();
                                });
                            }
                        });
                        _self.OnLogout();
                        return;
                    }
                }

                if ($moduleloaded("WindowManager")) {
                    if (UI.WindowManager.Error(e) == true) {
                        return;
                    }
                }

                Application.ShowError(e, function () {
                    if (typeof e.indexOf != 'undefined') {
                        if (e.indexOf("Username or password is invalid.") != -1) {
                            _self.ShowLogin(true);
                            setTimeout(function () { $("#txtUsername").select(); }, 500);
                        }
                    }
                });

                if (!m_loaded) {
                    //m_hideErrors = true;
                    _self.Disconnect();
                    setTimeout(function () { $("#txtUsername").select(); }, 1000);
                    _self.OnLogout();
                    return;
                }

            } catch (err) {
            }
        };

        this.Close = function () {

            try {

                Application.Fire("Exit");

                if (Application.auth.SessionID != "") {
                    //Application.auth.Layout = $.toJSON(m_layout); //Save layout.
                    Application.Disconnect();
                }

            } catch (e) {
            }
            return;
        };

        //#endregion

        //#region Main Menu Functions

        this.AddPopular = function (def_) {

            for (var i = 0; i < m_popular.length; i++) {
                if (m_popular[i].name == def_.name) {
                    m_popular[i].count += 1;
                    _self.RefreshFavorites();
                    return;
                }
            }

            def_.count = 1;
            m_popular.push(def_);
            _self.RefreshFavorites();			
            _self.SavePopular();
        };

        this.RefreshFavorites = function () {

            $(".favoritemenu").remove();

            for (var i = 0; i < m_favorites.length; i++) {
                for (var j = 0; j < m_popular.length; j++) {
                    if (m_popular[j].name == m_favorites[i].name) {
                        m_popular.splice(j, 1);
                        break;
                    }
                }
                if (Application.CheckOfflineObject("PAGE", m_favorites[i].formid)){
                    var li = _self.PrintSideLink(m_mainMenu, m_favorites[i].icon, m_favorites[i].name, m_favorites[i].action, true);
                    li.addClass('favoritemenu');
                }
            }

            if (m_popular.length > 0) {

                m_popular.sort(function (a, b) {
                    if (a.count == b.count)
                        return 0;
                    if (a.count > b.count) {
                        return -1;
                    } else {
                        return 1;
                    }
                });

                var added = false;
                for (var i = 0; (i < m_popular.length && i <= 5); i++) {
                    if (Application.CheckOfflineObject("PAGE", m_popular[i].formid)) {
                        if (!added){
                            var st = _self.PrintSideText(m_mainMenu, UI.IconImage('mdi-star',null,14) + ' <b>Popular</b>', true);
                            st.addClass('favoritemenu');
                        }
                        added = true;
                        var li = _self.PrintSideLink(m_mainMenu, m_popular[i].icon, m_popular[i].name, m_popular[i].action, false, true);
                        li.addClass('favoritemenu');
                    }
                }
                if (added){
                    var li = _self.PrintSideLink(m_mainMenu, 'close', 'Clear Popular', "Application.App.ClearPopular();", false, true);
                    li.addClass('favoritemenu');
                }
            }

            _self.RefreshMenu();
        };

        this.RefreshMenu = function () {
        };

        this.LoadMainMenu = function () {

            //Clear menu.
            $("#divSide").html('');

            //Load favorites.
            _self.LoadFavorites();

            //Load popular.
            _self.LoadPopular();

            UI.WindowManager.HasHome(false);

            var w = $wait();

            $code(

				function () {

				    var id = "VP$RoleCenterPage" //Dynamic Virtual Page.

                    var mnu = _self.PrintSideGroup('MAIN MENU');

				    if (id != 0 && !Application.IsInMobile()) {
                        _self.PrintSideLink(mnu, 'home', "Dashboard", "Application.App.LoadPage('" + id + "',null,{homepage:true});");
                        _self.PrintSideLink(mnu, 'mdi-logout', "Logout", "Application.App.Logout();");
				    }
					
					var mnu2 = Application.Fire("CreateMenu", mnu);		    
					if (mnu2)
					    mnu = mnu2;

                    m_mainMenu = mnu;

                    if (!Application.IsInMobile())
                        _self.RefreshFavorites();

                    if (Application.IsInMobile()) {

                        m_mainMenu.children().first().html(Application.auth.Username).addClass("mnuUser");

                        if(!Application.IsOffline())                        
                            _self.PrintSideLink(mnu, 'key3', (m_params["returnurl"] != null ? 'Exit' : 'Logout'), "Application.App.Logout();");
                    }	

                    //Load external page or home page.
                    if (m_params["pageid"] != null) {

                        if (id != "") {
                            _self.LoadPage(id, null, { homepage: true });
                            UI.WindowManager.HasHome(true);
                        }
                        _self.LoadExternalPage(m_params["pageid"]);

                    } else if (id != "") {
                        _self.LoadPage(id, null, { homepage: true });
                        UI.WindowManager.HasHome(true);
                    }
                },

                Application.LoadMainMenu,

                function (m) {

                    //Load menu groups.
                    for (var i = 0; i < m.length; i++) {

                        var mnu2 = _self.PrintSideGroup(m[i].Name);

                        var added = false;

                        //Load menu items.
                        for (var j = 0; j < m[i].Items.length; j++) {

                            var item = m[i].Items[j];
							
							var skip = false;
							if(Application.IsInMobile() && Application.HasOption(item.Options,"desktoponly"))
								skip = true;
							if(!Application.IsInMobile() && Application.HasOption(item.Options,"mobileonly"))
								skip = true;

                            if (Application.CheckOfflineObject(item.Type, item.ID) && !skip) {
                                added = true;
                                if (item.Icon == "")
                                    item.Icon = "window";
                                _self.PrintSideLink(mnu2, item.Icon, item.Name, "Application.App.LoadPage('" + item.ID + "');", false, false, item.ID);
                            }
                        }

                        if (m[i].Name == "Admin" && !Application.IsOffline() && !Application.IsInMobile()) {
                            added = true;
                            _self.PrintSideLink(mnu2, 'mailbox_empty', 'Send Message', "Application.Notifications.ShowMessageForm();");
                            _self.PrintSideLink(mnu2, 'media_play', 'Start Maintenance', "Application.App.StartMaintenanceMode();");
                            _self.PrintSideLink(mnu2, 'media_stop', 'Finish Maintenance', "Application.App.EndMaintenanceMode();");
                            _self.PrintSideLink(mnu2, 'box_software', 'Update Platform', "Application.RunNext(function(){return Application.UpdateManager.CheckForUpdates(true);});");
                        }

                        if (!added && mnu2)
                            mnu2.remove();
                    }

                    if (!Application.IsInMobile()) {

                        var mnu3 = _self.PrintSideGroup('TOOLS', 'mnuTools');
                        _self.PrintSideLink(mnu3, 'document_certificate', 'License', "Application.App.LoadPage('VP$LicenseViewer');");
                        if (!Application.IsOffline()) {

                            _self.PrintSideLink(mnu3, 'window_edit', 'Clear Layout', "UI.WindowManager.ClearLayout();");
                            _self.PrintSideLink(mnu3, 'box_next', 'Clear Cache', "UI.WindowManager.ClearCache();");
                            _self.PrintSideLink(mnu3, 'window_edit', 'Split Objects', "Application.App.SplitObjects();");
                            _self.PrintSideLink(mnu3, 'window_edit', 'Merge Objects', "Application.App.MergeObjects();");

                            var mnu4 = _self.PrintSideGroup('SERVER INFO', 'mnuServerInfo');
                            $("#mnuMain").append('<li><div id="divServerInfo" style="font-weight: normal; font-size: 12px; padding: 3px; height: auto; width: 200px; overflow-x: auto;"></div></li>');
                        }
                    }
                    m_serverInfo = $("#divServerInfo");

                    Application.Loading.Hide("tdMain");

                    _self.RefreshMenu();

                    //Auto check for updates.
                    if (m_params["updates"].toLowerCase() == "true")
                        Application.RunNext(Application.UpdateManager.CheckForUpdates);

                    Application.Fire("MenuLoaded", m);

                    m_loaded = true;
                }

            );

            return w.promise();
        };

        this.PrintSideGroup = function (name_, id_) {
            Application.LogInfo("Creating menu group: " + name_);
            var li = $('<ul class="menu-items"><li class="menu-item-group">'+name_+'</li></ul>');
            $("#mnuMain").append(li);
            return li;
        };

        this.PrintSideLink = function (mnu_, img_, name_, action_, fav_, pop_, id_) {
            
            Application.LogInfo("Creating menu item: " + name_);

            if (fav_ == null) fav_ = false;
            if (pop_ == null) pop_ = false;

            var image = "";
            if(img_){
                var path = img_.split("/");
                img_ = path[path.length-1];
                img_ = img_.split(".")[0];
                image = "<i class='mdi "+UI.MapMDIcon(UI.MapIcon(img_))+"' style='color: black; font-size: " + 
                    (Application.IsInMobile()?'20':'14')+"px'></i>";
            }

            var li = $('<li onclick="'+action_+'" data-ripple>'+image+
                (Application.IsInMobile()?' ':'&nbsp;&nbsp;')+name_+'</li>');
            if(!Application.IsInMobile()){
                if (!name_.within(["Dashboard", "Offline", "Clear Popular"]))
                    li.on('click', function () {
                        _self.AddPopular({
                            id: 1,
                            icon: img_,
                            name: name_,
                            action: action_,
                            formid: id_
                        });
                    });
            }
            mnu_.append(li);
            li.ripple({ color: "gainsboro"});

            var evname = 'contextmenu';
            if (Application.IsInMobile())
                return li;

            if (name_ == "Dashboard" || pop_ || name_ == "Offline" || name_ == "Clear Popular") {
                li.bind(evname, function (e) {
                    return false;
                });
                return li;
            }

            li[0].definition = {
                id: 1,
                icon: img_,
                name: name_,
                action: action_,
                formid: id_
            };

            if (!fav_) {
                li.bind(evname, function (e) {

                    for (var i = 0; i < m_favorites.length; i++) {
                        if (m_favorites[i].name == this.definition.name) {
                            return false;
                        }
                    }

                    Application.Confirm("Add this link to the Main Menu?", function (r) {
                        if (r == true) {
                            m_favorites.push(li[0].definition);
                            _self.RefreshFavorites();
							_self.SaveFavorites();
                        }
                    }, "Main Menu");
                    return false;
                });
            } else {
                li.bind(evname, function (e) {

                    Application.Confirm("Remove this link from the Main Menu?", function (r) {
                        if (r == true) {
                            for (var i = 0; i < m_favorites.length; i++) {
                                if (m_favorites[i].name == li[0].definition.name) {
                                    m_favorites.splice(i, 1);
                                    break;
                                }
                            }
                            _self.RefreshFavorites();
							_self.SaveFavorites();
                        }
                    }, "Main Menu");
                    return false;
                });
            }

            return li;
        };

        this.PrintSideText = function (mnu_, name_, pop_) {
            if (pop_ == null) pop_ = false;
            var li = $('<li class="menu-item-group">'+name_+'</li>');
            mnu_.append(li);
            return li;
        };

        this.SaveLayout = function () {

            Application.RunNext(function () {
                return Application.SaveUserLayout(Application.auth.Username, "MAINMENU", $.toJSON(m_layout));
            },null,null,true);
        };

        this.LoadFavorites = function () {

            m_favorites = new Array();

            if (m_layout && m_layout.Favourites) {
                m_favorites = m_layout.Favourites;
                return;
            }
        };

        this.SaveFavorites = function () {            
            m_layout.Favourites = m_favorites;
            _self.SaveLayout();
        };

        this.LoadPopular = function () {

            m_popular = new Array();

            if (m_layout && m_layout.Popular) {
                m_popular = m_layout.Popular;
                return;
            }
        };

        this.SavePopular = function () {            
            m_layout.Popular = m_popular;
            _self.SaveLayout();
        };

        this.ClearPopular = function () {
            Application.Confirm("Are you sure you wish to clear popular pages?", function (r) {
                if (r) {
                    m_popular = [];
                    _self.SavePopular();
                    _self.RefreshFavorites();
                }
            }, "Main Menu");
        };

        //#endregion

        //#region Login Functions

        this.ShowLogin = function (fromError_, skipFocus_) {

            Application.Loading.Hide("divLogin");

            if (Application.IsInMobile())
                $("#mainPage,.ui-panel-wrapper").css("background-color", $("#divMobileHeader").css("background-color"));

            Application.auth.Type = Application.authType.Login;
            $("#divMobileHeader,#AppWindows").hide();
            $("#divLogin,#imgHeader").show();

            $("#txtUsername, #txtPassword, #chkRemember").unbind("keyup", _self.LoginClick);
            $("#txtUsername, #txtPassword, #chkRemember").keyup(_self.LoginClick);
            
			if(!skipFocus_)
				$("#txtUsername").focus();

            Application.Fire("ShowLogin");
			
			if(Application.IsMobileDisplay()){
				$("#divLogin").css("max-width",$(window).width()-20);
			}

            $(window).resize();
        };

        this.LoginClick = function (ev) {
            if (ev.isDefaultPrevented())
                return;
            if (ev.keyCode == 13 && !UI.DialogVisible()) {
                Application.RunNext(_self.Login);
            }
        };

        this.Login = function () {

            if ($("#txtUsername").val() == "" || $("#txtPassword").val() == "") {

                //Check required fields.
                Application.ShowError("All form fields are required.", function () {
                    if ($("#txtUsername").val() == "")
                        setTimeout(function () { $("#txtUsername").select(); }, 500);
                    else if ($("#txtPassword").val() == "")
                        setTimeout(function () { $("#txtPassword").select(); }, 500);
                });

            } else {

                return $codeblock(

					function(){						
						if($moduleloaded("OfflineManager")){
							Application.auth.Username = $("#txtUsername").val();
							Application.auth.Username = Application.auth.Username.toUpperCase();
							var w = $wait();
							Application.Offline.HasDataPack(function(r){
								if(Application.IsOffline() == false && r){									
									Application.Confirm("You have an offline data package. Please select an option.",function(ret){
										if(ret == false){
											$("#offlineIndicatorText").click();	
											Application.Error("");										
										}else{
											w.resolve();
										}
									},null,"Go online and load the data to the server","Continue to work offline with the current data package")									
								}else{
									w.resolve();
								}	
							});
							return w.promise();												
						}
					},
				
                    function () {

                        return _self.Authorize({
                            type: "Login",
                            username: $("#txtUsername").val(),
                            password: $("#txtPassword").val(),
                            remember: RememberLogin()
                        });
                    },

                    function () {

                        //Clear the password.
                        $("#txtPassword").val("");

                        //Show the app.                        
                        return _self.OnLogin();
                    }
                );
            }

        };

        this.LoginFromCookie = function () {

            //#90 - Rewrite for secure cookies.

            return $codeblock(

                function () {
                    if (Application.IsOffline()) {
                        return true;
                    } else {
						Application.supressServiceErrors = true;
						return Application.LoginCookieExists(_self.GetInstance() + Application.authType.Login);
                    }
                },

                function (ret) {

					Application.supressServiceErrors = false;
				
                    if (ret) {

                        return $codeblock(

                            function () {

                                return _self.Authorize({
                                    type: "Cookie",
                                    offlineAuth: m_params["user"]
                                });
                            },

                            function () {

                                $("#txtUsername").val(Application.auth.Username);

                                //Show the app.                        
                                return _self.OnLogin();
                            }

                        );

                    } else {

                        //Show the login form.
                        _self.ShowLogin();

                    }

                }
            );
        };

        this.LoginFromWindowsAuth = function () {

            if (!Application.IsOffline()) {

                var w = $wait();

                $code(

                    function () {

                        return _self.Authorize({
                            type: "Windows"
                        });
                    },

                    function () {

                        //Show the app.                        
                        return _self.OnLogin();
                    }
                );

                return w.promise();

            } else {

                //Show the login form.
                _self.ShowLogin();
            }

        };

        this.LoginFromAppSecret = function (secret) {

            if (secret && !Application.IsOffline()) {

                var w = $wait();

                $code(

                    function () {

                        return _self.Authorize({
                            type: "AuthSecret",
                            secret: secret
                        });
                    },

                    function () {

                        //Show the app.                        
                        return _self.OnLogin();
                    }
                );

                return w.promise();

            } else {

                //Show the login form.
                _self.ShowLogin();
            }

        };

		this.LoginFromToken = function (token) {

            if (token && !Application.IsOffline()) {

                var w = $wait();

                $code(

                    function () {

                        return _self.Authorize({
                            type: "Token",
                            token: token
                        });
                    },

                    function () {

                        //Show the app.                        
                        return _self.OnLogin();
                    }
                );

                return w.promise();

            } else {

                //Show the login form.
                _self.ShowLogin();
            }

        };

        this.OnLogin = function () {

            //Can be used to hijack session!
            //$("#divStatus").html('Session ID: ' + Application.auth.SessionID);
            if (!Application.restrictedMode)
                $("#divStatus").html(Application.auth.Username);

            //Start the page timer.
            m_serverInfo = $("#divServerInfo");
            if(m_timer)
            m_timer.Start(true);

            if ($moduleloaded("FileDownloadManager"))
                Application.FileDownload.Start();

            //Show Elements.           
            if (!Application.restrictedMode)
                $("#lnkMenu,#lnkLogout,#sideToggle,#menuToggle,#txtGlobalSearch,#imgProfile,.search-container,#menuMain").show();
            $("#divMobileHeader,#AppWindows").show();

            //Hide Elements.
            Application.Loading.Hide("divLogin");
            $("#divLogin,#divAutoLogin").hide();
            if (Application.IsInMobile())
                $("#imgHeader").hide();

            if (Application.IsInMobile())
                $("#mainPage,.ui-panel-wrapper").css("background-color", '');

            if (!Application.restrictedMode) {

                //Show menu.            
                _self.ToggleMainMenu(true);
                //Hide side.            
                _self.ToggleSide(false);
            }

            Application.Fire("Login");

            return $codeblock(

                function () { //Load startup scripts
                    return $codeblock(
                        function () {

                            m_runningStartup = true;

                            var r = new Record();
                            r.Table = "Xpress Object";
                            r.View = "WHERE(Type=CONST(CODE),Startup=CONST(True))";
                            return r.FindFirst();
                        },
                        function (r) {
                            if (r.Count > 0)
                                return $loop(function (i) {
                                    return $codeblock(
                                        function () {
                                            return new CodeModule(r.Name);
                                        },
                                        function (cm) {
                                            if (cm.OnRun)
                                                return cm.OnRun(Application.auth);
                                        },
                                        function () {
                                            if (r.Next())
                                                return $next;
                                        }
                                    );
                                });
                        }
                    );
                },

				function(){
					
					m_runningStartup = false;
					
					if($moduleloaded("OfflineManager"))
						return Application.Offline.LoadDatapack();
                },
                
                _self.CheckChangePassword,

                function(){
                    COUNT("Xpress Global Search Setup",null,function(r){
                        if(r.Count === 0){
                            m_hideSearch = true;
                            $(".search-container").hide();
                        }
                    });
                },
				
                function () { //Load the main menu.                      

                    if (Application.IsInFrame() || Application.restrictedMode) {
                        _self.LoadFrame();
                    } else {
                        return _self.LoadMainMenu();
                    }
                }
            );
        };

        //#endregion

        //#region Logout Functions

        this.Logout = function () {

            if (Application.auth.SessionID == "") {
                _self.OnLogout();
                return;
            }

            Application.RunNext(function () {

				var msg = "Are you sure you want to logout?";
				if(m_params["returnurl"] != null)
					msg = "Do you want to exit?"
				
                Application.Confirm(msg, function (r) {
                    if (r == true) {
                        if (Application.IsOffline())
                            Application.Offline.RemoveLoginCookie();
                        if (m_params["returnurl"] != null) {
							window.location = m_params["returnurl"]+(Application.IsInMobile() ? "?mobile=true" : "");
						}else{
                            _self.Disconnect(true);
                        }
                    }
                }, "We'll miss you..");

            });
        };

        this.CheckChangePassword = function(){ 
            //Check if password needs changing.
            FINDSET("Xpress User",{Username: Application.auth.Username},function(r){
                if(r["Change Password On Login"]){
                    OPENPAGE("Change User Password", null, {
                        dialog: true
                    });
                }
            });
        };

        this.OnLogout = function () {

            _self.ToggleSide(false);

            if (Application.IsInMobile())
                $("#divSideMenu,#divFactbox").panel("close");

            //Hide menu.
            _self.ToggleMainMenu(true);

            if ($moduleloaded("WindowManager")) {
                UI.WindowManager.RemoveAll();
            }

            Application.Fire("Logout");

            m_loaded = false;

            //Page timer finish.
            if(m_timer)
            m_timer.Stop(true);

            if (m_serverInfo != null) {
                if ($moduleloaded("LoadingManager") && m_serverInfo.length > 0 && !Application.IsInMobile())
                    Application.Loading.Hide(m_serverInfo[0].id);
                m_serverInfo.html('');
            }
            m_serverInfo = null;

            if ($moduleloaded("FileDownloadManager"))
                Application.FileDownload.Finish();

            $("#menuToggle,#sideToggle,#lnkActions,#lnkMenu,#lnkLogout,#divMobileFooter,#txtGlobalSearch,#imgProfile,.search-container,#menuMain").hide();
            UI.StatusBar(false);
            $("#divSide,#divStatus,#tdImg,#mnuMain").html('');
            m_maintenanceMode = false;

            Application.auth = Application.Objects.AuthInfo();

            //Show login.
            _self.ShowLogin(true);
        };

        //#endregion        

        //#region Timer Functions

        this.OnTimer = function () {

            if (Application.IsOffline() || m_processing)
                return;

            var start_time = new Date().getTime();

            if (Application.auth.SessionID != "") {

                if ($moduleloaded("OfflineManager"))
                    if (Application.Offline.DownloadRequest() != null)
                        return;

                m_processing = true;
                Application.ExecuteWebService("GetServerInfo", { auth: Application.auth }, function (r) {                    

                    //Check for new website version.
                    try {
                        if(Application.serviceWorkerReg){
                            Application.serviceWorkerReg.update();
                        }else if (window.applicationCache && Application.connected)
                            window.applicationCache.update();
                    } catch (e) {
                        Application.LogError(e);
                    }

                    if (r == null)
                        return;

                    if (r[2]) {
                        if (!m_maintenanceMode)
                            Application.Message(r[2], null, "Scheduled Maintenance");
                        m_maintenanceMode = true;
                    } else if (m_maintenanceMode) {
                        m_maintenanceMode = false;
                    }

                    //Notifications.
                    if ($moduleloaded("NotificationManager"))
                        Application.Notifications.OnTimer(r[3]);

                    //Print server info.        
                    if (m_serverInfo != null && !Application.IsInFrame()) {
                        _self.PrintServerInfo(r, start_time);
                    }

                }, true, null, true);
            }
        };

        this.PrintServerInfo = function (r, time) {

            var html = "";
            html += '<b>User:</b> ' + Application.auth.Username + "<br/>";
            html += '<b>Login Time:</b> ' + $.format.date(Application.auth.LoginTime, 'hh:mm a') + "<br/>";
            html += '<b>Idle Time:</b> ' + r[0] + "<br/>";
            html += _self.PrintServerLoad(r[1], time) + "<br/>";

            var info = UI.WindowManager.GetWindowInfo();
            if (info != null) {
                html += '<br/><b>Page Name:</b> ' + info.ID + "<br/>";
                html += '<b>View:</b> ' + info.View + "<br/>";
            }

            m_serverInfo.html(html);
        };

        this.PrintServerLoad = function (str, time) {

            var ms = new Date().getTime() - time;

            if (ms < 0)
                ms = ms * -1;
            var color = "#00CC00";
            var text = "Good";
            if (ms > 300) {
                color = "#FF9999";
                text = "Bad";
            }
            return '<b>Server Load: <span style="color: ' + color + '">' + text + "</span></b>";
        };

        //#endregion

        //#region UI Functions

        this.Height = function () {

            var padding = 0;

            if (Application.IsInFrame()) {
                padding += 30;
            }

            if ($("#divWarning").is(":visible"))
                padding += $("#divWarning").outerHeight();

            return ($('#tdMain').outerHeight() - $("#AppWindows").outerHeight() - 30 - padding);
        };

        this.Width = function () {
            if (Application.IsInFrame()) {
                return $("#AppWorkspace").width() - 15;
            } else {
                return $("#tdMain").width() - 5;
            }
        }

        this.SideWidth = function () {
            return $("#AppSideWorkspace").width() - 5;
        }

        //#endregion                        

        //#region Private Functions        

        function CookieID(extra) {
            extra = Default(extra, "");
            var u = Application.auth.Username.replace("\\", "").replace("/", "");
            return "Liveapp Framework" + Application.auth.Instance + u + extra;
        };

        function RememberLogin(value) {

            if (value === undefined) {
                return $("#chkRemember").prop('checked');
            } else {
                $("#chkRemember").prop('checked', value);
                if (Application.IsInMobile())
                    $("#chkRemember").checkboxradio('refresh');
            }
        };

        //#endregion        

    });
/// <reference path="../Application.js" />

DefineModule("CacheManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '27/02/15   PF  Created class.'
        ]
    },

    function () {

        //#region Members

        var _self = this;
        var m_cache = new Object();

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.Cache = this;

            Application.On("Logout", _self.OnLogout);
        };

        this.OnLogout = function () {
            m_cache = new Object();
        };

        this.Check = function (cache_, key_) {
	
            if (Application.debugMode == true || Application.developerMode == true)
				return null;
		
            if (m_cache[cache_] == null)
                m_cache[cache_] = new Object();

            if (m_cache[cache_][key_] == null)
                return null;

            var r = new Object();
            app_deepTransferObjectProperties.call(r, m_cache[cache_][key_]);
            return r;
        };

        this.Save = function (cache_, key_, obj_) {

            if(Application.debugMode == true || Application.developerMode == true)
				return null;
			
            if (m_cache[cache_] == null)
                m_cache[cache_] = new Object();

            var r = new Object();
            app_deepTransferObjectProperties.call(r, obj_);
            m_cache[cache_][key_] = r;
        };

        this.Remove = function (cache_, key_) {
			
            if(Application.debugMode == true || Application.developerMode == true)
				return null;
			
            if (m_cache[cache_] == null)
                return;
            m_cache[cache_][key_] = null;
        };

        this.RemoveAll = function () {
            m_cache = new Object();
        };

        //#endregion

    });


/// <reference path="../Application.js" />

DefineModule("CameraManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2014, 01, 31),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '27/01/15   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {
            Application.Camera = this;
        };

        this.TakePhoto = function (callback, quality, width) {

            quality = Default(quality, 20); //Issue #73: Lower quality of photos
            width = Default(width, 800);

            if (!window.FileReader)
                Application.Error("Unable to access camera. Please contact support");

            var id = $id();

            $("body").append('<input id="file' + id + '" type="file" style="display:none;" />');
            
            $('#file' + id).fileReaderJS({
                on: {
                    load: function (url) {
                        $('#file' + id).remove();
                        UI.ImageManager.Resize(url, width, 0, 0, function (resimg) {
                            UI.ImageManager.ChangeQuality(resimg, quality, function (img) { //Issue #73: Lower quality of photos     			
								//alert(img.length);
                                callback(UI.ImageManager.Base64(img));
                            });
                        });
                    }
                }
            });
            $('#file' + id).click();
            
        };

        //#endregion

    });
/// <reference path="../Application.js" />

DefineModule("CodeEditor",

    {
        singleInstance: false,
        requiresVersion: '3.0',
        created: new Date(2014, 01, 31),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '31/01/14   PF  Created class.'
        ]

    },

    function (parent_, onchange_) {

        //#region Members

        var _self = this;
        var m_editor = null; //Codemirror

        //#endregion

        //#region Public Methods

        this.Constructor = function (parent_, onchange_) {

            if (Application.testMode && arguments[0] == null) return;

            m_editor = CodeMirror.fromTextArea(parent_, {
                mode: "javascript",
                lineNumbers: true,
                viewportMargin: Infinity,
                lineWrapping: true,
                extraKeys: {
                    "Ctrl-Space": "autocomplete"
                },
                gutters: ["CodeMirror-lint-markers"],
                lint: true
            });

            if(onchange_)
                m_editor.on("change", onchange_);
        };

        this.Value = function (value) {
            if (value == null) {
                return m_editor.getValue();
            } else {
                m_editor.setValue(value);
            }
        };

        this.OnLoad = function () {
        };

        //#endregion

        this.Constructor(parent_, onchange_);

    });
/// <reference path="../Application.js" />

DefineModule("CodeEngine",

     {
         singleInstance: true,
         depends: ["IDEngine"],
         requiresVersion: '3.0',
         created: new Date(2013, 09, 03),
         version: '1.0',
         author: 'Paul Fisher',
         copyright: 'Copyright 2015, Paul Fisher',

         changelog: [
            '03/09/13   PF  Created class.',
            '26/09/13   PF  Updated language.',
            '02/10/13   PF  Changed thread timer to 10ms from 500ms'
        ]

     },

    function () {

        //#region Members

        var _self = this;
        var m_running = true;
        var m_currentThread = 0;
        var m_queue = [];
        var m_priority = [];
		var m_killed = [];

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.CodeEngine = this;

            //Global Assign
            $wait = Application.CodeEngine.Wait;
            $code = Application.CodeEngine.Code;
            $codeblock = Application.CodeEngine.CodeBlock;
            $codeinsert = Application.CodeEngine.CodeInsert;
            $loop = Application.CodeEngine.Loop;
            $next = "<NEXTLOOP>"; 
            $stopallthreads = Application.CodeEngine.StopAllThreads;
            $thread = Application.CodeEngine.CreateThread;
            $locked = Application.CodeEngine.Locked;
            $flag = "<FLAG>";

            Application.On("Login", function () {
                m_killed = [];
            });
        };

        this.Wait = function () {
            return new $.Deferred();
        };

        this.Code = function () {

            //Create a new queue.
            m_queue[m_queue.length] = [];

            //Check for argument array.
            if (arguments.length > 0 && $.isArray(arguments[0])) {

                //Add the async functions to the new queue.
                for (var i = 0; i < arguments[0].length; i++) {
                    m_queue[m_queue.length - 1].push(arguments[0][i]);
                };

            } else {

                //Add the async functions to the new queue.
                for (var i = 0; i < arguments.length; i++) {
                    m_queue[m_queue.length - 1].push(arguments[i]);
                };
            }

            Application.LogDebug(Application.StrSubstitute("Created new queue: #$1 with $2 methods.", (m_queue.length - 1), arguments.length));

            //Resolve the first function.
            setZeroTimeout(function () { _self.ResolveQueue() });

        };

        this.CodeBlock = function () {

            var w = $wait();

            var arr = new Array();

            for (var i = 0; i < arguments.length; i++) {
                arr.push(arguments[i]);
            };
            //Bug fix for code insert.
            arr.push(function (r) { return r });

            _self.Code(arr);

            return w.promise();
        };

        this.CodeInsert = function () {

            //Create a queue if one does not exist.
            if (m_queue.length == 0)
                m_queue[m_queue.length] = [];

            var currQueue = m_queue[m_queue.length - 1];

            //Find insert point in current block.
            var index = 0;
            for (index = 1; index < currQueue.length; index++) {
                var method = currQueue[index];
                if (method != null)
                    if (method.toString().indexOf("$flag") == -1)
                        break;
            }

            if (index == 0)
                index += 1;

            //Add the async functions to the existing queue.
            for (var i = 0; i < arguments.length; i++) {
                currQueue.splice(index, 0, arguments[i]);
                index += 1;
            };
        };

        this.RemoveLevel = function () {
            m_queue.splice(m_queue.length - 1, 1);
        };

        this.IsNested = function () {
            return m_queue.length > 1
        };

        this.ResolveQueue = function (result_) {

            if (m_queue.length == 0) return;

            var i = m_queue.length - 1;

            Application.LogDebug(Application.StrSubstitute("Attempting next method in Queue #$1.", i));

            //Save result.
            var arr = [];
            arr.push(result_);

            var method = m_queue[i][0];
            if (m_queue[i].length <= 1) {
                Application.LogDebug(Application.StrSubstitute("Last method in Queue #$1.", i));
                _self.RemoveLevel();
            }

            //Don't run null methods.
            if (method == null) {
                Application.LogDebug("No method! Running next method.");
                _self.RunNextFunction();
                return;
            }

            Application.Fire("CodeBlockFire", method.toString());

            Application.LogDebug(method.toString());

            try {

                $.when(

                //Run method.
		        method.apply(null, arr)

            ).then(

                function (result2) { //Sucess.     

                    Application.LogDebug("Finished method.");

                    //Check if this thread is still running.
                    if (!_self.CheckStatus())
                        return;

                    //Run next function.
                    _self.RunNextFunction(result2);

                },

			    function (e) { //Error.
			    }

            );

            } catch (e) {
				
				//Log the method for debugging purposes.
				Application.Log.LogObject(method);
				
                if (e != "")
                    Application.Error(e);
                if (Application.testMode)
                    _self.RunNextFunction(result_);
            }
        };

        this.RunNextFunction = function (param_) {

            if (m_queue.length > 0) {
                m_queue[m_queue.length - 1].shift();
                setZeroTimeout(function () {
                    _self.ResolveQueue(param_)
                });
            }

        };

        this.Loop = function (func) {

            var recfunc = function (i) {

                var w2 = $wait();

                $code(

                    function () {
                        return func(i);
                    },

                    function (ret) {
                        if (ret != null) {
                            if (ret == $next) {
                                return recfunc(i + 1);
                            } else {
                                return ret;
                            }
                        }
                    }
                );

                return w2.promise();
            };

            var w = $wait();

            //Start recursion
            $code(
		        function () {
		            return recfunc(0);
		        }
	        );

            return w.promise();
        };

        this.CheckStatus = function () {

            if (!m_running) {

                _self.ClearThread();
                _self.Start();

                return false
            }
            return true;
        };

        this.StopAllThreads = function () {

            Application.LogDebug("Clearing all threads.");
            m_killed = m_killed.concat(m_priority);
            if (m_killed.indexOf(m_currentThread) != -1)
                m_killed.splice(m_killed.indexOf(m_currentThread), 1);
            _self.Stop();            
			m_priority = [];

        };

        this.CreateThread = function (func, id, i, skipDelay, threaduid) {

            if (skipDelay)
                return $codeblock(func);

            if (id == null || threaduid != null) {
                id = Default(threaduid, $id());
                if (m_priority.indexOf(id) != -1)
                    return;
                m_priority.push(id);
                Application.Fire("ThreadCreated");
                Application.LogDebug(Application.StrSubstitute("Created new thread: #$1", id));
            }
			
			//Check killed threads.
            if (m_killed.indexOf(id) != -1) {
                m_killed.splice(m_killed.indexOf(id), 1);
                if (m_priority.indexOf(id) != -1) {
                    m_priority.splice(m_priority.indexOf(id), 1);
                }
                return;
            }

            if (i == null) i = 0;
            if (m_priority.length > 0) {

                //A different thread is still running.    
                if (m_priority[0] != id || m_running == false) {				
					
                    setTimeout(function () {
                        //Application.LogInfo(Application.StrSubstitute("Queued Thread: #$1.", id));
                        $thread(func, id, i + 1);
                    },1);
                    return;
                }
            }

            //Run this thread!
            m_currentThread = id;
            Application.LogDebug(Application.StrSubstitute("Started Thread: #$1.", id));
            Application.Fire("ThreadCreated");

            $code(

                function () {
                    return func();
                },
                
                function () {					
                    Application.LogDebug(Application.StrSubstitute("Stopped Thread: #$1.", id));
                    _self.Stop();
                    Application.Fire("ThreadFinished");					
                }                

            );

        };

        this.ClearThread = function () {
            if (m_currentThread != 0) {
                if (m_priority.length > 0)
                    m_priority.splice(0, 1);
                m_currentThread = 0;
                m_queue = [];
            }
        };

        this.Start = function () {
            if (m_queue.length <= 0) {
                _self.ClearThread();
                m_running = true;
            }
        };

        this.Stop = function () {
            m_running = false;
            _self.Start();
        };

        this.Restart = function () {
            m_queue = [];
            _self.StopAllThreads();
            //_self.Start();
        };

        this.Locked = function () {
            return m_queue.length != 0;
        };

        //#endregion

    });


/// <reference path="../Application.js" />

DefineModule("CookieManager",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 17),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '17/09/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;

        //#endregion

        //#region Public Methods       

        this.OnLoad = function () {

            //Assign Module
            Application.CookieManager = this;
        };

        this.Get = function (name) {
            try {
                name = name.toLowerCase();
                //Get the cookie.
                var cookie = $.cookie(name);
                return cookie;
            } catch (e) {
                return null; //Cookies not allowed.
            }
        };

        this.Save = function (name, val, expires) {
            //Save the cookie.
            try {
                name = name.toLowerCase();
                $.cookie(name, val, { expires: expires, path: '/' });
            } catch (e) {
                return false;
            }
            return true;
        };

        this.Remove = function (name, expires) {

            try {
                name = name.toLowerCase();
                $.removeCookie(name, { expires: expires, path: '/' });
            } catch (e) {
            }
        };

        //#endregion

    });
/// <reference path="../Application.js" />

DefineModule("FileDownloadManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_files = [];
        var m_timer = null; //Timer        
        var m_requests = [];		
		var m_chunksize = null;
		var m_timeout = 5000;
		var m_showProgress = true;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {
        };

        this.OnLoad = function () {

            //Assign Module
            Application.FileDownload = this;

            m_timer = new Timer(50, _self.OnTimer, null, function () {
                for (var i = 0; i < m_requests.length; i++) {
                    var xhr = m_requests[i];
                    xhr.abort();
                }
                m_requests = [];
            });

            Application.On("ProgressCancel", function (id) {
                if (id != "FileDownload") return;
                Application.HideProgress();
                _self.Finish();
                m_files = [];
                _self.Start();
            });
        };

        this.Start = function () {
            if(m_timer)
            m_timer.Start(true);
        };

        this.Finish = function () {
            if(m_timer)
            m_timer.Stop(true);
        };

        this.ShowUploadDialog = function (title_, callback_) {

            var id = $id();
            var value = null;
            var boxy = new Boxy("<div id='" + id + "' class='ui-widget-content' style='border-width: 0px; height: 98%;'></div>", {
                title: UI.BigIconImage("arrow_up_blue", null, 30) + " " + title_,
                closeText: "X",
                modal: true,
                unloadOnHide: true,
                show: false,
                beforeHide: function () {
                    if (callback_ && value)
                        callback_(value[0], value[1]);
                    return true;
                }
            });

            var win = $("#" + id);
            var field = new Application.Objects.PageFieldInfo();
            field.Editable = true;
            field.Name = "File";
            field.Caption = "File";
            var cont = new FileLookup(field, null);
            cont.CreateDesktop(win);
            cont.OnValueChange = function (name, val) {
                val = atob(val);
                value = val.split("|");
                boxy.hide();
            };
            cont.SetSize(340, 300);
            boxy.center();
            boxy.show();
            boxy.tween(350, 300);
        };

        this.UploadFile = function (name_, data_, finish_, cancel_, showUI_, mime_) {

            showUI_ = Default(showUI_, true);
            mime_ = Default(mime_, 'text/plain');

            return $codeblock(

                function () {
                    return Application.CreateFileForUpload(name_, data_.length, 30000, mime_);
                },

                function (info_) {

					var w = $wait();
					
                    info_ = InitInfo(info_);
                    info_.finish = function(file){
						w.resolve(file);
					};
                    info_.chunksize = 30000;
					if(m_chunksize)
						info_.chunksize = m_chunksize;
                    info_.showUI = showUI_;
					info_.failedChunks = [];

                    AddFile(info_, false);

                    info_.chunks = [];
                    for (var i = 0; i < info_.chunkcount; i++) {
                        if (i * info_.chunksize + info_.chunksize > data_.length) {
                            info_.chunks.push(data_.substr(i * info_.chunksize));
                        } else {
                            info_.chunks.push(data_.substr(i * info_.chunksize, info_.chunksize));
                        }
                    }
					
					return w.promise();
                },
				
				function(file){
					if(finish_){
						return finish_(file);
					}
				}
            );
        };

        this.DownloadFile = function (info_, finish_, cancel_, showUI_) {

            Default(showUI_, true);

            info_.Expires = Application.ConvertDate(info_.Expires);

            if (!showUI_) {
                _self.InitDownload(info_, finish_, cancel_);
                return;
            }

            Application.Confirm("<p><img src='https://go.scrubit.com.au/Images/Icons/document_attachment.png' /></p><p>Name: " + info_.Name + "<br/>Size: " + PrintLength(info_) + "</br>Expires: " + $.format.date(info_.Expires, 'hh:mm a') + "</p><p>Do you wish to download this file?</p>", function (r) {

                if (!r) {
                    if (cancel_)
                        cancel_();
                    return;
                }

                _self.InitDownload(info_, finish_, cancel_);

            }, "File ready for download");
        };

        this.InitDownload = function (info_, finish_, cancel_, showUI_) {

            showUI_ = Default(showUI_, true);

            info_ = InitInfo(info_);
            info_.showUI = showUI_;
            info_.finish = finish_;
            info_.chunksize = 50000;
            if (info_.Length > 100000)
                info_.chunksize = 100024;
			if(m_chunksize)
				info_.chunksize = m_chunksize;
			info_.failedChunks = [];

            setTimeout(function () {
                AddFile(info_, true);
            }, 500);
        };

        this.RemoveFile = function (info) {
            for (var i = 0; i < m_files.length; i++) {
                if (m_files[i].Name == info.Name) {
                    //m_files[i].control.remove();
                    m_files.splice(i, 1);

                    if (m_files.length == 0 && m_showProgress) {
                        Application.HideProgress();
                    }
                    return;
                }
            }
        };

        this.OnTimer = function () {

            if (Application.IsOffline())
                return;

            for (var i = 0; i < m_files.length; i++) {

                if (!m_files[i].finished) {

                    if (m_files[i].download) {
                        var j = m_files[i].chunks.indexOf(null);
                        if (j == -1) {
                            j = m_files[i].chunks.indexOf("");
                            if (j == -1)
                                m_files[i].finished = true;
                        } else {
                            DownloadChunk(i, j);
                        }
                    } else {
                        var j = m_files[i].chunks.firstObject();
                        if (j == -1) {
                            j = m_files[i].chunks.indexOf("");
                            if (j == -1)
                                m_files[i].finished = true;
                        } else {
                            UploadChunk(i, j);
                        }
                    }

                } else if (m_files[i].running == false) {

                    var err = m_files[i].error;

                    if (m_files[i].finish && m_files[i].error == "")
                        m_files[i].finish(m_files[i]);

                    _self.RemoveFile(m_files[i]);

                    if (err != "")
                        Application.Error(err);

                } else {

                    m_files[i].running = false;

					if(m_showProgress)
						Application.HideProgress();
                }
            }
        };

        this.DownloadBlob = function (name_, data_, mime_) {

            var blob = Base64toBlob(data_, mime_);

            if (window.saveAs) {
                window.saveAs(blob, name_);
            }
            else {
                navigator.saveBlob(blob, name_);
            }
        };
		
		this.DownloadText = function (name_, data_, mime_) {

            var blob = new Blob([data_], { type: mime_ });

            if (window.saveAs) {
                window.saveAs(blob, name_);
            }
            else {
                navigator.saveBlob(blob, name_);
            }
        };
		
		this.ChunkSize = function (value_) {

			if (value_ !== undefined) {
				m_chunksize = value_;
			} else {
				return m_chunksize;
			}
		};
		
		this.Timeout = function (value_) {

			if (value_ !== undefined) {
				m_timeout = value_;
			} else {
				return m_timeout;
			}
		};

		this.ShowProgress = function (value_) {

			if (value_ !== undefined) {
				m_showProgress = value_;
			} else {
				return m_showProgress;
			}
		};
		
        //#endregion

        //#region Private Methods

        function InitInfo(info_) {

            info_.finished = false;
            info_.running = true;
            info_.error = "";
            info_.chunks = [];
            info_.completedchunks = 0;

            var id = $id();
            info_.id = id;
            return info_;
        };

        function AddFile(info_, download_) {

            var img = "down";
            var txt = "Download";
            if (!download_) {
                img = "up";
                txt = "Upload";
            }

            info_.download = download_;

            if (info_.Length < info_.chunksize) {
                info_.chunkcount = 1;
            } else {
                info_.chunkcount = Math.ceil(info_.Length / info_.chunksize);
            }

            for (var i = 0; i < info_.chunkcount; i++)
                info_.chunks.push(null);

            if (info_.showUI == true && m_showProgress)
                Application.ShowProgress(info_.Name, txt + "ing", 0, info_.chunkcount);

            m_files.push(info_);

        };

        this.GetFileData = function (file_) {
            var ret = "";
            for (var i = 0; i < file_.chunks.length; i++)
                ret += file_.chunks[i];
            return ret;
        };

        function PrintLength(file_) {
            var len = file_.Length / 1000;
            var unit = "KB";
            if (len > 1000) {
                len = len / 1000;
                unit = "MB"
            }
            return Math.ceil(len) + unit;
        };

        function DownloadChunk(file, chunk) {

            Application.LogInfo("Downloading file chunk: " + m_files[file].Name + ", chunk: " + chunk);

            var callbacks = new Object();

            callbacks.onsend = function (xhr) {
                m_requests.push(xhr);
            };

            callbacks.onsuccess = function (r) {

                if (r != null)
                    if (r.Message)
                        if (r.Message != "FALSE") {
                            callbacks.onerror(r.Message);
                            return;
                        }

                try {

                    m_files[file].chunks[chunk] = r
                    m_files[file].completedchunks += 1;

					if(m_showProgress)
						Application.ShowProgress(m_files[file].Name, "Downloading", m_files[file].completedchunks, m_files[file].chunkcount);

                } catch (ex) {
                }
            };

            callbacks.onerror = function (e) {				
                try {					
                    m_files[file].chunks[chunk] = null;
					Application.LogInfo($.toJSON(e));
                    if (typeof e == "string" && e != "abort" && e != "timeout") {
                        m_files[file].error = e;
                        m_files[file].finished = true;						
                    }else if(typeof e == "string" && e == "timeout"){
						//Increase timeout
						m_timeout += 5000;
					}
                } catch (ex) {
                }
            };

            try {
                m_files[file].chunks[chunk] = "";
                Application.ExecuteWebService("DownloadChunk", { auth: Application.auth, name_: m_files[file].Name, chunk_: chunk, chunkSize_: m_files[file].chunksize }, null, true, null, true, callbacks, m_timeout);
            } catch (ex) {
            }
        };

        function UploadChunk(file, chunk) {

            Application.LogInfo("Uploading file chunk: " + m_files[file].Name + ", chunk: " + chunk);

            var c = m_files[file].chunks[chunk];

            var callbacks = new Object();

            callbacks.onsend = function (xhr) {
                m_requests.push(xhr);
            };

            callbacks.onsuccess = function (r) {

                if (r != null)
                    if (r.Message)
                        if (r.Message != "FALSE") {
                            callbacks.onerror(r.Message);
                            return;
                        }

                try {

                    m_files[file].chunks[chunk] = null;
                    m_files[file].completedchunks += 1;

					if(m_showProgress)
						Application.ShowProgress(m_files[file].Name, "Uploading", m_files[file].completedchunks, m_files[file].chunkcount);

                } catch (ex) {
                }
            };

            callbacks.onerror = function (e) {				
                try {					
                    m_files[file].chunks[chunk] = c;
					Application.LogInfo($.toJSON(e));
                    if (typeof e == "string") {						
                        if (e.indexOf("does not exist") != -1 || e.indexOf("Error saving chunk") != -1 && e != "timeout") {
                            m_files[file].error = e;
                            m_files[file].finished = true;
                        }else if(typeof e == "string" && e == "timeout"){
							//Increase timeout
							m_timeout += 5000;
						}
                    }					
                } catch (ex) {					
                }
            };

            try {
                m_files[file].chunks[chunk] = "";                
				Application.ExecuteWebService("UploadChunk", { auth: Application.auth, name_: m_files[file].Name, chunk_: chunk, chunkData_: c }, null, true, null, true, callbacks, m_timeout);				
            } catch (ex) {				
            }
        };

        function Base64toBlob(data_, contentType_) {

            contentType_ = contentType_ || '';
            var sliceSize = 512;
            data_ = data_.replace(/^[^,]+,/, '');
            data_ = data_.replace(/\s/g, '');
            var byteCharacters = window.atob(data_);
            var byteArrays = [];

            for (var offset = 0; offset < byteCharacters.length; offset += sliceSize) {
                var slice = byteCharacters.slice(offset, offset + sliceSize);

                var byteNumbers = new Array(slice.length);
                for (var i = 0; i < slice.length; i++) {
                    byteNumbers[i] = slice.charCodeAt(i);
                }

                var byteArray = new Uint8Array(byteNumbers);

                byteArrays.push(byteArray);
            }

            var blob = new Blob(byteArrays, { type: contentType_ });
            return blob;
        }

        //#endregion

        this.Constructor();

    });
/// <reference path="../Application.js" />

//27/01/15      Issue #11       PF      Removed old code.

DefineModule("IDEngine",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.'
        ]
    },

    function () {

        //#region Members

        var _self = this;
        var m_lastID = 0;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.IDEngine = this;

            //Global Assign
            $id = Application.IDEngine.AssignID;
        };

        this.GenerateID = function () {

            //Use date to generate new ID.
            var dte = new Date()
            return dte.getTime();

        };

        this.AssignID = function (c) {

            var id = _self.GenerateID();
            while (id <= m_lastID)
                id += 1;            

            m_lastID = id;
            return id;
        };

        //#endregion

    });

/// <reference path="../Application.js" />

DefineModule("ImageManager",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        depends: ['AppUI'],
        created: new Date(2014, 07, 07),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '07/07/14   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_canvas = null;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign module.
            UI.ImageManager = this;
        };

        this.Resize = function (img_, maxWidth_, maxHeight_, angle_, callback_) {

            $.canvasResize(img_, {
                width: maxWidth_,
                height: maxHeight_,
                crop: false,
                rotate: angle_,
                callback: function (img, width, height) {
                    callback_(img, width, height);
                }
            });

        };

        //Issue #73: Lower quality of photos
        this.ChangeQuality = function (img_, quality_, callback_) {

            var tempImg = new Image();
            tempImg.src = img_;
            tempImg.onload = function () {

                var canvas = document.createElement('canvas');
                canvas.width = tempImg.naturalWidth;
                canvas.height = tempImg.naturalHeight;
                var context = canvas.getContext("2d").drawImage(tempImg, 0, 0);
                var url = canvas.toDataURL(_self.GetMimeType(img_), quality_ / 100);
                delete context;
                delete canvas;
                setZeroTimeout(function () {
                    callback_(url);
                });

            };

        };

        this.Crop = function (img_, destX_, destY_, destWidth_, destHeight_, callback_) {

            var tempImg = new Image();
            tempImg.src = img_;
            tempImg.onload = function () {

                var canvas = document.createElement('canvas');
                canvas.width = destWidth_;
                canvas.height = destHeight_;
                var context = canvas.getContext('2d'); 
			    if((destX_+destWidth_) > tempImg.width) destWidth_ = tempImg.width - destX_;
				if((destY_+destHeight_) > tempImg.height) destHeight_ = tempImg.height - destY_;
                context.drawImage(tempImg, destX_, destY_, destWidth_, destHeight_, 0, 0, destWidth_, destHeight_);
                var url = canvas.toDataURL()
                delete context;
                delete canvas;
                setZeroTimeout(function () {
                    callback_(url);
                });
            };
        };

        this.Dimensions = function (img_, callback_) {

            var tempImg = new Image();
            tempImg.src = img_;
            tempImg.onload = function () {

                var tempW = tempImg.width;
                var tempH = tempImg.height;

                setZeroTimeout(function () {
                    callback_(tempW, tempH);
                });
            };
        };

        this.Base64 = function (img_) {
            try {
                return img_.split(';')[1].substr(7);
            } catch (e) {
                return "";
            }
        };

        this.GetMimeType = function (img_) {
            try {
                return img_.split(';')[0].substr(5);
            } catch (e) {
                return "";
            }
        };

        //#endregion

    });
/// <reference path="../Application.js" />

DefineModule("InputManager",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        depends: ["AppUI"],
        created: new Date(2013, 10, 01),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '01/10/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_keyBindings = [];
        var m_protectedKeys = ['o', 'p', ' ', 'c', 'v'];

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign module.
            UI.InputManager = this;
        };

        this.OnKeyPress = function (ev) {

            if (ev.isDefaultPrevented())
                return;

            if (!Application.UnsupportedIE()) {

                if ($moduleloaded("PhantomManager") && window.opener) {									
										
					if (ev.ctrlKey && (ev.which || ev.keyCode) == 82) { //Ctrl+R						
						Application.Phantom.ToggleRecording();
						ev.preventDefault();
						return false;
					}									
					
					if (ev.ctrlKey && (ev.which || ev.keyCode) == 66) { //Ctrl+B
						Application.Phantom.NewBlock();
						ev.preventDefault();
						return false;
					}

					if (ev.ctrlKey && (ev.which || ev.keyCode) == 75) { //Ctrl+K
					    Application.Phantom.InsertTest();
					    ev.preventDefault();
					    return false;
					}
					
					if (ev.ctrlKey && (ev.which || ev.keyCode) == 80) { //Ctrl+P
						Application.Phantom.StartPlayback();
						ev.preventDefault();
						return false;
					}
					
				}

                if (ev.ctrlKey && ev.key) {
                    var bind = m_keyBindings[ev.key.toLowerCase() + "0"];
                    if ($moduleloaded("WindowManager")) {
                        if (!bind && UI.WindowManager.ActiveWindow())
                            bind = m_keyBindings[ev.key.toLowerCase() + UI.WindowManager.ActiveWindow().ID()];
                    }
                    if (bind) {
                        $("#" + bind["obj"]).click();
                        ev.preventDefault();
                        return false;
                    }
                }

            }

            //Send the key to the window manager.
            if ($moduleloaded("WindowManager")) {
                return UI.WindowManager.OnKeyPress(ev);
            }

        };

        this.AddKeyBinding = function (text_, selector_, winid_) {

            return text_;

            //Removed code as it only worked in IE (boooo)
            /*
            if (Application.UnsupportedIE())
                return text_;

            text_ = Default(text_, "");
            if (winid_ == null) winid_ = 0;

            var bind = GetNextKey(text_, winid_);
            if (bind != null) {
                bind["obj"] = selector_;
                return text_.replace(bind["key"], "<u>" + bind["key"] + "</u>");
            }
            return text_;
            */
        };

        //#endregion

        //#region Private Methods

        function GetNextKey(text_, winid_) {
            for (var i = 0; i < text_.length; i++) {
                var c = text_[i];
                if (m_keyBindings[c.toLowerCase() + winid_] == null && m_keyBindings[c.toLowerCase() + "0"] == null && m_protectedKeys.indexOf(c.toLowerCase()) == -1) {
                    m_keyBindings[c.toLowerCase() + winid_] = { key: c, obj: null };
                    return m_keyBindings[c.toLowerCase() + winid_];
                }
            }
            return null;
        };

        //#endregion

    });
///// <reference path="../Application.js" />

//DefineModule("LicenseManager",

//    {
//        singleInstance: true,
//        requiresVersion: '3.0',
//        depends: ['Logging', 'WindowManager'],
//        created: new Date(2013, 12, 11),
//        version: '1.0',
//        author: 'Paul Fisher',
//        copyright: 'Copyright 2015, Paul Fisher',

//        changelog: [
//            '11/12/13   PF  Created class.'
//        ]

//    },

//    function () {

//        //#region Members

//        var _self = this;

//        //#endregion

//        //#region Public Methods

//        this.OnLoad = function () {

//            //Assign Module
//            Application.LicenseManager = this;
//        };

//        this.ShowLicense = function () {

//            if (Application.IsInMobile()) {
//                $("#divSideMenu").panel("close");
//            }

//            Application.LogInfo("Opening License Viewer");

//            //Check if window is already open.
//            var winid = UI.WindowManager.GetWindowByUID("LICENSEINFO");
//            if (winid != -1) {
//                Application.LogInfo("Opening Previous License Viewer");
//                UI.WindowManager.Open(winid);
//                return;
//            }

//            $thread(function () {

//                var w = $wait();

//                $code(

//                    Application.GetUserLicense,

//                    function (lic) {

//                        //Create the window.
//                        var win = new Window();
//                        win.Create(UI.IconImage("document_certificate") + " License Information", {
//                            closebutton: true,
//                            workspace: $("#AppWorkspace"),
//                            shortcutWorkspace: $("#AppWindows"),
//                            position: Application.position.normal
//                        });
//                        win.UID("LICENSEINFO");
//                        win.HideActions();

//                        var txt = $('<textarea id="txtLicense" rows="20" style="width: 90%; overflow: hidden; border-style: none; margin: 10px; font-size: 12px;" readonly="readonly"></textarea>');
//                        win.AddControl(txt);

//                        var str = "";
//                        str += "\nSoftware License Information\n";
//                        str += "Copyright © Scrubit Pty Ltd 2017\n";
//                        str += "------------------------------------------------\n\n";
//                        str += "Licensed to\t: " + lic.ClientName + "\n";
//                        if (lic.Address1 != "") str += "\t\t" + lic.Address1 + "\n";
//                        if (lic.Address2 != "") str += "\t\t" + lic.Address2 + "\n";
//                        if (lic.Address3 != "") str += "\t\t" + lic.Address3 + "\n";
//                        if (lic.Address4 != "") str += "\t\t" + lic.Address4 + "\n";
//                        if (lic.Address5 != "") str += "\t\t" + lic.Address5 + "\n";
//                        if (lic.Address6 != "") str += "\t\t" + lic.Address6 + "\n";
//                        if (lic.Address7 != "") str += "\t\t" + lic.Address7 + "\n";
//                        if (lic.Address8 != "") str += "\t\t" + lic.Address8 + "\n";
//                        str += "Product\t\t: " + lic.Program + "\n";
//                        str += "Product Version\t: " + lic.ProgramVersion + "\n";
//                        str += "Partner\t\t: " + lic.Developer + "\n";
//                        str += "License Date\t: " + lic.LicenseDate + "\n\n";

//                        txt.val(str);

//                        win.AddControl("<p style='padding: 10px;'><a style='cursor: pointer' onclick='Application.App.LoadPage(\"License List\");'>Load a different license</a></p>");

//                        //Add expired parts.
//                        AddLicenseParts(win, lic, false);

//                        //Add non-expired parts.
//                        AddLicenseParts(win, lic, true);

//                        //Add the window to the manager and open it.
//                        UI.WindowManager.Add(win);
//                        UI.WindowManager.Open(win.ID());
//                    }
//                );

//                return w.promise();
//            });
//        };

//        //#endregion

//        //#region Private Methods

//        AddLicenseParts = function (win, lic, expire) {

//            var first = true;
//            for (var i = 0; i < lic.AvailableParts.AvailableParts.length; i++) {

//                var dtearr = lic.AvailableParts.AvailableParts[i].Expires.split("/");
//                var dte = null;
//                try {
//                    if (dtearr.length == 3) {
//                        dte = new Date();
//                        dte.setDate(parseInt(dtearr[0]));
//                        dte.setMonth(parseInt(dtearr[1]) - 1);
//                        dte.setYear(parseInt(dtearr[2]));
//                        dte.setHours(0, 0, 0, 0);
//                    }
//                } catch (e) {
//                    dte = null;
//                }

//                var skip = false;
//                var today = new Date();
//                today.setHours(0, 0, 0, 0);

//                if (!expire && (dte && dte < today))
//                    skip = true;
//                if (expire && (!dte || dte >= today))
//                    skip = true;

//                if (!skip) {

//                    if (first) {
//                        if (!expire) {
//                            win.AddControl("<br/><br/>&nbsp;<b>Available Parts:</b><br/><br/>");
//                        } else {
//                            win.AddControl("<br/><br/>&nbsp;<b>Expired Parts:</b><br/><br/>");
//                        }
//                    }
//                    first = false;

//                    var info = ""
//                    var w = "60px"
//                    if (Application.IsInMobile()) {
//                        info = ' &nbsp;&nbsp;' + lic.AvailableParts.AvailableParts[i].Name + '<br/>&nbsp;&nbsp;(Expires: ' + lic.AvailableParts.AvailableParts[i].Expires + ')';
//                        w = "90%";
//                    }

//                    var img = $('<div class="main-windowsbtn ui-widget ui-state-default" style="padding: 4px; margin: 3px; width: ' + w + '; text-align: center;"><table><tr><td><img src="data:image/png;base64,' + lic.AvailableParts.AvailableParts[i].ImageBase64 + '" /></td><td style="text-align: left;">' + info + '</td></tr></table></div>');
//                    win.AddControl(img);

//                    if (!Application.IsInMobile()) {
//                        img.qtip({
//                            position: {
//                                at: 'bottom right'
//                            },
//                            content: '<b>' + lic.AvailableParts.AvailableParts[i].Name + '</b>' +
//                                    '<br/>Expires: <b>' + lic.AvailableParts.AvailableParts[i].Expires +
//                                    '</b><br/>Table Amount: <b>' + lic.AvailableParts.AvailableParts[i].Amount +
//                                    '</b><br/>Page Amount: <b>' + lic.AvailableParts.AvailableParts[i].PageAmount,
//                            style: {
//                                tip: {
//                                    corner: false
//                                }
//                            }
//                        });
//                    } else {
//                        img.buttonMarkup();
//                    }
//                }
//            }
//        };

//        //#endregion

//    });
/// <reference path="../Application.js" />

DefineModule("LoadingManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.'
        ]
    },

    function () {

        //#region Members

        var _self = this;
        var m_controls = [];
        var m_overlays = [];
        var m_loadersActive = 0;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.Loading = this;
        };

        this.Show = function (cont, type) {

			type = Default(type,"#");
			
			var c = $(type + cont);
            if (c.length == 0)
                return;

            if (m_controls.indexOf(cont) == -1) {

                m_controls.push(cont);

                var o;
                if (Application.UnsupportedIE() || Application.IsInMobile()) {
                    o = $('<div id="' + cont + 'Overlay" class="ui-widget-overlay app-overlay" style="opacity: .8"></div>');
                } else {
                    o = $('<div id="' + cont + 'Overlay" class="ui-widget-overlay app-overlay" style="opacity: .8"><input id="' + cont + 'OverlayProgress" type="text" data-thickness=".4" data-displayPrevious="true" data-linecap="round" readonly="true" data-min="0" data-max="100" style="position: absolute; opacity: .8" value="0"></div>');
                }
                c.append(o);
            }

            if (!Application.UnsupportedIE() && !Application.IsInMobile())
                $("#" + cont + 'OverlayProgress').knob().hide();

            var overlay = $("#" + cont + 'Overlay');
            overlay.width('100%').height('100%');
            overlay.show();
        };

        this.Progress = function (cont, value, type) {

            if (Application.IsInMobile() || Application.UnsupportedIE())
                return;

			type = Default(type,"#");
			
            var c = $(type + cont);
            if (c.length == 0)
                return;

            var progressbar = $(type + cont + 'OverlayProgress');
            var overlay = $(type + cont + 'Overlay');

            if (value != null) {

                value = Math.round(value);

                progressbar
                    .css("display", "")
                    .css("opacity", ".8")
                    .knob()
                    .show()
                    .css("display", "")
                    .css("opacity", ".8")
                .position({
                    'my': 'center',
                    'at': 'center',
                    'of': c[0]
                });
                progressbar.val(value).trigger('change');


            } else {
                return parseInt(progressbar.val());
            }
        };

        this.Hide = function (cont) {

            $("#" + cont + 'OverlayProgress').hide();
            $("#" + cont + 'Overlay').hide();
        };

        this.ShowOverlay = function (cont, msg, type) {

            msg = Default(msg, "Please fill out required fields above "+(Application.IsInMobile() ? " and press Save" : ""));
			type = Default(type,"#");
			
            var c = $(type + cont);
            if (c.length == 0)
                return;

            if (m_overlays.indexOf(cont) == -1) {

                m_overlays.push(cont);

                var o = $('<div class="ui-widget-overlay" id="' + cont + 'Overlay2" style="width: 100%; height: 100%; color: black; font-size: 12pt; font-weight: bold; opacity: 0.5; text-align: center; z-index: 1;"><p style="top: 50%; position: relative;">' + msg + '</p></div>');
                c.append(o);
            }

            var overlay = $(type + cont + 'Overlay2');
            overlay.width('100%').height('100%');
			overlay.children().html(msg);			
            overlay.show();

        };

        this.HideOverlay = function (cont, type) {

			type = Default(type,"#");
			
            $(type + cont + 'Overlay2').hide();
        };

        //#endregion

    });


/// <reference path="../Application.js" />

DefineModule("LocalStorageManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',
        changelog: []

    },

    function () {

        //#region Members

        var _self = this;
		var m_mode = -1; //-1 = No Storage, 0 = IndexedDB, 1 = LocalStorage, 2 = Web SQL
		var m_database = null;
		var m_storeName = "keyvaluepairs";
		
		var ERR_STORAGE = "Local Storage is not supported by your browser, some functions may not work. Please make sure your browser is not in Private mode.";

        //#endregion

        //#region Public Methods

        this.OnLoad = function () { 
			
            //Assign Module
            Application.Storage = this;

			try{
			
				if(IndexedDBSupported()){
					m_mode = 0;
				}else if(window.openDatabase){
					m_mode = 2;
				}else if(LocalStorageSupported()){
					m_mode = 1;
				}else{
					m_mode = -1;
				}

				//IndexedDB Mode
				if(m_mode == 0) {
					
					var openRequest = indexedDB.open("https://go.scrubit.com.au/",1);

					openRequest.onupgradeneeded = function(e) {
						
						Application.LogInfo("Upgrading...");
						
						//Create the object store.
						var thisDB = e.target.result; 
						if(!thisDB.objectStoreNames.contains(m_storeName)) {
							thisDB.createObjectStore(m_storeName);
						}
					}

					openRequest.onsuccess = function(e) {
						
						Application.LogInfo("Success!");
						
						//Save the database connection.
						m_database = e.target.result;
					}

					openRequest.onerror = function(e) {
						
						if(LocalStorageSupported()){
							m_mode = 1;
						}else{
							m_mode = -1;
							//Application.Message(ERR_STORAGE);
						}
						Application.LogError(e);
					}

				}

				//Web SQL
				if(m_mode == 2){
					
					m_database = openDatabase("https://go.scrubit.com.au/", "1", "Liveapp Framework", 2 * 1024 * 1024);
					m_database.transaction(function (t) {
						
						t.executeSql('CREATE TABLE IF NOT EXISTS ' + m_storeName + ' (id INTEGER PRIMARY KEY, key unique, value)', [], function () {
							
							Application.LogInfo("Success!");
							
						}, function (t, error) {
							
							if(LocalStorageSupported()){
								m_mode = 1;
							}else{
								m_mode = -1;
								//Application.Message(ERR_STORAGE);
							}						
							Application.LogError(error);
							
						});
					});
				}
			
			}catch(e){							
				
				m_mode = -1;
				//Application.Message(ERR_STORAGE);
				
			}			
			
        };
		
		this.Set = function(key_, value_, callback_){
		
			if(m_mode == -1){
				if(callback_) callback_();
				return;
			}
			
			//IndexedDB Mode
			if(m_mode == 0){
				
				if(!m_database){
					if(callback_) callback_();
					return;
				}
				
				var transaction = m_database.transaction([m_storeName],"readwrite");
				var store = transaction.objectStore(m_storeName);
				
				var req = store.put(value_, key_);
				
				transaction.oncomplete = function () {
					if(callback_) callback_();
				};
				transaction.onabort = transaction.onerror = function () {
					var err = req.error ? req.error : req.transaction.error;
					if(callback_) callback_(err);					
				};
				
			}else if(m_mode == 1){ //Local storage
				
				try{
					localStorage.setItem(key_,value_);				
					if(callback_) callback_();
				}catch(ex){
					if(callback_) callback_(ex);
				}
				
			}else if(m_mode == 2){ //Web SQL
				
				value_ = $.toJSON(value_);
				
				m_database.transaction(function (t) {
					t.executeSql('INSERT OR REPLACE INTO ' + m_storeName + ' (key, value) VALUES (?, ?)', [key_, value_], function () {
						if(callback_) callback_();
					}, function (t, error) {
						if(callback_) callback_(error);
					});
				}, function (sqlError) {
					if (sqlError.code === sqlError.QUOTA_ERR) {
						if(callback_) callback_(sqlError);
					}
				});
				
			}else{		
				Application.Error(ERR_STORAGE);
			}
		
		};
		
		this.Get = function(key_, callback_){
		
			if(m_mode == -1){
				if(callback_) callback_();
				return;
			}
			
			//IndexedDB Mode
			if(m_mode == 0){
				
				if(!m_database){
					if(callback_) callback_();
					return;
				}
				
				var transaction = m_database.transaction([m_storeName],"readwrite");
				var store = transaction.objectStore(m_storeName);
				
				var req = store.get(key_);

				req.onsuccess = function () {
					var value = req.result;
					if (value === undefined) {
						value = null;
					}					
					if(callback_) callback_(null,value);
				};

				req.onerror = function () {
					if(callback_) callback_(req.error);
				};
				
			}else if(m_mode == 1){ //Local storage
				
				try{
					var value = localStorage.getItem(key_);				
					if(callback_) callback_(null,value);
				}catch(ex){
					if(callback_) callback_(ex);
				}
			
			}else if(m_mode == 2){ //Web SQL
				
				m_database.transaction(function (t) {
					t.executeSql('SELECT * FROM ' + m_storeName + ' WHERE key = ? LIMIT 1', [key_], function (t, results) {						
						var result = results.rows.length ? results.rows.item(0).value : null;
						
						if(result)
							result = $.parseJSON(result);
						
						if(callback_) callback_(null,result);						
					}, function (t, error) {
						if(callback_) callback_(error);
					});
				});
				
			}else{		
				Application.Error(ERR_STORAGE);
			}
		
		};

		this.Remove = function(key_, callback_){
		
			if(m_mode == -1){
				if(callback_) callback_();
				return;
			}
			
			//IndexedDB Mode
			if(m_mode == 0){
				
				if(!m_database){
					if(callback_) callback_();
					return;
				}
				
				var transaction = m_database.transaction([m_storeName],"readwrite");
				var store = transaction.objectStore(m_storeName);
				
				var req = store['delete'](key_);
				
				transaction.oncomplete = function () {
					if(callback_) callback_();
				};

				transaction.onerror = function () {
					if(callback_) callback_(req.error);
				};

				transaction.onabort = function () {
					var err = req.error ? req.error : req.transaction.error;
					if(callback_) callback_(err);
				};
				
			}else if(m_mode == 1){ //Local Storage
				
				try{
					localStorage.removeItem(key_);				
					if(callback_) callback_();
				}catch(ex){
					if(callback_) callback_(ex);
				}
				
			}else if(m_mode == 2){ //Web SQL
					
				m_database.transaction(function (t) {
					t.executeSql('DELETE FROM ' + m_storeName + ' WHERE key = ?', [key_], function () {
						if(callback_) callback_();
					}, function (t, error) {
						if(callback_) callback_(error);
					});
				});
					
			}else{		
				Application.Error(ERR_STORAGE);
			}
		
		};
		
		this.Mode = function(){
			return m_mode;
		};
		
        //#endregion

        //#region Private Methods
        
		function IndexedDBSupported(){
			
			var self = window;
			var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB || self.mozIndexedDB || self.OIndexedDB || self.msIndexedDB;	        

	        var result =  !!(function () {
	            if (typeof self.openDatabase !== 'undefined' && self.navigator && self.navigator.userAgent && /Safari/.test(self.navigator.userAgent) && !/Chrome/.test(self.navigator.userAgent)) {
	                return false;
	            }
	            try {
	                return indexedDB && typeof indexedDB.open === 'function' &&
	                typeof self.IDBKeyRange !== 'undefined';
	            } catch (e) {
	                return false;
	            }
	        })();
			
			return result;
		};		

		function LocalStorageSupported(){
			try{
				return window.localStorage && 'setItem' in window.localStorage && window.localStorage.setItem;	
			}catch(e){
				false;
			}			
		};
						
		//#endregion        

    });
/// <reference path="../Application.js" />

DefineModule("Logging",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.',
            '26/09/13   PF  Updated language.'
        ]

    },

    function (type_, errors_, info_) {

        //#region Members

        var _self = this;
        var m_type = 0; //0 = Console Log, 1 = Internal Log
        var m_log = [];
        var m_showErrors = true;
        var m_showInfo = true;

        var m_remote = Application.remoteStatus.Disconnected;
        var m_remoteWindow = null;
        var m_remoteOrigin = "https://www.liveapp.com.au:444"

        //#endregion

        //#region Public Methods

        this.Constructor = function (type_, errors_, info_) {
            m_type = type_;
            if (errors_ != null)
                m_showErrors = errors_;
            if (info_ != null)
                m_showInfo = info_;
        };

        this.OnLoad = function () { 

            //Assign Module
            Application.Log = this;
        };

        this.Info = function (msg) {
            if (m_showInfo)
                Output(msg);
        };

        this.Error = function (msg) {
            if (m_showErrors)
                Output(msg, 1);
        };

        this.Debug = function (msg) {
            if (Application.debugMode)
                Output(msg);
        };

        this.Warn = function (msg) {
            Output(msg, 2);
        };

        this.ClearLog = function () {
            m_log = [];
        };

        this.ShowLog = function (callback) {

            var msg = ""

            if ($moduleloaded("AppUI")) {
                msg = "<div style='text-align: left; width: 100%; height: 300px;'>";
                for (var i = 0; i < m_log.length; i++)
                    msg += m_log[i] + "<br/>";
                msg += "</div>";
            } else {
                for (var i = 0; i < m_log.length; i++)
                    msg += m_log[i] + "/n";
            }

            Application.Message(msg, callback, "Application Log");
        };

        this.LogObject = function (obj) {
            SendRemote("log", stringify(obj), "remote object");
			if(window.console && window.console.dir){
			    console.dir(obj);			    
				return;
			}
			Output($.toJSON(obj));
		};
		
		this.ToggleRemoteDebug = function () {

		    if (m_remote == Application.remoteStatus.Disconnected) {
		        
				if (Application.connected == false)
		            Application.Error("An internet connection is required for remote debug");
		        
				m_remote = Application.remoteStatus.Connecting;
		        
				Application.Message('Please quote to remote support:<p><h2 style="font-family: Times New Roman">' + UID + '</h2></p><small>Note: This code is cAsEsEnSiTive</small>');
				
				var id = $id();
				UI.StatusBar(true, UI.IconImage("bug_green") + " Remote Debug Mode - Code: " + UID + " <a id='"+id+"' style='cursor:pointer;'>(click here to stop debugging)</a>","#A6ECFF");
				$("#"+id).on("click",_self.ToggleRemoteDebug);							
				
		    } else {
				
				SendRemote("error", 'Connection lost with ' + _self.GetUserInfo(), "remote disconnect");
				
		        m_remote = Application.remoteStatus.Disconnected;
				
		        Application.Message('Your remote debug session has now ended');
				
				UI.StatusBar(false);
		    }

		};
		
		this.RemoteStatus = function(){
			return m_remote;
		};
        
		this.HandleMessage = function(event){
			
			  try {
				_self.LogObject(eval(event.data)); 	
			  } catch (e) {
				_self.Error(e);
				_self.LogObject(event.data);
			  }
		};
		
		this.GetUserInfo = function(){
		
			var browser = 'Internet Explorer ';
			if(Application.IsSafari()) browser = 'Safari ';
			if(Application.IsChrome()) browser = 'Chrome ';
			if(Application.IsOpera()) browser = 'Opera ';
			if(Application.IsFirefox()) browser = 'Firefox ';
			
			var mode = 'Desktop Mode';
			if(Application.IsInMobile()) mode = 'Mobile Mode';
			
			var device = 'desktop';
			if(Application.IsDevice()) device = 'mobile';
			
			return Application.auth.Username + '\nScreen Mode: '+mode+'\nBrowser: ' + browser + device + ' version '+ $.browser.version + '\nURL: '+window.location.toString();
			
		};
		
        //#endregion

        //#region Private Methods

        function Output(msg, type) {

            //Add date and time to msg.      
			if(typeof msg == "string")
				msg = $.format.date(new Date(), 'dd/MM/yyyy hh:mm:ss') + " - " + msg;

            //Console log.
            if (m_type == 0) {
                try {
                    if (window.console != null) {
                        if (type == 1) {
                            console.error(msg);                            
                        } else if (type == 2) {
                            console.warn(msg);                            
                        } else {
                            console.log(msg);                            
                        }
                    }
                } catch (e) { }

                try{
                    if (type == 1) {                        
                        SendRemote("error", msg, "remote error");
                    } else if (type == 2) {                        
                        SendRemote("log", "WARNING: " + msg, "remote warning");
                    } else {                        
                        SendRemote("log", msg);
                    }
                } catch (e) {
                }
            }

            //Internal log.
            if (m_type == 1) {
                m_log.splice(0, 0, msg);
            }
        };

        function SendRemote(msgType, message, info) {

            info = Default(info, "remote info");

            if (m_remote == Application.remoteStatus.Disconnected || !Application.connected) {
                return;
            }

            try {
                if (!m_remoteWindow)
                    m_remoteWindow = $("#remoteSupport")[0].contentWindow;
            } catch (e) {
                return;
            }

            if (m_remote == Application.remoteStatus.Connecting) {		
			
                m_remoteWindow.postMessage('__init__', m_remoteOrigin);                
                m_remote = Application.remoteStatus.Connected;							
				
            }

            var msg = $.toJSON({ response: " " + message + " ", cmd: info, type: msgType });

            m_remoteWindow.postMessage(msg, m_remoteOrigin);

        };	
		
        function sortci(a, b) {
            return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
        };

        function stringify(o, simple) {
            var json = '', i, type = ({}).toString.call(o), parts = [], names = [];

            if (type == '[object String]') {
                json = '"' + o.replace(/\n/g, '\\n').replace(/"/g, '\\"') + '"';
            } else if (type == '[object Array]') {
                json = '[';
                for (i = 0; i < o.length; i++) {
                    parts.push(stringify(o[i], simple));
                }
                json += parts.join(', ') + ']';
                json;
            } else if (type == '[object Object]') {
                json = '{';
                for (i in o) {
                    names.push(i);
                }
                names.sort(sortci);
                for (i = 0; i < names.length; i++) {
                    parts.push(stringify(names[i]) + ': ' + stringify(o[names[i]], simple));
                }
                json += parts.join(', ') + '}';
            } else if (type == '[object Number]') {
                json = o + '';
            } else if (type == '[object Boolean]') {
                json = o ? 'true' : 'false';
            } else if (type == '[object Function]') {
                json = o.toString();
            } else if (o === null) {
                json = 'null';
            } else if (o === undefined) {
                json = 'undefined';
            } else if (simple == undefined) {
                json = type + '{\n';
                for (i in o) {
                    names.push(i);
                }
                names.sort(sortci);
                for (i = 0; i < names.length; i++) {
                    parts.push(names[i] + ': ' + stringify(o[names[i]], true)); // safety from max stack
                }
                json += parts.join(',\n') + '\n}';
            } else {
                try {
                    json = o + ''; // should look like an object
                } catch (e) { }
            }
            return json;
        };

        //#endregion

        this.Constructor(type_, errors_, info_);

    });
/// <reference path="../Application.js" />

DefineModule("NotificationManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2014, 02, 23),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '23/02/14   PF  Created class.'
        ]
    },

    function () {

        //#region Members

        var _self = this;                

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.Notifications = this;            
        };

        this.Send = function (user, message, options, notify) {
            Application.RunNext(function () {
                return $codeblock(
                    function () {
                        if (options == null) options = "";
                        return Application.WebServiceWait("SendNotification", { auth: Application.auth, user_: user, message_: message, options_: options, skipUser_: false, sendFromCurrent_: true });
                    },
                    function () {
                        if (notify)
                            Application.Message("Message Sent");
                    }
                );
            });
        };

        this.ShowMessageForm = function () {

            if (Application.IsInMobile())
                return;

            Application.RunNext(function () {

                Application.LogInfo("Opening Message Form...");

                //Check if window is already open.
                var winid = UI.WindowManager.GetWindowByUID("MESSAGEFORM");
                if (winid != -1) {
                    Application.LogInfo("Opening previous Message Form");
                    UI.WindowManager.Open(winid);
                    return;
                }

                //Create the window.
                var win = new Window();
                win.Create(UI.IconImage("mailbox_empty") + " Send Message", {
                    closebutton: true,
                    workspace: $("#AppWorkspace"),
                    shortcutWorkspace: $("#AppWindows"),
                    position: Application.position.normal
                });
                win.UID("MESSAGEFORM");
                win.HideActions();

                win.AddControl($('<center><div class="ui-dialog ui-dialog-content ui-widget ui-widget-content ui-corner-all" style="text-align: left; width: 70%; border: none;"><fieldset>' +
                            '<label for="txtUser">' +
                            '    Username</label>' +
                            '<input type="text" id="txtUser" class="text ui-widget-content ui-corner-all" value="" tabindex="1" />' +
                            '<label for="message">' +
                            '    Message</label>' +
                            '<textarea id="txtMessage" rows="20" style="width: 95%; margin: 10px; font-size: 12px;" tabindex="2"></textarea>' +
                            '<br />' +
                            '</fieldset><br />' +
                            '<br />' +
                            '<input id="btnSend" type="button" value="Send Message" tabindex="4" /></div></center>'));

                $("#btnSend").on("click", function () {
                    Application.Notifications.Send($("#txtUser").val(), $("#txtMessage").val(), "", true);
                });

                win.AddControl($('<br/><br/>'));

                //Add the window to the manager and open it.
                UI.WindowManager.Add(win);
                UI.WindowManager.Open(win.ID());

            });
        };

        this.OnTimer = function (queue) {

            if (Application.IsOffline() || !Application.connected)
                return;

            if (Application.auth.SessionID != "") {

                if ($moduleloaded("OfflineManager"))
                    if (Application.Offline.DownloadRequest() != null)
                        return;                               

                if (queue == null)
                    return;

                for (var i = 0; i < queue.length; i++) {

                        try {

                            var msg = queue[i][1];

                            queue[i][2] = Default(queue[i][2], "");
                            queue[i][3] = Default(queue[i][3], "");

                            eval("var opts = {" + queue[i][2] + "};");
                            opts.style = Default(opts.style, "info");
                            opts.autoHide = Default(opts.autoHide, false);
                            opts.statusbar = Default(opts.statusbar, false);
                            opts.statuscolor = Default(opts.statuscolor, null);
                            opts.messagebox = Default(opts.messagebox, false);
                            opts.messagetitle = Default(opts.messagetitle, null);
                            opts.messagecallback = Default(opts.messagecallback, "");

                            if (opts.statusbar) {

                                UI.StatusBar(true, msg, opts.statuscolor);

                            } else if (opts.messagebox) {

                                Application.Message(msg, function () {
                                    if (opts.messagecallback != "")
                                        eval(opts.messagecallback);
                                }, opts.messagetitle);

                            } else {

                                var user = queue[i][3];
                                user = user.replace('\\', '');

                                var dte = new Date();

                                var img = "";
                                if (!Application.UnsupportedIE() && user != "")
                                    img = '<div class="square-img-small" style="background-image: url(' + Application.App.ProfileImageURL(user) + ');"></div>';

                                if (Application.IsInMobile()) {

                                    msg = '<table><tr><td width="30px">' + img + '</td><td style="padding-left: 5px; text-align: left;">' + msg + '</td></table>';

                                    var delay = 3000;
                                    if (!opts.autoHide)
                                        delay = 99999999;

                                    if (opts.style == "info")
                                        opts.style = "";

                                    $.notifyBar({
                                        html: msg,
                                        delay: delay,
                                        cssClass: opts.style,
                                        animationSpeed: "normal",
                                        position: "bottom"
                                    });

                                } else {

                                    msg = '<table><tr><td>' + img + '</td><td style="padding-left: 5px;">' + msg +
                                '<br/><br/><span style="color: Gray;">' + UI.IconImage("calendar") + ' ' + $.format.date(new Date(), 'hh:mm:ss dd/MM/yyyy') + '</span>' +
                                '</td></table>';

                                    $.notify(msg, {
                                        globalPosition: 'bottom right',
                                        autoHide: opts.autoHide,
                                        className: opts.style
                                    });
                                }

                        }

                    } catch (e) {
                    }
                }
                
            }
        };

        //#endregion

    });
// <reference path="../Application.js" />

DefineModule("OfflineManager",

{

    singleInstance: true,
    requiresVersion: '3.0',
    created: new Date(2013, 10, 03),
    version: '1.0',
    author: 'Paul Fisher',
    copyright: 'Copyright 2015, Paul Fisher',

    changelog: [
        '16/04/14   PF  Created class.'
    ]

},

function () {

    //#region Members

    var _self = this;
    var m_instance = "";
    var m_offline = false;
    var m_recordSets = [];
    var m_modifiedRecords = [];
    var m_deletedRecords = [];
    var m_insertedRecords = [];
    var m_pack = null;    
    var m_downloadReq = null;
    var m_downloadInfo = null;
    var m_offlineInfo = null;
    var m_info = { mainsize: 0, subsize: 0 };
	var m_save = false;
	var m_params = [];
	var m_zipDataPacks = true;
	var m_showsuccess = true;
	var m_offlineMode = 0; //0 = Classic Offline, 1 = Toggle Offline 
	var m_datapackid = 0;
	var m_lastSwitchCallback = null;

    //#endregion

    //#region Public Methods

    this.OnLoad = function () {

		Application.LoadParams(m_params, PAGE_PARAMETERS);
		
        //this.Clear();

        //Global assign.
        Application.Offline = this;

        //Hook events.
		if(m_params["offline"] == "true"){
			Application.On("Load", _self.LoadEvent);
			Application.On("CreateMenu", _self.CreateMenuEvent);
			Application.On("MenuLoaded", _self.MenuLoadedEvent);
			Application.On("ShowLogin", _self.ShowLoginEvent);
			Application.On("Login", _self.LoginEvent);		
			Application.On("Logout", _self.LogoutEvent);			
		}
		
		Application.On("Connected", function () {
			if(m_offline == false && m_offlineMode == 1){
				
				//Reset transactions
				Application.transactionStarted = 0;			
				
				function Reconnect(){
					Application.Confirm("You have an existing offline data package to upload.", function (r) {
							if(!r){										
								Application.RunNext(function(){
									return $codeblock(
									  _self.CheckForUpload,
									  function(){
										  _self.HideLoad();
										  if(ThisViewer()) ThisViewer().HideLoad();
										  if(m_lastSwitchCallback) return m_lastSwitchCallback();
									  }
									)
								});
							}else{
								Application.Confirm("Please confirm that you want to delete the existing data package.", function (r2) {
									if(r2){
										//Clear packs.
										RemoveDataPack(MainPackName());
										RemoveDataPack(SecondaryPackName());
										Reset();
										Application.RunNext(function(){
											_self.HideLoad();
											if(ThisViewer()) ThisViewer().HideLoad();
											if(m_lastSwitchCallback) return m_lastSwitchCallback();
										});
									}else{
										Reconnect();
									}
								});
							}
						},null,"Delete the data pack","Upload the data pack");
				}
				
				_self.HasDataPack(function(ret){
					UI.Progress(false);	
					if(ret){
						Reconnect();
					}else{
						_self.HideLoad();
						if(ThisViewer()) ThisViewer().HideLoad();
					}
				});
			}
		});
		
		Application.On("ConnectionLost", function () {
			if(m_offline == false && m_offlineMode == 1){
				_self.ShowLoad();
				UI.StatusBar(false);
				UI.Progress(true, "You have limited or no connectivity. Offline data package saved. <br/><br/>Attempting to reconnect... <br/><br/><a onclick='Application.App.OnTimer();'><u>Click here to reconnect now</u></a><br/><br/>", "Connection Lost", null, null, null, true);						
			}
		});
    };
	
    this.Clear = function () {
		//Not Used
    };

	this.ShowLoad = function(){
		Application.Loading.Show("ui-mobile-viewport",".");
	};
	
	this.HideLoad = function(){
		Application.Loading.Hide("ui-mobile-viewport");
	};
	
    this.Load = function (callback) {

        GetDataPack(SecondaryPackName(), null, function(pack){
			
			if (pack == null || pack == ""){
				callback();
				return;
			}				
			
            m_info.subsize = pack.length;

            try {
				if(m_zipDataPacks)
					pack = LZString.decompressFromBase64(pack);				
                pack = $.parseJSON(pack);
                m_modifiedRecords = pack.Modified;
                m_deletedRecords = pack.Deleted;
                m_insertedRecords = pack.Inserted;
            } catch (e) {
            }
			
			callback();
		});
        
    };

    this.Save = function () {

        if (m_offline) {

            var pack = new Object();
            pack.Modified = m_modifiedRecords;
            pack.Deleted = m_deletedRecords;
            pack.Inserted = m_insertedRecords;

            pack = $.toJSON(pack);
            //pack = Application.Zip.Encode(pack);//, CreateKey());

            m_info.subsize = pack.length;

            SaveDataPack(SecondaryPackName(), pack);
        }
    };

    this.DeleteSecondaryData = function () {

        Application.Confirm("Are you sure you wish to delete this data? All offline modifications will be cleared.", function (r) {
            if (r) {
                Reset();
                _self.Save();
                m_info.subsize = 0;
                m_recordSets = [];
            }
        }, "Delete offline data?");

    };

    this.Info = function () {
		
        var id = $id();
        Application.Message("<h3>Data Packs</h3>" +
        "<span style='padding-left: 400px;'></span><br/>" +		
        UI.IconImage("package_ok") + " <b>Main Data</b><br/>... " + PrintLength(m_info.mainsize) + "<br/>" +
        UI.IconImage("package_add") + " Secondary Data<br/>... " + PrintLength(m_info.subsize) + " <a id='" + id + "' style='cursor: pointer;' onclick='UI.CloseDialog();Application.Offline.DeleteSecondaryData();'><u><b>delete</b></u></a><br/><br/>" +
        "Used <b>" + PrintLength(m_info.mainsize + m_info.subsize) + "</b><br/><br/>" +
        "<h3>Records</h3>" +
        "New: " + m_insertedRecords.length + ", " +
        "Modified: " + m_modifiedRecords.length + ", " +
        "Deleted: " + m_deletedRecords.length, null, "Offline Info");
    };

    this.GoOnline = function () {

        if (!Application.App.Loaded()) {

            //_self.Save();
            _self.LogoutEvent();
            _self.SetOffline(false);
            Application.App.ShowLogin();

            //if (Application.App.GetLoginCookie() == null)
            //    Application.Message("You are now online. Please login to continue.");

            Application.RunNext(Application.App.LoginFromCookie);
            return;
        }

        _self.Logout();
    };

    this.Logout = function () {
		//_self.Save();        
        _self.LogoutEvent();
        _self.SetOffline(false);
        Application.App.OnLogout();
        Application.RunNext(Application.App.LoginFromCookie);
    };

    this.CheckForUpload = function () {
		
        var uploading = false;
        if ((m_insertedRecords.length + m_modifiedRecords.length + m_deletedRecords.length) > 0) {   

            return Application.FileDownload.UploadFile("DataPack" + m_datapackid, $.toJSON([m_insertedRecords, m_modifiedRecords, m_deletedRecords]), function (file) {

                if (uploading == true)
                    return;

                uploading = true;

                //Clear packs.
                RemoveDataPack(MainPackName());
                RemoveDataPack(SecondaryPackName());
                Reset();

                var int_id = null;
                var callbacks = new Object();
                callbacks.onerror = function (err) {			
                    Application.Error(err);
                };
                callbacks.onsuccess = function (err) {

                    if (err.length == 0) {
						if (m_showsuccess)
							Application.Message('Offline data has been successfully processed');
                    } else {
                        var msg = "<p>The following errors have occurred:</p>";
                        for (var i = 0; i < err.length; i++) {
                            msg += "<p>" + err[i] + "</p>";
                        }
                        Application.Message(msg, null, "Upload Error");
                    }
					w.resolve();
                };
                callbacks.onsend = function () { };
				
				var w = $wait();
                Application.ExecuteWebService("UploadDataPack", { auth: Application.auth, name_: file.Name }, null, true, null, true, callbacks);
				
                return w.promise();
            });            
        }else{
			Application.RunNext(function(){
				RemoveDataPack(MainPackName());
				RemoveDataPack(SecondaryPackName());		
			});			
		}
    };

    this.GoOffline = function (remove_) {

		m_offlineMode = 0;
	
        if (!Application.App.Loaded()) {
            _self.SetOffline(true);
            Application.App.ShowLogin();
            return;
        }

        _self.CancelDownload("A download has already started, do you wish to cancel?", function () {
            Application.RunNext(function () {
                Application.Confirm("Do you wish to download offline data?", function (r) {
                    if (r)
                        _self.Download();
                }, "Data download", "Yes", "No");
            });
        });
		
		if (m_downloadReq != null)
			return;
		    
         _self.Download();
    };

    this.GetObject = function (type_, name_) {

        var o;

        if (type_ == "PAGE") {
            o = m_pack[0];
        } else if (type_ == "TABL") {
            o = m_pack[1];
        } else if (type_ == "CODE") {
            o = m_pack[2];
        }

        for (var i = 0; i < o.length; i++) {
			if (o[i].Name && name_ && o[i].Name.toLowerCase() == name_.toLowerCase()) {
                return o[i];
            }
        }
        
        return null;
    };

    this.RemoveRecordFromSet = function (id_, view_, recid_) {
        for (var i = 0; i < m_recordSets.length; i++) {
            var recs = m_recordSets[i][2];
            for (var j = 0; j < recs.length; j++) {
                if (recs[j].RecID == recid_) {
                    recs.splice(j, 1);
                    j -= 1;
                }
            }
        }
    };

    this.GetRecordSet = function (id_, view_) {

        //Add the records from pack to memory.
        var r = [];
        r[0] = id_;
        r[1] = view_;
        r[2] = GetRecordsFromPack(id_, view_);

        //Return the record set.
        return r[2];
    };

	this.HasDataPack = function(callback){
		GetDataPack(MainPackName(), null, function(pack){
			if(pack == null || pack == ""){
				callback(false);
				return;
			}
			callback(true);
		});		
	};
	
	this.CheckOfflineObject = function(type, id) {

		if (!Application.IsOffline())
			return true;
		
		var f = Application.Offline.GetObject(type, id);
		if (f != null)
			return true;
		
		return false;
	};
	
    this.Process = function (method, args, callback) {

        if (method == "GetLastMessage" || method == "SendNotification" || method == "BeginTransaction") {
            callback(null);
            return true;
        }

        if (method == "CheckUpdates") {
            callback("");
            return true;
        }

        if (method == "Authorize") {

            setTimeout(function () {

                if (Default(Application.auth.OfflineAuth,"") == "") {
                    Application.auth.Username = Application.auth.Username.replace(/\/{1,}/g, "\\");                    
                } else {
                    Application.auth.Username = Application.auth.OfflineAuth.split("|")[0];                    
                }

                GetDataPack(MainPackName(), null, function(pack){
					
                if (pack == null || pack == ""){
					Application.Confirm("You do not have an offline data package. Would you like to change to online mode?", function(ret){
						if(ret){
							_self.Toggle();						
						}
					});
					Application.Error("");
				}                   

                m_info.mainsize = pack.length;

				if(m_zipDataPacks)
					pack = LZString.decompressFromBase64(pack);											               
				if (pack == "" )
                    Application.Error("Username or password is invalid.");
                m_pack = $.parseJSON(pack);
					
                Application.auth.Password = '';
                Application.auth.LoginDate = new Date();
                Application.auth.SessionID = "OFFLINEMODE";

                //Issue #77 - Date and time in wrong format offline
                var d = new Date()
                Application.auth.TZ = d.getTimezoneOffset();

					//Load secondary data pack.
					_self.Load(function(){

                Application.connected = true;
                Application.Fire("Connected");
                callback(Application.auth);

					}); 				
					
				});
				                

            }, 50);
            return true;

        } else if (method == "CommitTransaction"){
			
			if(m_save){
				//Application.RunNext(_self.Save);
				_self.Save();
				m_save = false;
			}
			callback(null);
            return true;
		
		} else if (method == "RollbackTransaction"){
			
			_self.Load(function(){
			callback(null);
			});
			
            return true;
			
		} else if (method == "RecordInit") {

            var tbl = _self.GetObject("TABL", args.name_);
            if (!tbl)
                Application.Error("Offline table not found: " + args.name_);

            callback(InitRecord(tbl));
            return true;

        } else if (method == "RecordSet") {

            var r = [];

            r = _self.GetRecordSet(args.table_, args.view_);

            //Get the table.
            //var tbl = _self.GetObject("TABL", args.table_);           

            callback(r);
            return true;

        } else if (method == "RecordInsert") {

            var rec = new Object();
            args.rec_.Record.NewRecord = false;
            CloneRecord(args.rec_.Record, rec, true);
			
			rec.Timestamp = $id();
            m_insertedRecords.push(rec);
			m_save = true;
			
            callback(rec);
            return true;

        } else if (method == "RecordModify") {

            var rec = new Object();
            CloneRecord(args.rec_.Record, rec);

			rec.Timestamp = $id();
            ModifyRecord(rec, callback); //Issue #78 - Bug Fix
			m_save = true;

			var rec2 = new Object();
            CloneRecord(args.rec_.Record, rec2, true);
			
            callback(rec2);
            return true;

        } else if (method == "RecordModifyAll") {

            var r = args.rec_;
            if (r.Count > 0) {
                r.First();
                do {
                    var rec = new Object();
                    CloneRecord(r.Record, rec);
					rec.Timestamp = $id();
                    ModifyRecord(rec, callback); //Issue #78 - Bug Fix
                } while (r.Next());
            }
			m_save = true;
						
            callback(true);
            return true;

        } else if (method == "RecordDelete") {

			var rec = new Object();
			CloneRecord(args.rec_.Record, rec);
			
			rec.Timestamp = $id();				
            DeleteRecord(rec);
			m_save = true;

            callback(null);
            return true;

        } else if (method == "RecordDeleteAll") {

            var r = args.rec_;
            if (r.Count > 0) {
                r.First();
                do {
					var rec = new Object();
                    CloneRecord(r.Record, rec);
					rec.Timestamp = $id();
                    DeleteRecord(rec);
                } while (r.Next());
            }
			m_save = true;
						
            callback(true);
            return true;

        } else if (method == "LoadMainMenu") {

            Application.Storage.Get(("XpressMenu-" + m_instance).toLowerCase(), function(err, mnu){
				mnu = Default(mnu, "[]");
				callback($.parseJSON(mnu));
			});            
			
            return true;

        } else if (method == "PageFetch") {

            var f = _self.GetObject("PAGE", args.id_);
            if (f != null) {
                callback(f);
                return true;
            }

            Application.Error("Offline page not found: " + args.id_);

        } else if (method == "TableFetch") {

            var f = _self.GetObject("TABL", args.name_);
            if (f != null) {
                callback(f);
                return true;
            }

            Application.Error("Offline table not found: " + args.name_);

        } else if (method == "CodeModuleFetch") {

            var f = _self.GetObject("CODE", args.name_);
            if (f != null) {
                callback(f);
                return true;
            }

            Application.Error("Offline codemodule not found: " + args.name_);
			
        } else if (method == "BatchProcess"){
		
			var recs = [];
			
			for(var i = 0; i < args.insert_.length; i++){
				recs.push([args.insert_[i],"INS",args.insert_[i].Timestamp]);
			}
		
			for(var i = 0; i < args.modify_.length; i++){
				recs.push([args.modify_[i],"MOD",args.modify_[i].Timestamp]);
			}
			
			for(var i = 0; i < args.delete_.length; i++){
				recs.push([args.delete_[i],"DEL",args.delete_[i].Timestamp]);
			}
			
			recs.sort(function (a, b) {
				if (a[2] == b[2])
					return 0;
				if (a[2] > b[2]) {
					return 1;
				} else {
					return -1;
				}
			});
			
			for(var i = 0; i < recs.length; i++){				
				if(recs[i][1] == "DEL"){
					_self.Process("RecordDelete",{rec_: {Record: recs[i][0]}},function(){});
				}
				if(recs[i][1] == "INS"){
					_self.Process("RecordInsert",{rec_: {Record: recs[i][0]}},function(){});
				}
				if(recs[i][1] == "MOD"){
					_self.Process("RecordModify",{rec_: {Record: recs[i][0]}},function(){});
				}
			}
			
			callback(null);
			return true;
		}

        return false;
    };

    this.Toggle = function () {

        if (Application.IsInMobile()) {
            $("#divSideMenu").panel("close");
        }

        if (m_offline) {

			if(Application.auth.SessionID != ""){
				var len = $.toJSON([m_insertedRecords, m_modifiedRecords, m_deletedRecords]).length;
				if ((m_insertedRecords.length + m_modifiedRecords.length + m_deletedRecords.length) > 0) {
					Application.Confirm("A data package of size " + PrintLength(len) + " will be sent over your current internet connection. Do you want to continue?", function (ret) {
						if (ret == true) {
							Application.RunNext(function () {
								return _self.GoOnline();
							});
						}
					});
				}else{
					Application.RunNext(function () {
						return _self.GoOnline();
					});
				}
			}else{
				Application.RunNext(function () {
					return _self.GoOnline();
				});
			}

        } else {

            Application.RunNext(function () {
                return _self.GoOffline();
            });

        }
    };

    this.Download = function () {

        if (!CheckStorage())
            Application.Error("Local storage is not supported in your browser.");

        //Get the offline cookie.
		_self.RemoveLoginCookie();
		if(Application.auth.Remember)
			Application.RunNext(function () {
				return $codeblock(
					Application.GetOfflineCookie,
					function (c) {
						_self.SaveLoginCookie(c);
					}
            );
        });

		UI.StatusBar(true, "<img src='https://go.scrubit.com.au/Images/loader.gif' /> Processing offline data");
		
		_self.DownloadDataPack(function(){
			Application.App.Disconnect();
			Application.RunNext(function () {
				_self.SetOffline(true);
				return Application.App.LoginFromCookie();
			});
		});  

    };
	
	this.SwitchOffline = function(offline_, callback_){
		
		m_instance = Application.auth.Instance;
		m_offlineMode = 1;
		m_lastSwitchCallback = callback_;
		Application.FileDownload.ShowProgress(false);
		_self.ShowLoad();
		
		function DownloadTempDataPack(){
			
			Reset();
			_self.DownloadDataPack(function(f){
				
				m_offline = true;
				m_info.mainsize = f.length;

				m_pack = null;
				try {								
					m_pack = $.parseJSON(f);						
				}catch(e){					
				}
				if(!m_pack)
					Application.Error("Data pack corruption");									

				//Load secondary data pack.
				_self.Load(function(){

					$("#AppWindows").hide();
					$("#AppWorkspace").css("margin-top","0px");
			
					Application.RunNext(function(){
						return $codeblock(
							function(){
								_self.HideLoad();
								if(callback_) return callback_();
							}
						);
					});

				}); 											
				
			});
		};
		
		if(offline_){	

			_self.HasDataPack(function(ret){
				if(ret){
					Application.Confirm("You have an existing offline data package to upload.", function (r) {
						if(!r){
							Application.RunNext(function(){
								return $codeblock(
								  _self.CheckForUpload,
								  function(){
									  DownloadTempDataPack();				  
								  }
								)
							});
						}else{
							Application.Confirm("Please confirm that you want to delete the existing data package.", function (r2) {
								if(r2){
									DownloadTempDataPack();
								}else{
									Application.Error("");
								}
							});
						}
					},null,"Delete the data pack","Upload the data pack");
				}else{
					DownloadTempDataPack();
				}
			});
			
		}else{
			$("#AppWindows").show();
			if (!Application.IsMobileDisplay() && Application.IsInMobile())
				$("#AppWorkspace").css("margin-top","45px");
			m_offline = false;
			Application.RunNext(function(){
				return $codeblock(
				  _self.CheckForUpload,
				  function(){
					_self.HideLoad();
					if (callback_) return callback_();					  
				  }
				)
			});
		}
	};
	
	this.DownloadDataPack = function(callback_){
		
		Application.RunNext(function () {

			var w = $wait();
		
            UI.ScrollToTop();
            
            var callback = new Object();

            callback.onsend = function (xhr) {
                m_downloadReq = xhr;
            };

            callback.onsuccess = function (info) {

                if (info != null)
                    if (info.Message)
                        if (info.Message != "FALSE") {
                            callback.onerror(info.Message);
                            return;
                        }

                m_downloadInfo = info;

                UI.ScrollToTop();
				
				if(m_offlineMode == 0)
					UI.StatusBar(true, "<img src='https://go.scrubit.com.au/Images/loader.gif' /> Downloading offline data (" + PrintLength(m_downloadInfo.Length) + ")", "#99FF66");

                Application.FileDownload.DownloadFile(info, function (file) { //Download success.

                    var f = Application.FileDownload.GetFileData(file);

                    m_downloadReq = null;

                    //Clear packs.
                    RemoveDataPack(MainPackName());
                    RemoveDataPack(SecondaryPackName());
                    Reset();

					Application.FileDownload.RemoveFile(m_downloadInfo);
                    m_downloadInfo = null;
					
					Application.ExecuteWebService("DownloadedDataPack",{ auth: Application.auth, name_: file.Name },function(){
						
						_self.SetDataPackID(file.Name.replace("DataPack","").replace(".pak",""));
						
						UI.StatusBar(false);
					
						//Save datapack.                                        
						SaveDataPack(MainPackName(), f, function(){
							
							w.resolve();							
							
							Application.RunNext(function(){
								if(callback_) callback_(f);
							});							
						}); 
						
					});										                                    

                }, function () { //Cancel download.
                    if (m_downloadInfo)
                        Application.FileDownload.RemoveFile(m_downloadInfo);
                    m_downloadInfo = null;
                    m_downloadReq = null;
                    UI.StatusBar(false);
					w.resolve();
                }, false);

            };

            callback.onerror = function (e) {
                if (m_downloadInfo)
                    Application.FileDownload.RemoveFile(m_downloadInfo);
                m_downloadInfo = null;
                m_downloadReq = null;
                UI.StatusBar(false);
				Application.HideProgress();        	
				Application.Offline.HideLoad();						
                if (e != "abort")
                    Application.Error(e);
            };

            Application.ExecuteWebService("DownloadDataPack", { auth: Application.auth }, null, true, null, false, callback);
			
			return w.promise();
			
        },null,null,true);
		
	};

    this.SetOffline = function (value) {

        m_offline = value;
        Application.Storage.Set("IsOffline-" + m_instance, value.toString());
	
	};
	
	this.SetDataPackID = function (value) {

        m_datapackid = value;
        Application.Storage.Set("DataPackID-" + m_instance, value.toString());
	
	};

    this.UpdateMenuItem = function () {
        if (m_offline) {
            $('.Offline').text('Go Online');
            m_offlineInfo.show();
        } else {
            $('.Offline').text('Go Offline');
            m_offlineInfo.hide();
        }
    };

    this.CancelDownload = function (msg, callback, cancel) {

        if (m_downloadReq != null) {
            Application.Confirm(msg, function (r) {
                if (r) {
                    m_downloadReq.abort();
                    if (m_downloadInfo)
                        Application.FileDownload.RemoveFile(m_downloadInfo);
                    m_downloadInfo = null;
                    m_downloadReq = null;
                    if (callback) callback();
                } else {
                    if (cancel) cancel();
                }
            }, "Cancel?", "Yes", "No");
        }
    };

    this.AddOfflineAction = function (action_) {

    };

    this.RemoveOfflineAction = function (action_) {

    };

    this.SaveLoginCookie = function (cookie) {

        if (!$moduleloaded("CookieManager"))
            return;

        Application.CookieManager.Save('XPRESSOFFLINE' + Application.auth.Instance, cookie, 100);
    };
	
	this.RemoveLoginCookie = function () {

        if (!$moduleloaded("CookieManager"))
            return;

        Application.CookieManager.Remove('XPRESSOFFLINE' + Application.auth.Instance, 100);
    };

    this.GetLoginCookie = function () {
        var cookie = Application.CookieManager.Get('XPRESSOFFLINE' + Application.App.Params()['instance']);
        if (cookie == "")
            cookie = null;
        return cookie;
    };

    //#endregion      

    //#region Temp Records

    this.FindTempRecordSet = function (formID_, view_) {

    };

    this.DeleteTempRecord = function (recid) {

    };

    this.InsertTempRecord = function (rec) {

    };

    //#endregion        

    //#region Public Properties

    this.IsOffline = function () {
        return m_offline;
    };

    this.DownloadRequest = function () {
        return m_downloadReq;
    };

    this.DownloadInfo = function () {
        return m_downloadInfo;
    };
	
	this.ZipDataPacks = function (value_) {

		if (value_ !== undefined) {
			m_zipDataPacks = value_;
		} else {
			return m_zipDataPacks;
		}
	};

	this.ShowSuccess = function (value_) {

		m_showsuccess = value_;
	};

    //#endregion        

    //#region Application Events

    this.LoadEvent = function (params) {

        if (!CheckStorage())
            return;

        m_instance = params["instance"];

        //_self.Clear(); //Temp.

		var w = $wait();
		
        Application.Storage.Get("IsOffline-" + m_instance, function(err, lastState){
			
			lastState = Default(lastState, "false");
			if (lastState != "false") {
				m_offline = true;
			}
			
			Application.Storage.Get("DataPackID-" + m_instance, function(err, dpid){
				
				m_datapackid = dpid;
				
				w.resolve();
				
			});
			
		});   

		return w.promise();
    };

    this.CreateMenuEvent = function (mnu) {

        //Application.App.PrintSideLink(mnu, Application.executionPath + 'Images/ActionIcons/replace2.png', "Offline", "Application.Offline.Toggle();");
        m_offlineInfo = Application.App.PrintSideLink(mnu, Application.executionPath + 'Images/ActionIcons/preferences.png', "Offline Info", "Application.Offline.Info();");
        _self.UpdateMenuItem();
    };

    this.MenuLoadedEvent = function (mnu) {

        if (!CheckStorage())
            return;

        if (!m_offline)
            Application.Storage.Set(("XpressMenu-" + m_instance).toLowerCase(), $.toJSON(mnu));
    };

    this.ShowLoginEvent = function () {

        if (m_offline) {
            $("#spanRemember").hide();
        } else {
            $("#spanRemember").show();
        }

        $("#txtPassword").val('');
        $("#tdOffline").show();
    };

    this.LoginEvent = function () {
	};
	
	this.LoadDatapack = function(){
		
		return $codeblock(
		
			function(){
				
				//Load the datapack.
				var w = $wait();				
				_self.Load(function () {			
					w.resolve();
				});  
				return w.promise();
			},
			function(){
				
				//Check for upload.       
				if (!m_offline)          				
					return _self.CheckForUpload();			
			}
		);
	};

    this.LogoutEvent = function () {

		//_self.Save();
	
        m_recordSets = [];
        m_pack = null;        
        m_info = { mainsize: 0, subsize: 0 };
        Reset();

    };

    //#endregion

    //#region Private Methods

	function StripFlowFields(rec){
		
		var table = _self.GetObject("TABL", rec.Table);
		if(!table)
			return rec;
		
		for(var i = 0; i < rec.Fields.length; i++){
			
			var col = GetColumnFromTable(table,rec.Fields[i].Name);
			if(col && col.FlowField && col.FlowField != ""){
				rec.Fields[i].Value = null;				
			}					
		}
		return rec;
	}
	
	function GetColumnFromTable(table, col_){
		
		for (var j in table.Columns) {
			if (table.Columns[j].Name == col_) {
				return  table.Columns[j];
			}
		}			
			
		return null;
	};
	
    function CreateKey() {
        var u = Application.auth.Username;
        if (u.indexOf("\\") != -1)
            u = u.substr(u.indexOf("\\") + 1);
        u = u.toLowerCase();
        return CryptoJS.SHA1(u + Application.auth.Password).toString(CryptoJS.enc.Base64);
    };

    function CheckStorage() {
        return (localStorage != null);
    };

    function SaveDataPack(name, pack, callback) {

        name = name.toLowerCase();

		if(m_zipDataPacks)
			pack = LZString.compressToBase64(pack);
		
		Application.Storage.Set(name, pack, function(err){
			if(err){				
				Application.Error(err);
            }
			if(callback)callback();
		});
    };

    function GetDataPack(name, err, callback) {

        name = name.toLowerCase();

        err = Default(err, false);

		Application.Storage.Get(name, function(err, value) {
			if(err){				
				Application.Error(err);
            }
			if(callback)callback(value);
		});			
    };

    function RemoveDataPack(name) {
		name = name.toLowerCase();
		Application.Storage.Remove(name);
    };

    function MainPackName() {
        return ("MainPak-" + m_datapackid).toLowerCase();
    };

    function SecondaryPackName() {
        return ("SubPak-" + m_datapackid).toLowerCase();
    };

    function GetRecord(recid_, arr_) {

        //        for (var i = 0; i < arr_.length; i++) {
        //            if (arr_[i].RecID == recid_)
        //                return arr_[i];
        //        }
        //        return null;
    };

    function InitRecord(table_) {

        var rec_ = Application.Objects.RecordSetInfo();

        //Clear the current record.
        rec_.Record = Application.Objects.RecordInfo();
        rec_.Record.NewRecord = true;
        rec_.Record.Table = table_.Name;
        rec_.xRecord = Application.Objects.RecordInfo();
        rec_.xRecord.NewRecord = true;
        rec_.xRecord.Table = table_.Name;

        //Setup the record set.
        rec_.Position = 0;
        rec_.Blank = true;
        rec_.Count = 0;
        rec_.View = "";
        rec_.Keys = [];

        if (table_.InsertCode != "") {
            rec_.Functions.push(["Insert", table_.InsertCode]);
        }

        if (table_.ModifyCode != "") {
            rec_.Functions.push(["Modify", table_.ModifyCode]);
        }

        if (table_.DeleteCode != "") {
            rec_.Functions.push(["Delete", table_.DeleteCode]);
        }

        rec_.DelayInsert = table_.DelayInsert

        for (var i = 0; i < table_.Columns.length; i++) {

            var col = table_.Columns[i];

            //Setup the record column.
            var reccol = Application.Objects.RecordFieldInfo();
            reccol.Name = col.Name;
            reccol.Value = ConvertColumnInfoTypeToObject(col.Type);
            reccol.Caption = col.Caption;
            //reccol.FlowField = col.FlowField;
            reccol.Type = col.Type;

            //Add the column to the record set.
            rec_.Record.Fields.push(reccol);
            rec_.xRecord.Fields.push(reccol);

            if (col.LookupDisplayField != "") {
                var reccol2 = Application.Objects.RecordFieldInfo();
                reccol2.Name = "FF$" + col.Name;
                reccol2.Value = null;
                reccol2.Caption = col.Caption;
                //reccol2.FlowField = col.FlowField;
                reccol2.Type = col.Type;
                rec_.Record.Fields.push(reccol2);
                rec_.xRecord.Fields.push(reccol2);
            }

            //Add functions.
            if (col.ValidateCode != "") {
                rec_.Functions.push([col.Name, col.ValidateCode]);
            }

            if (col.PrimaryKey && !col.Identity) {
                rec_.Keys.push(col.Name);
            }
        }

        return rec_;
    };

    function ModifyRecord(rec, callback) {

        for (var i = 0; i < m_modifiedRecords.length; i++) {
            if (m_modifiedRecords[i].RecID == rec.RecID && m_modifiedRecords[i].Table == rec.Table) {
                m_modifiedRecords[i] = rec;
                callback(rec);
                return true;
            }
        }

        m_modifiedRecords.push(rec);
    };

    function DeleteRecord(rec) {

        m_deletedRecords.push(rec);

        for (var i = 0; i < m_modifiedRecords.length; i++) {
            if (m_modifiedRecords[i].RecID == rec.RecID) {
                m_modifiedRecords.splice(i, 1);
                i -= 1;
            }
        }

        for (var i = 0; i < m_insertedRecords.length; i++) {
            if (m_insertedRecords[i].RecID == rec.RecID) {
                m_insertedRecords.splice(i, 1);
                i -= 1;
            }
        }
    };

    function ConvertColumnInfoTypeToObject(type_) {
        if (type_ == "Integer") {
            return null;
        } else if (type_ == "Decimal") {
            return null;
        } else if (type_ == "Text") {
            return null;
        } else if (type_ == "Char") {
            return null;
        } else if (type_ == "Code") {
            return null;
        } else if (type_ == "Date") {
            return null;
        } else if (type_ == "DateTime") {
            return null;
        } else if (type_ == "Time") {
            return null;
        } else if (type_ == "BLOB") {
            return null;
        } else if (type_ == "BigBlob") {
            return null;
        } else if (type_ == "Image") {
            return null;
        } else if (type_ == "Boolean") {
            return false;
        }
        return "";
    };

    function GetTableIndex(id_) {
        for (var i = 0; i < m_pack[1].length; i++) {
            if (m_pack[1][i].Name == id_)
                return i;
        }
        return -1;
    };

    function GetRecordsFromPack(id_, view_) {

        var recs = [];

        var tbl = _self.GetObject("TABL", id_);

        var index = GetTableIndex(id_);
        if (index == -1)
            return recs;

        //Get Records.
        recs = m_pack[3][index];

        var ret = [];

		//Add all table records.
		for (var i = 0; i < recs.length; i++) {
			ret.push(recs[i]);
		}
		
		//Update with inserts.
		for (var i = 0; i < m_insertedRecords.length; i++) {
			if (m_insertedRecords[i].Table == tbl.Name) {				
				var rec2 = new Object();
				CloneRecord(m_insertedRecords[i], rec2, true);
				ret.push(rec2);						
			}
		}		
		
		//Update with modifications.
		for (var i = 0; i < m_modifiedRecords.length; i++) {
			if (m_modifiedRecords[i].Table == tbl.Name) {					
				for (var j = 0; j < ret.length; j++) {					
					if (m_modifiedRecords[i].RecID == ret[j].RecID) {
						CloneRecord(m_modifiedRecords[i], ret[j]);
						found = true;
						break;
					}					
				}														
			}				
		}
		
		//Update deleted records.
		for (var i = 0; i < m_deletedRecords.length; i++) {
			if (m_deletedRecords[i].Table == tbl.Name) {	
				for (var j = 0; j < ret.length; j++) {
					if (m_deletedRecords[i].RecID == ret[j].RecID) {
						ret.splice(j, 1);
						break;
					}
				}
			}
		}
						
		var ret2 = [];
		
        //Filter records by view.
        for (var i = 0; i < ret.length; i++) {
            if (ApplyViewToRec(tbl, ret[i], view_))
                ret2.push(ret[i]);
        }

        return ret2;
    };

    function ApplyViewToRec(table_, rec_, view_) {

        var filters = Application.GetFilters(view_);
        if (filters.length == 0) return true;

        //Added back in 11/05/15 - Need for temp records.
        if (rec_.UnAssigned) {
            for (var k = 0; k < filters.length; k++) {
                if (filters[k][1] != "") {
                    var value = GetKeyValue(table_, rec_, filters[k][0]);
                    if (value) {
                        try {
                            eval("var match = (\"" + value.toString().toLowerCase() + "\" " + Application.FilterType(filters[k][1]) + " \"" + Application.StripFilters(filters[k][1]).toString().toLowerCase() + "\");");
                            if (!match)
                                return false;
                        } catch (e) { };
                    }
                }
            }
        }

        for (var i = 0; i < rec_.Fields.length; i++) {

            var field = rec_.Fields[i];

            for (var j = 0; j < filters.length; j++) {

				if (filters[j][0] == field.Name && filters[j][1] != "") {
				
					var subfilters = filters[j][1].split("|");
					var pipes = "OR";
					if(filters[j][1].indexOf("&") != -1){
						subfilters = filters[j][1].split("&");
						pipes = "AND";
					}
				
					var found = false;
					for(var k = 0; k < subfilters.length; k++){
												
						try {
							
							eval("var match2 = (\"" + FormatValue(table_, field) + "\" " + Application.FilterType(subfilters[k]) + " \"" + Application.StripFilters(subfilters[k]).toString().toLowerCase() + "\");");
							
							if (subfilters[k].indexOf("*") != -1 && Application.FilterType(subfilters[k]) == "==")
								eval("var match2 = (\"" + FormatValue(table_, field) + "\".toLowerCase().indexOf(\"" + Application.StripFilters(subfilters[k]).replace(/\*/g, "") + "\".toLowerCase()) != -1);");
							
							if (subfilters[k].indexOf("*") != -1 && Application.FilterType(subfilters[k]) == "!=")
								eval("var match2 = (\"" + FormatValue(table_, field) + "\".toLowerCase().indexOf(\"" + Application.StripFilters(subfilters[k]).replace(/\*/g, "") + "\".toLowerCase()) == -1);");
							
							if (!match2 && pipes == "AND")
								return false;
							
							if(match2){
								found = true;								
							}
							
						} catch (e) {
						};											
					}
					
					if(!found && pipes == "OR")
						return false
				
					break;
				}
            }
        }
        return true;
    };

    function FormatValue(tbl, field) {
        var f = GetField(tbl, field.Name);
        if (f) {
            if (f.Type == "Option" && typeof field.Value == "number") {
                try {
                    return f.OptionString.split(",")[field.Value].toString().toLowerCase();
                } catch (e) {
                }
            }
            if (f.Type == "Date")
                return Application.FormatDate(field.Value);
			if (f.Type == "Integer" || f.Type == "Decimal")
				if(field.Value == null)
					return "0";
        }
        return field.Value.toString().toLowerCase();
    };

    function CloneRecord(rec, rec2,allowflowfields) {
        
		rec2.NewRecord = rec.NewRecord;
        rec2.UnAssigned = rec.UnAssigned;
        rec2.RecID = rec.RecID;
        rec2.Table = rec.Table;
		if(!allowflowfields){
			rec2.Fields = Default(rec2.Fields, []);
		}else{
			rec2.Fields = [];
		}
		
		var table = _self.GetObject("TABL", rec.Table);		
		
        for (var i = 0; i < rec.Fields.length; i++) {
			
			//Check for field skip.
			var skip = false;
			if(table && !allowflowfields){
				var c = GetColumnFromTable(table,rec.Fields[i].Name);
				if(c && c.FlowField && c.FlowField != ""){
					skip = true;			
				}	
			}
			
			if(!skip){
				
				if(!allowflowfields){
				
					//Delete field if it exists.
					for(var j = 0; j < rec2.Fields.length; j++){
						if(rec2.Fields[j].Name == rec.Fields[i].Name){
							rec2.Fields.splice(j,1);
							break;
						}
					}				
				}				
				
				var col = new Application.Objects.RecordFieldInfo();
				app_transferObjectProperties.call(col, rec.Fields[i]);
				rec2.Fields.push(col);
			}
        }
    };

    function GetKeyValue(form_, rec_, name_) {
        try {
            var keys = form_.TableKeys;
            var subkeys = keys[0].Columns.split(',');
            for (var i = 0; i < subkeys.length; i++) {
                if (subkeys[i].trim() == name_)
                    return rec_.RecID.split(": ")[1].split(",")[i].trim();
            }
        } catch (e) {
        }
        return null;
    };

    function GetField(table_, name_) {
        for (var i = 0; i < table_.Columns.length; i++) {
            if (table_.Columns[i].Name == name_)
                return table_.Columns[i];
        }
        return null;
    };

    function PrintLength(len) {
        var len = len / 1000;
        var unit = "KB";
        if (len > 1000) {
            len = len / 1000;
            unit = "MB"
        }
        return len.toFixed(2) + unit;
    };

    function Reset() {

        m_modifiedRecords = [];
        m_deletedRecords = [];
        m_insertedRecords = [];
        m_offlineActions = [];

    };

    //#endregion

});
/// <reference path="../Application.js" />

DefineModule("PhantomManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: []
    },

    function () {

        //#region Members

        var _self = this;
        var m_running = false;
		var m_blocks = [];
		var m_recording = false;
		var m_ghostFinger = null;
		var m_lastElem = null;
		var m_timestamp = null;
		var m_docTitle = "";
		var m_timerID = null;
		var m_currentBlock = "";
		var m_currentAction = null;
		var m_subWindow = null;
		
		var m_toASCII = {
        '188': '44',
        '109': '45',
        '190': '46',
        '191': '47',
        '192': '96',
        '220': '92',
        '222': '39',
        '221': '93',
        '219': '91',
        '173': '45',
        '187': '61', //IE Key codes
        '186': '59', //IE Key codes
        '189': '45'  //IE Key codes
		}

		var m_shiftUps = {
			"96": "~",
			"49": "!",
			"50": "@",
			"51": "#",
			"52": "$",
			"53": "%",
			"54": "^",
			"55": "&",
			"56": "*",
			"57": "(",
			"48": ")",
			"45": "_",
			"61": "+",
			"91": "{",
			"93": "}",
			"92": "|",
			"59": ":",
			"39": "\"",
			"44": "<",
			"46": ">",
			"47": "?"
		};
		
        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.Phantom = this;
			
			$handleclick = _self.HandleClick;
			
			$(window).on('click',_self.HandleClick);
			$(window).on('keydown', _self.HandleKeys);

			Application.On("Error", function (msg) {
			    if (m_running) {
			        if (m_recording) {
			            m_blocks[m_blocks.length - 1].errors += 1;
			        } else {
                        //Log Error
			        }
			    }
			});
        };
		
		this.Open = function(){
			var win = window.open(window.location,"phantom","width=1820px,height=980px,resizable=0");					
		};

		this.Running = function () {
		    return m_running;
		};

		this.HandleClick = function(e){
			if(m_recording){
				var d = new Date();
				m_blocks[m_blocks.length - 1].actions.push({ t: 'click', x: e.pageX, y: e.pageY, d: d.getTime() - m_timestamp });
				m_subWindow.$("#phantom-actions-" + m_blocks.length).text("Actions: " + m_blocks[m_blocks.length - 1].actions.length);
			}
		};
		
		this.HandleKeys = function(e){
			if(m_recording){
				if(e.keyCode == 16 || e.keyCode == 17) //Ctrl or Shift
					return;
				if (e.ctrlKey && (e.which || e.keyCode) == 82) //Ctrl+R
					return;
				if (e.ctrlKey && (e.which || e.keyCode) == 66) //Ctrl+B
				    return;
				if (e.ctrlKey && (e.which || e.keyCode) == 75) //Ctrl+K
				    return;
				var d = new Date();				
				m_blocks[m_blocks.length - 1].actions.push({ t: 'key', key: e.keyCode, s: e.shiftKey, c: e.ctrlKey, d: d.getTime() - m_timestamp });
				m_subWindow.$("#phantom-actions-" + m_blocks.length).text("Actions: " + m_blocks[m_blocks.length - 1].actions.length);
			}
		};
		
		this.ToggleRecording = function(){
			
			if(m_recording){
				
				_self.EndRecording();
				
				clearInterval(m_timerID);
				document.title = m_docTitle;
				
			}else{
				
				_self.StartRecording();
				
				m_docTitle = document.title;
				document.title = "( •_•)O RECORDING";
				m_timerID = setInterval(function(){
					if(document.title == "( •_•)O RECORDING"){
						document.title = "Q(•_• ) RECORDING";						
					}else{						
						document.title = "( •_•)O RECORDING";
					}
				},1000);
			}
		};
		
		this.StartRecording = function () {

		    m_subWindow = window.open("", "phantom-rec", "width=400px,height=600px,resizable=0");
		    m_subWindow.document.write('<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' +
                '<html xmlns="http://www.w3.org/1999/xhtml" style="height: 100%;">' +
                '<head><link href="' + Application.url + 'f/?t=css&ver=' + Application.version + '&instance=none" type="text/css" rel="stylesheet" />' +
                '<script src="' + Application.url + 'f/?t=js&ver=' + Application.version + '" type="text/javascript"></script>' +
                '<script language="javascript" type="text/javascript">function Append(html){ $("body").append(html); };</script>' +
                '</head>' +
                '<body style="font-family: Arial; font-size: 12px;"></body>' +
                '</html>');

		    m_running = true;
			m_blocks = [];						
			m_recording = true;
			m_currentBlock = "";
			_self.NewBlock();
			var d = new Date();
			m_timestamp = d.getTime();				
        };  
		
		this.EndRecording = function () {
			m_recording = false;	
			m_timestamp = null;
			m_running = false;
			Application.FileDownload.DownloadText("PhantomRecording-"+$id()+".txt",$.toJSON(m_blocks),"application/txt");
        };  
		
		this.NewBlock = function(){
			if(m_recording){
				m_recording = false;
				var name = prompt("Block Name");
				m_blocks.push({ name: name, actions: [], errors: 0 });
				m_subWindow.Append("<h1>"+name+"</h1><h3 id='phantom-actions-"+m_blocks.length+"'>Actions: </h3>");
				m_currentBlock = name;
				m_recording = true;
			}
		};

		this.InsertTest = function () {
		    if (m_recording) {
		        m_recording = false;
		        var name = prompt("Test Name");
		        var test = prompt("Test Code");
		        var d = new Date();		        
		        m_blocks[m_blocks.length - 1].actions.push({ t: 'code', n: name, c: test, d: d.getTime() - m_timestamp });
		        m_recording = true;
		    }
		};
		
		this.StartPlayback = function(pb){
		
			Application.FileDownload.ShowUploadDialog("Select Phantom File", function (filename, data) {
				
			    m_running = true;
				m_lastElem = null;
				m_currentBlock = "";
				m_blocks = $.parseJSON(atob(data.split(",")[1]));
				m_currentBlock = m_blocks[0].name;
				
				m_docTitle = document.title;
				document.title = "( •_•)O PLAYBACK";
					m_timerID = setInterval(function(){
						if(document.title == "( •_•)O PLAYBACK"){
							document.title = "Q(•_• ) PLAYBACK";						
						}else{						
							document.title = "( •_•)O PLAYBACK";
						}
					},1000);
													
				setTimeout(function(){
					_self.PlayBack();
				},1000);
				
			},true);
		};		

		this.PlayBack = function(i){
		
			i = Default(i, 0);
			
			if(!m_ghostFinger){
				m_ghostFinger = $("<div style='background-color: #9B59B6; width: 10px; height: 10px; border-radius: 50%; position: absolute; z-index: 9999999; top: 0px; left: 0px; border: 1px solid #8E44AD; opacity: 0.8;'></div>");
				$("body").append(m_ghostFinger);
			}
			
			var action = m_blocks[0].actions[i];
			m_currentAction = action;
				
			if(action.t == 'click'){
				
				if(m_lastElem != null){					
					$(m_lastElem).change();
					$(m_lastElem).blur();
				}
				
				m_lastElem = document.elementFromPoint(action.x, action.y);
				m_ghostFinger.animate({
					left: action.x - 5,
					top: action.y - 5
				},500);			
			}
			
			setTimeout(function(){
				
				if(m_lastElem != null){

					var ele = $(m_lastElem);
					
					if (action.t == 'code') {

					    Application.RunNext(function () {
					        return $codeblock(
                                function () {
                                    eval("var func = function(rec, viewer){" + action.c + "};");
                                    var viewer = ThisViewer();
                                    var rec = null;
                                    if (viewer)
                                        rec = viewer.Record();
                                    return func(rec, viewer);
                                },
                                function () {
                                    FinishAction(action, i);
                                }
                            );
					    });

					}else if(action.t == 'click'){

					    ele.click();

					    FinishAction(action, i);

					}else if(action.t == 'key'){		
					
						var send = '';
						if(action.key == 37){ send = "{leftarrow}"; }
						else if(action.key == 38){ send = "{uparrow}"; }
						else if(action.key == 39){ send = "{rightarrow}"; }
						else if(action.key == 40){ send = "{downarrow}"; }
						else if(action.key == 46){ send = "{del}"; }
						else if(action.key == 8){ send = "{backspace}"; }
						else if(action.key == 9){ send = "{tab}"; }
						else if(action.key == 13){ send = "{enter}"; }
						else{
							
							if (m_toASCII.hasOwnProperty(action.key)) {
								action.key = m_toASCII[action.key];
							}

							if (!action.s && (action.key >= 65 && action.key <= 90)) {
								send = String.fromCharCode(action.key + 32);
							} else if (action.s && m_shiftUps.hasOwnProperty(action.key)) {								
								send = m_shiftUps[action.key];
							} else {
								send = String.fromCharCode(action.key);
							}
							
							if(!action.s)
								send = send.toLowerCase();
						}

						ele.sendkeys(send);

						FinishAction(action, i);
					}									
				
				}								
			
			},(action.t == 'click' ? 500 : 0));
		
		};

        //#endregion

        //#region Private Methods

		function ok(exp, desc) {

		};

		function notOk(exp, desc) {

		};

		function equals(val1, val2, desc) {

		};

		function notEquals(val1, val2, desc) {

		};

		function FinishAction(action, i) {

		    if (i < m_blocks[0].actions.length - 1) {
		        var j = i + 1;
		        var delay = m_blocks[0].actions[j].d - action.d;
		        if (action.t == "code")
		            delay = 10;
		        setTimeout(function () {
		            _self.PlayBack(j);
		        }, delay)
		    } else {

		        m_blocks.splice(0, 1);
		        if (m_blocks.length > 0) {
		            m_currentBlock = m_blocks[0].name;
		            setTimeout(function () {
		                _self.PlayBack();
		            }, 1000);
		            return;
		        }

		        m_ghostFinger.remove();
		        m_ghostFinger = null;

		        clearInterval(m_timerID);
		        document.title = m_docTitle;

		        m_running = false;

		        Application.Message("Finished Playback");
		    }

		};

        //#endregion

    });
/// <reference path="../Application.js" />

DefineModule("ScrubitApp",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2011-2015, Liveware Solutions',

        changelog: [
            '03/09/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;

        //#endregion

        //#region Public Methods        

        this.OnLoad = function () {

            //Assign module.
            ScrubitApp = this;

            Application.On("Load", _self.LoadEvent);
        };

        this.LoadEvent = function () {

            var callback = Application.App.Authorize;
            Application.App.Authorize = function (options) {
                return ShowTerms(callback, options);
            };

            if (Application.App.Params()["instance"].toLowerCase().indexOf("app") != 0)
                return;
            
            setTimeout(function(){
                $("#divLogin").append("<p><a href='https://www.scrubit.com/pdf/Terms%20of%20Use.pdf' target='_new'>Terms of Use</a></p>");
            },1000);
            
        };

        //#endregion

        //Terms of use.
        function ShowTerms(callback, options) {

            var acceptedterms = Application.CookieManager.Get('ACCEPTSURGERYTERMS' + Application.auth.Username);
            if (acceptedterms !== null)
                return callback(options);

            return $codeblock(

                function () {

                    var id = $id();
                    var okclicked = false;
                    var w = $wait();

                    var width = 900;                    
                    var height = UI.MagicHeight()-50;
                    var style = 'height: ' + height + 'px; max-height: ' + height + 'px; max-width: ' + width + 'px; width: 900px;';
                    
                    if(Application.IsInMobile()){
                        style = 'height: calc(100vh - 50px); max-height: calc(100vh - 50px); width: 100vw; max-width: 100vw;';
                    }

                    var boxy = new Boxy('<div class="app-dialog" style="'+style+'"><iframe src="https://go.scrubit.com.au//Assets/Terms/index.html" style="height: 100%; width: 100%;"></div>', {
                        id: id,
                        title: "Terms of Use",
                        closeText: (!Application.IsInMobile() ? "X" : "<i class='mdi mdi-keyboard-backspace' style='font-size: 30px;'></i>"),
                        modal: true,
                        unloadOnHide: true,
                        show: false,
                        beforeHide: function (closeclicked) {
                            w.resolve(okclicked);
                        },
                        toolbar: (!Application.IsInMobile() ? "<a id='nobtn" + id + "' style='float: right; font-size: 11pt; width: 100px; margin: 10px;'>Decline</a> <a id='okbtn" + id + "' style='float: right; font-size: 11pt; width: 100px; margin: 10px;'>Accept</a> " : "")
                    });
                    boxy.center();
                    boxy.show();
                    if (Application.IsInMobile()) {
                        $("#okbtn" + id).ripple().click(function () {
                            okclicked = true;
                            boxy.hide();
                        });
                        $("#closebtn" + id).ripple().click(function () {
                            boxy.hide();
                        });
                    } else {
                        $("#okbtn" + id).button().click(function () {
                            okclicked = true;
                            boxy.hide();
                        });
                        $("#nobtn" + id).button().click(function () {
                            boxy.hide();
                        });
                    }

                    return w.promise();
                },
                function (okclicked) {
                    if (okclicked) {
                        Application.CookieManager.Save("ACCEPTSURGERYTERMS" + Application.auth.Username, "true", 999);
                        return callback(options);
                    } else {
                        Application.Error("You must accept the terms of use to continue");
                    }
                }
            );
        }

    });

    Application.ModuleManager.LoadModule(new ScrubitApp());
/// <reference path="../Application.js" />

DefineModule("SolutionManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        depends: [],
        created: new Date(2013, 12, 11),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '11/12/13   PF  Created class.'            
        ]

    },

    function () {

        //#region Members

        var _self = this;        

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.SolutionManager = this;
        };
        
        //#endregion

    });
//Removed 06/05/15 PF
DefineModule("TourManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2015, 07, 19),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',
        changelog: []
    },

    function () {

        //#region Members

        var _self = this;
		var m_stepDefaults = {
								width           : 500,
								position        : 'rm',
								offsetY         : 0,
								offsetX         : 0,
								fxIn            : '',
								fxOut           : '',
								showStepDelay   : 90,
								center          : 'hook',
								scrollSpeed     : 400,
								scrollEasing    : 'swing',
								scrollDelay     : 0,
								timer           : '00:00',
								highlight       : true,
								keepHighlighted : false,
								keepVisible     : false
							};					

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.TourManager = this;			
        };

        this.CheckTour = function (viewer) {
            
			if(!Application.CheckOfflineObject("TABL","Xpress Tour Header"))
				return false;
			
			if(!Application.CheckOfflineObject("TABL","Xpress User"))
				return false;
			
			if(!viewer.Page().Name || viewer.Page().Name == "")
				return;	

			if(Application.IsMobileDisplay())
				return;
			
			return $codeblock(
			
				function(){
					FINDSET("Xpress User",{"Username": Application.auth.Username},function(r){						
						return r;
					});
				},
			
				function(user){
					FINDSET("Xpress Tour Header",{"Page Name": viewer.Page().Name},function(r){						
						if(r.Count > 0){
							
							var skiptour = Default(user["Skip Tours"],false);
							if(skiptour){								
								return true;
							}
							
							var id = $id();
							var msg = Default(r["Welcome Message"],"Would you like to take a quick tour of this page?");
							msg += '<br/><br/><input type="checkbox" id="'+id+'">Do not show again</value>'
							FINDSET("Xpress Tour Users",{"Username": Application.auth.Username, "Page Name": viewer.Page().Name},function(usr){
								if(usr.Count == 0 || !usr["Taken Tour"])
									Application.Confirm(msg,function(ret){
										Application.RunNext(function(){
											return $codeblock(
												function(){
													if(usr.Count == 0 && !Application.IsOffline())
														INSERT("Xpress Tour Users",{"Username": Application.auth.Username, "Page Name": viewer.Page().Name});
													if($("#"+id).prop('checked'))
														MODIFY(user,"Skip Tours",true);
													if(ret){
														_self.RunTour(viewer);
													}
												}
											);
										},null,null,true);
									},null,"Begin Tour","No Thanks");
								return true;
							});			
						}else{
							return false;
						}							
					});
				}
			
			);
        };
		
		this.RunTour = function(viewer){
			
			$.powerTour('destroy');
			$('.single-step').remove();
			
			var page = viewer.Page();
			if(!page.Name || page.Name == "")
				return;
			
			var stepsHTML = "";
			var steps = [];
			FINDSET("Xpress Tour Line","SORTING(Sort) WHERE(Page Name=CONST("+page.Name+"))",function(r){
				
				do{
					
					var target = '';
					var pos = Default(r.Pos,'rm');
					if(Application.IsInMobile() && Default(r["Pos Mobile"]," ") != " ")
						pos = r["Pos Mobile"];
					var x = 0;
					var y = 0;
					
					var hdr = "";
					if(r.Heading != null)
						hdr = "<h2>"+r.Heading+"</h2>";
					var tourpos = "";
					if(r.Position+1 == r.Count)
						tourpos = 'tourpos="end"';
					stepsHTML += '<div class="single-step" id="step-id-'+(r.Position+1)+'" '+tourpos+'>';					
					stepsHTML += hdr+'<p>'+r.Content+'</p><br/><br/>';					
					if(r.Position != 0)
						stepsHTML += ' <a href="#" data-powertour-action="prev" style="border: 1px solid Black; padding: 5px; background-color: white; line-height: 30px; color: black;">Prev</a> &nbsp;&nbsp;';
					if(r.Position != r.Count - 1)
						stepsHTML += ' <a href="#" data-powertour-action="next" style="border: 1px solid Black; padding: 5px; background-color: #3276b1; line-height: 30px; color: white;">Next</a> ';					
					//if(r.Position == r.Count - 1)
						stepsHTML += '<a href="#" data-powertour-action="stop" style="float:right; border: 1px solid Black; padding: 5px; background-color: white; line-height: 20px; color: black;">End tour</a>';														
					stepsHTML += '</div>';
					
					if(r.Type == "CUSTOM"){
						
						target = r["Custom ID"];
						
						if(target == "#divSide"){
							if(Application.IsInMobile()){
								target = "#divSideMenu";
								$("#divSideMenu").panel("open");
							}else{
								Application.App.ToggleMainMenu(true);
							}
						}							
						
					}else if(r.Type == "TAB"){
						
						if(r["Tab Name"] == "General"){
							
							target = "#"+viewer.ID();
							
							if(viewer.State() == 1)
								viewer.ToggleState();
								
						}else{
							
							var tb = viewer.GetTabByName(DecodeHTML(r["Tab Name"]));
							if(tb){
								
								target = "#"+tb.ID();
								
								if(tb.State() == 1)
									tb.ToggleState();								
							}
						}
						
					}else if(r.Type == "ACTION"){
												
						var btn = viewer.Button(DecodeHTML(r["Action Name"]));
						if(btn){
							target = "#"+btn.attr("id");					
						}
						
					}else if(r.Type == "FIELD"){
						
						var cont = viewer.Control(DecodeHTML(r["Field Name"]));
						if(cont){
							target = "#"+cont.ID();					
						}else{
							var grd = viewer.GetPageGrid();
							if(grd){
								target = "#"+grd.ID()+"table_"+DecodeHTML(r["Field Name"]);
							}							
						}
					}
								
					var skip = false;
					var w = Default(r.Width,500);
					if(Application.IsInMobile() && r.Type == "TAB" && (pos == "bl" || pos == "bm" || pos == "br"))
						w = UI.Width()-10;
					
					var extra = 0;
					
					if(target != ''){
						
						var e = $(target);										
						
						if(Application.IsInMobile() && e.parent().attr("id") == "AppSideWorkspace"){
							extra = e.offset().top;
							target = "#divFactbox";
							e = $(target);
						}						
						
						if(target != "#divSideMenu" && target != "#divFactbox"){
							e.css("position","relative");	
						}else{
							e.css("position","inherit");
						}
						
						if(e.length == 0){
							target = "";
							skip = true;
						}					
						
						if(!skip){																			
							
							if(pos == "bl"){
								pos = "stl";
								y = (e.offset().top+e.height()+10)*-1;
								x = (e.offset().left - 20) * -1;								
							}
							if(pos == "bm"){
								pos = "stl";								
								y = (e.offset().top+e.height()+10)*-1;
								x = (e.offset().left + (e.width()/2) - (w/2)) * -1;								
							}
							if(pos == "br"){
								pos = "stl";								
								y = (e.offset().top+e.height()+10)*-1;
								x = (e.offset().left + w + e.width()) * -1;								
							}													
							if(pos == "lt"){
								pos = "stl";
								y = (e.offset().top - 10)*-1;
								x = (e.offset().left - (w + 40)) * -1;
							}
							if(pos == "tm"){
								pos = "stl";								
								y = (e.offset().top-500-10)*-1;
								x = (e.offset().left + (e.width()/2) - (w/2)) * -1;								
							}
							if(pos == "rt"){
								pos = "stl";
								y = (e.offset().top - 10)*-1;
								x = (e.offset().left + (e.width()) + 20) * -1;
							}							
							
							y -= extra;
							if(target == "#divSideMenu")
								x -= 272;
							if(target == "#divFactbox")
								x += 272;
						}
						
						e.attr("pos",pos)
					}
					
					if(target == "")
						pos = "sc";									
					if (r.Type != 'PLAIN' && target == "")
					    skip = true;
					
					if(!skip)
					steps.push({
						hookTo: target,
						content: '#step-id-'+(r.Position+1),
						position: pos,
						width: w,
						offsetY: y,
						offsetX: x,							
						onShowStep: function(t) {
							
							if(Application.IsInMobile()){									
								$("#divFactbox").panel("close");
							}
							
							//Get the target and step elements.
							var target = $(".powertour-highlight");
							var step = $(t.currentStep);																	
												
							if(target.length > 0 && target.is(':visible') == false){
								if(target.attr("class").indexOf("mnugrp") != -1)
									target.prev().trigger('click');												
								if(target.attr("class").indexOf("mnu-") != -1)
									target.parent().prev().trigger('click');												
							}
							
							setTimeout(function(){
								try{																					
												
									//Toggle the side menu.
									if(Application.IsInMobile() && target.attr("id") == "divFactbox"){										
										$("#divFactbox").panel("open");
									}																																						
									
									//Check if step is out of bounds.
									var left = step.offset().left;
									if(left+500>$(window).width())
										step.width(UI.Width()-left-20);
									if(left <= 0){
										step.width(UI.Width()-target.offset().left-10);
										step.css("left",5);																					
									}
									
									//Adjust offset.
									var offset = 100;
									if(Application.IsInMobile())
										offset = 5;
									
									//Get the top of the step and target.
									var top = step.offset().top - offset;
									var top2 = 999999999;
									if(target.length > 0)
										top2 = target.offset().top - offset;
									if(top < 0)
										top = 0;									
									if(top2 < 0)
										top2 = 0;	
									
									if(target.length > 0 && step.offset().top < (target.offset().top-50) && Default(target.attr("pos"),"sc") != "sc")
										step.css("top",target.offset().top-step.height()-10);

									//Scroll to the top of the target/step.
									if(Default(target.attr("pos"),"sc") != "sc"){
										var body = $("html, body");
										body.stop().animate({scrollTop:(top < top2 ? top : top2)}, '200');
									}
									
								}catch(e){									
								}		
							},100);								
						}
					});
					
				}while(r.Next());
				
				$('body').append(stepsHTML);
				
				setTimeout(function(){
					
					$.powerTour({
						tours:[
							{
								trigger: '',
								startWith: 1,
								easyCancel: false,
								escKeyCancel: true,
								scrollHorizontal: false,
								keyboardNavigation: true,
								loopTour: false,	
								onEndTour: function(t){																	
									
									var body = $("html, body");
									body.stop().animate({scrollTop:0}, '200');																	
									
									var step = $(t.currentStep);
									if(step.children().first().attr("tourpos")=="end"){
										Application.RunNext(function(){
											INSERT("Xpress Tour Users",{"Username": Application.auth.Username, "Page Name": viewer.Page().Name},function(tu){	
												tu.Record.NewRecord = false;
												MODIFY(tu,"Taken Tour",true,function(){
													Application.Message("You may run this tour again by clicking the ? icon at the top of this page");
												});
											},null,true);
										},null,null,true);
									}else{
										Application.Message("You may run this tour again by clicking the ? icon at the top of this page",null,"Tour Cancelled");
									}
									
									$('.single-step,.powertour-step').remove();
								},
								steps: steps,
								stepDefaults: [m_stepDefaults]
							}
						]
					});
					$.powerTour('run', 1);
			
				},500);
			});			
		};

        //#endregion

		function DecodeHTML(input){
			return $('<div/>').html(input).text();
		};

    });


/// <reference path="../Application.js" />

DefineModule("AppUI",

     {
         singleInstance: true,
         requiresVersion: '3.0',
         created: new Date(2013, 09, 03),
         version: '1.0',
         author: 'Paul Fisher',
         copyright: 'Copyright 2015, Paul Fisher',

         changelog: [
            '03/09/13   PF  Created class.',
            '10/09/13   PF  Added dialog boxes.'
         ]
     },

    function () {

        //#region Members

        var _self = this;
        var m_progressDialog = null;
        var m_timer = null; //Timer
        var m_progClosed = true;    
		var m_queue = [];
		
		var m_progressIcon = null;
		var m_hideCancel = null;
		var m_progressTitle = null;		

		var m_icons = new Object();	

		var m_borderWidth = {left:0,right:0};
		var m_xMargin = {left:0,right:0};
		var m_yMargin = {top:0,bottom:0};		
		
		//Glyphs
		m_icons.leftarrow = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACiElEQVQ4T61Uy4tSYRQ/Kjq6GY2ZnaToqq7jZCEKGYxLN6IuCl8zUFDtCgc3/gkDIoW46eWsVET8C3QjDMWI10woSBHCQacMjGojps45k158XNNFHxzuvefxu7/vvATwn49gBR7ZFShXx35f8PkTZbQsbhmgBAMeoTxQKpU3tVotjEYjaDQao1arxaL+FcprlP48MB/gNaFQmPZ6vfrDw0PY2dkB/L6MGw6HUC6XIRKJQDqdfo8/uYfq2jToPOB1qVRaSCQS2w6HgwOaZ0HACAgHBwdf+/3+HbTXJz7TgBvIpJTJZHQul2utUqVSKcCbsMjUjAF/KGga8Mn+/v7z4+PjpcxYlgXKp0JBdfqbAo/HQ2wfjvPKARJwuVKp3Njd3eVlF4vFIJ/PQzabnbGfnp6C2Wx+i0oLVX/CcEulUn2v1+sgFosXAP1+PxgMBggGgws2zCFg7PD8/FyOxt8TwFt7e3slYiASibigTqcDRqMRsEhgsRCBxTMYDABj4eTkhEHrJw7QarWWcrncDGC32wWbzQahUAicTucqQB06fJwAbqvV6k6tVuO9ciAQAIlEAkdHR7xXxthhu92mSv2aAAoFAgFLRdHr9bxMqO+i0SgUCgVAX86nWCyCyWR6h4rb00Uhh6fYqM/i8fjStmk2myCXy2Fzc5NrG5/PB9iPj1HxYr4PqbFZbAuGpmSdQ6zdbnd53NiXcz0/eoxMJiskk8ktu93+z9HDiaLR+9br9Wj0uHnmWw4MLQfsPR0tB4ZhZpZDtVqFcDhM1/yAzO4i2Ofp2yxbXxvoRHm5j01r0Gg03Po6Ozuj9fUG5SXKWutr/odXUKGmCqLQgv0xfudN86qNvU5tZnwuALbz9xWmz+eiAAAAAElFTkSuQmCC";
		m_icons.rightarrow = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACsElEQVQ4T62UPWhaURTHjxpDjR0sWKkQaUtal36QVsd0CE7ma6kQHRrioiFBAqFuBaHQTTvEIBZFUqmxCKk4WHBySSuB0gwltEubhGjAFgyC8RnqR/9XeOE9+2wy9MIZ7j3n/O4993/uldF/HrJzeEr478BuwwZgJdhnWK1fXj/gZSQ8HRwcdJvN5mtGo5GUSiUdHh5SoVBoVKvVFPzPYd97wVLAuwqFIr24uHjL6/WSXq8nuVxOMpmM2u02cRxH6+vr5PP5uEql4gLwjRDaCzSqVKoPqVRKOzk52YX0G3t7ezQ9PU27u7tPhFBhxgAAhY2NDbPdbr+QVPv7+2QymdhJ7/HlC4H2qampZCaT6ZbID6vVSpFIhIaHhyU3WVtbI4/H8xrOeRYgBL7PZrPWiYkJUeLR0RHNzs7S8vIy2Wy2v6C1Wo1txkGoq3Ce8EAFVPx1fHx8Ra1WS56ECdTpdMjv94v8rVaL2H3ncrlHcGzxQDV2qbE7gcJ9729zc5M0Gg1ZLJazGLaJy+WiaDTqwOJbHqjS6XT1YrHY7Tep0Wg0yOFw0OrqKhkMhrMQ1kpOp5Pi8fhjLL7jgXIo/KNUKl1nfdc78vk8oS8pmUzS6OioyN1sNmlsbIy2t7fvw/FFKEosHA473W63KCEQCLBeo1gsJnnyg4MDGhkZKeIubyCgJQSa8MQ+7ezs0NDQ0FkySqG5uTlJGCt3aWmJcJBnCHjR2zZs/gqluYLBoKgX+6mUTqdZK30D+CFiOCmgCotZQMdZe+AZSrJYqyQSCaZu+fT0dBxBX/lAqcd6Cc6XKH9hZWVFNjMzQ1qttnvier1OTKBQKMT6bgtx8zDRj/Ov//ABghegvgXAm/jK5OVy+SdU/Yj1OCwDa/eWcN4Hy18L+1zZA/8tBRFCLwLsp4nk+h/you4VE1i01AAAAABJRU5ErkJggg==";
		m_icons.noicon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAPuUlEQVR4Xu2dB5AmRRXHDwPmnFGRMyeMJQqmFQRzzqgoBkxYBgylpXCKViko5gQoJ2LOAQyUuKVijpgzlKKYA0aM/9/yfd7efjPfvNdhpie8qle7d9vT4fV/erpf6h02TTRqCeww6tFPg980AWDkIJgAMAFg5BIY+fCHvgJcWPO7WbyLeCfxJWbM/+84YyBw1oz/pJ+/Ff9G/AvxT2Z85lBxMiQAXE6TdHPxbuLri68nvmyiiQMMp4i/Lv6C+GTxGYnq7rSaPgPggpLcXuI7iPcWX7llSf5I7Z0o/rD44+K/tNx+kub6BoALaNR3Fd9PfHvxeZJIIb6Sv8+A8Hb9/KD4r/FVtlNDXwBwI4njAPG+4gu1I5rgVv6oJ98iPkr81eBaWnqwZACcQzK4m/ggMd/2PtKn1OkXiz8g/m+JAygRAEz8/cUHi69RotAC+vQdPbNF/M7SgFAaAO4kAb1QfJ0AIffhEU4STxN/tJTOlgKAa0kgLxHfrhTBZO7H8ar/SeIfZG6nsfquAYAy5pniZ4j5fUz0Dw32ebMV759dDbxLANxQg37TgJd765zyWXiwmJ+tUxcAoM2nig/N/NZzHOMY9m3x98WniX8mRtX7BzFndd48+sPqg07h4uJLii8v3kV8VfGuM75oxtlhNWAVfKm41dNC2wC4mAb4ZjHau9T0a1XI5mpV/EnxDxMKEzlxIuE4uqeYvQp2hdTEcXE/MeBthdoEALr594pTqmx/rvreMePP6+d/WpHapk0cVW8mvq/4PmIMTamIjeHdxaxc2aktAKC2ZaJSaPGY5A+JXyv+mPjf2aW0vIFz6s+saGgqOcYCjlhiBbiXGBtDVmoDAA+fTda5IkeCvv0NYjRrP46sK9fjV1PFHO8eJo61U7A/eYT42Fydpd7cAHii2uB8H0P/0sNHi58rxizbB7qCOvksMeCPAT4bwgPFr8416JwAeLo6/YLIjn9EzwOi70XW09Xj11bDR4hjFVxPUR2sfMkpFwCeoJ5ypAklnC1A/rtDKyjsOTaLLxdfJqJfj8uxEuQAAMseS3YosVl8tPj3oRUU+hw6BjaunBpCiM/BQ8Qoz5JRagCw28chIuS79zc991jx1mSjK7Oi/dWtV4nPF9A9NobI+KSAZysfSQkAzvmfFoce9VgmMZeOgfBZfI84RCfCEXF3MSbmaEoFADR8Xwoc0HwQKHVWxJ1byKKlaqsAlfP7xCHOLqi2byLGizmKUgCAOjBvplDvjg0E6ApQjaP08RLguac4ynaQAgAYdg7z9n5J+bGBAE0iCi5sAF7itMXpIphiAYBJ93Pi1Lb8sYGAedgaAAK0o3wKvhmKgBgAMOlfEedy3xobCFgJcCv3fg6+NgMBGlM3xQBgi1o7xN2i74GxgeC8Eg8GoD18YlrzJQjSuoYCAB8+kJd66a8a99hAwOmA8LPNDhDwKbiumGglF4UCAB29R7+NkgctFurhENv52EBwA8npM2KPsuj9Ko8fgYtCAIDNG3u8hzCPHiO+uvgTEwhMokNmrzeV3FbotvrV5UPgBQDODjgvejZ+bGwI9JjTBAL7rKIZvbe9+JoP5I3FZt2AFwAPUOXEvVkJqx4m0Y2GnQkENgliQELle2lb8bVSnCJQM5vIAwDefvzUPOFaoLfOpDuBwDRFa6vnW21F10p9Q4ytwbQKeABwDw+yVJaNYpN6eAKBbWbxfSQHgpXYp51gKewBAJY+q+ECpQTHEosnzwSC5pliz0V2EpRFFmKjjft6I1kBQHz+lxtr21YAx4fHOMpPIGgW1pEq8sjmYv8vgXmez8FSsgKACX1UU2Wzv6OUwM7tdeCcQLBcwDvrz5jKrco3jEQYi6IBQFoWJtPq6IEHK/5rITSBYLnUPC8iJy+UbryQtWRZATxHP4I2iKcjvVooxYDgdDV6m9mbEtp+yc8hm++KLfPGOPAXIBorCgA4HpCqxULEtlnLLqtvAkG9dNDCssu30EYl3MIzTUgiFRtJE61RLndUWdKmpaAJBNVS5AXjpbQQqeswLtV+BpoA4GkMgw0blZSxehMIFqcZj+ufiq1JMNHFoJOppCYAeDYdWPqIi0tNEwgWJfpK/Zd1o730NNAEAOzLVtdlnBg+m3r2Z/VNINhesLfUP8mBYCE2jfhvuFcAcu+yrFuI5AyEPZn0z5YKK8pMINgmFDSCyBx3/CZiTi4lJjPKAi1bATDkWAM1jlNZ8tzkJsKvV8UhTiVDOyK+TXIgZa6FSK9LxJYLALh64/JtIeLYvc4LlnqrykwgOFsqB4hfZxTi81WOcHUXAMi3s4+xAZbnNiN6JhCc7ZRjdQev1c8s+wSg/rUcNci4ZfkWGbFkLjZ2EDB3yJ7LL5roVBWodDKtAwCVWjNVraos6tcuaOwgsJro2QieX7ygEKoDAB4luH1bKMb4Y6m/qcyYQfAaCYdcCha6pgot+GfUAcCjASSFy8ssPchYZqwgIHXM4Ua5VmoE6wCAM4c1MRGuYlbdtLGvQcXGCAIcQN9llBaZWwhC3Y7qAMCRgVSuFiI4kdwAJdDYQECySqv2laRdC1HcdQAgtRtLu4VQFcfY/y1teMrEgmBFjZFmtg/EWEkWYSE+FdxVsB3VAQClDpEpFsJ3vbSETmMBAfmKMddbqNJPsw4AZKJ6kKVWlSGilWzXpdEYQMDRznpdHd9/9gGmFQBPEpI2WQjDRFtJmi39WV9m6CBA9ta8AKSiWXip61YADwBwUEjpBOKd5KbyQwZBNgB4PgEsQ4R/l0xDBQHh49ZLKl2fAM8mEDsAOunSaYggYANeaeevmAzXJtBzDLyKGis1fftGOQACwqa4EsZL+BOsiEs6IiJ7a39cx0CPIuim6gQpTfpCQwIBsidLm4VciiAMDBgaLNQYfGCppOUyQwGBx2vLpQr2GIOerMmLvRSi5flfa24IIED21nsEXMYgIksJR7ZQ1+ZgSx/ryvQdBLiE4RpmIZc5mEBQayJibsi+laUHhZbpMwhwDcdFvIncDiFUiEs4ruFNxBGQ40hOl/CmPsT+vY8gIGUPXluE7zURxrrK+I5lPoGeXIAEHhCA0GfqGwiyO4VyjfuC+bBmhtt0C88Jsj6BwOO0wyXVz64S3LIVwONtQuq4B+acmRbr7gsIuFvJev9QUGAILuHWNC/YpAkNK9Uq6MVP6SDAAEdomOVCa/ZmhIj/zrsCUB41I+pGC5FBjPy2Q6EYEHBLOa7yVjWtV2YregCVtoXI7Vib2bUpOtjjdoxnsNWNzNLxEsqUCgJuHeOGNQstDdtvAgDfDrJQWyhHgghLu7nLlAaCc2vArDDW9LFkdSfRZCU1AYAMYXzfcfuy0F1UyJtJ3FJv12VKAoEnY+ufJThCw4NTxCB4Eg/TqIUIQWbVGCKVAgKPfoYcw/sum4ymFYBniUEnFt1CnAJIJp1r82PpQ84yXYMAfT6bOsu8IQcukFj6CbdUhMsXx0FLFCqNsnG0blByTlauusmDuCoOcSqJPR3g1rW/cWB4CtHHpR7bFgDMJ9UahEiDCInBDpW6AMGVJExyMLAJtJDpVGYFAPcDckWclTBTWgFjrbO0cm2DYKsEwL1LViJb+7eaClsBQD2YfW/RVOHs7/iq41OQ5IJjY5tdFGsLBLtqcITrYwG0EPcGcX9QI3kA4PESomFSzHDV+dCpDRCsSoi3dghyaXLI9fV4AEBZlpTanHMVHeQEgdFi6JQTBGRfO9YhQDy5uHbORB4AUKHnSEj5X4q5NKrSEGHqYX8K5QABShw+owSBWqnx6Be6AvAcgOFbxPfdSuQatMYZWusstVxqEHCG9yjWyNNAvgYzeVcAKka3XJt8uKbl+cWR5o71uGAqEHgcPubiwgK56pFdCACo35OznvLEDu4utnoae8ZQYtlYEBykQfHdt6bpRwao7L03j5tVihuFjEqUC4k8HSR8bDexNZatxIn19CkGBJ52KEuAKOd+d6aW0BWARj3hY/MBnaxf9hKXmFDCK3RL+bZAQErfF1k6tLFMDABQSbLp8GwIaZ+bRDlNlJxTIESWdc/kBgHX+REjGCTPGAAwYCafwFDPp4Dn+L49VNznWAIPSHKBgL0Vl0UHa1xjAYAQuCXkCI80ZmUBAaeDIOQGtNf1IzlAgNXVGsRbOf4UAKAOEkV6zqvzzvA5wJ182hP44ZlEv5ICAHT9IuIvijkdeImNIXaG6XRglxxOIXz3cfmKolQAoBO4HjOZgMFLHF/IM2BNUO2tv7TyaEZJxBVCqNXRqVgTRC5tIyUAaIgjHvcGWp0W1neODc2B4oV8tiFSKvgZNHzkU/BunBnSWeK9xdYLoxrFkBoANLifeKs4tG6SH3NR9dAMSBh2jhaH7JWQK/6W7Jes/pmNk0+B0Elqqpw77bjbLpR+pQe5+TrpYEM7k+A5TLq89R6r3sZmSQRxVIK+bFdFLgDQCPrsIO3Uuh6eqN85Zja6NqUWTKL68OR5hdjjzFHVdLY7GXICgIGwEiCAmHbQE7AvIH09V6b2gXDgfI6YN9/qxlU1LpZ9fCuTv/nzxmImxjoRCIHEkyEbw/VtsAE6RozSKckO2DoARzn89smpQE7eFOPFCTTrZ7ANACC/PcWYK0OOiBvlj/r4BPGR4uPFXWsSmeg7z95UdugpZMoGmGisZLv9OhCn6Kz1BcGXEI0hdwymojNUEdpEztSEprcFBuLz8ZAmQQO5+qyBmpZxo+Rh8ltZ5doEAIMnuuiNYvzWUhNvDZvGk8QopBBkKmMT33EATDY0vG540y3JGbxjRL2LfSRaw2dtuG0A0C/afLyYHETWqGPreNaXI80dTiswt6CjbTxdjMoZsKB4mtsgdtTvZN4m8TXZNK4o3llMnCMTT2CMJRtXSD95hr5waooy7IQ03gUA5v3Eg4W09GYX5pAB9uAZ7PlslINNujFj7BIA9JtvKd4sB4tzrgYxMsr1LG5ch4hRELW1d1kYS9cAmHeIPEQc70LVpLkmKVe9bFwBvtuHL3WHSgHAfFzEs3G3Hd/cIRIudEz8aimDKw0AyIU+cQzaIkaVOgTCHZ7l3ppvqbUxlwiA+eDpG0GO3I/L0auPRJQu9hBvIE1rYy0ZAOuFwEpAOlp2yxzVSiaOmceJ0d8Xb8TqCwDmE85JgVUBt3LUr2QxK4FQ3JAgC40kb3tvfBz7BoD1kw0YVmaA2Ec/McS0RWgYObeTfw8PKHT2tanY2upUSDt9BsDG8eJssYcYZ0k+GcQsYJaNHSOTfaoYjeIpYuIgUDUPwmMpVjghoGvzGVYJQLBZvJMYNS/MjSiof+d+eSzZmJvPFJMYEybzKef008S9fLstgh46ACwyGHWZCQCjnv747+PIxdf/4U8rQP/nMGoEEwCixNf/h/8Hgm0OrkDelPgAAAAASUVORK5CYII=";
		m_icons.pencil = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAJqElEQVR4Xu1deehVRRTOIiLbpE0qM1ssoaJ9I5KifcGiCCqz1YzA9lWKIgrbtL1Iy6Aswfb+CCzNNLKyjSgKzEqzUiKkRSOXzL6v3uT9Xe9yZu7cZd49A4ff+70558y8832z3Jm59/ZaR1OdERiIwodADoMMgvSD9IasgCyGzIXMhrwBmQFZ5buyvXw7VH+5EWDMCfq1kENztdcoLMLHhyCPQH63sMtUVQL4iqTMD1v5OMhgmXqi1k/49irIpAI+/jdVAviIoszHUKiNh7CL95EmwskIyLIizpQARaInt70GqvfI1cWaM6HJ4cR5SFACiGPtrDgKlqOdrfMN34PKca4kUALkB7iIxg0wvqOIA6GtMwmUAMIIO6hdD5s7HexcTZxIoARwDXe23XXIvqsc15le30Xu8TbDgRLAP0p1gW9+iRUJlAB+CdAX7uZANvPr1tobScCJ4ZI8SyVAXoTs8w+AydRQSKAEsAdYYhEMCZQAEjjddIIggRLADVypVVNIMKtzdbDWnEAJIIXSXa/RJFACuAHLrdytIfwrSU0hwXRU9gTIclNpJYAEvp46BP3uzldjAiTBBNR5uBLAHnhaRME3HkIkwemo/Av8AdoDyImQBL4LCfaH0TRInYtFC1H+bpClSgAZAbLAD5UEPKMwVgmQTwAJ+MbLZfjAc3uSVHdPsACV3FEJkA2VDfgfwtUxkF8l6Hd06ibBYCVAOlplg29KrpMEtysBkglQFfh1k2CaEmBtAlQNfp0kmK8E6EmAusCviwR6GRjBvyzwN0UZwyC8o0eSOCfgeYI+EuWCOiu1B/gvgmWCPwX+D4HYrBhWRYJflADVgG8aatNI8HnbCVBFy4/30k0iweQ2E8Dm9K7NIg/HfNPtpw3RTSHByLYSoE7wmzQc9G8jAZoAfhNI8CYqcVTbCNAk8OsmAfctpraJAE0E34UE+8GI5wmKrBNwjsKjYavbQoAmg181Cfgsgb0h81hwGwhgC/7RiMtvghU2yWxf4KaHis3VgUtPsBqlnQZ52ZTa7QQICXyDySX48JiQObYkuBR+H4767mYChAj+TIBzIuQPIQGoJiUBHyx1X9xvtxKgLeAbPPNIkAh+t84B2gZ+HglSwe9GApQJ/usI2MEWXbNU1aXbT/Md7wkywe82ArQd/GhPwPMEtyWN+d06B+h28LcAcDxUcr+wW9kKej9LdLthEtgG8LluvxdkLIQ3dHhLoROgTeAb0L2SIGQC2DyHj/v5Nit8TZjwsds3LT/e4u/FF1f76AZCJUCbwTe4c1GHs/xCKUQCKPhrIC9MgtAIoOD3bO9X4N8HinQBIRFAwfcMPt2FQgAb8D/A7+JpF+mWbtMnfEkNvHDLN05DIICCX0LLD4UACn6J4Dd9CFDwSwa/yQRQ8CsAv6kEUPArAr+JBFDwKwS/aQQoE3y+evWgIgsmKbY2hzmy1vZLvdTL+t1NuQxU8Ctu+U26DFTwawK/CUOAzXv1bFf4tNsXjHl1DgEKfo0tv+4hQMFvAPh1DQEKfkPAr4MACn5P8C/Hvw8KhurSVKqcAyj4DQO/yh7ABvzZqNixEOl+foiz/dpbfpWTQAW/gS2/KgIo+A0Gv+whQMFvOPhlEkDBDwD8sghQFvh8yxYPcIa2q9eYCV/StaTvy0AFP5CWX8YkUMEPDHyfQ4CCHyD4vgig4AcKvg8CjIQT6YsSbVb4dMJX2up/T8dFJoGbw9UPkA0FdVXwBUGqQ6UIAU5GhV8RVFrBFwSpLpUiBDgVlX4xp+IKfl3ICsstQoC+KON7yPopZbUBfJuXRQshqVatCAFY05shtyZUWcGvFkfn0ooSgAVfDOHTunaC/AJ5GnIjRPLA41Bn+8G3fMMYHwQwvjbAh+UWVFTwLYJVlqpPAtjUUcG3iVaJunUQQMEvEVBb11ICUI+vGymaFPyiEfRsLyXAuSj3C8hHBcrfBLZ8inVo+/ldM+FLwk5KgEkwPglyHuQlRxJw1ZCrh75TmbdodzX4BEJKgB+hu20Huefwl5d5X1sgOQS6r1roS1UVfGmkUvQkBNgVtnNi9n/jfz7ImK36fcgnOfWYjvwjCtY1bq7gewiohAAjUM64jLIWI2/LjPyNkMebPNbzUF/jQsH3FEwJATj+n5lR3qfI2ycjf0/kfeapvnSj4HsMpoQA0fE/qWg+uCFrZr8v8j/2VGcF31MgjZs8AgyE4lc5ZX6J/N0zdLZB3kIP9VbwPQQx7iKPABfBYHxOuXwZMRd4shKvGHYuUP8ywV/rdaoF6hmcaR4BnsUvOkvwqwZA57sMvZuQx9eYuSQF3yVqQps8AvDM33YCX1wp5DZwWuIqIIeKfgJfURUF3zJgtupZBJCM/6Y8LvKcklM437rJtYPewkoq+MJAFVHLIsBwOH5c6Hwl9HaALMrR59XC85Dtc/SeQT7nH8sE5ds+gbPVY348nlkEIAhDBQAYFen77DaGAe8n4LAxKOKfYLOH4CvRuHIoSQq+JEoZOlkE4IFPmzGbp4H2gNjsEfDeAu4x0JaTyBUWv0fBtwhWmmoaAXaBwVwH/+/A5nDIKgdbGxMF3yZaDj2Azfgfd88XHF/pqX5JbhR8j8FN6wFsx/94lbhdPNpjPY2rPvgwA8IXKUuSTvhyopRGANvxP6kY9gR807XP4YBXJeydJEnBF0QpiQBcsrWZyGUVMwuZ50Nc5hNxv+viCy47c3s5Lyn4eRHq5CcR4ELkPSG0l6hxZv8oZAyEO4uuiZePSwTGCr4gSEYliQATkXm2hQ+p6l9QnALhKaK3Iexl4ieN2cp52igtzUPGgIx8BV+KRkYPsAB5eSt1lsUkqv/Z6RHYqnlXEfccePqIZw7TUtbpJAXfAZV4D+Bz/Heozr/DxLU5hqOQf0uHNFTlcTM+iu0plwLbbhMngO/x3za+vPeAq4l5iWsBB0K4B8FDqUvzDDQ/OQJxAnBLd1jNweKGEY+ZaaogAnECcD2+fwXlZhXxGjJ5E4qmCiIQJQDv7/+mgjIlRZwBpckSRdUpFoEoAS6AqwnF3Hmz5ph+pA4F3uKZ6ihKgCaM/6woVw1nQDgUlHE7WflRDaiEKAHqGv8N4ASd4uMIeUAQ1FtVQ4Aqx3+uABqw+bfI8nC90euC0g0BuGHzZEm/hxPLtyKgK+AlBdrFrSEAV9HOcXGQYEPAoy2cR8s1NTQChgDzUT+e6nVJ33YAN61cAXeJYk02JMCOEIIoTQZw08p5eERToBEgAfLGf27BRrt07hZq6pIIkADx8Z/DQXTSpoB3CdhJP4MEYOuOtnKuB2hqSQT+AfteIOc5B8HnAAAAAElFTkSuQmCC";	
		
        //Icons 48x48
		m_icons.camera = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAHHElEQVRoQ+1ZeWyURRT/zXy7++1NoS2WUpSj0paAFTGtCgHXA1MqRlE8Y7wSTLzQSMAbjCQKtojigQoeSD2ikUPQRqEVRYuIup6FYhuploW2tGW717f7HWZm2611t3Z329KSOP/tzpv33u/93pv3zQzBST7ISe4//gcw2AzGZGBZSckkgK5UiOagGsyxnCSAF9AqACxetmjR/sECEgWAOa+oWhWl1B6PUwQ4DmjnDBYIDmBZSUmuopInKcWFAGzxOD5YMox5RcVOTRMWL19y7wHyyIrVOYSE9lBKUwbLqWTsqqrapmn6c8ijK0s3UYrLk1Ey6GsItpClJaXuoZ42PQVK1VQPA6AJOh2sNhv0oghKhnZr0DQNwaAEr9sNWVZAnli9Whuelg4yxB3/NwsMSGtzE8iq9a9potE46OmcjANSQAJZs7FMG+pp0xM4xgJ5oextLRn0sdZYzWacmpmJkalpGGazwqDXc7FgMIjjHi8ajzWj/vBheHy+Xk02ulwxZUaOGtXt/34BYDGbkZ+XhzEZGb06xgT+dLnwY3U1vH5/j/InDMDY0Vk4+4zJEKgQl/OdQoqi4tuff8KhhoaY664pLo75/3vbt/cfA3kTJuCM3NweHVdVlc9RSnuUcVZX40BdXdT8gANgkS88Mz/K8G81dfh4x1dw/lqD5pY2Pj8ydTjyJ+eg+KLpyM0eG7Vmj9PZIxO90ZpUDbCcL5o1s1va+PwBPLf+XXz+1Xew2yyABrS528MMEIrOo9PFMwtx561XwygaIr7JioLyXbv+syZ6ApIUgPPOmoYxo7oK1h+QsGT5c6iprcfll8zCgpuu5ADWrNuITdt2AIRAEHTQGYy8YU6aOB5PPnwXREN4l2Kj/rALVT9831vAo+YTBsC2ymKHo5uiFS+8icrd+6CpCrZseAZGUeTzjJU519wekWXO641mUCqgyHEeFi64rpuebRUVCbOQMIBJ2dmYkpMTMVx98A/c91gpoGkI+D14d10pMtJT+fyRxmO4+Z6lUBUFoVAAGitqQiCarSAgePGpBzD+tNERXT/t34/q2tqEWEgYwKyCQmSkp0WMlK4tw2e79iAUlKCEJEzOm4g7brseLIdefutDHPj9EJflH2EBLweh04vQGUTMnT0Td94yP6LrSFMTdu3dO7AALrvgAphMpoiRm+5eiqPNLQj6PWDbpoGliKADRuUCZ17KgcC5HXDth6LICAV8IIRyFk4dnYFXSh6O6PL5ffioonJgAcwvKors6yyqc25YyKMb8LJjBWA028M7TtEiwNABVPIB5aUcTMAb3pmMFjsMegO2bmD/h4eiKPigvPzEAii+YSFUBsDXzuvAaLbxPEfR/YCh40JD8gLlq6IAsK108xsnGMBchwNmc9dNyy33Pg7X0WZIfpbfCgyiGVTXkUL57HOApdA24EgNVFlGUPKBCgIMRgvGjcnESysfjETc6/NiW+XnA8vA9KlTkZWZGTHy7Lp38MnOr6HIQYSkAAil3LmoA5KmQeooYr1ogqDTY94cBxbcOC+iq76hAVVO58ACGJuRgcJp0yJG6g414I4HnuKBDkpevmUyEKxpCUL4A0+Vu7ZR1tD0jCVKsPbph3ghd46qfftQf/TowAJQpSCunXdFt0vVNevfw/Ydu3kxy1IAihKK6YQg6KE3hgv739Fna9/ZtAlCRxOMF0XCfcDn8WBGQQFOHzcuYiMUDOHRlWv5BxyPuCJDkWVeE2wwRgS9HpTq+O+z8/OwdNEC6FmtdIya2lrs3vcdLFZLvL6HdSd6ImNbnezz4fqr5kOn6zoDMBCvvr0ZH336JWci1mBH1yuKHLj5urndnA/JMsrefx8GiyWSdvGiSBgAU+xubcVpWVmYff75UXbq/3KhvLIKzl8OwNV4jBdzxshUTJ2SiyLHucjKPCVqTXllBf487II9JfHLwaQAMBZampowdcoUTC8oiDdYMeV27/kGzl9/wYj09ISjn1QKdXoR8PvhbmtDTnY2HDNmdEuJeBCxtNn55Rc4WFuHYSnDIZqSu9pJioFOB30eLzztbtitVpzLCnv8+F6ffFh9HKyrw9ff7kW7xwur3Q6zJbHC/WeA+gSAKWJMtB8/zguXATl9wgTe6EYMT4FJDEfVLwXQ0tKGv1wNPOJuj4fXhn1YStKR7wRBnt9YpvX1WpHVhNfdDingZ/2s12E0mWCx2ZLK+X8q5xdbq9a/ronG8Amqr4MBkfx+fpGlhGSoWsetBGF9QAe9QYTR1NWh+2pPCgRAHl/9rC81Lc3UVxb66kyi69nZo7Wx0UeWlZRsFXS6uRbbMBhEw5C/peYnO0mCt70dwaC8mQHI7XjUS7yLJBq2fpQnQKusKoX8NYO9kwk6ZYWqqhdSQq39aKffVbFXGUrpZ4qiLFm+ePHBof0cEwf8/wHEEaQBFTnpGfgbUMcL3YOLmYUAAAAASUVORK5CYII=";		
		m_icons.cross = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAIUElEQVRoQ+2Ze1DU1xXHv/f+9gHsgqAGeWdqJ7Gp1s4ERXmJj8ZXaDImJbFNbGsnqVNNnDbTxAoYjMZXpu00jTZWJ+10tG2qTupE0DjVAAqLDzB1GmxoxmlVdhEfRWV3YX+7v3s7dwnIb9n9PYBMxpne/+B3zrnnc865557fbwnu8UXucf/xf4AvOoOjkgFeViZd63HnKYTOpQqbxgl/EISkM1CnAKRgXnDeQYjUBk6aQdmHE+IyzpL9+5WRBmBEAJ5vFuUQjlUMbBkFTTfjDAHcnGCvErJszzpS125Gd7DssAA6FhXfRyS+SQFbTkEtw91c6DEgKHH8jlFLZcahuhtmbZkG8JQWPkPA3wJoitnNdOT/SzhZlVZz8l0zdg0DtJZNtqX0JO8gIM+Z2cC0LCM70zr9q0lLS9CIriGAq/PnO7jddwCcLDRidOQy5DAn/rKMQy1+PVu6ACLyY3tS3gewQM/YaD7nBDXpnp4lepnQBfCUFu7+3MsmJjl/O726caVWYDQB+g4s2TuakTVri4AvTatu/EssvZgAV5cUpPIgPvkcuo05BoXcVOICk7L+euZmNMXYAKVFuzjwvOZuhEBatgK80wN2VBwT40tatAR83Hiwvbv1lTj7TXqNa5VhAHHDcs4ual5SwvnvrwSdtzhsVziifHBQ3xkxWix+EtJ3ftCnd/QQlD07tfUY5BBVJmZXN7kjBaNmoKO0aBuAV7SsSst+CLrgcZWI8qd3wA6/p+kMLf0WpKXLVTJCR+hqLQ6yJaP6ZLkugBjM3D0ejwSSqnn6vzoV0k/Xg9jsaoh3fw9WfSCqKn3sKUhPfU/1jAd6obxRBd72sSYAA+vImObKIuvF9HF3DclAZ2lBPgN16dXCNZ8fwYem4v71bwyF2PcHsPf3qUxIjz8NWvbdCOcD+M+rL8H2r38i1RGvtyUAMiO9+uQZTYD2x4rXSYxv0LPmD4XQfqcbzodnIKdqG4jVpi6LA3ugHOwba6Ql3wZ98lm183IAl6pehv98C7KSnIi36M+EhPOKtJrGzZoAVxYU1FusdJYegHjuCwbhvuODMy8fOZVbQKxWNcR7fwz/TZ94Ru18UMbl19bAe+40shITkWDVd14YkEOh2vs/ODVXG2BRQadFopr1P9jAAMTMIuRUbALRiSQPBnFp41r4zjYhM8kBRwS0VuAUhXVmHXGlaQK4Hy2UKSHqUOqkwysy0e1FUkEJste+DiJJUTV4KITLmyrgPdVg2nlhkClczjzSqOoaQw5xe2kRk2D+Zd8rB+EREMVzkfWzDSCUqstGUXBlSyXuuOqRleg0Ffl+Q4yDZ9Y0qAwPAXCXFnH11kZOQ5+MgPDl5iPz5aqoAO5tVXD8/QycNlMJHnCAcyCjpkHl89AMPFrIJaI7pEalooVzIK14CYiIfr8wVxSwt38OduqE8agMklQYR9bhRm2Afy/MZ3EWyTQBLZoHacWPAXI3f6LmxVIdbMYQ2vkLcFedaYgeReETjzRpl9Cn8/Nkp81cjumsRyA9v1rtfDCIK5vXAYQgu3zjEAhl1y/BGmpNQXh7ZfmBY2e0D/HHc6Z3jnPYDbdRWrIA0nMvhh0dKJVgEJc3lcN7ujH8L+fMYuSUv66+JziDsutNsJPHDEPc9Po6p9R9pN1GT8+aWpeTlFRixCqduxDS8hcinJdxaWM5vM0uZDgd4Xbm6fbBOaMQORWbh0Ls/jXYib8Z2U7c/Mennzj/Dc17oL7ga5UTkxM3WmIcxH5lMUaLcVoVeTmAyxvXorvlFDKdzoFuI7qT2+tF4vQC5FQKiEFjB+dQ3nkLrO6oJkRIYbh451b57MYLWzQBagsfmpka72gaGxenaTASgIvZ5rU18J07G/WSGoCYlo+cdWLs+AzCIMDNnl7c6OnJm+1qPasJsK+sTEp3t7m/PDZpglYrutUrQy6eh8zVa8CDMi6tfwW+j5o1b1hxY3vE7JSbh5xXt4JYrHD/aitsrg+RHKcey9W3IPDp7S5PcUNrNgl/zLu7ovpYO3Py1nRnwpoxGkYFQKfPh5RHSiFf64D//LnwVKk3mPlEOXX74Hh4Giwp43Hr+BFMcCRoAnT1BnDN79s823WhIrIsogLUT5+SzW3s4gPJKVaqcandDgRw1esPH4NME+NB/wDICUeaIwFj7LGjr3COi123ZYkEv1TU2OYxBCCEavOn7Bxjs65IT3RongUBYaUUCSamSmHQJ4egcIYku/o9InIz0cG8sry9pKn1xWiOxCzz2twHxxObtS3NkTBWq5QM9b9hConSuXrHf91qo5OKG/7RZQognIWCyUspx58zk4Y3PQ7T77Ba/3TLCC+b47oQ/SVbjCl6m4hSooSvMFPjejb1noed93oBjpil029DF6A5N9fqtQYOEsIXp+p0Cz3HjDwXZXPd5wcDPwR76hNz6ur6JsIYSxdA6DXn5iZ4rYH9IHxxot2KCQkOSNSQqhGfwzKi23R6/eiWZXDwQ4ly/NJpLaPweb3fg3Am7D1vgpMfCefHx8cjWbS/kXJwoCvQixv+XjDOhbntzH7fT/Qib7iEIkNYP3PK05zwHQDGWShBclwcxtht0JudIu2I2ea2LONWbwAhxsAUXCcWvlLrwJruQrHyfyzvK+MsVNoAAvFzk00kwW6xwGG1wG6RYJMkWAhF/5udKI8QZ5AVBYGQEv4c06so4pCKJYOQ30qUVMVqlSM+A7EMHM//eqYFoRc4lGcBKctwwYsvDIRdoSB7LETZEe2GNWprpBUc3kcMgGntrbkMmEc4cjnoJBAufjdO/MyRbnDSAcI/4UALIThe4mptiRzMjDo9WG5UAIaz8Wjp3PMA/wMALkVeefu39gAAAABJRU5ErkJggg==";
		m_icons.dashboard = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAADI0lEQVRoQ+1ZTU8TQRh+ZrqKhH6AGBQVImLwgyjKhYIBogRvhhhPSgL/wI+DeNKEm1w0Mf4BPHAyhnBFMQSkJBoIQQTFAAkghKDQ7ZYIdGfMLrRmt7RN6W4/zO5pOjvzvs/zvs/M7NshyPCHZDh+WARSnUFNBj4MDZ2TGZ5xmVynFI5Ug9P6534w0kcP8LZrNTVTwXchAgp4xvgwOHWlF3AdGsK8lBJ3kESIwLvBoW7CSRMZHwF9+xqcEPDbLeDlV1QLo1sz6PINgHCg2VmPioOn1P486SNKll8BIJg9dg9rdrfp/BlnPY11V5sURyECvf0eUZGNrf0B4Jd2QDickJ88V5uPfnXCz/7sdNND6MhvVduVP+5AkEW1HbC5MHKmy3wCgNRYW61KPETg/YCHKx229oeA36eC4HYH2NMXartttRMSDxLIRkd+yy6BuxBkr9reFlwYLTWfgOKrobZaxR5GgEyMgr7p3JVQK3j5ZRXc2NYcunz96pRmex0uZQUlNIyS5ZfgBJg9eh/r9irTMxCVQFK8G+AkYgYMsJ0UE2EEVte96hrIlOdIrku7BiwCSU7d/58Br+jDwuJPBAKyJrY2QUDxiUI4ndpPpUjjE01MJH8xMzAx+S0MfBCMIAgoP1+mwRZtfKIk9vIXk8DY+NeofisuXtC8/zL5HXIgkCjWPecnhYAo+jC/uISAwSQU8EUnC+F0aCVreAZMCX0UoxYB/RqwMhBnBAyXUNqdA/Fuoxl/DsQiHKdCwobr15zhErIIxEiRlQF9gPQRsSRkSUhX1MeShCWhOA8GaxeydqE4JRMrYDE/JaLVuHvVqGlXE0eqcSPVqCmviVd+r3NKM+PSkjGGgsN52v9GZ+YXuL7yT1C2pk33iiJKi4u0BAY+fd4oO12abbNR0xwbYViWZUxNz23UuytzFHv/bmj6PT1Z2Vk3jxcWwJ6TA0rTi4giG58kYWl5BZub290Nte5bGgLKNWtAph4KnmtEpMyywRnWGEjVjXr3tIaA8qNvcPAsA+3gnDRQwG4WiP3YZYBEGXplkMdB8GEE9mM41XMyY9+MEqW/uZnwQL2vtQgAAAAASUVORK5CYII=";		
		m_icons.star = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAFvUlEQVRoQ+2ZW2xUVRSG/7XPXDqddi6VlnZASi+MWEw0sVEijAlERRNfiBqiicEEJYq81BAk2NKhtWqNGiIJCUp8qA8aI4kvmqAihlbUIA+aUOPQC0WopdLOpZ1r5+xlzjREStvpOWWmlIT9NMn5z1rrW2ufvdfeQ7jFB93i8SOvAGMni0pZJXZsGLuSr0TlDUALPi2UbjBUxSLXOB4cG8kHRN4AQp3OdiLszgTNaHP6wo23DEDkRPESVngAQimcBJDjDLHC5QsHcw2RlwpEupxtDOydEizTfqcv5F/0AOFTjhJIHgBE0ZRgVRlR7aYVJfXBcC4hcl6BcKfLD+LmmYJkQqNrXbht0QKM/uZ2KrH0BQjhmDFIVQZTirWydP2VsVxB5LQC4U5HI4haswXHjD0uX7h90QH827Wk2MLJCyDhyhaclBhJxgsqyzddjuYCImcVCHU59xDwtp6giGmXwxd6X492Lk1OAIaOLbVbbYkBIXDHXA6151LFsMtcvJIeuhjXo8+muWGAzLLJogHMxnZaYj9L+vBGNzddAHxquS2KaG2apReMuwjsZUleBrx6sz5bFiVwBUwBQTLAoAAIAROJgB32Hj0VmgYQPuV4AFKsA3EtmL2A9ALKihsttdH3pQQLSG1JDkADA3pA8ifnusjpa21NAwiddMZIwGbU4cLoZdS5fmzKDj8d4HjJN2RVn1iYgIx54bj4yvVocHPWCvzjr4pZ7onaTOVJY9bzrE4PWhHvtkeX+/uzV+BiY02HUPh5a904TMsWB0T6YgGSf9oBlT72vNm7PWsFePv95qGy0U9ZoS3W1VGY7kzkObfZzU8MFCAVsGuHio4KqtxG/h/TWQG0h/wMlMG66iMEvGBZFYV55c2BmOizIdVbCMk4vEz07SA/5PW4s+4D7IcY5OqDBOywVMdhroktaCVSPYXQAEA4ULG/7zXSDqYzjKwbGQM02FzzLjHvslTFYV61MBCpv+zQpg5AbRUtvU2zBa/xzLkTZyD2VTcT0GxekYBldU6ayFmrmey2Q/toAW70tPTPefiZE+Cqp0tNNbuJuN28LAlL3bgOdIMzjoHk2SJoyyUYDZ7WvgN6LOgG0IxdaqraSUQHC+ojUEom9NjXrVFHLEicKdYmxcuelt7Del80BJCB2Fe1zf5w6AgVTFsQ9PqcUSfjChIn3VsrWns7jBgyDDDyS4nDlFZzerOQCZiBqM1u99QPGlopDAOEuxxrAfrZSJb0aplR7/KFz+jV61qFrjcWPu7eCas8aMSJXi1NKC85Nowe0aufF8DoMffnil1uMeJEr1ZGRYd7U3CrXv28AILfus6KQq4z4kSvlmPK767HRu/Tq58fwAnHuDCT1l3lfHCKI66NEacRw4Y+4lCn002EUT0OZNiE5LnJy2mrNwbhmNJEzmoiBbPDyM2dIYBIl3s9Q3ZmA5AxBalzhVCHLf+3XwQoZSlYVsUgCtXs/Mxrnb7Ir3qSZHgKBX9wNQgLfzCTcU4JpHpsk62AJK3vPa2AXicBUmW6naDUQ3DmkKR1t2SdZSNMiVedG4OH8gNwzPWlsPNTU4ynCanzNkwM2IBMcuU5Itpbvr//6NUuUmsIh/ZVPQ1VvsWKUguFYa6Mw1KVgPb72qGO47OSx8PP5QUg9L2zmwpwt2acJSH9tzXTs/OEAEsMkSB/xZDrE/rozIyNUua0Vx58UQWaBbCULBLmqgTM2qlPTILIqPKHe9PovXkBGPmi9LSyNFWvXrZmTkocF5CQYwLULmKxA+Xv6buwHfavKVJlokGV6d1CKEVkU2GpjUMpS2Ji0NpV+uywLy8Ag03V34HwyGSqZAqKOAQytXn8gXn9jTrUXFMmId9g5lcIwjwZNH/tael/Mj8AzTVtYG6QhKMKyaYK//nzeh1l0132e6tVTrWCxWYwWjytfe/otWtoGdVrdCF1twEWMtsz+bpdgZtdgf8A5rogT4B9l9YAAAAASUVORK5CYII=";

        //Large Icons 256x256
		m_icons.camera_large = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAAgAElEQVR4Xu1dCXRV1dX+7n1j5jkBFEQBmedJJkVwqlP9HavWtlbF1raoEKRVIEGcCgRoxQGtVhG0irO2ioqMyjyjgIwiQ0gImZOXN9z7r31DMIQk79z37pvy9l5ltavZ55x9vnPed8+wz94SWBgBRiBqEZCitufccUaAEQATAE8CRiCKEWACiOLB564zAkwAPAcYgShGgAkgigefu84IMAHwHGAEohgBJoAoHnzuOiPABMBzgBGIYgSYAKJ48LnrjAATAM8BRiCKEWACiOLB564zAkwAPAcYgShGgAkgigefu84IMAHwHGAEohgBJoAoHnzuOiPABMBzgBGIYgSYAKJ48LnrjAATAM8BRiCKEWACiOLB564zAkwAPAcYgShGICwJIHvGjLh4YLAiy10lBRdAQjKgxkNVTaEaK0UyqbLqqZIkuVyFekhV5d2S4lo/deLEo6GyidtlBPxFIGwI4G9PzU2zWpy3q1Bvk1RlMGTZ4m/nglFegrpbhfSRIkvzp40b910w2uQ2GAGjEAg5AeTOnt1edbv/ChW/gyzbjOpYKOpRIH0tSeoTj48fvzQU7XObjIBeBEJGALm5uXY1LuFRqMojkf7Dbwi6ouBjRVbHPpmd/aPeAWF9RiCYCISEACbNnt0VHuUdE9AjmJ0Nclt0VnD/49nZbwW5XW6OERBGIOgEkJOXd7Wk4h0ViBO2MpIVVcyamj0uG5KkRnI32PaWiUBQCSBnxqxfKZL6hgyYWyacTfRKVRZIlZW/zc3NVaKq39zZsEcgaARAX35FxUdR9+OvmwIqXpg6YfwDYT8j2MCoQiAoBEB7frNHWR81y/6mFgJQxz6enf1sVM0w7mxYIxBwAqDTfsTHb1AhdQ9rJIJgnAI4TYo8JPeRhzcFoTlughHwikDACSBnRt7jkDDZqyVRouCRsGl327aDFt16qydKuszdDGME/CKAnBkzekmQR0HFAEVSOkuq2lYxmRJkFbFh3Gc2jRGISAQUCVWyx1MuyaZDqqrsViVpg6yqS3InTNjha4d0E8Cjs2e3NivKGNXj+Y0smy7wtWEuxwgwAsYgoKjKXkmW58sez8u5jzySr6dWYQJ4dM6cLIvbnQtFvbulee7pAYx1GYFwRUABHDLUV51Wa+7TY8cWitgpRABT8vLuVz3KM7IsJ4tUyjqMACMQOgQkoFhRMfHxCeNf9mZFswQw8Zlnkqxm66sy1Bu9VcR/ZwQYgfBCQIH0rslqvid37NiypixrkgBor291uRarsqlneHWLrWEEGAFRBCRV2QpVvaqps4FGCYB+/CaXaxUf8onCzHqMQPgiIAH7oHiGN0YCZxEALftjZHklf/nDd0DZMkZALwLaSsBmu7jhduAsApg8c9Z7vOfXCy/rMwLhj4AELMrNHn9rfUvPIIDcmTPHqJDmhX9X2EJGgBHwBQFVle59fMK4V+rKniaAnBkzMhUVu/mqzxdYuQwjEBkIKIpy0iRLnXOzs0+QxfUIIO95SPhjZHSDrWQEGAGfEZAwd+r48X85TQB06m9xuQ+wh5/PkHJBRiBiECCPQY/Z1P6phx46rq0ApuTl5UgqciOmB2woI8AI+IWABGlybva4JzQCyJ2Zt1cFOvhVIxdmBBiBiEFA8eCHaRPHd5Ymz5rVU1bUbRFjORvKCDAChiAgQe0uTZk580EJ0hxDauRKGAFGIHIQUKW/SLnT8xaoMu6MHKvZUkaAETAEAVWZL02ZMWO9JMkDDKmQK2EEGIGIQUCFuk7KmT49H7IpK2KsZkMZAUbAEAQUIF+anJdXyTH8DMGTK2EEIgoBCaiUcmbm+ZWyyiSbYLZaYDabIJlMkCUZkna5KBRsKKIAY2MZgdAhoEJVAUVVoLgVeDwuuFxuKB7/gkv7RABmsxn22BhYbXbQ/2ZhBBiB0CDgdntQ43CgproKbrdbtxG6CMBqtSE2IR5Wq1V3Q1yAEWAEAouA01mDyvJKuJw1wg0JEYDJZEJ8YhJsdptwxazICDACoUGgpsaBitIyeAS2B14JwB4Tg4SkJEi1G3sWRoARiAAEFFVFeWkJaqodzVrbJAHQzz0uMRGxcXER0F02kRFgBBpDoKqyApVl5WjqpL9JAkhMTgZ9/VkYAUYgshGorq5GeUlJo51olABoyR8Ty+n9InvY2XpG4GcEqiurUF5WehYkZxFATFwcEhITGTtGgBFoYQjQwWBVVeUZvTqDACwWC5LT0vjAr4UNPHeHESAEVFVFSVERXC7XaUBOEwAd+qWkZ8BsYcceni6MQEtFgH78xSe0eKCanCaAmLhYJCQmtdR+c78YAUbgFALlpaWorqr6mQDojj8tIwOyycQgMQKMQAtHgByEThYUaFeD2gqArvvo2o+FEWAEogOBspISOKqrawkgJS0VFiu7+UbH0HMvGQHAWeNEyckiSFNnz1HTMjP58S7PCkYgyhA4cfw4pKefe17l5X+UjTx3lxEAUFpSDGnmS/9S6QaAhRFgBKILAfIOlGb/+zWV3/dH18BzbxkBQoDiB0j/nP+GSu/9WRgBRiC6EKDrQGnugoUqv/WProHn3jIChICiKJCeW/imX0FBGcrwR0CWZS2Mm91iBb33MJtlyJIJslwb5EVRVCiqB263AqfLiRqXC06nU5sgLLUI0NfS7fzZhz7YuMgmGZYAhOJjAgj2SAawvbiYGCQlJCI5MQFJ8QmIjY1BfEwM7Ha7T61W1zhQWVWNyqoqlFVUoKS8HKVlZaisrvapvkguRJF16NQ8VGK3xyAxxXhnPSaAUI2on+3Sti05MRFZaelIT01GenIKbLbgOHPV1NSgsLgYJ4qLUVB0AiUUcYZiVrdgYQJowYMbKV2jHAytMzNwTlYrtM5ID9oP3hs+jpoa5BcW4sjx4zhaWOh3rHpv7YXi70wAoUCd29RiM7RKT0f7c85Fm1ZZMIf5jQ3FpiciOHj4MI4XFbWYlQETAP8Yg4qA3WZDh3ZtcX7bdqC9fSRKRVUVDvz0E/b99BNo2xDJwgQQyaMXQbYnJiSg8/nttS8+nd63BKHbhIOHj2D3gf3aYWIkChNAJI5aBNlMP/wenTqhbevWEWS1flMPHT2KHXv2oDzCiIAJQP9YcwkBBGLtdvTs3AXtzz1HQLtlqNCNwcEjh7F91w+gq8ZIECaASBilCLKRTvS7dLgAXTt0hMnUMpb6euF3ezzYuXcvdh04EPY3B0wAekeX9ZtEIDMtDQN79UI8517QMKqorMS6bdtReLIobGcNE0DYDk3kGGYxm9GnW1dc0LZd5BgdREv3HzqEzTt3+pTmOtBmJscnaB6WoRJy0T5a+HM0X6PsYE9Ao5D0Uk96SgoG9+nDX30vONHV4ZrNm1HURCqrIA3XWc20a9MGQ/r2DVXzOHT0GFZv3mR4+0wAhkN6ZoXkyNOtYwd073QhJ1wRxJoOCbft3o1d+/YJlgi8GhNA4DFucS1YLRYM7tMbbTKzWlzfgtGhw/n5WLd1K1xudzCaa7YNJoCQD0FkGRAfF4dLBg4E/TeL7wiQ49CK9eu1F4mhFCaAUKIfYW1npKZiWP/+sAXg/XaEQWGIuTVOJ1Zu2ICi4tA9x2UCMGQoW34l9FJvaL++LcaNN1xGTPF4sGrTJhwrKAiJSUwAIYE9shqlSXJRnz582BegYVNUVbsh+OnYsQC10HS1TABBhzyyGiRX3sG9+0SW0RFoLd0QrN26FT8eORJU65kAggp3ZDXWtnUrDOnbj7/8QRo2IoFvN20C3RIES5gAgoV0hLVDEXqGDxgIWaoNsBnuQsEtKyqr4XA64Xa5NdIymU2w26xIiIuNmLMLemK8csN65AfAO66xMWQCCPeZHQL7UpKSMHrI0LB8zFNcUoadew9g/8Gj+PHwURwrKELBiZMoK69sEikig8T4OGRmpKJ1ZhrOa9sGHc47B106tkdyUujcYJsymB4TLfn2Gy0mIYtvCLAnoG+4ITbGjsuHDQdF7gkHIV/xTdt2Y92W77Bp2y7kFxj7sKZNqwz079UVA3t3Q9+enWGxmMOh26h2OPDVN9+gyhEZz4rDArR6RjAB+DAi9JT3smFDtai8oRTNZXbnXny+9Fus2bAd1Y7ghN0i8hs2sDeuvPQidO/cIeRnHydLSrFkzeqwf1IcyrnSVNtMAD6MCrn3UsiuUImjxomvlq/FB58vw5FjobkXr+t7u3Na4carL8Xo4QNhsVpCBQn2/XQIG7ZtD1n7kdowE4DOkbugXTsM7NlTZylj1GucLnyyeDkWfbIEpeXhFVsvJTkRt11/Ba4ZPTRkRLBu6zYcOPyTMWBHSS1MADoGOjE+HleMGA7aAgRTyAFm2aoNeOWtj1BUXBrMpnW3lZWeinvuvAEjBgffIYoOBRevXKkFGGERQ4AJQAwn7XrssqHDkJIU3H0/LfFnv/QWduzaK2hpeKjRQeGD996OVplpQTVIOw9Y/S3nNRREnQlAEKjunTqhx4UXCmr7r0YHfB8vXoF/vfURXCFMSulPT2xWC+6/6yb8YvTQoB4Ubtu1CzvDKJaAPxgGuiwTgADCtPS/csSIoDnJlFdUYfrz87F+83cC1oW/ytCBvTH+D79GXKxvSUr19pCchD5bsYK3AgLAMQEIgDR6yBCkp6YKaPqvsv/QUTye95LP9/hms0lLH+Z0ukBnB2eJqmrpuuhfnfMiqZETEP07/X/635UzaiA/gtzsMaBbg2BIQVERlq5ZE4ymIroNJgAvwxdMF9CN23bhidn/0nWfT4FGhw7qjRGD+6Jrp/OQdiqFtNvtweFjx7F5+y58sexb7PphP1RFAeAti6+krXQk2QTZRP/Mhi3f42NjMGX8GPTq1jEoP5pvNm4M6nuBoHTK4EaYAJoBlOL1Xz3yUlDyjkDLyrVb8Myzr4F89UVl+KDeGPObm5CZluK1yNqN2zBn3nwcyy/0qttQgcjAZDbDZLZAkvzLYUCENenh32Nwv8BfpVZWV+N/y5ezg1AzI84E0Aw4XTt0QK8uXXT/YPQWWP7tRvx97uuNL9kbqYy+0A/87hZce/lwXU2Rp+DUGc9hzfqtusrVVzaZzDBZbNrqwFcxmUx4dOzdGDaot69VCJfbsnMndu/fL6wfbYpMAE2MOH2prh01ChTYM5CyeuM2TJv1ivC1Fe3Tx91/By6/5CKfzKIVxqNP/gNrN/hOAtQwrQosNhtk2bc3AXRWkTN+DAb26eZTP0QLUTixT5cuDctcA6J9CKQeE0AT6Pa4sJMWyjuQsvOHA3jkyWd1XfNdf+XF2tffH6msqsY9Yychv8D/RBO0LTBbbT5tDeiacGbuw+h0flt/uuO17Pbdu/H93sjyo/DaKYMUmAAaAZJO0a8bPTqgX//jhScx9rEZulx6yd3233NytLf7/sqqNRsx6al/+lvNqfISLDa7dkagV6hPc5+acPrwUm95EX1aBXyy5Gt4FPHzFZF6W4IOE0Ajo9ipfXv06949YONLjj0P587G3gP6/Nbvvu063HbDFYbZdfefH8OBQ4cNq89ktsJitQM6Y6N07dQe06c8CNp2BUo2bN+OfYcOBar6iK2XCaDB0NEe++qRIwOawuv51xZpXn565Y25jyND4MRftN433/0vXpr/jqi6kJ4sm2C1x+r2J7j5ustw7x2/FGrDFyV6H0A3AuT/wPIzAkwADWZD64wMXDxoUMDmyIatOzHpmed11a+qCtKS4vDmvOm6ynlT/n73Pjww4XFvarr/TleF1pg43f4Dz0z6C/p0D9y5y7K1a3H8hP/nHroBCeMCTAANBocSepzbKjDealXVDozJfhInTpYITwn6YjkdlRjUtwf+njNeuJyIYkVlFa69/Y8iqrp1aCVVSwLifgP0cOjF6Y8acsbRmMGHjh3D6k3GJ9jUDU4YFWACqDcYFN6LDv8CFeDzhdffxUefLxcfflVFTXUlaAUwasRgTJnwgHhZQc2R1/9WUFO/miTLsNr1rQRuue5y3HPH9fobEyhBbwQ+XrIEdCjIUosAE0C9mdCx/Xno371HQObGj4eP4Y8TnxG+7yePXWdN5WkvtmGD+uHJSQ8aahv9EK779YO1+2JVhaJ4tH+1LsPGCDkMEQmICvkHvDTjMdDbgUAIHwaeiSoTQD08Rg25CBmpgXm/njNjHtZu2iE8p101DnjcP3+pzm93Lv4990nh8iKKB346ij8+8vRZqtpjIcUDj8sFj8clUlWzOibLqdsBwZoomMhjD90jqK1PjR8JMQE0OmPsdjt+OXq0vtkkqL1zz0E8PCVPUBtQ3G44a87Mhkvusx8tmIv4uFjherwp/verVXj2lbebVaPth9vlrCUjPw7QLfZYkBuxqDz/zF9xwXnniKoL6xG5fUTbgJrgBFAVNixEirwCOAX8BW3bYmCvXgEZhpwZL2HtJsGAldq+v6LR66oJf/k9rrn8EsNsnDjtn9j6/R6h+mhb4HI5NHLyRWoPBeOFbwYuvqgvHn3w97405bXM2i1bcfCIcf4PXhsMYwUmgFODM7Rff1CKL6Pl8NHjuHf8E8LVup3VcLsaX3bTNuCVfz4BWdbpadNI63v2H8LYSTN134t73C7Q9sSX5YDZYoWZHIUEhA5iX52TE5CQYoeOHsXqzZsFrGj5KkwAdBIqSfi/K64IiCfai6+/hw8/XyY0k+grS1//5uTP992Jm6/zzxuQAoWMz5kF2pr4InSa7nJUabcTesVGqwBZ7GowUDcCTpcLH375pW7y09vXSNBnAgC0BB8U8stoIZffOx6YhPLKM/fzTbXjdFRB8TS/xLZaLZjz5N/QrXMHn819eeGHeO/TJT6Xp4L043dW6ycB2WyB1RYj1DalI1swdxroZsBoWbxiJUrKy4yuNuLqYwIAEKjrv2/Xb8Xjs/4lNCnoq+r08vWvqygxIQ5PTx6H7l30R9Z5Y9F/8eYHiw35+mkrFkeldoUoLBJgs4uvAp746wMY0LurcPWiiht2bMe+H/ltABMAgCF9+qLdOW1E546w3tPPvgYK9iEiDa/9vJWxWCwY87vbcOPVo0A3BN6EvA/pxF/PVaS3Ounv5DfgrNYXh1/PWQDFPRj/hztFTNGl8+ORI1izZYuuMi1RmQkAwC8uuQQU+ddIoZh8t475K8j916uogKO6XNeXlA7T6IfUOisdv7zqEi0RR108wLr26Mrrh32H8NXKdVi8dA0ogWggxO2qgdspfq2m3QjEJgg9GkxKjMdbLz5luHdmaUU5Pl+u/0FWIPALZZ1RTwDkqXbzlVcKX0+JDhYl8sie+g8h9dqT9WohXVKiQzRaRtf/BdGPKiM1GZkZabBZzdq5w+GjBWIEJNxy04q0CqDVgKhY7DEwmcTiB/zziQm4sEM70aqF9Ogg9L3PPxf3zBSqNfKUop4AKNPPFcONPwBc+P7noP22iDhrqqG4xT3u6JENPbvVLZYY4NweQFYHIKk1UOeiS/v4knygYA9weAfgEli1NGhc8Xi0R0uiQsFDLIKHgfRMmJ4LGy2LV65ASVm50dVGVH1RTwCBCvtNT37p6a9XUYGaqnKogm52FIPPGqPTG5DIotNQoONQwOwlmhB5/P2wCti3mjb4Xs2vr0AEQEQgIrRiscUmiKhiSP9eyMm+T0hXj9K3mzbip2P5eoq0ON2oJ4CuHTugV2djI//S3vtX9z8qFO5L5O6//qyjYBsUq19YbPHA4NuAFJ2HnCd/Ata9Q+wk3BRdYdJVpqjYYskz0LtPQHpqMhY8N020WmG9rTt3Ydf+fcL6LVEx6gmAUn1Tym8jpbikDLf/8TGhKj0uJ1xOsSU3/VjoRyMs1hhg+N1Ago8PnMoKgVWvAy7B8wlazWhuzGIrh9o4gmLxDRe9/HckxOtc+XgBau+PP2LjDvEHWsK4R5Bi1BPAxQMHonVmpqFDtn3nHkx4XCzgpp7rPz3XZ1qKr4tuBzJ9dxjSQMn/oXYlIHjX35wrc0OQ9fRn9tRx6Hrh+YaO09GC41i5foOhdUZaZVFPAJcNG4a05GRDx+3L5WuQ9+JCoTpFvP/qKrLaYiGLBs48tzvQ/0YhG7wqrVsEHNvlVY0U6PmwyyG2YqCtjBY/UED++uffYeSw/gKa4ionioux5NtvxQu0QM2oJ4BrKABonHjACpE58NYHi/H6O5+KqKKmSnzJbKdDs7qMns3VTjqX3g8kGBRUo/Q4sPxlsVWAqsJRJXayrgUQjRHDPhA3AeUUKHSZ2DsNocGMQKWoJ4AbLr8cNqvYPlR0fOfNfx8ffLZUSL2mUuwGQM+puXbFN/JeofaFlb6eB5QXCKlrBCCyZZAkaKQmILdefxl+f7uxUYMpIhI9CopmiXoCuOmqq7R02kYKLf9pGyAijqoyoZe1ukJrdRwCdDf43nz7YmD/OpEuaa7BYk5BEuxxYgRw1aiheOi+24XaF1Vyud14f/FiUfUWqRf1BHDLL36hpcM2Up6Z+xqWfSP2BsBRKfYiTc9+GX2uBc7ra2SXgAMbgW3/E6pTz7mGPS5RqM7LRgxC9gN3CemKKtEDrEWffSaq3iL1op4AbrvmGsMH9sk5r4DSfYuIKAHo8ZzDwJuBNga/oDv8HbDxfZEuabECPF6eNddVJEoAdABIB4FGy9v/FfPWNLrdcKkv6gkg9CsAOjDz/pxWFwH0uwFo29PYOXZoK7D5Y6E66RZAJJionnMNXgEIQa9bKeoJICBnAC8swJcr1goNhugtgC4X4C6XAp2HC7UvrLRrKbB7lZC66BZAj2NTIM4A3B6P9iAomiXqCYBCgVktYq/SRCeKnlsAUf95PT8WZHUCLvqVqLliet8sAE4cENIVJjUdOQMCER6MbwE4MQiuufRSwxOBvvn+YsxfJOYH4Kqpgkck0q4E2GPFDsxAbwWufAig139GCL0H+GK22OMgim1ANxsComdbQ9mCiASMFPYDYALAZUOGIC011ch5pV0BinoCUsx9t+BbAF3PgLuMBDob9Mx55zLgh5VCGOmJEGSx2mCy2ITqDYQnYGFREb5eI3ZdK2RkBCpF/RZgWN9+OLdNa0OHbtv3e/HINLFgIHpe0NVFARIylh7ZjPoDEJMkpN6kUmUxsHQeIJghSBeh6XjZGIi3AIeOHMHqKA8LFvUE0KdzF3Tu6OeDmQa/npPFpVo0YCEJkOus1nbKOcCw30DbEvgi9KOn14Alx4RLizsBQYsHQDcBIvLOS8+AgqEaKbv27sXW3buNrDLi6op6ArigzTkY2LePoQOnJx4ANaznR0PZdXQ5LmVeAAy8FTDrPOikwCBr3xE++KN+6Fn+6/FspFiHC583Ph7A+s2bsf/oUUPHPtIqi3oCyEhMxKgA5AR47OnnsHGb2As6PUE19TyhPT0Z6VFQ3+vFg4IUHwE2fQRUFOmaz3qeNlusdlDSUBEZ3K8npk4YI6KqS+er5StQVCH2cElXxRGkHPUEYIGEG6+52vAhW/jeZ3jjXTHXWV1RgSiUlo4cez93TAJadwbaDwAyzqPIomf2mYJ4FB4EDm4EjtGy2LtzUv0KaNVD13+i5USjAVEbgbgBoHrf/+RTuAxIs2b45AlihVFPAOXFJ3Hvr431Mafx0xMVWNsG6Iinp+f6rNG5RNuBhEyAwoWR1JQD5YWAjsCkDeulqMYU3VhEdL1rAPCPadno3PE8kap16bw8fz4S03yMlqSrpfBVjnoCKMzPx923/wpxscYeMFFegFvum4hqh1i8fF2hwSXAaosD7aPDQfRGBLbYYmESDGySlBCPt+YZnxegvKISr7/9H2S0Mj4hbDiMiagNTAD5+bj2iivQvm1bUcyE9Z76x6tYsUY8C62oBx0ZQLkBrPY44VN0YaP1KmrpzCuF4wDq8mgEEIg3ANTFg4cO4dMvv2QCeG7hm/o2e3onSJjrnzh+HAN698bg/saGm6Jur1q3FU/MFssNSPoet/NU6m0x0PQupcVq1acl6vdfVyvlAqAtjKhMe+QPGNi3u6i6sN7qDRuwads2pGdlCZdpiYpRvwIoKihA66ws/N/Vxh8EUiquO/4wCRVVYjHytO24jhBhpE9LaYs19owsQcGaqHr2/XWrFjrAFBVKC0bhwC2C2wXReknv/U//i+MnCpCaYWxAWD02hINu1BNA8YkTWviqMb/5jb77dcHRe/61Rfh4sXgOOr376VoSoCw7dtoYCFrlp5oKOJ1VUETeMNRrihKa0KtGUbnp2tG4784bRNWF9TyKgpfmvw5JNiGFDwGjewtQWlyMGocDN117Ddq0MtYlmGbkoSP5GJP9pPDkJEU99+l1FVOATcq3J5JoQ5cxDZQp5j+lMlMFMwDVFdd7c0Eegq/Mmow2rQwKbFqvH4ePHsUH//sfbHYbklKMfQfiD7ahKBv1K4Dy0lJUV1Whf+/eGDpwYEDGYMqMF7Fu03c66q69U6e7dV0iSdAe2Agm29BV9+kzCrrV0GeXLweWwwf1xqSHDQ5seqrDq9auw+bt2xATF4uERD/fSugFMcz0o54AqioqUFFejvTUVNx+o0Fx9BsM8s4fDuDhnFm6hl5zq6Vkm/p+a1obtBqgh0NGXRPSgyVK/y0W6PPMbtKmxOJDMtPnnp6IDu3P1YWZqPKb776HopJixCcmIDZO/ExCtP5I0ot6AnA4qlFWXKLtnu+69VYkJQq+udc5ypP//gLWb/leVyldvgGN1EwEQKuB2jt3/ecDdCtBNogm/Gysc3ru/OvKDxvUG5MD9PUvLinBwnff1Xg1KSUZNrtBMRN0jWz4KEc9AbhcLmgHgQCGDBiAAX2MfRhUN9QHfjqKP018BpSXXo/oyR3YZL0SrQrMWlJRekhE5wSS5gJbRwoqVEXV7vLpK09ffNrj67P07Nb1+PvXlTabTZg3/VGc0zowp/PrNm3G2k21EZtT09NhNjgalJ6xDQfdqCcA2mefyM/XJnt6Sipuvykw2wAa7Of+vQiffCF+I1A3QfQ8FgqHSUU2mK02mAWDfdWBof8AABJJSURBVNS3+aZrRuO+Xxt/8l/XxsL33sPJ4mItw1JGVlboHalCPGBRTwCE/8nCQrhPXWnddsMNyExPD8iwVFY5MCb7CRQVl+quP5JIQE/W3/pAZKWn4sUZjyLGLhYlSC+I+QUFWPRxbWRjs9mC1IzAjLNeu0KpzwQAoKykBI7qWmedHl264NLhBkfUrTfCazftQM6MeT6NOcXar0286e/i3KfmvRaiqzuLNUY8gWmDGp969E/o17OL13Z8Vfh65Up8dyoAiD0mFonJ0X0DQDgyAQCorqxCeVntV5kiBP/+zjsD4n1WN3GffeVt/PcrsRDbDSc7ZbOhQKL0hDichM4WLPZYn/0Qbrz6Uoy5K3DbL6fLhVcXLgSlAyNJSEpCTKxYZuJwwtloW5gAALjdLpwsrD0IJBlx0UXo06OH0Vifro9chB+aPAv7fzziUxv0/fc4HaD4e+Egtft9Cu6h/6aB7KenvjOnPASLRdxLUG+/6d6f7v/rJDUjA+YAuBjrtSvU+kwApxbURcePg76uJInx8fjNbbcF9IAov6AIf3lsOsorqnyeA6rigYvu5wXTcPncUBMF6WaB9vvk6OOrJCcl4NknH0FGWrKvVXgtR+M6/+23QWHASWRZQnpWdD8DrgONCeAUEqUlxaipdpyeTFeOvBQXGhwstOFM3bF7H/72xNzTy1KvM7kJBbqnp9Divjjq+NImXSfSF5/+2x+xWqyYMWVsQIJ91Ldr1949+HLZ8tP/lz0mBonJgSMcfzAJdlkmgFOI0yEgHQbWSUpyEu686eaArgKoLXoy/NScV3T7BzQ2UYgAyG9Au8fX6W/gbeLRAZ+J/Ajohy/7H4jEZDJhyrh7QPH+Ainkd7Fg0SKUlv2crIR+/EQCLHwIeHoO0DKRtgH1z9cvu+QSdO3UKeDz5KuV65D3wgLDfrTUB8XjguL2QFHcPh8Y0tKelvnaD99MP3rf9vgNAZQlCRP//FtcMtT4GAwN2/pu9y58vfLMA1eKAaArsnLAZ0DoGuAVQD3si4tOanvqOqGzgF/fcgvoaxVoWfrNBsx4/o3T5xCGtqeq2vaAPP3qPP5qVwh1dCfVrnQkCbLmJUj/TAFZ/ZCn31//cjfosU+gxe1xY8E7i07v/ak9q82K5NTojgNYH3cmgHpo0KtAeh1YXy4aMAADA+Qe3PAHsH7zd3jyH6/CURMep/tG/0BjY+yaj3/fnp2NrrrR+tZt2oS1mzad8bfEpCTY+frvNCZMAPWmR2PbAIpGc9ettxgeNLSpX8C+g4cxdeZLKCgqDsqPJFiNtMpMQ+6EMWh/bpugNEkn/gsWvQMKzlontMpJy6TlvzFbmaB0JMCNMAE0ALi0uAQ1mrfdz9KxfXv84rLLAjwUP1dfWl6B6XNfF04sEjTDfGxocL8eyH7gLiTEBc/x5tMvvsSBQz+eYbEtxo6k5BQfe9EyizEBNBhXZ00NSk6ePGu0r77sMnRo3z5os4BOrz/4bClee+sTv68Jg2Z0g4YsVgvuu+MGXHfFiICcJzTVrz37D+Dzr5ec9efk1FRYbYF5ZxAqjP1tlwmgEQQpUKinQcgryhtwx003wh7kCXTo8DHMefk/+P6H/f6OdVDL9+rWEQ/dd0dAQno11xHKw/Dm+++hqupMBys6fIz2AKCN4cYE0AgqjR0GklqwtwJ1ptFqYMmKtXj1P5+guOTn++yg/qIFG0tPTca9d9yAS4b2C+pXv868xpb+9Df2/W98AJkAGsGFrsiKCsg1+OxXd6MvHoFuFwbnFLuhafR1owjD737yFcorfXchFvwt61KjEN63/vJyXHf5cJCHXyhkx65dWLrq7EdWdOeflpkZEkIKBQ562mQCaAKtyooKVJafnTmWbgVu/uX1WvCQUAkRweJlq/HB/5bieOHZ5xXBtKt1VjpuunoULh95EWxW8YQfRttYWFSEdz/+BHT331DiEhIRF29s6jej7Q9VfUwATSBPy+6TTawCKG4gBQ6xWUPzpau/Ndi8fTe+WLYaazZuR41TLDmnv5ONAnZcNKAnrhw5BL26dQJ59oVSHDU1eOfDD1HaCGHz17/5kWECaAafqsoKVJQ1nj+ecglSTkHNgy4MhJyHNm7diQ1bvsfGbTsN9yOge/z+vbpiQJ+u6N+rS8iW+Q2hJqL+ZPHnOHS48afVCYmJiInjr39TU5QJoJkfL50FULiwhjcCdUV6duuKkUOHhcHP/2wTCotKsHPPARw4dAQHDx1DfsEJ5BcWec1WHBdrR2ZGGlpnpOP8dq3Rvt056Hbh+UhLCc/oOV+vWonvdu1udAwoGjIF/gwXkg7HicIE4GVUyCmInIOakmGDBqFfr17hOLaN2uRyulBWWQmHwwmn203u/7CYzLDbrVochEAG5TAapA1btmL1hvVNVpuUmgKbljKNhVcAPs4BugcoLSqC09m4fz5tAC4dMRzdOwculp2PprfoYjt27sKyb1Y1GR2RHH6SUlMNer/YcqHkFYDA2Hrcbpw8caLJ57p0CHb5JSMDHkBEwNSoUNm9dy++XL68yfGgJT+F/ArGK85IB5wJQHAE61KINaVOp82jR4xAlyDEDxA0uUWq7dzzA75esbLZACqc8kt86JkABLGirUDJiROgTEJN7qckSTsU7NGVtwOCsOpS2/bd91ixZnWzgVMsVitSUlO12AYs3hFgAvCO0WkNug2gW4Hmwm3RtBvYry8G9wt8tBsdpke86poNG7Bhy5ZmMyLQViyFl/66xpoJQBdc0BKI1I8d2FTxLh07YdTFI2DyI2KuTtNapDqR7lcrVuCHffu89o9j/XmF6CwFJgD9mGlRg+jBkDdpk9UKvxg9CrEcgcYbVI3+vbKqEp8tWYJjxwu8lo+Ji0VCYnj6Kng1PoQKTAA+gE9bgBKKHyiQmCMuNhZXjRqNNq2yfGgpeoscyT+Gz5d8japTKduaQ4LiDlCcP3b40T9fmAD0Y6aV8CgelBQWaf/tTWgbMKBvXy22IE/S5tEi1971mzeBnHzqErU0V4Ku+pLT03mr5W0SNvF3JgAfgaNibpcLJUVFwjH927RqhctHjtQ87ljORqCsvBxfLFsqtOSn0kSmKenpnOLLj8nEBOAHeFSUQoiVFhcLx/Sn58SDB/RHn+49eDVwCnv66m/Zvk2L4Fs/iGdzQ0M//qSUFA7x5ef8ZQLwE0AqXuNwoIxIQEddmenpuGToULTKzNRRquWpHjt+HMtXf4vCE0XinaMff3IKbHaO7ycOWuOaTAD+IniqvOj1YP3m6Ct2YYcOGDZoYNDCjhvUXb+rqaisxDfr1mHPvn26iJP8LBJSkmG3c2ovvweBtlHPLXxTz4fLiDZbbB2+rAQIDApY2bNrN/Tv3Rsx9pb9eq26uhobtm4FPeZpLHqPt2U/3fXbWjhGwfyBMAEYjHZNDW0HSoTPBOo3T+cDPbt1Q+8e3REf27KCWNAXf8uOHdixc6dPYc55z2/wRD1VHRNAAHCl9wKlJ08KXWM11jxdbXW64AL07t4ddFYQyXK8sBBbv/sOe/fvh0dRfOqKbDJpB34WS+hiDvpkeAQUYgII0CCRCyuRgNt9dpBKPU2mp6WiR+eu6NThgqDnJNBjZ31dClpKe3vKzHuikSQreuo1m83au35+2qsHNXFdJgBxrHRr0vVWeUnpWanGdFcEaI4u57ZpoxFB+7bngQJzhpNUOxxaKq49+/fjyNFjPn/t6/fJHhOjxfNn56nAjTQTQOCw1WqmE9ZqCi5aXgFoKbn9F3r1lpGeDgpMem6b1shKzwDFvwum0AEeLe8PHz2KH386jIJmAqbotYtO+uNOBfPkR7160dOnzwSgDy+ftclrkF4R+rslaMwAWh5npKUhKyMDaSmpSEtNQSo5yRi0Z3a6XCg6WYyTxSdxovgkjhcU4kQRuUH7tqdvDkQiMjrp5/2+z1NNV0EmAF1w+adMj4gqysqEXhL61xK0WHg2mw2JCQlIiI+H3W7XrhjtdhssJgtkkwyzbNKacSseKB4FLo8LDkcNaDnvIOeminKUl1egpqZG1129L7aTvRS+Oy4hgZf8vgDoYxlp7oKFKu+xfETPx2IupxNlpaWgWIMs5AdhRgJ/9YM+FeiDJD37xgKV4tmxBBcBAr+6sgpVFeXCj4mCa2HgW6N5Fxsfj5jYWP7qBx7us1qgLZw057XXVEuIkjmGoM9h1yQ9eaUchI6qqoAvs8Om85KEmJgYbbnPH5/QjQqtRKW8f72i0nULS2gRIL+ByvIKOKq9RxoKraX+tU5zjX74fK/vH45GlCa3bOnvL7yoxicmGlEf12EAAkQElJPQUVXtkzuxASYYXgWdMdljYxAbGxf060rDO9OCKiwvK4U0bc4/VEqiwBJeCNDWoLqqGo6qyiZzE4aXxWdbQ1d6MTGxsMfGQpb5Rj/cxquosBBSzsw8NS0zk5dk4TY6p+wh1yHaq9VUV8FR7Qj7VQHt6emdvi0mFhSjn3/24Tmx6AbqNAHExcdr+zKW8EaAbg4oAlHdv6ayFge7F7Sfp1x8VrsNVpudf/TBHgAf2qsoLwdlu9JWAPTaKi0jg69ifAAyVEVoZUAsTmTgdrrgdDmheLwHKDXCXvrBm60WWC02WGxWbV/PX3ojkA1OHfQhKSoo0F6ragRAzVJMdYqtzhK5CNC9rsfl0tyN3S43FI9bOz8gYtD7CoF+0PRhoB+7bDLDbDFrDjv0j/5/lshFoKqyUvNIJZEmz8zzyKDrWFnLqMr3spE7sM1ZTmyvKorG+irRAf3n1OMkzRNU+4+kjb8kyzwPWuY00Maf0ttpX39F8UiTp88olWVZuweMiaXnl8kttOvcLUaAEaAHaRS/Uvv6A6VS7sy8gypwXh00WrTVmJYdl46nASMQjQg0DFyrQD0oTZ45a4kMdVQdIPTWPDktXdvzsTACjEDLQIDC1FESm/qZrRWoX9EKYK4K/Kl+N+mQJyUtjX0DWsbYcy+iHAE6FNYyWDWM3yDhn1LOjFm/gqS+1RAjIoHklFReCUT55OHuRzYCWvq6JgPUqrdIOTNmZCqSfIxuAs4iAUlCfHISJ2GI7DnA1kcpArTnp1T29Zf9dVDQDUCNOyZL89/ImZ73FWSMbgone0ws4hP56WaUziPudoQhoCgUear09Gl/Y+YrEr6YNn78lRoBTJk5804J0oLm+kn3w+QyTA87OIJQhM0INjcqEKAvPcWVqKQgM0rzrl8q1Dsez85+SyOAMfPmWbIqKvbKKtp5Q4qIgEiAAjoEOxKtN9v474xANCJAGZXpsVh1VZVoMpoDUkX5hbm5ue7TLty5M2eOUSHN0wMguYWSLzhFcDWZLVrsevIi4xWCHhRZlxEQQ4C+8OTNSe7d9E97A+Ks0R1pWpJwT+748a9Sqz8TQG6urMTFrZUkeYCYOazFCDACkYeAtHbq+IeHQJK0PcIZj7gm5+X1lj3KWshyeKWdiTyU2WJGIOwQUAAHZGnQtHHjttcZd9YrzpyZs/4AqC+EnfVsECPACPiFgAT1/tzs7JfqV9LoM+6c6bPmQFYf9Ks1LswIMALhg4CKWVMnjB/f0KDG4zioqpQza9bLUHFP+PSALWEEGAGfEFDwr6kTxo2p2/d7XQHUKeTm5T2lqvibT41yIUaAEQg9Aor01NRHxj3WlCFeIznlzpx5IyC9qgJJoe8NW8AIMAIiCCiKUmKSpbtzs7M/bE7fKwFQ4cdmzTrHoqizVeAWkcZZhxFgBEKJgPofeDzjp06ceNSbFUIEUFfJ5Omzh0FyT5Il+SpvFfPfGQFGILgISJA+86jStGkTHl4t2rIuAqirdNL06Z1MkukuSfXcoELqwVkfROFmPUbAQAQURfXIpu0mKB9Clt+YOm7cXr21+0QA9Ruh58SQ5QGqqnaWJIneEiRAVeMAijTJwggwAsYgQLm8pUoA5ZKCHxVJ3e2yWjc8PXZsoT/184/UH/S4LCMQ4QgwAUT4ALL5jIA/CDAB+IMel2UEIhwBJoAIH0A2nxHwBwEmAH/Q47KMQIQjwAQQ4QPI5jMC/iDABOAPelyWEYhwBJgAInwA2XxGwB8EmAD8QY/LMgIRjgATQIQPIJvPCPiDABOAP+hxWUYgwhFgAojwAWTzGQF/EGAC8Ac9LssIRDgCTAARPoBsPiPgDwJMAP6gx2UZgQhHgAkgwgeQzWcE/EGACcAf9LgsIxDhCDABRPgAsvmMgD8IMAH4gx6XZQQiHAEmgAgfQDafEfAHASYAf9DjsoxAhCPw/93jZcYv2Tv1AAAAAElFTkSuQmCC";

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            UI = this;            

            //Default the dialog boxes from UI module.
            if (!Application.UnsupportedIE()) {
                Application.MessageBox = UI.Alert;
                Application.ConfirmBox = UI.Confirm;
                Application.ProgressBox = UI.Progress;
            }
			
			Application.On("ModalClose",function(){
				setTimeout(_self.ProcessQueue,500);
			});

            //Setup the timer.
            m_timer = new Timer(1000, _self.OnTimer, null, null);		

			//Load layout values.
			var win = $("<div style='display-none' class='ui-dialog ui-dialog-content ui-widget ui-widget-content ui-corner-all app-window ui-state-active' />");	
			$("body").append(win);
			m_borderWidth.left = parseInt(Default(win.css("border-left-width"),0));					
			m_borderWidth.right += parseInt(Default(win.css("border-right-width"),0));
			m_xMargin.left = parseInt(Default(win.css("margin-left"),0));		
			m_xMargin.right += parseInt(Default(win.css("margin-right"),0));		
			m_yMargin.top = parseInt(Default(win.css("margin-top"),0));		
			m_yMargin.bottom += parseInt(Default(win.css("margin-bottom"),0));
			win.remove();
		
        };

        this.OnTimer = function () {
			if(!m_progClosed){
				Application.ExecuteWebService("GetMessage", { auth: Application.auth }, function (r) {
					if (r)
						UI.Progress(true, "<img src='https://go.scrubit.com.au/Images/loader.gif' /> " + r + "<br/><br/>", (m_progressTitle ? m_progressTitle : "Progress"), null, null, m_progressIcon, true);					
				}, true, null, true);
			}			
        };			

        this.ShowServerProgress = function (title, icon, hideCancel) {											
				
			m_progressIcon = icon;
			m_hideCancel = hideCancel;
			m_progressTitle = title;
			
            m_progClosed = false;	
            if(m_timer)		
			m_timer.Start(true);						
        };

        this.HideServerProgress = function () {
						
            m_progClosed = true;
            _self.Progress(false);
            if(m_timer)
            m_timer.Stop(true);			
			
        };

        this.Height = function () {
            return 'auto';
        };

        this.Width = function () {
            return 'auto';
        };

        this.SideWidth = function () {
            return 'auto';
        };
		
		this.BorderWidth = function(){
			return (m_borderWidth.left == 0 ? m_borderWidth.right : m_borderWidth.left) + (m_borderWidth.right == 0 ? m_borderWidth.left : m_borderWidth.right);
		};
		
		this.XMargin = function(){
			return (m_xMargin.left == 0 ? m_xMargin.right : m_xMargin.left) + (m_xMargin.right == 0 ? m_xMargin.left : m_xMargin.right);
		};
		
		this.YMargin = function(){
			return (m_yMargin.top == 0 ? m_yMargin.bottom : m_yMargin.top) + (m_yMargin.bottom == 0 ? m_yMargin.top : m_yMargin.bottom);
		};
		
		this.MagicWidth = function(){
			var multiplier = .70;
			if(Application.IsInMobile())
				multiplier = 1;
			var w = $(window).width() * multiplier;
			var h = $(window).height() * multiplier;
			if(w < h)
				return w;
			return h;
		};
		
		this.MagicHeight = function(){
			var multiplier = .70;
			if(Application.IsInMobile())
				multiplier = 1;
			//var w = $(window).width() * multiplier;
			var h = $(window).height() * multiplier;
			//if(w < h)
			return h;
			//return w;
		};

		this.Icon = function (img, size, source) {
			
            size = Default(size, 15);
			
			var icon = m_icons[img];
			if(!icon)
				icon = m_icons.noicon;

			if(source)
				return icon;
			
            return '<img src="' + icon + '" style="vertical-align:middle;width:' + size + 'px;height:' + size + 'px" />';
        };
		
        this.IconImage = function (img, path, size) {    
            
            img = _self.MapIcon(img);
            size = Default(size, 15);

            if(img.indexOf("mdi-") !== 0)
                return img + "<i/>";
       
            return '<i class="mdi ' + img + '" style="font-size: '+size+'px" />';
        };

        this.BigIconImage = function (img, path, size) {
            
            size = Default(size, 48);
            return _self.IconImage(img, path, size);
        };

		this.Paused = function(value_){
			//not used.
		};		       
		
		this.ProcessQueue = function(check){
			
			if(m_queue.length == 0)
				return;
			
			if(_self.DialogVisible() && check){
				setTimeout(function(){
					_self.ProcessQueue(check);
				},500);
				return;
			}
			if(m_queue.length > 0){
				var func = m_queue[0];
				m_queue.splice(0,1);
				setTimeout(func,500);
			}
		};

        this.Alert = function (msg, title, callback, icon) {            

			m_queue.push(function(){

				msg = FixMessage(msg);
				title = Default(title, "");

				if (title.indexOf('Error') != -1) {

					if (title == 'Application Error')
						title = "Oops";

					swal({
						title: title,
						text: msg,
						type: "error",
						width: ($(window).width() < 438 ? $(window).width() - 60 : null)
					},
					function () {									
						if (callback)
							Application.RunSilent(callback);
					});

				} else {

					var type = "warning";
					if (msg.toLowerCase().indexOf("done") != -1 || msg.toLowerCase().indexOf("success") != -1 ||
					title.toLowerCase().indexOf("done") != -1 || title.toLowerCase().indexOf("success") != -1)
						type = "success";

					if (title == 'Application Message')
						title = "";

					swal({
						title: title,
						text: msg,
						type: (icon ? null : type),
						imageUrl: icon,
						width: ($(window).width() < 438 ? $(window).width() - 60 : null)
					},
					function () {									
						if (callback)
							Application.RunSilent(callback);
					});
				}   
				
			});
			_self.ProcessQueue(true);
        };

        this.Confirm = function (msg, title, callback, yescaption, nocaption) {            			
			
            m_queue.push(function () {
			
                msg = FixMessage(msg);

                yescaption = Default(yescaption, "OK");
                nocaption = Default(nocaption, "Cancel");

                var type = "question";
                if (msg.toLowerCase().indexOf("done") != -1 || msg.toLowerCase().indexOf("success") != -1 ||
                    title.toLowerCase().indexOf("done") != -1 || title.toLowerCase().indexOf("success") != -1)
                    type = "success";

                if (title == 'Application Confirmation')
                    title = "";

                swal({
                    title: title,
                    text: msg,
                    type: type,
                    showCancelButton: true,
                    confirmButtonText: yescaption,
                    cancelButtonText: nocaption,
					width: ($(window).width() < 438 ? $(window).width() - 60 : null)
                },
                function (r) {                   				    
                    if (callback)
						Application.RunSilent(function(){
							callback(r);
						});
                });
				
            });            
			
			_self.ProcessQueue(true);
        };

        this.CloseDialog = function () {
            swalclose();            
        };

        this.Progress = function (show, msg, title, i, num, icon, hideCancel) {

            //Hide progress.
            if (!show) {
				
				if(m_progressDialog){
					setTimeout(function(){		
						if(_self.DialogVisible())
							swalclose();
						m_progressDialog = null;	
					},500);
				}												
                				
                return;
            }

            //Show/update progress.
            if (m_progressDialog != null) {

				if($("#" + m_progressDialog).length > 0){
					
					$("#" + m_progressDialog).html(msg);

					if (i != null && num != null) {
						var perc = Math.round(i / num * 100);
						if (Application.UnsupportedIE()) {
							$("#" + m_progressDialog + "Progress").html(perc + "%");
						} else {
							var progressbar = $('#' + m_progressDialog + 'Progress');
							progressbar
								.css("display", "")
								.css("opacity", ".8")
								.knob()
								.show()
								.css("display", "")
								.css("opacity", ".8")
							;
							progressbar.val(perc).trigger('change');
						}
					}

				}

            } else {				
			
				m_queue = []; //Kill queue.
				
				m_progressDialog = $id();	
					
				setTimeout(function(){											

					if(_self.DialogVisible()){
						 swalclose();					 
					}									
					
					var prog = "";
					if (i != null && num != null) {
						if (Application.UnsupportedIE()) {
							prog = '<br/><br/><center><div id="' + m_progressDialog + 'Progress" style="font-size: 18pt;"></div></center>';
						} else {
							prog = '<br/><br/><center><input id="' + m_progressDialog + 'Progress" type="text" data-thickness=".4" data-displayPrevious="true" data-linecap="round" readonly data-min="0" data-max="100" style="opacity: .8" value="0"></center>';
						}
					}
					
					var cancelFunc = function () {
						Application.Error(""); //Kill process.
					};
					
					if(hideCancel)
						cancelFunc = null;

					swal({
						title: title,
						text: "<div id='" + m_progressDialog + "'>" + msg + "</div>" + prog,
						confirmButtonText: 'Cancel',
						hideOKButton: hideCancel,
						imageUrl: icon,
						width: ($(window).width() < 438 ? $(window).width() - 60 : null)
					},function(){						
						if(cancelFunc)
							cancelFunc();
					});

					if (!Application.UnsupportedIE())
						$('#' + m_progressDialog + 'Progress').knob().hide();
				
				},500);
                

            }
        }

        this.StatusBar = function (show, msg, color) {

            color = Default(color, "#FFFFA6");
            msg = Default(msg, "You have limited or no connectivity.");

            $("#divWarning").html(msg).css("background-color", color);
            if (show) {
                $("#divWarning").show();
            } else {
                $("#divWarning").hide();
            }

            $(window).resize();
        };

        this.DevBar = function (show, msg, color) {

			if(!Application.developerMode)
				return; 
			
            color = Default(color, "#FFFFA6");
            msg = Default(msg, "");

            if (show) {
				$("#tdMainMenuTop").html(msg).css("background-color", color).css("color","black");
            } else {
                $("#tdMainMenuTop").html("").css("background-color","");
			}
        };
		
        this.FindEditorInput = function (elem) {

            for (var i = 0; i < elem.children().length; i++) {
                if (elem.children()[i].nodeName == "INPUT" || elem.children()[i].nodeName == "TEXTAREA") {
                    if (elem.children()[i].className != 'noinput')
                        return $(elem.children()[i]);
                }
                var v = _self.FindEditorInput($(elem.children()[i]));
                if (v != null)
                    return v;
            }

            return null;
        };

        function FixMessage(msg) {

            try {
                if (msg.message) {
                    msg = msg.message;
                }
                msg = msg.replace(/\n/g, '<br />')
            } catch (e) {
            }

            if(msg)
                msg = Application.ProcessCaption(msg);

            return msg;

        };

        this.ScrollToTop = function () {

            if (Application.IsInMobile())
                $.mobile.resetActivePageHeight();
            $('html, body').scrollTop(0);
        };

        this.DialogVisible = function () {
            return $('.sweet-alert').is(":visible");
        };

        this.ContextMenu = function (menu, callback) {
            var mnu = [];
            for (var i = 0; i < menu.length; i++) {
                if (menu[i].GroupID) {
                    if (mnu.length == 0 || mnu[mnu.length - 1].id != menu[i].GroupID) {
                        mnu.push({ title: menu[i].GroupName, id: menu[i].GroupID, children: [] });
                    }
                    mnu[mnu.length - 1].children.push({ title: menu[i].Name, cmd: menu[i].ID });
                } else {
                    mnu.push({ title: menu[i].Name, cmd: menu[i].ID });
                }
            }
            $(document).contextmenu({
                menu: mnu,
                select: function (ev, ui) {
                    if (callback)
                        callback(ui.cmd);
                }
            });
        };
		
		this.Blur = function(){
			if ("activeElement" in document)
				document.activeElement.blur();
        };

        this.Standalone = function(){
            
            var standalone = false;
            if('standalone' in window.navigator){
                standalone = window.navigator.standalone;
            }else if('matchMedia' in window){
                standalone = window.matchMedia('(display-mode: standalone)').matches;
            }
            return standalone;
        }

        this.MapMDIcon = function(oldvalue) {
            if(oldvalue.indexOf('mdi-') == 0)
                return oldvalue;
            if(oldvalue == 'arrow_left_grey')
                return 'mdi-keyboard-backspace';
            if(oldvalue == 'navigate_left')
                return 'mdi-keyboard-backspace';
            if(oldvalue == 'arrow_right_grey')
                return 'mdi-keyboard-backspace mdi-rotate-180';
            if(oldvalue == 'navigate_right')
                return 'mdi-keyboard-backspace mdi-rotate-180';
            if(oldvalue == 'completesetup')
                return 'mdi-playlist-check';
            if(oldvalue == 'createsetup')
                return 'mdi-format-list-checks';
            if(oldvalue == 'currentsetup')
                return 'mdi-playlist-play';
            if(oldvalue == 'mailbox_empty')
                return 'mdi-playlist-play';
            if(oldvalue == 'document_new')
                return 'mdi-plus-circle';
            if(oldvalue == 'dosetup')
                return 'mdi-checkbox-marked-outline';
            if(oldvalue == 'instrument')
                return 'mdi-needle';
            if(oldvalue == 'location')
                return 'mdi-map-marker';
            if(oldvalue == 'package_add')
                return 'mdi-archive';
            if(oldvalue == 'preference_cards')
                return 'mdi-tooltip-text';
            if(oldvalue == 'redo')
                return 'mdi-undo';
            if(oldvalue == 'table_selection_column')
                return 'mdi-format-list-bulleted';
            if(oldvalue == 'today')
                return 'mdi-calendar-today';
            if(oldvalue == 'account management')
                return 'mdi-square-inc-cash';
            if(oldvalue == 'box_next')
                return 'mdi-minus-circle';
            if(oldvalue == 'delete')
                return 'mdi-minus-circle';
            if(oldvalue == 'bug_green')
                return 'mdi-bug';
            if(oldvalue == 'calculate')
                return 'mdi-calculator';
            if(oldvalue == 'calendar')
                return 'mdi-calendar';
            if(oldvalue == 'completesetup')
                return 'mdi-playlist-check';
            if(oldvalue == 'contact')
                return 'mdi-account';
            if(oldvalue == 'contacts')
                return 'mdi-account-multiple';
            if(oldvalue == 'copy')
                return 'mdi-content-copy';
            if(oldvalue == 'creditcards')
                return 'mdi-credit-card-multiple';
            if(oldvalue == 'data import')
                return 'mdi-import';
            if(oldvalue == 'document_ok')
                return 'mdi-import';
            if(oldvalue == 'document_out')
                return 'mdi-export';
            if(oldvalue == 'disk_blue')
                return 'mdi-download';
            if(oldvalue == 'disk_blue_ok')
                return 'mdi-download';
            if(oldvalue == 'doctor')
                return 'mdi-stethoscope';
            if(oldvalue == 'document')
                return 'mdi-file-document';
            if(oldvalue == 'document_certificate')
                return 'mdi-file-document';
            if(oldvalue == 'document_text')
                return 'mdi-file';
            if(oldvalue == 'elements2')
                return 'mdi-view-sequential';
            if(oldvalue == 'go_offline')
                return 'mdi-sync';
            if(oldvalue == 'history')
                return 'mdi-history';
            if(oldvalue == 'home')
                return 'mdi-home-circle';
            if(oldvalue == 'icon-queueitem')
                return 'mdi-vanish';
            if(oldvalue == 'id_cards')
                return 'mdi-account-card-details';
            if(oldvalue == 'import_preference_cards')
                return 'mdi-account-switch';
            if(oldvalue == 'instrumentnotready')
                return 'mdi-pencil-off';
            if(oldvalue == 'key1')
                return 'mdi-key';
            if(oldvalue == 'key3')
                return 'mdi-key-variant';
            if(oldvalue == 'keyboard_key')
                return 'mdi-settings';
            if(oldvalue == 'laptop')
                return 'mdi-laptop';
            if(oldvalue == 'link')
                return 'mdi-link-variant';
            if(oldvalue == 'lock')
                return 'mdi-lock';
            if(oldvalue == 'lock_information')
                return 'mdi-folder-lock';
            if(oldvalue == 'match')
                return 'mdi-share-variant';
            if(oldvalue == 'nav_down_blue')
                return 'mdi-arrow-down-drop-circle-outline';
            if(oldvalue == 'nav_up_blue')
                return 'mdi-arrow-up-drop-circle-outline';
            if(oldvalue == 'nav_left_blue')
                return 'mdi-arrow-left-drop-circle-outline';
            if(oldvalue == 'nav_right_blue')
                return 'mdi-arrow-right-drop-circle-outline';
            if(oldvalue == 'operating theatre')
                return 'mdi-seat-flat';
            if(oldvalue == 'package_ok')
                return 'mdi-archive';
            if(oldvalue == 'pda2')
                return 'mdi-cellphone-android';
            if(oldvalue == 'photo')
                return 'mdi-camera';
            if(oldvalue == 'preferences')
                return 'mdi-information-outline';
            if(oldvalue == 'printer')
                return 'mdi-printer';
            if(oldvalue == 'remove_filter')
                return 'mdi-filter-remove-outline';
            if(oldvalue == 'replace2')
                return 'mdi-swap-horizontal';
            if(oldvalue == 'row_add')
                return 'mdi-table-row-plus-after';
            if(oldvalue == 'row_add_after')
                return 'mdi-table-row-plus-after';
            if(oldvalue == 'solution')
                return 'mdi-puzzle';
            if(oldvalue == 'start')
                return 'mdi-arrow-right-bold-box';
            if(oldvalue == 'table_sql_run')
                return 'mdi-arrow-right-bold-box';
            if(oldvalue == 'surgery')
                return 'mdi-pulse';
            if(oldvalue == 'table')
                return 'mdi-table-large';
            if(oldvalue == 'table_sql')
                return 'mdi-table-large';
            if(oldvalue == 'table_selection_row')
                return 'mdi-sunglasses';
            if(oldvalue == 'table_sql_view')
                return 'mdi-sunglasses';
            if(oldvalue == 'table_sql_select')
                return 'mdi-auto-fix';
            if(oldvalue == 'tables')
                return 'mdi-share-variant';
            if(oldvalue == 'text_code_javascript')
                return 'mdi-language-javascript';
            if(oldvalue == 'window_application_add')
                return 'mdi-home-circle';
            if(oldvalue == 'window_colours')
                return 'mdi-lead-pencil';
            if(oldvalue == 'window_application_add')
                return 'mdi-home-circle';
            if(oldvalue == 'window_edit')
                return 'mdi-codepen';
            if(oldvalue == 'window_sidebar')
                return 'mdi-book-open';
            if(oldvalue == 'window_split_ver')
                return 'mdi-folder';
            if(oldvalue == 'windows')
                return 'mdi-asterisk';
            return 'mdi-checkbox-blank-circle';
        };

        this.MapIcon = function(oldvalue) {
            
            if(oldvalue.indexOf('mdi-') == 0)
                return oldvalue;
            if(oldvalue == 'document_certificate')
                return 'mdi-certificate';
            if(oldvalue == 'home')
                return 'mdi-home';
            if(oldvalue == 'window_side_bar')
                return 'mdi-application';
            if(oldvalue == 'disk_blue')
                return 'mdi-content-save';
            if(oldvalue == 'disk_blue_ok')
                return 'mdi-content-save-all';
            if(oldvalue == 'text_code_javascript')
                return 'mdi-language-javascript';
            if(oldvalue == 'keyboard_key')
                return 'mdi-settings';
            if(oldvalue == 'window_split_ver')
                return 'mdi-folder-multiple';
            if(oldvalue == 'table_sql_run')
                return 'mdi-play';
            if(oldvalue == 'history')
                return 'mdi-history';
            if(oldvalue == 'table_sql_select')
                return 'mdi-source-pull';
            if(oldvalue == 'document_new')
                return 'mdi-plus-circle';
            if(oldvalue == 'delete')
                return 'mdi-minus-circle';
            if(oldvalue == 'table_sql_view')
                return 'mdi-message-settings-variant';
            if(oldvalue == 'nav_down_blue')
                return 'mdi-arrow-down-drop-circle-outline';
            if(oldvalue == 'nav_up_blue')
                return 'mdi-arrow-up-drop-circle-outline';
            if(oldvalue == 'nav_left_blue')
                return 'mdi-arrow-left-drop-circle-outline';
            if(oldvalue == 'nav_right_blue')
                return 'mdi-arrow-right-drop-circle-outline';
            if(oldvalue == 'window_colors')
                return 'mdi-tooltip-edit';
            if(oldvalue == 'user1')
                return 'mdi-account-multiple';
            if(oldvalue == 'box_software')
                return 'mdi-puzzle';
            if(oldvalue == 'id_cards')
                return 'mdi-account-card-details';
            if(oldvalue == 'user1_lock')
                return 'mdi-key';
            if(oldvalue == 'user1_lock')
                return 'mdi-key';
            if (oldvalue == 'users3_preferences')
                return 'mdi-account-multiple';
            if (oldvalue == 'users1')
                return 'mdi-account-settings-variant';
            if (oldvalue == 'houses')
                return 'mdi-web';
            if (oldvalue == 'server_warning')
                return 'mdi-cloud-download';
            if (oldvalue == 'user1_information')
                return 'mdi-account-alert';
            if (oldvalue == 'window_gear')
                return 'mdi-format-list-checks';
            if (oldvalue == 'row')
                return 'mdi-format-list-bulleted';
            if (oldvalue == 'document')
                return 'mdi-file-document';
            if (oldvalue == 'data_find')
                return 'mdi-search-web';
            if (oldvalue == 'chart')
                return 'mdi-file-chart';
            if (oldvalue == 'mailbox_full')
                return 'mdi-email';
            if (oldvalue == 'document_out')
                return 'mdi-export';
            if (oldvalue == 'window_information')
                return 'mdi-format-list-bulleted-type';
            if (oldvalue == 'component_add')
                return 'mdi-power-plug';
            if (oldvalue == 'mailbox_empty')
                return 'mdi-email-open';
            if (oldvalue == 'media_play')
                return 'mdi-play-circle';
            if (oldvalue == 'media_stop')
                return 'mdi-stop-circle';
            if (oldvalue == 'window_edit')
                return 'mdi-codepen';
            if (oldvalue == 'help2')
                return 'mdi-bus-side';
            if (oldvalue == 'document_ok')
                return 'mdi-import';
            if (oldvalue == 'document_text')
                return 'mdi-file';
            if (oldvalue == 'box_next')
                return 'mdi-minus-circle';
            if (oldvalue == 'tables')
                return 'mdi-share-variant';
            if (oldvalue == 'table_sql_check')
                return 'mdi-sync';
            if (oldvalue == 'table')
                return 'mdi-table-large';
            if (oldvalue == 'window_sidebar')
                return 'mdi-book-open';
            if (oldvalue == 'windows')
                return 'mdi-asterisk';
            if (oldvalue == 'lock_add')
                return 'mdi-account-key';
            if (oldvalue == 'lock_view')
                return 'mdi-security';
            if (oldvalue == 'table_selection_column')
                return 'mdi-menu';
            if (oldvalue == 'undo')
                return 'mdi-undo-variant';
            if (oldvalue == 'table_selection_row')
                return 'mdi-message-settings-variant';
            if (oldvalue == 'close')
                return 'mdi-eraser';
            if (oldvalue == 'key1')
                return 'mdi-account-key';
            if (oldvalue == 'key3')
                return 'mdi-key-variant';
            if (oldvalue == 'lock')
                return 'mdi-lock';
            if (oldvalue == 'link')
                return 'mdi-link-variant';
            if (oldvalue == 'lock_information')
                return 'mdi-lock-outline';
            if (oldvalue == 'businessman2')
                return 'mdi-account-settings-variant';
            if (oldvalue == 'check2')
                return 'mdi-cloud-sync';
            if (oldvalue == 'box_delete')
                return 'mdi-play-pause';
            if (oldvalue == 'arrow_down_green')
                return 'mdi-content-copy';
            if (oldvalue == 'arrow_down_blue')
                return 'mdi-content-duplicate';
            if(oldvalue == 'lock_ok')
                return 'mdi-lock';
            return oldvalue;
        }

        //#endregion

    });
/// <reference path="../Application.js" />

DefineModule("UpdateManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        depends: ['Logging'],
        created: new Date(2013, 12, 11),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '11/12/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.UpdateManager = this;
        };

        this.CheckForUpdates = function (skipVersion_) {

            Application.LogInfo("Checking for application updates.");

            var w = $wait();

            $code(

                function () {
                    if(!skipVersion_)
                        return Application.CheckUpdates();
                    return Application.CheckUpdatesSkipVersion();
                },

                function (ret) {

                    //No updates available!
                    if (ret == "") {
                        Application.LogInfo("There are no new updates.");
                        return "There are no new updates.";
                    }

                    Application.LogInfo(ret);

                    //Ask the user if they wish to update.
                    Application.Confirm(ret, function (r) {
                        if (r) {
                            Application.Loading.Show("tdMain");
                            //Get the updates.
                            Application.RunNext(_self.GetUpdates);
                        }
                    }, (skipVersion_ ? "Update Platform" : "New Framework Version"));

                }
            );

            return w.promise();
        };

        this.GetUpdates = function () {

            var w = $wait();

            $code(

                Application.GetUpdates,

                function (ret) {

                    Application.Loading.Hide("divLogin");
                    //if (!Application.IsInMobile())
                    //    Application.Loading.Hide("tdMain");

                    Application.App.Disconnect();

                    //Return any messages.
                    if (ret && ret != "")
                        Application.Message(ret);
                }

            );

            return w.promise();
        };

        //#endregion

    });
DefineModule("WebsiteManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.'
        ]
    },

    function (setup_) {

        //#region Members

        var _self = this;     
		var m_setup = setup_;		
		var m_pages = new Collection();
		var m_params = {};
		var m_devMode = false;
		var m_devToggle = false;
		var m_record = null;
		var m_page = null;		

        //#endregion

		this.Constructor = function (setup_) {
            m_setup = setup_;
        };
		
        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Website = this;    

		    Application.OnError = function(err){
				_self.HideLoad();
				if(err && err.message)
					err = err.message;
				swal({
					title: "Oops",
					text: err,
					type: "error",
					width: ($(window).width() < 438 ? $(window).width() - 60 : null)
				});
			};

			window.onpopstate = function(event) {				
				_self.Process();
			};
			
			$(window).unload(function () {
				try {

					if (Application.auth.SessionID != "") {
						Application.Disconnect();
					}

				} catch (e) {
				}
				return;
			});
			
			$code(
				function(){
					return ExecuteQuery(m_setup.query);
				},
				function(recs){
											
					if(recs[0].length == 0)
						Application.Error("Domain not found");	
					
					var domain = recs[0][0];
					
					eval("var func = function(){" + domain.OnLoad + "};");
					eval("var func2 = function(){" + domain.OnError + "};");
					
					m_setup.onload = func;
					m_setup.onerror = func2;
					m_setup.homepage = domain["Home Page"];					
					m_setup.webpagequery = domain["Web Page Query"];
					m_setup.domain = domain.Code;
					if(m_setup.onload)
						m_setup.onload();
					_self.Process();		
					
				}
			);
        };        
		
		this.AddPage = function(page){
			m_pages.Add(page.code,page);
		};
		
		this.SelectVersion = function(version_){
			LoadVersion(version_);
		};
		
		this.Process = function(){
						
			var params = {};
			Application.LoadParams(params);					
			
			if(!m_devMode && params && params.admin == "true"){
				m_devMode = true;	
				m_devToggle = true;
				SetupDeveloperTools(params);															
				$("body").append('<button type="button" class="btn btn-default btn-sm" style="position: fixed; left: 0px; bottom: 15px; z-index: 999999; opacity: 0.6;" onclick="Website.ToggleDev();">Dev</button>');
			}
			
			if(!params || !params.page){
				Website.LoadPage(m_setup.homepage,params,true);	
			}else{
				Website.LoadPage(params.page,params,true);									
			}		
		};
		
		this.Error = function(body){			
			if(m_setup.onerror)
				m_setup.onerror();
			_self.HideLoad();
			_self.Main().html('<br/><br/><br/><div class="alert alert-danger"><strong>Website Error!</strong> '+body+'</div>');
			throw "";
		};
		
		this.ProcessLinks = function(){
			
			var links = $("a");
			if(links.length > 0){							
				for(var j = 0; j < links.length; j++){
					var link = $(links[j]);
					if(link.attr("app-page") && link.attr("app-page") != ""){	
						link.css("cursor","pointer");
						link.unbind("click");
						link.on("click",function(){
							var p = $(this).attr("app-params");
							if(p){
								try{
									p = $.parseJSON(p);
								}catch(e){
									var p_arr = p.split(",");
									p = {};
									for(var i = 0; i < p_arr.length; i++){
										var param = p_arr[i].split("=");
										p[param[0]] = param[1];
									}
								}								
							}
							Website.LoadPage($(this).attr("app-page"),p);
						});
					}
				}
			}	
			
		};
		
		this.LoadPage = function(code,params,skiphistory){							
			
			$("body").scrollTop(0);
			if(m_devMode && m_record && m_record.Code != code){
					Application.RunNext(function(){
						FINDSET("Web Page",{Code:(code), Domain: m_setup.domain},function(wp){									
							m_record = wp;
							LoadVersion();
						});
					});
					var pstring = "";
					if(params)
						for(var p in params){
							if(p != "page"){						
								pstring += "&"+p+"="+params[p];											
							}
						}
						
					if(!skiphistory && window.history && window.history.pushState)
							window.history.pushState({page:code,params:params},m_page.title, (code == m_setup.homepage ? "/" : "/?page="+code+pstring));	
					return;
			}
				
				
			_self.ShowLoad();
			
			Application.RunNext(function(){							
				
				return $codeblock(
				
					function(){						
						return ExecuteQuery(m_setup.webpagequery,[code]);						
					},
					
					function(recs){																	
						
						if(recs[0].length == 0)
							Application.Error("The page you are looking for was not found");	
						
						var p = recs[0][0];
												
						if(m_devMode && m_record){
							p = m_record;
						}
						
						eval("var func = function(template,results){" + Default(p.OnFillTemplate,"return template;") + "};");
						eval("var func2 = function(){" + p.OnLoad + "};");
						eval("var func3 = function(){" + p.OnSetupQuery + "};");								

						m_params = params;											
						
						m_page = {
							code: p.Code,							
							title: p.Title,
							query: p.Query,
							filltemplate: func,
							onload: func2,
							setupquery: func3,
							template: p.TemplateHTML
						};

						var pstring = "";
						if(params)
							for(var p in params){
								if(p != "page"){						
									pstring += "&"+p+"="+params[p];											
								}
							}

						if(!skiphistory && window.history && window.history.pushState)
								window.history.pushState({page:code,params:params},m_page.title, (code == m_setup.homepage ? "/" : "/?page="+code+pstring));	

						document.title = m_page.title;											
						
						if(!m_page.query){
							
							var html = m_page.filltemplate(m_page.template);
							_self.Main().html(html);											
							_self.ProcessLinks();
							m_page.onload();
							return;
						}
						
						var params_arr = [];
						if(m_page.setupquery)
							params_arr = m_page.setupquery();													
						
						return ExecuteQuery(m_page.query,params_arr);
						
					},
					
					function(recs){																						
						
						recs = Default(recs,[]);
						
						var html = m_page.filltemplate(m_page.template,recs);
						_self.Main().html(html);											
						
						for(var i = 0; i < recs.length; i++){
							
							var recset = recs[i];
							
							var parent = $("[app-source='"+i+"']");
							if(parent.length > 0){
								
								for(var j = 0; j < parent.length; j++){
									
									var currparent = $(parent[j]);
									var repeat = null;
									
									if(currparent.attr("app-repeat")=="true"){
										repeat = parent[j].outerHTML;
									}
									
									if(recset.length == 0)
										currparent.remove();
									
									for(var k = 0; k < recset.length; k++){
										
										var rec = recset[k];
										
										for(var f in rec){
											var element = currparent.find("[app-field='"+f+"']");
											if(element.length > 0)
												element.html(rec[f]);
											currparent.html(currparent.html().replaceall("%"+i+"-"+f+"%",rec[f]));
										}
										
										if(repeat && k < recset.length - 1){
											var newparent = $(repeat);
											currparent.after(newparent);
											currparent = newparent;
										}
										
										if(!repeat)
											break;
										
									}
									
								}
							}
																				
						}																	
						
						_self.ProcessLinks();
						
						var jscode = $(".javascriptCode");
						jscode.each(function(index){
							var ce = jscode[index];
							var text = $(this).html();
							text = text.replace(/\<br\>/g,"\n");
							text = text.replace(/\&nbsp\;/g," ");			   
							var editor = CodeMirror(function(node){ce.parentNode.replaceChild(node, ce);}, {
								mode: "javascript",
								value: text,
								lineNumbers: true,
								lineWrapping: true,
								readOnly: true
							});
						});
						
						m_page.onload();		
						_self.HideLoad();						
					}
				);
			});
		};
			
		this.OnSearch = function(query, search, onclick, rowdef){	
		
		$("body").scrollTop(search.offset().top-60);
		
		 if(search.val() == "")
			 return;
		  Application.RunNext(function () {		
			return $codeblock(
			  function () {																	
				return ExecuteQuery(query,[search.val()]);
			  },
			  function (ret) {										
				$(".searchdropdown").remove();			
				ret = ret[0];
				if(ret.length !== 0){											
				  var dd = $("<div style='position:absolute; background-color: white; max-width: 400px; max-height: 400px; overflow-y: auto; z-index: 1001;' class='searchdropdown'>");
				  dd.css("width",400);
				  $("body").append(dd);
				  dd.css("top",search.offset().top+45).css("left",search.offset().left);
				  for(var i = 0; i < ret.length; i++){
					var item = $("<div rid='"+i+"' style='font-size: 14pt; padding: 5px; cursor: pointer;'>"+rowdef(ret[i])+"</div>");
					dd.append(item);
					item.on("click",function(){
						var i = $(this).attr("rid");
						onclick(ret[i]);
						$(".searchdropdown").remove();
					});
				  }											
				}														
			  }
			);
		  });
		};

		this.Main = function(){
			return $(m_setup.main);
		};
		
		this.DevBar = function(){
			return $(m_setup.devbar);
		};
		
		this.Params = function(){
			return m_params;
		};
		
		this.EditHTML = function(){
			EditMode();
		};
		
		this.ToggleDev = function(){
			if(m_devToggle){
				_self.DevBar().hide();
			}else{
				_self.DevBar().show();
			}
			m_devToggle = !m_devToggle;
		};
		
		this.DevMode = function(){
			return m_devMode;
		}
		
		this.ShowLoad = function(){
			if($("#divOverlay").length == 0){
				var o = $('<div id="divOverlay" style="position: fixed; top: 0px; left: 0px; opacity: .8; z-index: 30000;color: #EB8C79; background-color: #18506F;">'+
				'<div class="banner-container"> <div class="loading-banner"> LOADING <div class="loading-banner-left"></div> <div class="loading-banner-right"></div> </div> </div>'+
				'</div>');
				$("body").append(o);
				o.width('100%').height('100%');
			}
		};
		
		this.HideLoad = function(){
			$("#divOverlay").remove();
		};
		
		this.Publish = function(){
			Application.RunNext(function(){
				FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain, Published: true},function(wp){
					MODIFY(wp,"Published",false,function(){
						MODIFY(m_record,"Published",true,function(){
							FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain},function(wp){
								m_record = wp;
								LoadVersion();			
							});
						});	
					});
				});
			},null,null,true);
		};
		
		this.NewVersion = function(){
			Application.RunNext(function(){
				FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain},function(wp){
					if(wp.Count > 0){
						wp.Last();
						INSERT("Web Page",{
							Domain: m_record.Domain,
							Code: m_record.Code,
							Title: m_record.Title,
							Query: m_record.Query,
							OnFillTemplate: m_record.OnFillTemplate,
							OnLoad: m_record.OnLoad,
							OnSetupQuery: m_record.OnSetupQuery,
							TemplateHTML: m_record.TemplateHTML,
							Version: wp.Version+1
						},function(wp2){
							FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain},function(wp){
								
								m_record = wp;
								LoadVersion(wp2.Version);																	
								
							});
						});
					}
				});
			},null,null,true);
		};
		
		this.DeleteVersion = function(){
			if(m_record.Published)
				Application.Error("You cannot delete the published version");
			Application.RunNext(function(){
				DELETE(m_record,function(){
					FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain},function(wp){
						m_record = wp;
						LoadVersion();			
					});
				});
			},null,null,true);
		};
		
		this.EditVersion = function(){
			
			var divEdit = $('<div id="divEditVersion" style="position: fixed; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 40000; overflow-y: auto; background-color: white; padding: 15px;">'+
			'<p>OnFillTemplate - function(template,results)</p><textarea id="txtOnFillTemplate">'+Default(m_record.OnFillTemplate,"")+'</textarea>'+
			'<p>OnLoad - function()</p><textarea id="txtOnLoad">'+Default(m_record.OnLoad,"")+'</textarea>'+
			'<p>OnSetupQuery - function()</p><textarea id="txtOnSetupQuery">'+Default(m_record.OnSetupQuery,"")+'</textarea>'+
			'<br/><br/><button id="btnCloseEdit" type="button" class="btn btn-default" data-dismiss="modal">Close</button></div>');
			
			$("body").append(divEdit);
			
			AddCodeEditor($("#txtOnFillTemplate")[0]);
			AddCodeEditor($("#txtOnLoad")[0]);
			AddCodeEditor($("#txtOnSetupQuery")[0]);
			
			$("#divDevTools").hide();
			
			$("#btnCloseEdit").unbind("click");
			$("#btnCloseEdit").on("click",function(){	
				Application.RunNext(function(){
						
						var onFillTemplate = $("#txtOnFillTemplate").val();
						if(onFillTemplate == "")
							onFillTemplate = null;
						var onLoad = $("#txtOnLoad").val();
						if(onLoad == "")
							onLoad = null;
						var onSetupQuery = $("#txtOnSetupQuery").val();
						if(onSetupQuery == "")
							onSetupQuery = null;
						
						divEdit.remove();
						$("#divDevTools").show();
						
						if(m_record.OnFillTemplate != onFillTemplate || m_record.OnLoad != onLoad || m_record.OnSetupQuery != onSetupQuery){
							
							if(!confirm("Save your changes?"))
								return;
							
							m_record.OnFillTemplate = onFillTemplate;
							m_record.OnSetupQuery = onSetupQuery;
							m_record.OnLoad = onLoad;
							
							MODIFY(m_record,null,null,function(){																
								_self.Process();
							});							
						}
				},null,null,true);				
			});
			
		};
		
		this.HTMLEditor = function(html, onsave){
			
			_self.Main().hide();
			
			//Add editor window.
			_self.Main().after('<div id="divEditor"></div>');								
		
			var edit = $("#divEditor");
			edit.html(html);
			edit.css({
				'max-height': 'calc(100vh - 50px)',
				overflow: 'auto'
			});	
			edit.trumbowyg({
				fullscreenable: true,
				closable: true,
				btns: ['viewHTML',
				  '|', 'formatting',
				  '|', 'btnGrp-design',
				  '|', 'link',
				  '|', 'insertImage',					  
				  '|', 'btnGrp-justify',
				  '|', 'btnGrp-lists',
				  '|', 'horizontalRule']
			});
			
			var cssClass = 'trumbowyg-fullscreen';
			edit.parent().toggleClass(cssClass);
			$('body').addClass('trumbowyg-body-fullscreen');																			
			$(edit.parent().children()[0]).css('width', '100%');									
			$(window).trigger('scroll');			
			$(".trumbowyg-fullscreen-button").hide();
			$(".trumbowyg-textarea").css('max-height','calc(100vh - 50px)');		

			edit.unbind("tbwclose");
			edit.on("tbwclose",function(){	
				Application.RunNext(function(){
						if(html != edit.html()){
							if(onsave)
								return onsave(edit.html());
						}
				},null,null,true);
				_self.Main().show();
				$("#divEditor").remove();
			});

			edit.show();
			
		};
		
		function ExecuteQuery(code, params_arr){
			
			params_arr = Default(params_arr,[]);
			
			return $codeblock(
				function(){
					
					var params = Application.StrSubstitute('"param1_": "$1", "param2_": "$2", "param3_": "$3", "param4_": "$4", "param5_": "$5"',
						Default(params_arr[0],""),
						Default(params_arr[1],""),
						Default(params_arr[2],""),
						Default(params_arr[3],""),
						Default(params_arr[4],"")
						);					
					
					var w = $wait();
					
					Application.ExecuteEndpoint(Application.StrSubstitute(Application.url+'/q/?e=Server&m=ExecuteQueryJSONP&p={"instance_": "'+m_setup.instance+'", "code_": "$1", '+params+'}',code),function(results){
						w.resolve(FormatRecordset(results));
					},null,'jsonp');
					
					return w.promise();
				}				
			);
			
		};

		function FormatRecordset(results){
			
			var ret = [];
			for(var i = 0; i < results.length; i++){
				
				var ret2 = [];
				for(var j = 0; j < results[i].length; j++){
					
					var rec = {
						Table: results[i][j].Table,
						RecID: results[i][j].RecID
					};
					for(var k = 0; k < results[i][j].Fields.length; k++){
						rec[results[i][j].Fields[k].Name] = results[i][j].Fields[k].Value;
					}
					ret2.push(rec);
				}
				ret.push(ret2);
				
			}
			return ret;
			
		};
		
		function SetupDeveloperTools(params){
			
			//Create containers.
			var cont = $('<div style="padding: 10px;" />');
			_self.DevBar().append(cont);			
			var divLogin = $('<form id="divLogin" class="form-inline" />');
			cont.append(divLogin);
			var divDevTools = $('<div id="divDevTools" class="input-group" style="display: none;" />');
			cont.append(divDevTools);
			
			//Add login fields.			
			divLogin.append('<input id="txtUser" type="text" class="form-control input-sm" placeholder="Username">');
			divLogin.append('<input id="txtPass" type="password" class="form-control input-sm" placholder="Password">');
			divLogin.append('<button id="btnLogin" type="button" class="btn btn-default btn-sm">Login</button>');
			
			//Add dev bar buttons.			
			divDevTools.append('<span class="input-group-btn"><div class="dropdown"><button id="btnVersion" class="btn btn-primary dropdown-toggle btn-sm" type="button" data-toggle="dropdown"><span id="lblVersion">Versions</span>&nbsp;<span class="caret"></span></button><ul id="cmbVersions" class="dropdown-menu"></div></span>');
			divDevTools.append('<span class="input-group-btn"><div class="dropdown"><button class="btn btn-primary dropdown-toggle btn-sm" type="button" data-toggle="dropdown">Tools<span class="caret"></span></button><ul class="dropdown-menu">'+
			'<li><a onclick="Website.EditHTML();">Edit HTML</a></li>'+
			'<li><a onclick="Website.EditVersion();">Edit Page</a></li>'+
			'<li><a onclick="Website.Publish();">Publish</a></li>'+
			'<li><a onclick="Website.NewVersion();">New Version</a></li>'+
			'<li><a onclick="Website.DeleteVersion();" style="color: #e74c3c;">Delete Version</a></li>'+
			'</ul></div></span>');			
			divDevTools.append('<input id="txtTitle" type="text" class="form-control input-sm" placeholder="Page Title">');				
				
			$("#txtTitle").on("change",function(){
				Application.RunNext(function(){
						var val = $("#txtTitle").val();
						if(m_record.Title != val){							
							MODIFY(m_record,"Title",val,function(){
								m_record.Title = val;
								m_record.SaveCurrent();
								_self.Process();
							});							
						}
				},null,null,true);				
			});		
			
			$("#btnLogin").on("click",function(){
					_self.ShowLoad();
					Application.RunNext(function(){
						return $codeblock(
							function(){
								Application.auth = new Application.Objects.AuthInfo();
								Application.auth.Instance = m_setup.instance;
								Application.auth.Type = Application.authType.Login;
								Application.auth.Username = $("#txtUser").val();
								Application.auth.Password = $("#txtPass").val();
								return Application.Authorize();									
							},
							function(a){
								
								Application.auth = a;
								
								$("#divLogin").hide();
								$("#divDevTools").show();																		
								
								FINDSET("Web Page",{Code:(m_page.code ? m_page.code : m_setup.homepage), Domain: m_setup.domain},function(wp){
									
									m_record = wp;
									LoadVersion();
									_self.HideLoad();
									
								});
							}
						);

					});
			});
		};
		
		function EditMode(){
			
			_self.Main().hide();
			
			//Add editor window.
			_self.Main().after('<div id="divEditor"></div>');								
		
			var edit = $("#divEditor");
			edit.html(m_record.TemplateHTML);
			edit.trumbowyg({
				fullscreenable: true,
				closable: true,
				btns: ['viewHTML',
				  '|', 'formatting',
				  '|', 'btnGrp-design',
				  '|', 'link',
				  '|', 'insertImage',					  
				  '|', 'btnGrp-justify',
				  '|', 'btnGrp-lists',
				  '|', 'horizontalRule']
			});
			
			var cssClass = 'trumbowyg-fullscreen';
			edit.parent().toggleClass(cssClass);
			$('body').addClass('trumbowyg-body-fullscreen');									
			edit.css({
				'max-height': 'calc(100vh - 50px)',
				overflow: 'auto'
			});									
			$(edit.parent().children()[0]).css('width', '100%');									
			$(window).trigger('scroll');			
			$(".trumbowyg-fullscreen-button").hide();
			$(".trumbowyg-textarea").css('max-height','calc(100vh - 50px)');		

			edit.unbind("tbwclose");
			edit.on("tbwclose",function(){	
				Application.RunNext(function(){
						if(m_record.TemplateHTML != edit.html()){
							if(!confirm("Save your changes?"))
								return;
							MODIFY(m_record,"TemplateHTML",edit.html(),function(){
								m_record.TemplateHTML = edit.html();
								m_record.SaveCurrent();
								_self.Process();
							});							
						}
				},null,null,true);
				_self.Main().show();
				$("#divEditor").remove();
			});

			edit.show();
			
		};
		
		function LoadVersion(version_){
			
			$("#cmbVersions").empty();
									
			if(m_record.Count > 0){
				m_record.First();
				do{
					$("#cmbVersions").append('<li><a onclick="Website.SelectVersion('+m_record.Version+');">Version '+m_record.Version+(m_record.Published ? " (Published)" : "")+'</a></li>');						
				}while(m_record.Next());	
			}
			
			if(version_){
				SelectVersionByNumber(version_);
			}else{
				SelectVersionByPublished();
			}
							
			$("#lblVersion").html("Version: "+m_record.Version+(m_record.Published ? " (Published)" : ""));
			$("#txtTitle").val(m_record.Title);			
			
			if(m_record.Published){
				$("#btnVersion").removeClass("label-info");
				$("#btnVersion").addClass("label-success");
			}else{
				$("#btnVersion").addClass("label-info");
				$("#btnVersion").removeClass("label-success");
			}
			
			_self.Process();
			
		};
		
		function AddCodeEditor(element){
			var editor = CodeMirror.fromTextArea(element, {
                mode: "javascript",
                lineNumbers: true,
                viewportMargin: Infinity,
                lineWrapping: true,
                extraKeys: {
                    "Ctrl-Space": "autocomplete"
                },
                gutters: ["CodeMirror-lint-markers"],
                lint: true
            });
			editor.on("change", function(){
				$(element).val(editor.getValue());
			});
		};
		
		function SelectVersionByPublished(){			
			if(m_record.Count > 0){
				m_record.First();
				do{
						if(m_record.Published)
							return;
				}while(m_record.Next());	
			}
		};
		
		function SelectVersionByNumber(version_){
			if(m_record.Count > 0){
				m_record.First();
				do{
						if(m_record.Version == version_)
							return;
				}while(m_record.Next());	
			}
		};
		
        //#endregion
		
		this.Constructor(setup_);

    });
	
/// <reference path="../Application.js" />

DefineModule("WindowManager",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        depends: ['AppUI', 'IDEngine', 'Logging'],
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '03/09/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_queue = [];
        var m_selectedWindow = null;
        var m_focusWindow = null;
        var m_hasHome = false;
        var m_uiHeight = 0;
        var m_uiWidth = 0;
        var m_uiSideWidth = 0;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign module.
            UI.WindowManager = this;

            UI.Width = _self.Width;
            UI.Height = _self.Height;
            UI.SideWidth = _self.SideWidth;
        };

        this.Add = function (win) {
            m_queue.push(win);
        };

        this.Count = function () {
            return m_queue.length;
        };

        this.SelectedWindow = function (value_) {
			if(typeof value_ == "undefined"){
				return m_selectedWindow;
			}else{
				 m_selectedWindow = value_;
			}
        };

        this.ActiveWindow = function () {
            return m_focusWindow;
        };

        this.Remove = function (id_) {

            for (var i = 0; i < m_queue.length; i++) {
                if (m_queue[i].ID() == id_) {
                    m_queue.splice(i, 1);
                }
            }
        };

        this.GoHome = function () {

            if (!m_hasHome) {

                if (m_queue.length == 0)
                    return;

                _self.CloseAll(false);

                return;
            }

            if (m_queue.length == 1)
                return;

            _self.CloseAll(true);
        };

        this.CloseAll = function (keephome_) {

            Application.RunNext(function () {
                return $loop(function (i) {
                    return $codeblock(

                        function () {

                            var id = m_queue[m_queue.length - 1].ID();
                            //_self.Open(id);
                            return _self.Close(id, true);
                        },

                        function (r) {

                            var id = m_queue[m_queue.length - 1].ID();

                            if (r == true) //cancelled
                                return;

                            if (m_queue.length != 0 && !keephome_)
                                return $next;

                            if (keephome_) {
                                if (m_queue.length != 1) {
                                    return $next;
                                } else {
                                    return _self.Open(m_queue[0].ID());
                                }
                            }
                        }
                    );
                });
            });
        };

        this.RemoveAll = function () {

            if (Application.IsInMobile())
                $("#divSideMenu,#divFactbox").panel("close");

            $("#btnCloseAll").remove();
            ShowScroll();

            for (var i = 0; i < m_queue.length; i++) {
                var win = m_queue[i];
                win.Remove();
            }
            m_queue = [];
            m_selectedWindow = null;
            m_focusWindow = null;
        };

        this.HideAll = function () {

            if (Application.IsInMobile())
                $("#divSideMenu,#divFactbox").panel("close");

            $("#saveBtn,#saveCloseBtn").show();
            $("#lnkActions, #divMobileFooter, #okBtn, #customBtn1, #customBtn2").hide();
            $("#btnCloseAll").remove();
            ShowScroll();

            if (Application.App.SideVisible() && !Application.restrictedMode)
                Application.App.ToggleSide();

            _self.FocusWindow(0);
            m_selectedWindow = null;

            for (var i = 0; i < m_queue.length; i++) {
                m_queue[i].Hide();
            }

            _self.GetUIDimensions();
        };

        this.GetWindow = function (id_) {

            var win = null;
            for (var i = 0; i < m_queue.length; i++) {
                if (m_queue[i].ID() == id_) {
                    win = m_queue[i];
                    return win;
                }
            }
            return null;
        };

        this.PreLoad = function (id_) {

            var win = _self.GetWindow(id_);
            if (win == null) {
                return;
            }

            if (!win.Dialog())
                _self.HideAll();

            m_selectedWindow = win;
            if (win.LastFocus() == 0)
                win.LastFocus(id_);
            _self.FocusWindow(win.LastFocus());

            win.PreLoad();

        };

        this.Open = function (id_) {

            var win = _self.GetWindow(id_);
            if (win == null) {
                return;
            }

            if (!win.Dialog())
                _self.HideAll();

            win.Show();

            //Close all button.

            var check = 0;
            if (m_hasHome)
                check = 1;

            if (m_queue.length != check && $("#btnCloseAll").length == 0) {

                var winbtn = $("<div id='btnCloseAll' class='main-windowsbtn ui-widget ui-state-default app-closeall-btn'><table><tr><td class='unselectable' style='font-weight: normal; font-size: 14px;'>" + UI.IconImage("mdi-close-circle",null,15) + " Close All</td><td></td></tr></table></div>");
                if (Application.IsInMobile()) {
                    var winbtn = $("<div id='btnCloseAll' class='main-windowsbtn ui-page-theme-a ui-btn app-closeall-btn'><table><tr><td class='unselectable' style='font-weight: normal; font-size: 14px;'>" + UI.IconImage("mdi-close-circle",null,15) + " Close All</td><td></td></tr></table></div>");
                }
                $("#AppWindows").append(winbtn);
                winbtn.on("click", function () {
                    _self.GoHome();
                }).slideDown(300);

                ShowScroll();
            }

            m_selectedWindow = win;
            if (win.LastFocus() == 0)
                win.LastFocus(id_);
            _self.FocusWindow(win.LastFocus());

			if (win.Dialog())
				_self.FocusWindow(id_);
			
            _self.OnOpen(win);

            if (Application.IsInMobile()) {

                //Left Side Button
                $('#lnkMenu').text("Menu");
                $("#lnkMenu").buttonMarkup({ icon: "bars", mini: Application.MiniMode() });
                $("#lnkMenu").unbind("click");
                $("#lnkMenu").click(function () {
                    $("#divSideMenu").panel("toggle");
                });

                //Right Side Button 
                $("#lnkInfo").unbind("click");
                $("#lnkInfo").click(function () {
                    $("#divFactbox").panel("toggle");
                });
				$("#lnkInfo").addClass("app-header-btn");

                $.mobile.resetActivePageHeight();
            }

            return win;
        };

        this.OnResize = function () {

            Application.LogInfo(Application.StrSubstitute("Resizing $1 Windows.", m_queue.length));

            _self.GetUIDimensions();

            if (m_selectedWindow)
                m_selectedWindow.Resize();
        };

        this.BeforeClose = function (id_, okclicked_) {

            //Get the window.
            var win = _self.GetWindow(id_);
            if (win && win.OnBeforeClose) {
                return win.OnBeforeClose(okclicked_);
            }
            return true;
        };

        this.Close = function (id_, skipOpen_, skipFunc_) {

			if($("#powertour-mask").is(":visible"))
				return;
				
            //Get the window.
            var win = _self.GetWindow(id_);

			//Focus the window.
			if(win){
				m_selectedWindow = win;
				if (win.LastFocus() == 0)
					win.LastFocus(id_);
				_self.FocusWindow(win.LastFocus());
			}
			
            var w = $wait();

            $code(

                function () {

					if(skipFunc_)
						return;
				
                    if (win && win.Dialog() && win.OnSave)
                        return win.OnSave(true, true);

                    //Run on close?
                    if (win && win.OnClose) {
                        return win.OnClose();
                    }
                },

                function () {

                    if (win && win.CancelClose()) {
                        win.CancelClose(false);
                        return true;
                    }

					var parentwin = null;
					if (win && win.GetParentWindow())
						parentwin = win.GetParentWindow().ID();
					
                    //Remove the window.
                    if (win)
                        win.Remove();

                    _self.FocusWindow(0);
                    m_selectedWindow = null;
                    _self.Remove(id_);

					if(m_queue.length == 0)
						$("#btnCloseAll").remove();
					
                    //Try to open the next window.
                    if (!skipOpen_) {
                        if (m_queue.length > 0) {
                            if (parentwin) {
                                return _self.Open(parentwin);
                            } else {
                                return _self.Open(m_queue[m_queue.length - 1].ID());
                            }
                        }
                    }
                }
            );

            return w.promise();
        };

        this.FocusWindow = function (id_) {

            if (m_selectedWindow != null) {

                if (m_focusWindow != null)
                    m_focusWindow.Focus(false);

                if (m_selectedWindow.ID() == id_) {
                    m_focusWindow = m_selectedWindow;
                } else {
                    m_focusWindow = m_selectedWindow.GetSubWindow(id_);
                }

                if (m_focusWindow != null) {
                    m_selectedWindow.LastFocus(m_focusWindow.ID());
                    m_focusWindow.Focus(true);
                }
            }
        };

        this.UpdateWindow = function (id_) {

            var win = _self.GetWindow(id_);
            if (!win && m_selectedWindow != null)
                win = m_selectedWindow.GetSubWindow(id_);

            if (win && win.Update)
                Application.RunNext(function () {
                    return win.Update(true, true, true);
                });
        };

        this.PinWindow = function (id_) {            
        };

        this.Error = function (err) {
            if (m_focusWindow != null) {
                if (typeof m_focusWindow.OnError != 'undefined') {
                    m_focusWindow.OnError(err);
                    return true;
                }
            }
            return false;
        };

        this.OpenClick = function (id_) {

            Application.RunNext(function () {
                return _self.Open(id_);
            },null,null,null,true);

        };

        this.CloseClick = function (id_) {

            //Get the window.
            var win = _self.GetWindow(id_);

            //Run before close?
            if (win && win.Save) {
                win.Save();
            }

            Application.RunNext(function () {
                return _self.Close(id_);
            },null,null,null,true);

        };

        this.PreviousWindow = function () {
            if (m_selectedWindow == null)
                return;
            for (var i = 0; i < m_queue.length; i++) {
                if (m_queue[i].ID() == m_selectedWindow.ID()) {
                    if (i > 0) {
                        return m_queue[i - 1];
                    }
                    break;
                }
            }
            return null;
        };

        this.Previous = function () {
            if (_self.PreviousWindow() == null)
                return;
            Application.RunNext(function () {
                return _self.Open(_self.PreviousWindow().ID());
            });
        };

        this.NextWindow = function () {
            if (m_selectedWindow == null)
                return;
            for (var i = 0; i < m_queue.length; i++) {
                if (m_queue[i].ID() == m_selectedWindow.ID()) {
                    if (i != m_queue.length - 1) {
                        return m_queue[i + 1];
                    }
                    break;
                }
            }
            return null;
        };

        this.Next = function () {
            if (_self.NextWindow() == null)
                return;
            Application.RunNext(function () {
                return _self.Open(_self.NextWindow().ID());
            });
        };

        this.OnKeyPress = function (ev) {

            //Ctrl+PageUp.
            if (ev.which == 33 && ev.ctrlKey) {
                _self.Previous();
                ev.preventDefault();
                return false;
            }

            //Ctrl+PageDown.
            if (ev.which == 34 && ev.ctrlKey) {
                _self.Next();
                ev.preventDefault();
                return false;
            }

            //Ctrl+Home.
            if (ev.which == 36 && ev.ctrlKey) {
                if (m_selectedWindow != null) {
                    m_selectedWindow.FocusPrevious();
                }
                ev.preventDefault();
                return false;
            }

            //Ctrl+End.
            if (ev.which == 35 && ev.ctrlKey) {
                if (m_selectedWindow != null) {
                    m_selectedWindow.FocusNext();
                }
                ev.preventDefault();
                return false;
            }

            if (m_focusWindow != null) {
                if (typeof m_focusWindow.OnKeyPress != 'undefined') {
                    return m_focusWindow.OnKeyPress(ev);
                }
            }
        };

        this.ClearLayout = function () {
            if (m_focusWindow != null) {
                m_focusWindow.ClearLayout();
            }
        };

        this.ClearCache = function () {
            if (m_focusWindow != null) {
                m_focusWindow.ClearCache();
            }
        };

        this.GetWindowInfo = function () {

            if (m_focusWindow != null) {
                return m_focusWindow.GetInfo();
            }

            return null;
        };

        this.GetWindowByUID = function (uid_) {
            for (var i = 0; i < m_queue.length; i++) {
                if (m_queue[i].UID() == uid_) {
                    return m_queue[i].ID();
                }
            }
            return -1;
        };

        this.OnSave = function (close, addnew) {

            if (m_focusWindow != null) {

                if (addnew) {

                    var viewer = null;
                    if (m_focusWindow.Options().parentviewer)
                        viewer = m_focusWindow.Options().parentviewer;

                    if (viewer) {
                        setTimeout(function () {
                            Application.RunNext(function () {
                                return viewer.OnNew();
                            });
                        }, 1000);
                    }
                }

                if (m_focusWindow.Dialog()) {
                    if (!close)
                        return m_focusWindow.OnSave(close, true, true);
                    m_focusWindow.HideDialog(true);
                    return;
                    //return m_focusWindow.OnSave(close, true);
                }

                return m_focusWindow.OnSave(close);
            }
        };

        this.HasHome = function (value_) {
            if (value_ !== undefined) {
                m_hasHome = value_;
            } else {
                return m_hasHome;
            }
        };

        this.GetUIDimensions = function () {

            $("#AppWorkspace,#AppSideWorkspace").hide();
            m_uiHeight = GetHeight();
            m_uiWidth = GetWidth();
            m_uiSideWidth = GetSideWidth();
            $("#AppWorkspace").show();
            if (Application.App.SideVisible())
                $("#AppSideWorkspace").show();
        };

        this.Height = function () {            
            return m_uiHeight;
        };

        this.Width = function () {
            return m_uiWidth;
        };

        this.SideWidth = function () {
            return m_uiSideWidth;
        };

        function GetHeight() {

            var padding = 20;

            if ($("#divWarning").is(":visible"))
                padding += $("#divWarning").outerHeight(true);

			if (Application.IsInMobile())
                return $(window).height() - $("#divMobileHeader").outerHeight(true) - 20 - padding;
			
            return ($('#tdMain').innerHeight() - padding);
        };

        function GetWidth() {
            return $("#tdMain").width() - 5;
        };

        function GetSideWidth() {
			
            if (Application.IsInMobile())
                return $("#divFactbox").innerWidth() - 5;

            return $("#tdSide").innerWidth() - 5;
        };

        function ShowScroll() {

            if (!Application.IsInMobile())
                return;

            $(".windows-navigate").remove();
            $("#AppWindows").css("padding-left", "0px").css("padding-right", "0px");

            if ($("#btnCloseAll").length > 0) {

                //Check for a scrollbar.
                if (($("#btnCloseAll").position().left + $("#btnCloseAll").width()) > $("#AppWindows").width()) {
                    $("#tdMain").append("<div class='windows-navigate' style='position: fixed; top: 47px; right: 0px; z-index: 950; background-color: rgb(249, 249, 249); height: 30px; padding-top: 13px;'><img src='https://go.scrubit.com.au/Images/ActionIcons/navigate_right.png' /></div>");
                    $("#tdMain").append("<div class='windows-navigate' style='position: fixed; top: 47px; left: 5px; z-index: 950; background-color: rgb(249, 249, 249); height: 30px; padding-top: 13px;'><img src='https://go.scrubit.com.au/Images/ActionIcons/navigate_left.png' /></div>");
                    $("#AppWindows").css("padding-left", "15px").css("padding-right", "15px");
                }
            }
        };

        //#endregion

        //#region Overrideable Methods

        this.OnOpen = function (win) {
        };

        //#endregion

    });
/// <reference path="../Application.js" />

Application.wrapperTypes = {
    Titanium: 1
};

DefineModule("WrapperManager",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: []

    },

    function () {

        //#region Members

        var _self = this;
        var m_type = Application.wrapperTypes.Titanium; //Default the wrapper.

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Assign Module
            Application.Wrapper = this;
        };        

        this.IsInWrapper = function () {

            if (m_type == Application.wrapperTypes.Titanium) {
                try {                    
                    return typeof Ti.App != "undefined";
                } catch (e) {
                    Application.LogError(e);
                }
                return false;
            }
        };        

        this.FireEvent = function (name_, params_) {

            if (m_type == Application.wrapperTypes.Titanium) {
                try {
                    Ti.App.fireEvent(name_, params_);
                } catch (e) {
                    Application.LogError(e);
                }
            }

        };

        //#endregion

        //#region Private Methods

        //#endregion

    });

    //#region Titanium UI

    if (typeof window.TiApp != "undefined") {

        var Ti = {
            _event_listeners: [],
            createEventListener: function (listener) {
                var newListener = {
                    listener: listener,
                    systemId: -1,
                    index: this._event_listeners.length
                };
                this._event_listeners.push(newListener);
                return newListener;
            },
            getEventListenerByKey: function (key, arg) {
                for (var i = 0; i < this._event_listeners.length; i++) {
                    if (this._event_listeners[i][key] == arg) {
                        return this._event_listeners[i];
                    }
                }
                return null;
            },
            API: TiAPI,
            App: {
                addEventListener: function (eventName, listener) {
                    var newListener = Ti.createEventListener(listener);
                    newListener.systemId = TiApp.addEventListener(eventName, newListener.index);
                    return newListener.systemId;
                },
                removeEventListener: function (eventName, listener) {
                    if (typeof listener == 'number') {
                        TiApp.removeEventListener(eventName, listener);
                        var l = Ti.getEventListenerByKey('systemId', listener);
                        if (l !== null) {
                            Ti._event_listeners.splice(l.index, 1);
                        }
                    } else {
                        l = Ti.getEventListenerByKey('listener', listener);
                        if (l !== null) {
                            TiApp.removeEventListener(eventName, l.systemId);
                            Ti._event_listeners.splice(l.index, 1);
                        }
                    }
                },
                fireEvent: function (eventName, data) {
                    TiApp.fireEvent(eventName, JSON.stringify(data));
                }
            },
            executeListener: function (id, data) {
                var listener = this.getEventListenerByKey('index', id);
                if (listener !== null) {
                    listener.listener.call(listener.listener, data);
                }
            }
        };
        var Titanium = Ti;

    }
    
    //#endregion

// <reference path="../Application.js" />

DefineModule("ZipManager",

    {

        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 10, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2015, Paul Fisher',

        changelog: [
            '16/04/14   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;

        //#endregion

        //#region Public Methods

        this.OnLoad = function () {

            //Global assign.
            Application.Zip = this;
        };

        this.Encode = function (s, password) {

            var dict = {};
            var data = (s + "").split("");
            var out = [];
            var currChar;
            var phrase = data[0];
            var code = 256;
            for (var i = 1; i < data.length; i++) {
                currChar = data[i];
                if (dict[phrase + currChar] != null) {
                    phrase += currChar;
                }
                else {
                    out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
                    dict[phrase + currChar] = code;
                    code++;
                    phrase = currChar;
                }
            }
            out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
            out = $.toJSON(out);
            if (password)
                out = Application.EncryptData(out, password);
            return out;
        };

        this.Decode = function (data, password) {

            if (password) {
                data = Application.DecryptData(data, password);
                if (data == "")
                    return "";
            }

            data = $.parseJSON(data);

            var dict = {};
            var currChar = String.fromCharCode(data[0]);
            var oldPhrase = currChar;
            var out = [currChar];
            var code = 256;
            var phrase;
            for (var i = 1; i < data.length; i++) {
                var currCode = data[i];
                if (currCode < 256) {
                    phrase = String.fromCharCode(data[i]);
                }
                else {
                    phrase = dict[currCode] ? dict[currCode] : (oldPhrase + currChar);
                }
                out += phrase;
                currChar = phrase[0];
                dict[code] = oldPhrase + currChar;
                code++;
                oldPhrase = phrase;
            }

            return out;
        };

        //#end region                

    });
/// <reference path="../Application.js" />

//27/01/15      Issue #7        PF      Added new control.

Define("Article",

    function (field_, viewer_) {
        return new Control("Article", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
		var m_completed = null;
        var m_form = null;       
        var m_record = null;
		var m_options = null;
		
        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Article");
        };

        this.CreateDesktop = function (window_, form_, options_) {

            m_form = form_;
			m_options = Default(options_,{
				bodyFont: "22px"
			});

            //Create the control.
            m_container = $('<div id="' + _base.ID() + '" style="padding: 15px; font-size: '+m_options.bodyFont+';"></div>');
			m_completed = $("<div id='completed"+_base.ID()+"'  style='padding: 15px; font-size: "+m_options.bodyFont+"; display: none;'></div>");
			var filters = $('<div id="artfilters' + _base.ID() + '" style="padding: 15px; font-size: '+m_options.bodyFont+'; display: none;"></div>');
			
			window_.AddControl(filters);
            window_.AddControl(m_container);
			window_.AddControl(m_completed);
									
            _self.Loaded(true);
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function (value_) {
            //Not used.            
        };

        this.Update = function (rec_) {
	
			
            m_record = rec_;
			
			//Add title.
			m_container.append("<h1 style='font-weight: 200; font-size: 46px'>"+rec_.Title+"</h1>");
			
			//Add body.
			if(rec_.Body)
				m_container.append("<p>"+rec_.Body+"</p>");	           			
		   
		   // var jscode = $(".javascriptCode");
		   // jscode.each(function(index){
			   // var ce = jscode[index];
			   // var text = $(this).html();
			   // text = text.replace(/\<br\>/g,"\n");
			   // text = text.replace(/\&nbsp\;/g," ");			   
			   // var editor = CodeMirror(function(node){ce.parentNode.replaceChild(node, ce);}, {
					// mode: "javascript",
					// value: text,
					// lineNumbers: true,
					// lineWrapping: true,
					// readOnly: true
				// });
		   // });
			
			_self.Loaded(true);
        };

        this.Height = function (h) {			
            m_container.height(h - 70);
        };

        this.Width = function (w) {			
			m_container.width(w - 20);			
        };	

        //#endregion

        //#region Private Methods

        
		
        //#endregion        

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        this.PageControl = function () {
            return true;
        };

        //Constructor
        this.Constructor();

    });  
/// <reference path="../Application.js" />

Define("BreadCrumb",

    function (field_, viewer_) {
        return new Control("BreadCrumb", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;        

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("BreadCrumb");
        };

        this.CreateDesktop = function (window_) {

		    //var container = $('<div id="' + _base.ID() + '" style="display: none"></div>');
			var container = $('<div id="' + _base.ID() + '"></div>');
            //Call base method.
            _base.Create(window_, container, null);
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");
			
            //Call base method.
            return _base.CreateList(container, cont, value_);
			
        };
		
		this.FormatValue = function(cellvalue, rowObject){
			
			if(!cellvalue)
				return "";

			var splitchar = Default(Application.OptionValue(_base.Field().Options, "splitchar"), "~");
			var fieldsoption = Application.OptionValue(_base.Field().Options, "fields");
			var flds = fieldsoption.split(",");
			var crumbs = cellvalue.split(splitchar);		
			var uid = $id();
			var page = _base.Viewer().Page();
						
			Application.BreadClick = function(id,field){
				var container = $("#"+id);
				var value = container.html();
				if(value.indexOf("<span") == 0)
					return;				
				var combo = new Combobox(page.GetField(field), _base.Viewer());
				var ele = combo.CreateList(value,true);
				var editor = UI.FindEditorInput(ele);	
				if(editor){	
					editor.on("change",function(){
						
						_base.Viewer().RecordValidate(field,editor.val());		
						
						Application.RunNext(function(){
							container.html(_base.Viewer().Record()[field]);
						});					
						Application.RunNext(function(){
							ShowHideControls(id);
						});					
					});
					editor.on("blur",function(){																													
						_base.Viewer().RecordValidate(field,editor.val());						
						Application.RunNext(function(){
							container.html(_base.Viewer().Record()[field]);
						});					
						Application.RunNext(function(){
							ShowHideControls(id);
						});								
					});
				}
				container.html("");
				combo.Loaded(true);
				container.append(ele);
				setTimeout(function () { combo.Focus(); }, 50);		
			};
			
			var html = "<div id='"+uid+"'>";	
			$.each(flds, function( index_, value_ ) {
				var divid_ = index_+1;
				html += "<div id='"+uid+divid_+"' style='display:inline-block;margin-right:3px;padding: 5px; border: 1px solid grey; border-radius: 3px;";
				 if (crumbs[index_-1]==='' && index_!==0) {
					 html += " display: none;";
				 }
				 html += "' onclick='Application.BreadClick(\""+uid+divid_+"\",\"" +value_+ "\");'>"+crumbs[index_]+"</div>";	
			});
			
			// var html = "<div id='"+uid+"'>";	
			// html += "<div id='"+uid+1+"' style='display:inline-block;margin-right:3px;padding: 5px; border: 1px solid grey; border-radius: 3px;' onclick='Application.BreadClick(\""+uid+1+"\",\"Location1\");'>"+crumbs[0]+"</div>";
			// html += "<div id='"+uid+2+"' style='display:inline-block;margin-right:3px;padding: 5px; border: 1px solid grey; border-radius: 3px;";
			// if (crumbs[0]==='') {
				// html += " display: none;";
			// }
			// html += "' onclick='Application.BreadClick(\""+uid+2+"\",\"Location2\");'>"+crumbs[1]+"</div>";			

			// html += "<div id='"+uid+3+"' style='display:inline-block;margin-right:3px;padding: 5px; border: 1px solid grey; border-radius: 3px;";
			// if (crumbs[1]==='') {
				// html += " display: none;";
			// }
			// html += "' onclick='Application.BreadClick(\""+uid+3+"\",\"Location3\");'>"+crumbs[2]+"</div>";			

			// html += "<div id='"+uid+4+"' style='display:inline-block;margin-right:3px;padding: 5px; border: 1px solid grey; border-radius: 3px;";
			// if (crumbs[2]==='') {
				// html += " display: none;";
			// }
			// html += "' onclick='Application.BreadClick(\""+uid+4+"\",\"Location4\");'>"+crumbs[3]+"</div>";
			// html += "</div>";
			
			return html;
			
		};

        //#endregion

        //#region Private Methods

		function ShowHideControls(id_) {
			var fieldsoption_ = Application.OptionValue(_base.Field().Options, "fields");
			var flds_ = fieldsoption_.split(",");

			var id_str = id_.substring(0, id_.length-1);
			$.each(flds_, function( index_, value_ ) {
				var n = index_+1;
				if (index_!==0) {		
					$("#"+id_str+n.toString()).css('display','inline-block');
				}
			});
			$.each(flds_, function( index_, value_ ) {
				var n = index_+1;
				if ($("#"+id_str+n.toString()).text()===''){
					var m = index_+2;
					$("#"+id_str+m.toString()).css('display','none'); 
					$("#"+id_str+m.toString()).text("");
				}		
			});	
			// $("#"+id_str+'2').css('display','inline-block');
			// $("#"+id_str+'3').css('display','inline-block');
			// $("#"+id_str+'4').css('display','inline-block');	
			// if ($("#"+id_str+'1').text()===''){
				// $("#"+id_str+'2').css('display','none'); 
				// $("#"+id_str+'2').text("");
			// }
			// if ($("#"+id_str+'2').text()===''){
				// $("#"+id_str+'3').css('display','none'); 
				// $("#"+id_str+'3').text("");
			// }
			// if ($("#"+id_str+'3').text()===''){
				// $("#"+id_str+'4').css('display','none'); 
				// $("#"+id_str+'4').text("");
			// }
		};
		
        function CreateBreadCrumb(cont) {

        };

        //#endregion

        //#region Overrideable Methods

        this.Update = function (rec_) {
							
            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);
            
			var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.Loaded(true);
                return;
            }			
					
			var html = _self.FormatValue(value,rec_);
            html = '<table style="width: 100%"><tbody><tr><td><label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px; display: inline-block;" class="app-label">'+_base.Field().Caption+'</label></td><td style="width: 52%; padding-right: 10px; text-align: left; vertical-align: top;">' + html + '</td></tr></tbody></table>';			
			_base.Container().html(html);
            _self.Loaded(true);
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.SetSize = function (width, height) {
			_base.Container().width(width);		
        };

//		this.IgnoreColumns = function () {
//            return true;
//        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Captcha",

    function (field_, viewer_) {
        return new Control("Captcha", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_captcha = [];

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            _base = Base("Captcha");

            Application.On("Error", _self.OnError);
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="margin: 20px;"><table style="max-width: 700px; float: right; margin-right: 30px;"><tr><td id="instruct' + _base.ID() + '" style="background-color: #dfeffc; font-size: 12pt; width:100%; text-align: center; padding: 20px;"></td></tr><tr><td id="images' + _base.ID() + '" style="font-size: 12pt; width:100%; text-align: center; padding: 20px;"></td></tr></table></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

            });
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="margin: 20px;"><center><table style="max-width: 500px;"><tr><td id="instruct' + _base.ID() + '" style="background-color: #dfeffc; font-size: 12pt; width:100%; text-align: center; padding: 20px;"></td></tr><tr><td id="images' + _base.ID() + '" style="font-size: 12pt; width:100%; text-align: center; padding: 20px;"></td></tr></table></center></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {
            });
        };

        this.CreateList = function (value_) {
        };

        //#endregion

        //#region Overrideable Methods

        this.IgnoreColumns = function () {
            return true;
        };

        this.OnError = function (err) {
            //if (err && err.indexOf("ROBOT") != -1) {
                m_captcha = [];
                _self.Update();
                _self.OnValueChange(_base.Field().Name, null);
            //}
        };

        this.Update = function () {
            _base.Loaded(true);
            if (m_captcha.length == 0) {
                $('#images' + _base.ID()).html("");
                Application.RunNext(function () {
                    var w = $wait();
                    Application.ExecuteWebService("GenerateCaptcha", { auth: Application.auth }, function (r) {
                        m_captcha = r;
                        $('#instruct' + _base.ID()).html("Click or touch the <b>" + r[1] + "</b>");
                        if (Application.IsMobileDisplay())
                            $('#instruct' + _base.ID()).css("font-size", "9pt");
                        for (var i = 2; i < r.length - 5; i++) {
                            var width = "";
                            if (Application.IsMobileDisplay())
                                width = " width: 30px";
                            $('#images' + _base.ID()).append("<img id='img" + _base.ID() + i + "' class='captchaimg' src='" + r[i] + "' style='padding: 10px; cursor: pointer;" + width + "' answer='" + r[i + 5] + "' />");
                            $("#img" + _base.ID() + i).on("click", function () {
                                $(".captchaimg").css("border", "");
                                $(this).css("border", "dashed #7BC0E9 4px");
                                _self.OnValueChange(_base.Field().Name, m_captcha[0] + "|" + $(this).attr("answer"));
                            });
                        }
                        w.resolve();
                    });
                    return w.promise();
                });
            }
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Chart",

    function (field_, viewer_) {
        return new Control("Chart", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
        var m_chart = null;
        var m_data = null;
        var m_form = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Chart");
        };

        this.CreateDesktop = function (window_, form_) {

            m_form = form_;

            //Create the control.
            m_container = $('<div id="' + _base.ID() + '" class="ct-chart ct-perfect-fourth xpress-resize" style="max-width: 800px; max-height: 400px;"></div>');

            if (Application.UnsupportedIE()) {
                m_container = _base.CreateUnsupported();
                m_container.css('display', '');
            }

            window_.AddControl(m_container);
            _self.Loaded(true);
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function (value_) {
            //Not used.            
        };

        this.Update = function (rec_) {

            if (Application.UnsupportedIE())
                return;

            var data = GenerateChartData(rec_);

            if (m_chart) {
                CreateChart(_base.ID().toString(), data);
            } else {
                Application.RunNext(function () {
                    CreateChart(_base.ID().toString(), data);
                });
            }
        };

        this.Height = function (h) {

            m_container.height(h);
    
            $('#' + _base.Viewer().ID() + 'main').css('overflow-y', 'hidden');
        };

        this.Width = function (w) {
            m_container.width(w - 10);
			m_container.css("max-width",w);
            if (m_data != null) {
                Application.RunNext(function () {
                    CreateChart(_base.ID().toString(), m_data);
                });
            }
        };

        this.PageControl = function () {
            return true;
        };

        //#endregion

        //#region Private Methods

        function CreateChart(id_, data_) {

            if ($("#" + id_).length == 0) return;
            $("#" + id_).html("");

            m_chart = null;

            m_data = data_;

            var labels = [];
            var series = [];
            var links = [];

            for (var i = 0; i < m_data.length; i++) {
                for (var j = 0; j < m_data[i].length; j++) {
                    if (j == 0) {
                        labels.push(m_data[i][j].data);
                    } else {
                        if (series[j - 1] == null) {
                            series[j - 1] = [];
                            links[j - 1] = [];
                        }
                        series[j - 1].push({ meta: m_data[i][j].meta, value: m_data[i][j].data });
                        links[j - 1].push(m_data[i][j].link);
                    }
                }
            }

            var type = Default(Application.OptionValue(_base.Viewer().Page().Options, "type"), "bar");

            if (type == "bar") {
                m_chart = new Chartist.Bar(".ct-chart", { labels: labels, series: series, links: links }, {
                    axisY: {
                        scaleMinSpace: 50
                    }
                }).on('draw', function (data) {
                    if (data.type === 'bar') {
                        data.element.attr({
                            style: 'stroke-width: 30px'
                        });
                    }
                });
            } else if (type == "stackbar") {
                m_chart = new Chartist.Bar(".ct-chart", { labels: labels, series: series, links: links }, {
                    stackBars: true,
                    axisY: {
                        scaleMinSpace: 50,
                        labelInterpolationFnc: function (value) {
                            return (value / 1000) + 'k';
                        }
                    }
                }).on('draw', function (data) {
                    if (data.type === 'bar') {
                        data.element.attr({
                            style: 'stroke-width: 30px'
                        });
                    }
                });
            } else if (type == "line") {
                m_chart = new Chartist.Line(".ct-chart", { labels: labels, series: series, links: links }, {
                    lineSmooth: false,
                    axisY: {
                        scaleMinSpace: 50
                    },
                    plugins: [
                        Chartist.plugins.tooltip({
                            appendToBody: true
                        })
                    ]
                });
            } else if (type == "area") {
                m_chart = new Chartist.Line(".ct-chart", { labels: labels, series: series, links: links }, {
                    lineSmooth: false,
                    showArea: true,
                    axisY: {
                        scaleMinSpace: 50
                    },
                    plugins: [
                        Chartist.plugins.tooltip({
                            appendToBody: true
                        })
                    ]
                });
            } else if (type == "pie") {
                m_chart = new Chartist.Pie(".ct-chart", { labels: labels, series: series, links: links }, {
                    axisY: {
                        scaleMinSpace: 50
                    }
                });
            } else if (type == "gauge") {
                m_chart = new Chartist.Pie(".ct-chart", { series: series, links: links }, {
                    donut: true,
                    donutWidth: 60,
                    startAngle: 270,
                    total: 200,
                    axisY: {
                        scaleMinSpace: 50
                    }
                });
            }

            //Add on click.
            var chart = $('.ct-chart');
            chart.unbind('click');
            chart.on('click', '.ct-point,.ct-bar', function () {
                var point = $(this);
                var link = point.attr('ct:link');
                if (link && link != '')
                    eval(point.attr('ct:link'));
            });
        };

        function GenerateChartData(rec_) {

            var recs = new Array();
            if (rec_.Count > 0)
                do {
                    recs.push(ConvertRecordToChartData(rec_));
                }
                while (rec_.Next())

            return recs;
        };

        function ConvertRecordToChartData(rec_) {

            var r = new Array();

            for (var i = 0; i < m_form.Fields.length; i++) {

                var field = m_form.Fields[i];

                var link = null;
                if (field.CustomControl == "Drilldown") {

                    var page = Application.OptionValue(field.Options, "drilldownpage");
                    var view = Application.OptionValue(field.Options, "drilldownview");

                    var parentid = _base.Viewer().ParentWindow().ID();

                    link = "Application.App.LoadPage(\"" + page + "\", \"" + Application.MergeView(view, rec_) + "\", { caption: \"" + field.Caption + "\" }, " + parentid + ");";
                }

                r.push({ data: rec_[field.Name], link: link, meta: field.Caption });
            }

            return r;
        };

        //#endregion        

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });  
/// <reference path="../Application.js" />

Define("ColorPicker",

    function (field_, viewer_) {
        return new Control("ColorPicker", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("ColorPicker");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; vertical-align: top;"><input id="ctl' + _base.ID() + '" class="simple_color" style="width: 100px; display: inline-block;"></td></tr></table></div>');

            var colours;
            var colcount;
            if (Application.HasOption("ColorPicker_Dark", _base.Field().Options)) {
                colours = darkcolours();
                colcount = 8;
            }

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {
                cont.simpleColor({
                    colors: colours,
                    columns: colcount
                });
            });
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");
            var cont = $('<input class="simple_color" style="display: none; background-color: white; color: white;">').appendTo(container)
            .val(value_);
            var colours;
            var colcount;
            if (_base.Viewer().Page().FieldOption(_base.Field(), "ColorPicker_Dark")) {
                colours = darkcolours();
                colcount = 8;
            };
            setTimeout(function () {
                cont.simpleColor({
                    colors: colours, columns: colcount,
                    onSelect: function (hex, element) {
                        _base.Viewer().Save();
                    }
                });
                $(".simpleColorDisplay").trigger("click");
            }, 5);
            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        function darkcolours() {
            return [
			'000080', '0000CD', '0000FF', '006400', '008000', '008080', '008B8B', '00BFFF',
			'00CED1', '00FF00', '00FF7F', '00FFFF', '1E90FF', '20B2AA', '228B22', '2E8B57',
			'2F4F4F', '32CD32', '3CB371', '40E0D0', '4169E1', '4682B4', '483D8B', '48D1CC',
			'4B0082', '556B2F', '5F9EA0', '6495ED', '66CDAA', '696969', '6A5ACD', '6B8E23',
			'708090', '778899', '7B68EE', '7CFC00', '7FFFD4', '9ACD32', 'ADFF2F', '8FBC8F',
			'90EE90', '87CEEB', 'ADD8E6', 'AFEEEE', '800000', '800080', '808000', '808080',
			'8A2BE2', '8B0000', '8B008B', '8B4513', '9370DB', '9400D3', 'A52A2A', 'A9A9A9',
			'B22222', 'B8860B', 'BA55D3', 'BC8F8F', 'BDB76B', 'C71585', 'CD5C5C', 'CD853F',
			'D2691E', 'D2B48C', 'DA70D6', 'DAA520', 'DB7093', 'DC143C', 'DDA0DD', 'DEB887',
			'E9967A', 'EE82EE', 'F08080', 'F4A460', 'FA8072', 'FF0000', 'FF00FF', 'FF00FF',
			'FF1493', 'FF4500', 'FF6347', 'FF69B4', 'FF7F50', 'FF8C00', 'FFA07A', 'FFA500'
			];
        };

        //#endregion

        //#region Overloaded Methods

        this.Update = function (rec_) {

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined')
                return;

            _base.Control().val(value);
            _base.Control().setColor(value);            
        };

        //#endregion

        //#region Overrideable Methods

        this.SetSize = function (width, height) {
            _base.Container().width(width);
            //m_control.width((width / 2) - 18);
        };

        this.FormatValue = function (value_, cont_) {

            try {
                value_ = $(value_)[0].firstChild.innerHTML;
            } catch (e) {
            }
            var val = Default(value_, 'White');
            var cont = "<center><div class='cp' style='width: 90%; height: 90%; background-color: $1; color: $1; border: 2px solid gray; -moz-border-radius: 5px; -webkit-border-radius: 5px; -khtml-border-radius: 5px; border-radius: 5px; font-size: 1; cursor: pointer'>" + val + "</div></center>";
            return Application.StrSubstitute(cont, val);
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Drilldown",

    function (field_, viewer_) {
        if(field_)
        field_.Enabled = false;
        return new Control("Drilldown", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Drilldown");
        };

        this.FormatValue = function (value_, cont_) {

            var value = "";
            try {
                value = $.base64.decode(value_);
            } catch (e) {
            }

            //Remove control chars
            value = value.replace(/[\n\r\t\0\f\v]/g, '');

            value = value.split("~");

            if (value.length != 4) return "";

            var link = Application.StrSubstitute("Application.App.LoadPage(\"$1\",\"$2\",null,$3);", value[1], value[2].replace('\\', '\\\\'), _base.Viewer().ParentWindow().ID());
            var cont = "<center><a onclick='$1' style='cursor: pointer; text-decoration: underline; color: black;'>$2</a></center>";

            if (value[0] == "") return "";

            if (value[3].indexOf("b") == -1) {
                return Application.StrSubstitute(cont, link, value[0]);
            } else {
                return Application.StrSubstitute(cont, link, "<b>" + value[0] + "</b>");
            }
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");

            var cont = $('<input>')
            .appendTo(container)
            .addClass("ui-widget ui-widget-content ui-corner-left")
	        .css("width", "80%")
	        .css("width", "calc(100% - 2px)");

            cont.val(_self.FormatValue(value_));

            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("FileLookup",

    function (field_, viewer_) {
        return new Control("FileLookup", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_loaded = false;
        var m_baseImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAIAAAAiOjnJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzA3MzhDNDI0MjlBMTFFMjlCOTdDRDNGRTM1MTAwQjUiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzA3MzhDNDE0MjlBMTFFMjlCOTdDRDNGRTM1MTAwQjUiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo0RTU3QjVDMTQyMjkxMUUyQkY0N0UwQ0IyRjFGN0U5QSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo0RTU3QjVDMjQyMjkxMUUyQkY0N0UwQ0IyRjFGN0U5QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pohpf/0AAAR5SURBVHja7NzLSltBHMDh5qioBMWN+AIu1aXvj2+g7gS3rpVG4wWTDg4Mp1ptNU37nznfb1ECvXByzpe5lTiaTCbfpL/dCCyBJbAElrsgsASWwJLAElgCSwJLYAksCSyBJbAksASWwJLAElgCSwJLYAksCSyBJbAksASWwJLAElgCSwJLYAksCSyBJbAksP5z8/l89FJ6AVagp9J1XX4k+QnlXyvl1X/x031vnZ0Ra1meTIVgLUtY+rU/+uaBCiwtOqEXT0asWMusk5OTGmeWdM0rKyvPz8/5ysfj8cHBwfr6el5XDWSu7CJi7y1sa3wG6VORVeWLv729PT8/f3x8HNTo1dU1EvTXK5EvMpOazWb5xd3d3dnZWbaVp0iwYu228nOKPIz1r62s3Iutp6engYxb1cDqP7Aq5se3s/l0Ok22Hh4ePjjEamb5VeWwXMWHvuhJE2K57GQrrbfu7+/fmxCbGc9CHzekXeGrR7WxsbGzs1PXLb65uUnzYH/Du7m5eXh4mPeJmV17+8TVugaqra2t/f39D/6rJOA1X15eZlhlRZ/HraOjo7W1tVaPHupbY5UVccxHUnYYb9dMeZOYp8i83kpr+fJnGlvUVwOrv1J59fCiXecHC/PyW+lF/wzCiBViVxj58/0p8Q2fbw3isC5yrZ5vgfX/a/J8C6wQO8f2zrfAirLkL7bKMr/qyRGsKCcUxVZay5eDCbC00HDV3vkWWCFGrPbOt8CKewZR9fkWWKFt1Xu+BVbcqj7fAituVZ9vgRV9w1jp+RZYoXeL9Z5vgRV6uKr3fAus0CNWvedbq57fstve3v4yhevr6zRW9W2dnp4eHx+XbyyCNdzxZnd3d29v7wu20l+5uLgosLKktIqPr8pUuCxSZQ3U/3Ffn1WV/+KrL3/X8qMfwPr79Z/9l3/A2gffDANruDNg+R7RIgje+7aPxftwzwgqEmDEqm+BtcgY86lD9oCCwVoir0VWRb/8+uR7/07AVRdYlW0LTIUadGAJLIElsCSwBJbAksASWAJLAktgCSwJLIElsCSwBJbAksASWAJLAktgCSwJLIElsCSwBJbAksASWAJLAktgCSwJLIElsCSwBJbAksASWAJLAktgCSwJLIElsCSwBJbAksASWAJLAktgCSwJLIH1J41GIw8vcqt1Xe50Or26uiqq0ov5fN7qs0lvLb3fSt9jZbC+v5Ru9BBGrPQeZ7NZ/51W9Ma7Gj/HA5kHk6qu6ypdAHR1kRrU6ipPgpXO9V1dN3qAq+DRS2D9u0Gr4WX7L981WEsftAY1J1b6NkeTySTs8jxfW9tnCl9oPB6nRX3eMIa9ORFh5ZuVN9vlDvJUPnXpnsT/pEWEpT/ZKhZeMQetoLDKzarlA/qP1wnxlwdGrHaGMbBauHFuRZW7wrLNRuq3vKyxNKDRCyyBJbAEFlgCS2AJLAksgSWwJLAElsCSwBJYAksCS2AJLAksgSWwJLAElsCSwBJYAksCS2AJLAksgSWwJLAElsCSwBJYAkv6XD8EGAD9LvkdGZgSPQAAAABJRU5ErkJggg==";
        var m_fileImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAAAAAAAAAB6mUWpAAAACV0RVh0U29mdHdhcmUATWFjcm9tZWRpYSBGaXJld29ya3MgTVggMjAwNId2rM8AAAiwSURBVHic7d3Pa9toGsDxp8viYMcJOJM6gxMczBSqDmYWDN6eTA6FYf6A+T/n2osPIXsZDIGCSVSYRcTEpklTe7ATiegye+g67aTxY0mWrF/fz3FsK++0+daSXunVs6s/r/4SAE/6R9wDAJKMQAAFgQAKAgEUBAIoCARQEAigIBBAQSCAgkAABYEACgIBFAQCKAgEUBAIoCAQQEEggIJAAAWBAAoCARQEAigIBFAQCKAgEEBBIICCQAAFgQAKAgEUBAIoCARQEAigIBBAQSCAgkAABYEACgIBFP+MewBZMBqPpH/Zl6vpldiu/bfXqltVeVV7JYfPD6VYKMY0QgT1jKfcBuO4jlx8vJDBp8GTYTxW3arKQeVAmvUmoaQIgQRgDk05H53L9ew60Odb9RahpASB+OC4jvQHfTkdnK68repWVV7/8FpqO7UQRoaoEIhHjuvIiXki1o0V2jZLhZK8+fENkSQYZ7E8CjsOERHbtaV71hXHdULdLsJDIB6YQzP0OOZs15YT8ySSbWN1BLLEaDySntWL9GdYN5aYQzPSn4FgmAdZYjgeLj2FK/L5eGJve0/q39Uf/tvMmcnl5NLT2a6e1WOuJIEIROG4jpgflv/L3thtSPOg+eTBdtNtejrzZbu2XHy8EGPfCDxehI9dLMXFx4ul3x6N3YZ0jM7CM1HFQlHaL9py9PJo6c8bfBoEGieiQyCKmTNTXy8VStIxOp52i4x9Qxq7DfU9d/d3nNFKGAJRTOyJ+rrxveHrmKF50JRSobTw9dv7W8/bwnoQyAKO68jd/Z36nv2dfV/brJQrUt4oL3zddm2Z3OpRYr0yf5A+Go8i2/bUmUrFrYT6Sz11piLj0Da3ELP33mT2UpPReCS///f3wBcUZh3XgnmTyV0sx3Wke9YlDsX17Fq6Z91Iv2GzIJOBvH331tPkXt7NrwUjksUyGQjfHN4RiS6TgcAfIlmMQCAiRLIIgeABkXwr8/MgT2nsNqRSqiydKV+2GIPX7SSBl4UlRL5Ewp2On+UukFKhtPDK28d+6/2m/lJ53U4S9P7oeb6Xnki+YBcrJ/x+y80jyfuNXASygJeraqfOdA0jiY/t2tKzermOhECgynskBIKlbNeW4/fHuYyEQOBZHiMhEPiSt0hyd5o3KRzXebiPpFKupGo1k+P3xyIiuVhggkBi8PhelVKhJMb3hrRftGMemXd5iYRdrDUbjUff3Ktiu7acDk5Tt+uSh90tAlmz/mV/4ex8z+qlblWT4/fHmb52i0DWaNlCEGldtKF71o17CJEhkJyolCqRbTvLd28SSE5sFbfiHkIqcRYrJ+Znm85H54E+n9fbmAkkR4x9Qw6fH/r+3OR2It2zbqZ3pRYhkJwJMiE5kfSdOAgLxyCAgkAABYEACgIBFAQCKAgEUBAIoCAQQEEggIJAAAWBrGC7uB33EBAxAgEUBLICv0uPTm4n6rPQtWeoIx4EskCxUJSDyoH6nsGnga9tDsdD9ZLx8kZZKuXo7vyDfwSiWHYXnnVjeV7Vw3EdMT/o793c2EzV+lh5wP0gCi8H4T2rJyL6+lDzdbCW3XAU5X3jCIZAFJVyRRq7DbFurIXvmS/sPPg0kPp3dTl8fijFQvFh5cTheCjmB3NpHKVCSZr1Ztj/C1gRgSiKhaI0D5pqIHPWjSXWjSUlqyTljbKIiNze33q+TXVve4/dqwQikCVqO7Wl3yJfs13b973bpUJJOkYnyPAQMQ7SPegYHaluVSPbfrvR5tsjoQjEg2KhKK9/eB3JPEWr3sr8AtBpRiAe1XZq8ubHN6FFUiqUpFVvpWpF9zwiEB9qOzX59d+/SmO3sVIo1a2qtBtt4kgBDtJ9KhaK8vNPP4s5NOV8dO7rTFUanwOSdwQSkLFviLFviDk0ZebM5HJyKSLyzbVW5Y2ybG5s/m2OJErm0HyYvNzb3pOO0eEEwAoIZEXzA+ym+3mS7/HjC9b5eDVzaD48+Unk/3Mz/7Hk6OURJwICIpCQzCMo7sTzr/XjOL6Wl8elRYGD9AzQ4pg7fn+cuqdXJQGBpJyXOOb6g37Eo8keAkkxP3GIyNLL7fEtjkFSqvdHT04Hp74+M7+IEt7xDZJCQeIQEXlVexXBaLKNQFImaByc6g2GQFKEONaPQFKCOOJBIClAHPHhLFYIHNeRE/Pk4a7Dxm4jtGugiCNeBLKip+YirBtL7t7dyS//+mWlSIgjfuxirUCbqLueXcvbd28DX95BHMlAIAGNxqOls9hBIyGO5CCQgPqX3q5r8hsJcSQLgQR0Nb3y/F6vkRBH8hBIQH6va1oWCXEkE4EEFOS6pkWREEdyEUhAxr4hRy+PfH/ucSTEkWzMg6xg/gvq554MkS+RbG5sel7S9GvEsT4EsqJVIpGZ/59HHOvFLlYIgu5u+UUc60cgIYk6EuKIB4GEKKpIiCM+BBKysCMhjngRSATCioQ44kcgEVk1EuJIBgKJUNBIiCM5CCRifiMhjmQhkDXwGglxJA+BrMmySIgjmbjUZI2MfUO2i9vSv+zL3f2diIhsbmxK86AptZ1azKPDUwhkzWo7NWJIEXaxAAWBAAoCARQEAigIBFAQCKAgEEBBIIAil4FUypW4h5Aqef7zyuVM+sXHC9kubsc9jNSYOtO4hxCb3AViu7b0rF7cw0gd27XjHkIscheISH7/suFfLo9BAK8IBFAQCKDIZCCteivuIeRKlv+8MxlI+0U7039pSdKqt6T9oh33MCKTyUBEiGQdsh6HiMizqz+v/op7EEBSZfYbBAgDgQAKAgEUBAIoCARQEAigIBBAQSCAgkAABYEACgIBFAQCKAgEUBAIoCAQQEEggIJAAAWBAAoCARQEAigIBFAQCKAgEEBBIICCQAAFgQAKAgEUBAIoCARQEAigIBBAQSCAgkAABYEACgIBFAQCKAgEUBAIoCAQQEEggIJAAAWBAAoCARQEAigIBFD8DzBjfau4wp8DAAAAAElFTkSuQmCC"//"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIBAMAAABfdrOtAAAAA3NCSVQICAjb4U/gAAAAG1BMVEW2trb09PS9vb3e3t7FxcXv7+/m5ubMzMzW1tYJEfE0AAAACXBIWXMAAAAAAAAAAAHqZRakAAAAJXRFWHRTb2Z0d2FyZQBNYWNyb21lZGlhIEZpcmV3b3JrcyBNWCAyMDA0h3aszwAAAy1JREFUeJzt2s9z0kAUB/CdtBaOZmJSjgxV6zH4a3pkLG29Ri31WGvFK9ZRrtSL/7a83QQ2ySPZkPdQZ967sDNk8uHLJrubBeXvoJQggggiiCCCCCKIIIIIIogggrRFojulThNe5P3SUOrtdoojEoyUru5WihsSLlRa53zIVWYo7xMbMlsh6gkXEqwN1eFCbixEDZkQ3e3HL05GW35fLkjYh69p2eMfAdnjQXSX/IBWvF2nuCA9uHQTaB0uW/sJCwKn7upW1M84cuTDEjnQrRC6vvntWIlMTd1Cd090E5DXU6taI7eqvpzGsgpEX7l15TSWVSCPHAylnrZDHjohLlFaIy5R2iMOUdojDlFqkM7v+Xx+lzVK1XeLUoPoTwmX2QF6yMItSjvETMvekACBsQufRdK5/2gXSF0UEqRutqRBalYXREh1lKbI5AuKVEdpiEQj7x5FKqM0RG7yp7OWr0M6ZJZfSFgIfrdugxQXEhbisSELazBmQ+JdIMHYFCviX+qa9FkRU5EggggiSGOk8sH0v0L2VmdDFvEUCOxImM0OaCE7EhSI3lsZQuudQvdWKJAIEFi5R9AlXR4k1IuS78nkF7wi+10UiH+tVwqP3+iXb0zIoVoXtklEgujbIy1s0UuC2Dud98iRNIg+i65n2JE0iH+VKvtDRsR/qRUP+7LoEP9kPBhcvLLff36cUCP+5XSa2G8H6yuNDilWrFaPV2yIHjUfMCP60aTLi5hfOzxeZGFuG1aklxvImBAThPfqygdhQvJBeJBCEDoknHWSrF0IQocsb76ztFkMQobAzZct64pByJBrOK2JUgpChuill4lSCkKGmOkXopSDkCEjlUUpByFD0k2nMywI6dWloyBBSO8TqAskCB1i/yZf3DulG7vsrcDCgpgOCTYGoRyF401BKJFgUxDS+STeEIQUCTYEoZ0ZYzwILRLgQYjn+BgNQowEaBDq1crX8U/kSL7nE0EEEWSXiNt/38J2yNHUpT63Q7yBU6lWSIMSZAdIr5GB7K67ILlf22sL352sR5pEqQryj/0bXRBBBBFEEEEEEUQQQQQRRBBBBBFEkL+D/AFFZyDrQXpu0wAAAABJRU5ErkJggg==";
        var m_cleared = false;
        var m_value = null;
		var m_lastID = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("FileLookup");
        };

        this.CreateDesktop = function (window_) {

            if (Application.HasOption(_base.Field().Options, "pathonly")) {

                //Create the control.
                var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px;"><input type="file" id="ctl' + _base.ID() + '" style="width: 100%;"></input></td></tr></table></div>');

                //Call base method.
                _base.Create(window_, container, _self.OnValueChange, function (cont) {

                    //Setup the FileLookup.
                    cont.attr("maxlength", _base.Field().Size);

                });

            } else {

                //Create the control.
                var container = $('<div id="' + _base.ID() + '" style="padding: 10px; text-align: center;"><img id="ctl' + _base.ID() + '" src="" style="border: 5px dashed gainsboro; width: 150px;" /><p><label id="filelbl' + _base.ID() + '">Click to upload a ' + _base.Field().Caption + ' or drag and drop<br/>your ' + _base.Field().Caption + ' into this box.</label></p><p><a id="clear' + _base.ID() + '" style="display: inline-block;">' + UI.IconImage("delete") + ' Delete</a> <a id="open' + _base.ID() + '" style="display: inline-block;">' + UI.IconImage("document_out") + ' Open</a></p><br/><input id="file' + _base.ID() + '" type="file" style="display:none;" /></div>');

                if (!window.FileReader) {
                    container = _base.CreateUnsupported();
                }

                //Call base method.
                _base.Create(window_, container, _self.OnValueChange, function (cont) {

                    if (!window.FileReader) {
                        container.width("95%");
                        return;
                    }

                    if (_base.Field().Editable) {

                        $('#clear' + _base.ID()).button().click(function () {
                            Application.Confirm("Are you sure you wish to delete this file?", function (r) {
                                if (r) {

                                    m_loaded = false;

                                    _self.OnValueChange(_base.Field().Name, null);
                                    m_cleared = true;
                                    $('#file' + _base.ID()).val("");
                                }
                            });
                        });

                        $('#ctl' + _base.ID()).click(function () {
                            $('#file' + _base.ID()).click();
                        });
                        $('#file' + _base.ID() + ',#' + _base.ID()).fileReaderJS({
                            on: {
                                load: function (url, e, file) {

                                    m_loaded = false;
                                    $('#file' + _base.ID()).val("");

                                    url = file.extra.nameNoExtension + "." + file.extra.extension + "|" + url;

                                    val = btoa(url);

                                    _self.OnValueChange(_base.Field().Name, val);
                                }
                            }
                        });

                    }

                    $('#open' + _base.ID()).button().click(function () {
                        if (m_value) {

                            var val = atob(m_value);
                            var v = val.split("|");

                            var url = v[1].split(";");
                            var byteString = atob(url[1].substr(7));

                            var ab = new ArrayBuffer(byteString.length);
                            var ia = new Uint8Array(ab);
                            for (var i = 0; i < byteString.length; i++) {
                                ia[i] = byteString.charCodeAt(i);
                            }
                            
                            var blob = new Blob([ia], { type: url[0] });
                            saveAs(blob, v[0]);
                        }
                    });

                    _base.Control().attr("src", m_baseImage);
                    _base.Control().css("border-style", "dashed");

                    $('#clear' + _base.ID()).hide();
                    $('#open' + _base.ID()).hide();

                });

            }
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");

            var cont = $('<input type="file">')
            .appendTo(container)
            .val(value_)
            .attr("maxlength", _base.Field().Size)
            .addClass("ui-widget ui-widget-content ui-corner-left")
	        .css("width", "80%")
	        .css("width", "calc(100% - 2px)");

            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        this.FormatValue = function (value_) {

            $('#filelbl' + _base.ID()).html("Click to upload a " + _base.Field().Caption + " or drag and drop<br/>your " + _base.Field().Caption + " into this box.");

            try {

                if (value_ != null) {

                    var val = atob(value_);
                    var v = val.split("|");

                    $('#filelbl' + _base.ID()).text(v[0]);
                    _base.Control().attr("src", m_fileImage);
                    _base.Control().css("border", "5px solid #82AE82");
                    if (_base.Field().Editable)
                        $('#clear' + _base.ID()).show();
                    $('#open' + _base.ID()).show();
                    m_loaded = true;
                    return;
                }

            } catch (e) {
            }

            _base.Control().attr("src", m_baseImage);
            _base.Control().css("border", "5px dashed gainsboro");
            $('#clear' + _base.ID()).hide();
            $('#open' + _base.ID()).hide();
        };

        this.Update = function (rec_) {

            if (Application.HasOption(_base.Field().Options, "pathonly"))
                return _base.Update(rec_);

            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            if (m_loaded && rec_.Record.RecID == m_lastID) {
                _self.Loaded(true);
                return;
            }

            var value = rec_[_base.Field().Name];

            m_value = value;

            if (typeof value == 'undefined') {
                _self.FormatValue(m_baseImage);
                _self.Loaded(true);
				m_lastID =  rec_.Record.RecID;
                return;
            }

            if (value == null && !m_cleared && rec_.Record.RecID == m_lastID) {
                _self.Loaded(true);
                return;
            }
            m_cleared = true;
			
			m_lastID =  rec_.Record.RecID;

            _self.FormatValue(value);
            _self.Loaded(true);
        };

        //#endregion

        //#region Overrideable Methods

        this.SetSize = function (width, height) {
            if (Application.HasOption(_base.Field().Options, "pathonly"))
                return;
            _base.Container().css("width", width);
        };

        this.IgnoreColumns = function () {
            if (Application.HasOption(_base.Field().Options, "pathonly"))
                return false;
            return true;
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Frame",

    function (field_, viewer_) {
        return new Control("Frame", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
		var m_url = null;
		var m_form = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Frame");
        };

        this.CreateDesktop = function (window_, form_) {
           
			m_form = form_;
			
            //Create the control.
            m_container = $('<iframe id="' + _base.ID() + '" style="width: 100%; height: 100%;"></div>');
            m_container.css("min-height", UI.Height() - 40);
            
            window_.AddControl(m_container);				

            _self.Loaded(true);			
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.Update = function (rec_) {
			
			m_url = rec_[m_form.Fields[0].Name];
			
			if(m_url)
				m_container.attr("src",m_url);
        };        
       
        //#endregion

        //#region Public Properties

        //#endregion

        //#region Private Methods        
		
        //#endregion        

        //#region Overridden Methods

        this.Height = function (h) {
        };

        this.Width = function (w) {
        };

        //#endregion

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });  
/// <reference path="../Application.js" />

Define("GoogleMap",

    function (field_, viewer_) {
        return new Control("GoogleMap", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_loaded = false;
        var m_address = "";

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("GoogleMap");
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="padding: 15px;"><a id="btn' + _base.ID() + '" data-role="button" data-icon="location" data-theme="c" data-inline="true">View Map</a></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                $('#btn' + _base.ID()).bind("click", function () {

                    _self.OpenMap();

                }).buttonMarkup({ icon: "location" });
            });
        };

        this.OpenMap = function () {
            window.open('http://maps.google.com.au/maps?q=' + m_address);
        };

        this.Update = function (rec_) {

            if (!Application.IsInMobile())
                return _base.Update(rec_);

            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.Loaded(true);
                return;
            }

            m_address = value;
            _self.Loaded(true);
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("HTMLEditor",

    function (field_, viewer_) {
        return new Control("HTMLEditor", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_okClicked = false;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("HTMLEditor");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '"><table style="width: 100%"><tr><td id="ctltd' + _base.ID() + '" style="width: 100%; padding-right: 10px;"><div id="ctl' + _base.ID() + '" style="width: 100%;"></div></td></tr></table></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {
                cont.trumbowyg({
					fullscreenable: true,
					btns: ['viewHTML',
					  '|', 'formatting',
					  '|', 'btnGrp-design',
					  '|', 'link',
					  '|', 'insertImage',					  
					  '|', 'btnGrp-justify',
					  '|', 'btnGrp-lists',
					  '|', 'horizontalRule']
				});		
				//var btn = $("<a>Save HTML</a>");
				//container.append(btn);
				cont.on("tbwblur",function(){					
					_self.OnValueChange(_base.Field().Name,cont.html());
				});
            });
        };

        this.CreateMobile = function (window_) {
            return _self.CreateDesktop(window_);
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");

            var cont = $('<input>')
            .appendTo(container)
            .val(value_)
            .attr("skipSelect", true) //Set this as we don't want to select the "base control"
            .focus(function (e) {
                CreateTextarea(cont);
            })
            .addClass("ui-widget ui-widget-content ui-corner-left")
	        .css("width", "80%")
	        .css("width", "calc(100% - 2px)");

            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        //#endregion

        //#region Private Methods

        function CreateTextarea(cont) {

            var val = cont.val();
            
            var boxy = new Boxy('<div id="html' + _base.ID() + '" style="padding: 10px; width: 100%;">'+val+'</div>', {
                title: "Edit HTML",
                closeText: "X",
                modal: true,
                unloadOnHide: true,
                show: false,
                beforeHide: function (closeclicked) {
                    if (closeclicked)
                        m_okClicked = false;
                    if (m_okClicked)
                        cont.val($('#html' + _base.ID()).html());
                },
                toolbar: "<a id='okbtn" + _base.ID() + "' style='float: right; font-size: 11pt; width: 100px; margin: 10px;'>OK</a>"
            });

            boxy.center();
            boxy.show();
            boxy.tween(UI.Width() / 2, UI.Height() / 2);

            $("#okbtn" + _base.ID()).button().click(function () {
                m_okClicked = true;
                boxy.hide();
            });

            $('#html' + _base.ID()).css("display","").trumbowyg({
                fullscreenable: false,
					btns: ['viewHTML',
					  '|', 'formatting',
					  '|', 'btnGrp-design',
					  '|', 'link',
					  '|', 'insertImage',					  
					  '|', 'btnGrp-justify',
					  '|', 'btnGrp-lists',
					  '|', 'horizontalRule']
            });
        };

        //#endregion

        //#region Overrideable Methods

		this.SetSize = function(w){
			_base.Container().width("100%");
		};
		
        this.Update = function (rec_) {
            
            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);
            
			var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.Loaded(true);
                return;
            }					

			_base.Control().html(value);			

            _self.Loaded(true);
        };
		
		 this.IgnoreColumns = function () {
            return true;
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("ImageLookup",

    function (field_, viewer_) {
        return new Control("ImageLookup", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_loaded = false;
        var m_baseImage = UI.Icon("camera_large", 48, true);
        var m_cleared = false;
        var m_cropper = null;
        var m_value = null;
		var m_boxy = null;
		var m_id = 0;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("ImageLookup");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="padding: 10px; text-align: left;"><div id="zoom'+_base.ID()+'"><div id="wrapper' + _base.ID() + '" data-download-url="false"><img id="ctl' + _base.ID() + '" src="" style="max-width: 200px;" /></div></div><br /><br /><a id="edit' + _base.ID() + '" data-role="button" data-theme="c" data-inline="true">Add/Edit</a><a id="clear' + _base.ID() + '" data-role="button" data-icon="delete" data-iconpos="notext" data-theme="c" data-inline="true">Delete</a><br/><input id="file' + _base.ID() + '" type="file" style="display:none;" /><div id="placeholder' + _base.ID() + '" style="width: 600px; height: 800px; display: none;"></div></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                cont.removeClass("app-control");

				if (Application.HasOption(_base.Field().Options, "zoom")) {
					_self.SetupZoom();
				}
				
                if (_base.Field().Editable) {

                    $('#clear' + _base.ID()).button().click(function () {
                        Application.Confirm("Are you sure you wish to delete this image?", function (r) {
                            if (r) {

                                m_loaded = false;

                                _self.OnValueChange(_base.Field().Name, null);
                                m_cleared = true;
                                $('#file' + _base.ID()).val("");
                            }
                        });
                    });

                    if (window.FileReader) {

                        $('#edit' + _base.ID()).button().click(function () {
                            $('#file' + _base.ID()).click();
                        });

                        $('#ctl' + _base.ID()).click(function (ev) {
							if (!Application.HasOption(_base.Field().Options, "zoom") || !m_value) {
                                $('#file' + _base.ID()).click();
                                ev.preventDefault();
                                return false;
							}
                        });

                        $('#file' + _base.ID()).fileReaderJS({
                            on: {
                                beforestart: function (e, file) {
                                    _base.Viewer().ShowLoad();
                                },
                                loadend: function (e, file) {
                                    _base.Viewer().HideLoad();
                                },
                                load: function (url) {

                                    m_loaded = false;
                                    $('#file' + _base.ID()).val("");

                                    if (Application.HasOption(_base.Field().Options, "crop")) {

                                        var id = $id();
                                        var win = "<div id='" + id + "' style='max-height: "+(UI.Height()-50)+"px; max-width: "+(UI.Width()-50)+"px;  max-width: "+(UI.Width()-50)+"px;'>" +
						                "<div id='" + id + "actions' class='ui-widget ui-state-default' style='border: 0px;'></div>"+
                                        "<div id='" + id + "main' class='ui-widget-content' style='border-width: 0px; width: 300px; height: 400px;'>" +
						                "<img id='" + id + "image' style='max-height: 300px; height: 300px; max-width: 100%; display: block; margin: auto;'>" +
						                "</div></div>";
                                    
                                        var cropbox = new Boxy(win, {
                                            title: "Loading...",
                                            closeText: "X",
                                            modal: true,
                                            unloadOnHide: true,
                                            show: false,
                                        });

                                        var rotate1 = $("<button class='unselectable app-button' style='border-width: 0px;'>Rotate -45</button>").button().on("click", function () {
                                            $('#' + id + 'image').cropper("rotate", -45);
                                        });
                                        $("#" + id + "actions").append(rotate1);

                                        var rotate2 = $("<button class='unselectable app-button' style='border-width: 0px;'>Rotate +45</button>").button().on("click", function () {
                                            $('#' + id + 'image').cropper("rotate", 45);
                                        });
                                        $("#" + id + "actions").append(rotate2);

                                        var zoom1 = $("<button class='unselectable app-button' style='border-width: 0px;'>Zoom In</button>").button().on("click", function () {
                                            $('#' + id + 'image').cropper("zoom", 0.1);
                                        });
                                        $("#" + id + "actions").append(zoom1);

                                        var zoom2 = $("<button class='unselectable app-button' style='border-width: 0px;'>Zoom Out</button>").button().on("click", function () {
                                            $('#' + id + 'image').cropper("zoom", -0.1);
                                        });
                                        $("#" + id + "actions").append(zoom2);

                                        var crop = $("<button class='unselectable app-button' style='border-width: 0px;'>Finish Crop</button>").button().on("click", function () {
                                            var url = $('#' + id + 'image').cropper("getCroppedCanvas", {
                                                width: 300
                                            }).toDataURL();
                                            cropbox.hide();
                                            _self.OnValueChange(_base.Field().Name, UI.ImageManager.Base64(url));
                                        });
                                        $("#" + id).append(crop);

                                        $('#' + id + 'image').attr("src", url).cropper();
                                        cropbox.setTitle("Crop");
                                        cropbox.center();
                                        cropbox.show();
                                        
                                    } else {

										if(_base.Viewer() && _base.Viewer().OnSaveImage){
											_base.Viewer().OnSaveImage(url,function(img){
												_self.OnValueChange(_base.Field().Name, img);
											});
											return;
										}											
									
										var maxwidth = Default(Application.OptionValue(_base.Field().Options, "maxwidth"), "400");
										var quality = Default(Application.OptionValue(_base.Field().Options, "quality"), "20");
									
										_base.Viewer().ShowLoad();
                                        UI.ImageManager.Resize(url, maxwidth, 0, 0, function (img) {
											UI.ImageManager.ChangeQuality(img, quality, function (img2) {   
												_base.Viewer().HideLoad();											
												_self.OnValueChange(_base.Field().Name, UI.ImageManager.Base64(img2));
											});
                                        });

                                    }
                                }
                            }
                        });

                    } else {
                        $('#edit' + _base.ID()).css("display", "none");
                    }

                } else {
                    $('#edit' + _base.ID()).css("display", "none");
                    $('#clear' + _base.ID()).css("display", "none");
                }
				
				if(Application.HasOption(_base.Field().Options, "nodelete"))
					$('#clear' + _base.ID()).css("display", "none");
				
                //Issue #72 - Allow image download
                $('#ctl' + _base.ID()).mousedown(function (ev) {
                    if (ev.which == 3 && m_value) {
                        UI.ContextMenu([{ Name: "Download", ID: 1 }], function (cmd) {
                            if (cmd == 1) {
                                Application.FileDownload.DownloadBlob("photo.jpg", m_value, "image.jpeg");
                            }
                        });
                        ev.preventDefault();
                        return false;
                    }
                });

                _base.Control().attr("src", m_baseImage);
            });
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="padding: 10px; text-align: left;"><div id="zoom'+_base.ID()+'"><div id="wrapper' + _base.ID() + '" data-download-url="false"><img id="ctl' + _base.ID() + '" src="" style="max-width: 200px;" /></div></div><br/><a id="edit' + _base.ID() + '" data-role="button" data-icon="edit" data-theme="c" data-inline="true">Edit</a> <a id="clear' + _base.ID() + '" data-role="button" data-icon="delete" data-theme="c" data-inline="true">Delete</a><br/><input id="file' + _base.ID() + '" type="file" style="display:none;" /></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

				if (Application.HasOption(_base.Field().Options, "zoom")) {
					_self.SetupZoom();
				}
				
                if (_base.Field().Editable) {

                    $('#clear' + _base.ID()).buttonMarkup().click(function () {
                        Application.Confirm("Are you sure you wish to delete this image?", function (r) {
                            if (r) {

                                m_loaded = false;

                                _self.OnValueChange(_base.Field().Name, null);
                                m_cleared = true;
                                $('#file' + _base.ID()).val("");
                            }
                        });
                    });

                    if (window.FileReader) {

                        $('#edit' + _base.ID()).buttonMarkup().click(function () {
                            $('#file' + _base.ID()).click();
                        });
                        $('#ctl' + _base.ID()).click(function (ev) {
							if (!Application.HasOption(_base.Field().Options, "zoom") || !m_value) {
                                $('#file' + _base.ID()).click();
                                ev.preventDefault();
                                return false;
							}
                        });
                        $('#file' + _base.ID()).fileReaderJS({
                            on: {
                                load: function (url) {
                                    m_loaded = false;
                                    $('#file' + _base.ID()).val("");
                                    UI.ImageManager.Resize(url, 400, 0, 0, function (img) {
                                        _self.OnValueChange(_base.Field().Name, UI.ImageManager.Base64(img));
                                    });
                                }
                            }
                        });
                    } else {
                        $('#edit' + _base.ID()).css("display", "none");
                    }

                } else {
                    $('#edit' + _base.ID()).css("display", "none");
                    $('#clear' + _base.ID()).css("display", "none");
                }
				
				if(Application.HasOption(_base.Field().Options, "nodelete"))
					$('#clear' + _base.ID()).css("display", "none");

                //Issue #72 - Allow image download
                $('#ctl' + _base.ID()).taphold(function (ev) {
                    if(m_value){
                        Application.FileDownload.DownloadBlob("photo.jpg", m_value, "image.jpeg");
                        ev.preventDefault();
                        return false;
                    }
                })

                _base.Control().attr("src", m_baseImage);
            });
        };

        this.FormatValue = function (value_) {

            m_value = null;

            try {
                if (value_ == null) {
                    _base.Control().attr("src", m_baseImage);
                    $("#wrapper"+_base.ID()).attr("data-src",m_baseImage);
                } else {
                    _base.Control().attr("src", "data:image/png;base64," + value_);
                    $("#wrapper"+_base.ID()).attr("data-src","data:image/png;base64,"+value_);
                    m_value = value_;
                }
            } catch (e) {
                _base.Control().attr("src", m_baseImage);
                $("#wrapper"+_base.ID()).attr("data-src",m_baseImage);
            }

            m_loaded = true;
        };

        this.Update = function (rec_) {

            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.FormatValue(null);
                _self.Loaded(true);
                return;
            }

            if (value == null && !m_cleared) {
                _self.FormatValue(null);
                _self.Loaded(true);
                return;
            }
            m_cleared = true;

            _self.FormatValue(value);
            _self.Loaded(true);
        };
		
		this.SetSize = function(w){
			_base.Container().width(w);
		};
		
		this.SetupZoom = function(){
			$("#zoom"+_base.ID()).lightGallery({                
				cssEasing: 'cubic-bezier(1.000, 0.000, 0.000, 1.000)'
			});
		};

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.NoFocus = function () {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />
//  28/01/16    BA      Added new control
Define("InteractiveMap",

    function(field_, viewer_) {
        return new Control("InteractiveMap", field_, viewer_);
    },

    function() {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
        var m_form = null;
        var m_record = null;
        var m_pathProps = [];
        var m_selectList = [];
        var m_subpage = false;
        var m_mapID = -1;
        var m_desc = null;



        //#endregion

        //#region Public Methods
        // _base.Viewer() -> viewer obj
        this.Constructor = function() {
            //Setup _base.            
            _base = Base("InteractiveMap");
        };


        this.CreateDesktop = function(window_, form_) {
            m_form = form_;
            var tx = Application.OptionValue(m_form.Options, "transx");
            var ty = Application.OptionValue(m_form.Options, "transy");
            //Create the control.
            m_container = $('<div id="map-container' + _base.ID() + '" style="margin:30px 25px;">' +
                '<svg id="svg' + _base.ID() + '" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="460px"' +
                'viewBox="0 0 150 460" width="150" height="460" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">' +
                '<g id="map-group' + _base.ID() + '" transform="translate(' + (tx ? tx : 0) + ' ' + (ty ? ty : 0) + ')" fill-rule="evenodd" cursor="crosshair">' +
                '</g>' +
                '</svg>' +
                '<div id="map-desc' + _base.ID() + '" style="height:30px; width:200px;float:right;white-space:pre-line"></div></div>');

            window_.AddControl(m_container);
            m_desc = document.getElementById("map-desc"+_base.ID());
            _self.Loaded(true);
        };

        this.CreateMobile = function(window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function(value_) {
            //Not used.            
        };

        this.New = function() {};

        this.Update = function(rec_) {
            // window update, rec_ = recordset of page
            m_record = rec_;

            //clear the svg canvas first
            $('#map-group' + _base.ID()).html("");

            rec_.First();
            if (rec_.Count > 0){
                do {
                    // set up paths
                    AddSVGPath(rec_)
                } while (rec_.Next());
                //AttachHandlers();
            }
            _self.Loaded(true);
        };

        this.Height = function(h) {
            m_container.height(h - 70);
        };

        this.Width = function(w) {
            m_container.width(w - 20);
        };
        //#endregion

        //#region Private Methods
        function MakeSVGElement(tag, attrs) {
            var el = document.createElementNS('http://www.w3.org/2000/svg', tag);
            for (var a in attrs)
                el.setAttribute(a, attrs[a]);
            return el;
        }

        function AddSVGPath(rec_,parent_) {
            var path = MakeSVGElement('path', {id: rec_["PathID"], fill: rec_["PathFill"], d:rec_["Path"], mapid:rec_.ID, handle:(rec_.Skip ? false : true)});
            document.getElementById(Default(parent_, 'map-group' + _base.ID())).appendChild(path);

            if (!rec_["Skip"]){
                //attach event handlers
                path.addEventListener('mouseenter', _self.HoverIn, false);
                path.addEventListener('mouseleave', _self.HoverOut, false);
                path.addEventListener('click', _self.ClickHandler, false);

                var pathOpts = _self.GetOptions(rec_["PathID"]);
                //if property object already exists, overwrite it
                if (pathOpts) {
                    pathOpts.ref = path;
                } else {
                    // store in a new object
                    m_pathProps.push({
                        id: rec_["PathID"],
                        mapid: rec_.ID,
                        colour: rec_["PathFill"],
                        selected: false,
                        ref: path
                    });
                }
                if (!pathOpts || !pathOpts.selected){
                    // clear colouring
                    path.style.fill = '#FFF';
                }
            }
        };

        function ShadeColour(col,amt) {
            var hash = false;
            if ( col[0] == "#" ) {
                col = col.slice(1);
                hash = true;
            }
            var num = parseInt(col,16);
            var r = (num >> 16) + amt;
            var b = ((num >> 8) & 0x00FF) + amt;
            var g = (num & 0x0000FF) + amt;
            if ( r > 255 ) r = 255;
            else if  (r < 0) r = 0;
            if ( b > 255 ) b = 255;
            else if  (b < 0) b = 0;
            if ( g > 255 ) g = 255;
            else if  ( g < 0 ) g = 0;
            return (hash?"#":"") + (g | (b << 8) | (r << 16)).toString(16);
        }
        //#endregion        

        //#region Overrideable Methods
        this.HoverIn = function(ev) {
            ev = ev || window.event;
            var areaOpts = _self.GetOptions(ev.target.id);
            ev.target.style.fill = ShadeColour(areaOpts.colour,-30);
        };

        this.HoverOut = function(ev) {
            ev = ev || window.event;
            var areaOpts = _self.GetOptions(ev.target.id);
            if (!areaOpts.selected) {
                ev.target.style.fill = '#FFF';
            } else {
                ev.target.style.fill = areaOpts.colour;
            }
        };

        this.ClickHandler = function(ev) {
            ev = ev || window.event;
            var areaOpts = _self.GetOptions(ev.target.id);
            areaOpts.selected = !areaOpts.selected;

            if (areaOpts.selected) {
                m_selectList.push(ev.target.id);
            } else {
                m_selectList.splice(m_selectList.indexOf(ev.target.id), 1);
            }
            // show selections in window
            /*
            m_desc.textContent = m_selectList.reduce(function(prev, curr) {
                return prev + "\r\n" + curr;
            },"");
            */
        };

        this.GetOptions = function(aid) {
            return m_pathProps.filter(function(el) {
                return (el.id == aid);
            })[0];
        };

        this.Enabled = function(value_) {};

        this.OnValueChange = function(name, value) {
            return true;
        };

        //#endregion

        this.PageControl = function() {
            return true;
        };

        //Constructor
        this.Constructor();

    }
);
/// <reference path="../Application.js" />

Define("Kudos",

    function (field_, viewer_) {
        if (field_)
            field_.Enabled = false;
        return new Control("Kudos", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Kudos");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.            
            var container = $('<div id="' + _base.ID() + '" class="ui-widget ui-state-default" style="-moz-border-radius: 5px;-webkit-border-radius: 5px;border-radius: 5px; padding-bottom: 100px; margin-left: 10px; "><figure class="kudo kudoable" data-id="1" id="kudos' + _base.ID() + '"><a class="kudobject"><div class="opening"><div class="circle">&nbsp;</div></div></a><a href="#kudo" class="count"><div id="count' + _base.ID() + '" style="margin-top:5px; color: white; text-shadow: black 0.1em 0.1em 0.2em; font-weight:bold; font-size: 20pt;"></div><label class="txt" id="lbl' + _base.ID() + '" style="margin-top:5px; color: white; text-shadow: black 0.1em 0.1em 0.2em; font-weight:bold; text-transform:uppercase; font-size: 20pt;"></label></a></figure></div>');

            if (Application.UnsupportedIE()) {
                container = _base.CreateUnsupported();
            }

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                if (Application.UnsupportedIE()) {
                    container.width("95%");
                    return;
                }

                container.width("95%");
                $("#kudos" + _base.ID()).kudoable();

                $("#kudos" + _base.ID()).unbind("kudo:added");
                $("#kudos" + _base.ID()).bind("kudo:added", function (e) {
                    _self.OnValueChange(_base.Field().Name, "Yes");
                });

                $("#kudos" + _base.ID()).unbind("kudo:removed");
                $("#kudos" + _base.ID()).bind("kudo:removed", function (e) {
                    _self.OnValueChange(_base.Field().Name, "No");
                });

                var bg = Application.OptionValue(_base.Field().Options, "background");
                if (bg)
                    container.css("background", "url(http://" + bg + ") no-repeat center");
            });
        };

        this.FormatValue = function (value_, count_) {

            if (Application.UnsupportedIE())
                return;

            if (count_)
                $("#count" + _base.ID()).html(count_);

            if (value_ == "Yes") {
                $("#kudos" + _base.ID()).removeClass("animate").addClass("complete");
            } else {
                $("#kudos" + _base.ID()).removeClass("complete").addClass("animate");
            }
        };

        this.Update = function (rec_) {

            if (Application.IsInMobile())
                return _base.Update(rec_);

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined')
                return;

            var count = null;
            var cntField = Application.OptionValue(_base.Field().Options, "countfield");
            if (cntField) {
                if (cntField == "TestCount") {
                    count = 12;
                } else {
                    count = rec_[cntField];
                }
            }

            _self.FormatValue(value, count);
        };

        this.SetSize = function (width, height) {

        };

        this.SetupTest = function () {
            _base.Field().Options = "background:richthediabetic.com/wp-content/uploads/2013/07/Pizza.jpg;countfield:TestCount";
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("MultiCombobox",

    function (field_, viewer_) {
        return new Control("MultiCombobox", field_, viewer_);
    },

    function (field_) {

        //#region Members

        var _self = this;
        var _base = null;
        var m_button = null;
        var m_values = null;
        var m_skipFocus = false;
        var m_loaded = false;
        var m_value = null;
		var m_allSelected = null;
		var m_search = null;
        var m_record = null;
        var m_view = "";

        //#endregion

        //#region Public Methods

        this.Constructor = function (field_) {

            if (Application.testMode && arguments[0] == null) return;

            //Setup _base.            
            _base = Base("MultiCombobox");

            //Create option combo.
            if (field_.OptionString != "") {

                m_values = new Array();
                var vals = field_.OptionString.split(",");
                var captions = field_.OptionCaption.split(",");

                for (var i = 0; i < vals.length; i++) {
                    var item = new Object();
                    item.Display = captions[i];
                    if (field_.Type == "Integer") {
                        item.Value = parseInt(vals[i]);
                    } else {
                        item.Value = vals[i];
                    }
                    m_values.push(item);
                }

                return;
            }
        };

        this.CreateDesktop = function (window_) {

            var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px; text-align: left;"><select class="multiselector" multiple="multiple" id="ctl' + _base.ID() + '" style="width: 100%;"></select></td></tr></table></div>');

            var height = Default(Application.OptionValue(_base.Field().Options, "height"), 175);

			var filters = _base.Field().LookupFilters;
			if(typeof filters == "function")
				filters = _base.Field().LookupFilters();
			
            //Call base method.
            _base.Create(window_, container, _self.OnChange, function (cont) {
                cont.multiselectcombo({
                    classes: "app-control",
                    selectedList: parseInt(Default(Application.OptionValue(_base.Field().Options, "selectedlist"),"1")),
                    height: height,
					drilldown: _base.Field().LookupAdvanced,
					drilldownview: filters
                });
            });
        };

        this.CreateMobile = function (window_) {

            var container = $('<label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="font-weight: bold;"></label><select multiple="multiple" id="ctl' + _base.ID() + '" data-native-menu="false" data-theme="a"></select>');
            
            //Call base method.
            _base.Create(window_, container, function(){
				
				var sel = $("#ctl" + _base.ID());
				
				var allSelected = $("option:first", sel).attr("selected");
	
				if (m_allSelected && !allSelected) {
					$("#ctl" + _base.ID()+" option:selected").removeAttr("selected");
					m_allSelected = allSelected;
				}else if (!m_allSelected && allSelected) {
					$("#ctl" + _base.ID()+" option").attr("selected", "selected");
					m_allSelected= allSelected;
				}
				
				sel.selectmenu("refresh", true);
				
				var val = sel.val();
				
				//Remove select all value.
				try{
				
					var blank = val.indexOf(-1);
					if(blank >= 0)
						val.splice(blank,1);
				
				}catch(e){					
				}				
				
				_self.OnChange(_base.Field().Name,val);
				
			}, function (cont) {				
            });
        };

        this.GenerateData = function (value) {

            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();

            if (m_values != null) {

                if (m_loaded) {				
                    _base.Control().html("");
                }

                for (var i = 0; i < m_values.length; i++) {
                    var sel = ""
                    if (value && value.indexOf(m_values[i].Value.toString()) != -1) {
                        sel = " selected";
                    }
                    cont.append('<option value="' + m_values[i].Value + '"' + sel + '>' + m_values[i].Display + '</option>');
                }

                if (!Application.IsInMobile()) {
                    cont.multiselectcombo('refresh');
                } else {
                    cont.selectmenu();
                }

                if (typeof value != 'undefined')
                    cont.val(value);

                m_loaded = true;
                _self.Loaded(true);

                return;
            }

			m_value = value;
            return Application.LookupRecord(field, viewer, "", PopulateControl, null);
        };

        //#endregion

        //#region Private Methods

        function PopulateControl(result, value, displcol) {

            if (m_loaded) {
                //if (!Application.IsInMobile()) {
                    // _base.Control().multiselectcombo("destroy");
                // } else {
                    // _base.Control().selectmenu("destroy");
                //}				
				_base.Control().html("");
			}
				
            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();
			value = m_value;
			
            var allowblank = false;
            if (Application.HasOption(field.Options, "allowblank"))
                allowblank = true;
			
            var lastcat = "";
            var html = "";
			
			if(Application.IsInMobile())
				html += '<option value="-1">Select/Deselect All</option>';
			
			var added = [];
			
            for (var i = 0; i < result.length; i++) {

                if (allowblank || result[i].BlankRow == false) {

                    var sel = ""

                    if (value && value.indexOf(result[i][field.LookupField].toString()) != -1) {
                        sel = " selected";
                    }

                    if (field.LookupCategoryField != "") {
                        if (result[i].BoldField == null) {
                            result[i].BoldField = "No Group";
                        }
                        if (lastcat != result[i].BoldField) {
                            if (lastcat != "")
                                html += '</optgroup>';
                            html += '<optgroup label="' + result[i].BoldField + '">';
                        }
                        lastcat = result[i].BoldField;
                    }

					var val = result[i][field.LookupField];
					if(added.indexOf(val) == -1 || Default(field.LookupCategoryField,'') != ''){
						added.push(val);						
						html += '<option value="' + val + '"' + sel + '>' + result[i][field.LookupColumns] + '</option>';
					}                    

                }
            }
            if (lastcat != "")
                html += '</optgroup>';

            cont.append(html);

            if (!Application.IsInMobile()) {
				cont.multiselectcombo('refresh');
            } else {
                cont.selectmenu();
				cont.selectmenu("refresh");
            }            

            if (typeof value != 'undefined')
                cont.val(value);

            m_loaded = true;
            _self.Loaded(true);

        };

        //#endregion

        //#region Overloaded Methods

        this.Update = function (rec_) {

            m_record = rec_;
            var value = rec_[_base.Field().Name];
            if (value != null) {
                value = value.toString().split(",");
            }
			
            if (m_loaded) {
                if (typeof value == 'undefined') {
                    _self.Loaded(true);
                    return;
                }
                _base.Control().val(value);
                _self.Loaded(true);
            }

            //if (!m_loaded || Application.IsInMobile()) {
                return _self.GenerateData(value);
            //}
        };

        //#endregion

        //#region Overrideable Methods

        this.OnChange = function (name, value) {

            var val = _base.Control().val();
            if (val != null && val.list)
                val = val.list();

            return _self.OnValueChange(name, val);
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.SetSize = function (width, height) {

            _base.Container().width(width);
            
			if(!Application.IsInMobile()){
				_base.Control().width((width / 2) - 18);
				_base.Control().multiselectcombo("refresh");
			}
        };

        //#endregion

        //Constructor
        this.Constructor(field_);

    });
/// <reference path="../Application.js" />

Define("MultiDatePicker",

    function (field_, viewer_) {
        return new Control("MultiDatePicker", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("MultiDatePicker");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td style="width: 50%"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label></td><td style="width: 50%; padding-right: 10px;"><input type="text" id="ctl' + _base.ID() + '" style="width: 100%;"></input></td></tr></table></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                //Setup MultiDatePicker.
                cont.multiDatesPicker({
                    showOn: "none",
                    showButtonPanel: true,
                    changeMonth: true,
                    changeYear: true,
                    dateFormat: ("dd/MM/yy").toLowerCase(),
                    onClose: function (d) {
                        _self.OnValueChange(_base.Field().Name, d);
                    }
                });
                cont.click(function () {
                    cont.multiDatesPicker('show');
                });                

                $("#ui-datepicker-div").addClass("ui-custom-combo");

            });
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");

            var cont = $('<input>')
            .appendTo(container)
            .multiDatesPicker({
                showButtonPanel: true, 
                changeMonth: true, 
                changeYear: true,
                dateFormat: ("dd/MM/yy").toLowerCase()
            })
            .addClass("ui-widget ui-widget-content ui-corner-left")
	        .css("width", "80%")
	        .css("width", "calc(100% - 2px)");
            
            cont.val(value_);

            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        //#endregion

        //#region Overloaded Methods

        this.Update = function (rec_) {

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined')
                return;

            value = Default(value, "");
            _base.Control().multiDatesPicker("value", value)

        };

        this.Loaded = function (value_) {

            if (value_ !== undefined) { //SET

                _base.Loaded(value_);
                this.HideDropdown();

            } else { //GET

                return _base.Loaded();

            }

        };

        this.HideDropdown = function () {
            //_base.Control().multiDatesPicker("hide");
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("MultiSelect",

    function (field_, viewer_) {
        return new Control("MultiSelect", field_, viewer_);
    },

    function (field_) {

        //#region Members

        var _self = this;
        var _base = null;
        var m_values = null;
        var m_loaded = false;
		var m_value = null;
		var m_allSelected = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function (field_) {

            if (Application.testMode && arguments[0] == null) return;

            //Setup _base.            
            _base = Base("MultiSelect");

            //Create option combo.
            if (field_.OptionString != "") {

                m_values = new Array();
                var vals = field_.OptionString.split(",");
                var captions = field_.OptionCaption.split(",");

                for (var i = 0; i < vals.length; i++) {
                    var item = new Object();
                    item.Display = captions[i];
                    if (field_.Type == "Integer") {
                        item.Value = parseInt(vals[i]);
                    } else {
                        item.Value = vals[i];
                    }
                    m_values.push(item);
                }

                return;
            }
        };

        this.CreateDesktop = function (window_) {

            var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td style="width: 100%"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label><br/><select multiple="multiple" id="ctl' + _base.ID() + '"></select></td></tr></table></div>');

            var w = Default(Application.OptionValue(_base.Field().Options, "width"), 340);
            var h = Default(Application.OptionValue(_base.Field().Options, "height"), 300);

            //Call base method.
            _base.Create(window_, container, _self.OnChange, function (cont) {
                cont.css("width", w);
                cont.css("height", h);
            });
        };

        this.CreateMobile = function (window_) {

            var container = $('<label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="font-weight: bold;"></label><select multiple="multiple" id="ctl' + _base.ID() + '" data-native-menu="false" data-theme="a"></select>');
            
            //Call base method.
            _base.Create(window_, container, function(){
				
				var sel = $("#ctl" + _base.ID());
				
				var allSelected = $("option:first", sel).attr("selected");
	
				if (m_allSelected && !allSelected) {
					$("#ctl" + _base.ID()+" option:selected").removeAttr("selected");
					m_allSelected = allSelected;
					}else if (!m_allSelected && allSelected) {
					$("#ctl" + _base.ID()+" option").attr("selected", "selected");
					m_allSelected= allSelected;
				}
				
				sel.selectmenu("refresh", true);
				
				var val = sel.val();
				
				//Remove select all value.
				try{
				
					var blank = val.indexOf(-1);
					if(blank >= 0)
						val.splice(blank,1);
				
				}catch(e){					
				}				
				
				_self.OnChange(_base.Field().Name,val);
				
			}, function (cont) {				
            });
        };

        this.Options = function () {
            return {
                sortable: false,
                searchable: true,
                dividerLocation: 0.6,
                nodeComparator: function (node1, node2) {
                    var text1 = node1.text(),
			            text2 = node2.text();
                    return text1 == text2 ? 0 : (text1 < text2 ? -1 : 1);
                },
                onchange: function () {
                    return _self.OnChange(_base.Field().Name);
                }
            }
        };

        this.GenerateData = function (value) {

            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();

            if (m_values != null) {

                for (var i = 0; i < m_values.length; i++) {
                    var sel = ""
                    if (value && value.indexOf(m_values[i].Value.toString()) != -1) {
                        sel = " selected";
                    }
                    cont.append('<option value="' + m_values[i].Value + '"' + sel + '>' + m_values[i].Display + '</option>');
                }

                if (!Application.IsInMobile()) {
                    cont.multiselect(_self.Options());
                } else {
                    cont.selectmenu();
                }

                if (typeof value != 'undefined')
                    cont.val(value);

                m_loaded = true;
                _self.Loaded(true);

                return;
            }

			m_value = value;
            return Application.LookupRecord(field, viewer, "", PopulateControl, null);
        };

        //#endregion

        //#region Private Methods

        function PopulateControl(result, value, displcol) {

            if (m_loaded) {
                if (!Application.IsInMobile()) {
                     _base.Control().multiselect("destroy");
                // } else {
                    // _base.Control().selectmenu("destroy");
                }				
				_base.Control().html("");
			}
				
            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();
			value = m_value;
			
            var allowblank = false;
            if (Application.HasOption(field.Options, "allowblank"))
                allowblank = true;
			
            var lastcat = "";
            var html = "";
			
			if(Application.IsInMobile())
				html += '<option value="-1">Select/Deselect All</option>';
			
			var added = [];
			
            for (var i = 0; i < result.length; i++) {

                if (allowblank || result[i].BlankRow == false) {

                    var sel = ""

                    if (value && value.indexOf(result[i][field.LookupField].toString()) != -1) {
                        sel = " selected";
                    }

                    if (field.LookupCategoryField != "") {
                        if (result[i].BoldField == null) {
                            result[i].BoldField = "No Group";
                        }
                        if (lastcat != result[i].BoldField) {
                            if (lastcat != "")
                                html += '</optgroup>';
                            html += '<optgroup label="' + result[i].BoldField + '">';
                        }
                        lastcat = result[i].BoldField;
                    }

					var val = result[i][field.LookupField];
					if(added.indexOf(val) == -1 || Default(field.LookupCategoryField,'') != ''){
						added.push(val);
						html += '<option value="' + val + '" description="' + encodeURI(result[i][field.LookupColumns]) + '" ' + sel + '>' + result[i][field.LookupColumns] + '</option>';
					}

                }
            }
            if (lastcat != "")
                html += '</optgroup>';

            cont.append(html);

            if (!Application.IsInMobile()) {
                cont.multiselect(_self.Options());
            } else {
                cont.selectmenu();
				cont.selectmenu("refresh");
            }            

            if (typeof value != 'undefined')
                cont.val(value);

            m_loaded = true;
            _self.Loaded(true);

        };

        //#endregion

        //#region Overloaded Methods

        this.Update = function (rec_) {

            m_record = rec_;
            var value = rec_[_base.Field().Name];
            if (value != null) {
                value = value.toString().split(",");
            }
			
            if (m_loaded) {
                if (typeof value == 'undefined') {
                    _self.Loaded(true);
                    return;
                }
                _base.Control().val(value);
                _self.Loaded(true);
            }

            if (!m_loaded || Application.IsInMobile()) {
                return _self.GenerateData(value);
            }
        };

        //#endregion

        //#region Overrideable Methods

        this.OnChange = function (name, value) {

            var val = _base.Control().val();
            if (val != null && val.list)
                val = val.list();

            return _self.OnValueChange(name, val);
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.SetSize = function (width, height) {

            _base.Container().width(width);
            //_base.Control().width(width);
            //_base.Control().multiselect("refresh");
        };

        //#endregion

        //Constructor
        this.Constructor(field_);

    });
/// <reference path="../Application.js" />

Define("NotesBox",

    function (field_, viewer_) {
        return new Control("NotesBox", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var showlabel = true;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("NotesBox");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
			Application.RunSilent(function(){
				if (_base.Viewer().Page().FieldOption(_base.Field(), "hidelabel"))
					showlabel = false;
			});
            var rows = Default(Application.OptionValue(_base.Field().Options, "rows"), 1);
            var container = $('<div id="' + _base.ID() + '" style="display: none;"><table style="width: 100%"><tr><td id="lbltd' + _base.ID() + '" style="width: 50%; vertical-align: top"><label id="lbl' + _base.ID() + '" id= for="ctl' + _base.ID() + '" style="width: 100%; padding-left: 6px;"></label></td><td id="ctltd' + _base.ID() + '" style="width: 50%; padding-right: 10px;"><textarea id="ctl' + _base.ID() + '" style="width: 100%;" rows="' + rows + '"></textarea></td></tr></table></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                if (showlabel == false) {
                    $("#lbltd" + _base.ID()).hide();
                    $("#ctltd" + _base.ID()).css("width", "100%");
                }

                //Setup the textbox.
                var size = Default(_base.Field().Size,0);
                if (size == 0)
                    size = 1000000;
                cont.attr("maxlength", size);

            });
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="font-weight: bold;"></label><textarea cols="40" rows="8" id="ctl' + _base.ID() + '"></textarea>');

            //Call base method.
            _base.Create(window_, container, _self.FixValue, function (cont) {

                cont.textinput();

                //Setup the textbox.
                if (_base.Field().Size > 0) {
                    cont.attr("maxlength", _base.Field().Size);
                }

                if (_base.Field().Editable == false) {
                    cont.css("color", "#000");
                }
            });
        };

        this.CreateList = function (value_) {

            //Create the control.
            var container = $('<span>')
            .addClass("ui-combobox")
            .css("width", "100%");

            var cont = $('<input>')
            .appendTo(container)
            .val(value_)
            .attr("maxlength", _base.Field().Size)
            .attr("skipSelect", true) //Set this as we don't want to select the "base control"
            .focus(function (e) {
                CreateTextarea(cont);
            })
            .change(function () {
                $('#notes' + _base.ID()).val($(this).val());
                $('#notes' + _base.ID()).select();
            })
            .addClass("ui-widget ui-widget-content ui-corner-left")
	        .css("width", "80%")
	        .css("width", "calc(100% - 2px)");

            //Call base method.
            return _base.CreateList(container, cont, value_);
        };

        //#endregion

        //#region Private Methods

        function CreateTextarea(cont) {

            var val = cont.val();
            if (val != null)
                val = val.replace(/\<br\>/g, '\r\n');

            var txt = $('<textarea id="notes' + _base.ID() + '" rows="10" cols="50">')
            .css("position", "absolute")
            .css("left", cont.offset().left)
            .css("top", cont.offset().top)
            .appendTo("body")
            .val(val)
            .attr("maxlength", _base.Field().Size)
            .blur(function (ev) {				
                ReturnFocus(this);
            })
            .resizable({
                handles: "se"
            })
            .keydown(function (ev) {
                if (ev.keyCode === 27 || ev.keyCode === 9) {
                    ReturnFocus(this, ev);
                    ev.preventDefault();
                    return false;
                }
            })
            .addClass("ui-widget ui-widget-content ui-corner-left");
			
		setTimeout(function(){
			txt.select();
		},500); //Set timeout for Edge compat.

            function ReturnFocus(editor_, ev_) {

                if (ev_ == null) {
                    ev_ = jQuery.Event("keydown");
                    ev_.ctrlKey = false;
                    ev_.keyCode = 13;
                }

                var val = $(editor_).val();
                if (val != null)
                    val = val.replace(/(?:\r\n|\r|\n)/g, '<br>');

                if (ev_.keyCode != 27) {

                    cont.val(val);
                    cont.change();
                }

                if (_base.Viewer().Type() == "List")
                    cont.trigger(ev_);

                $(editor_).remove();
            }
        };

        //#endregion

        //#region Overrideable Methods

        this.Update = function (rec_) {
				
			if(rec_[_base.Field().Name] && Application.HasOption(_base.Field().Options,"hashtml"))
				rec_[_base.Field().Name] = Application.DecodeHTML(rec_[_base.Field().Name]);
		
            if (!Application.IsInMobile())
                return _base.Update(rec_);

            Application.LogInfo("Updating control: " + _base.ID() + ", Caption: " + _base.Field().Caption);
            
			var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.Loaded(true);
                return;
            }					

            if (value != null && Application.IsInMobile())
                value = value.replace(/\<br\>/g, '\r\n');

			if (!Application.IsInMobile()){
				_base.Control().val($.fn.fmatter(_base.Field().Mask, value));
			}else{
				_base.Control().val(value);
			}
			
            Application.RunNext(function () {
                _base.Control().keyup();
            });

            _self.Loaded(true);
        };

        this.FixValue = function (name, value) {

            if (value != null)
                value = value.replace(/(?:\r\n|\r|\n)/g, '<br>');

            _self.OnValueChange(name, value);
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.SetSize = function (width, height) {
            if (showlabel == false) {
                _base.Container().width(width);
                _base.Control().css("width", width - 30);
            } else {
                _base.SetSize(width, height);
            }
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("NumberBox",

    function (field_, viewer_) {
        return new Control("NumberBox", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("NumberBox");
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="font-weight: bold;"></label><input type="number" data-clear-btn="false" id="ctl' + _base.ID() + '" value="">');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                cont.textinput();

                //Setup the textbox.
                cont.attr("maxlength", _base.Field().Size);

            });
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });

/// <reference path="../Application.js" />

//27/01/15      Issue #7        PF      Added new control.

Define("PhotoGallery",

    function (field_, viewer_) {
        return new Control("PhotoGallery", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
        var m_form = null;
        var m_baseImage = UI.Icon("camera_large", 48, true);
        var m_record = null;
		var m_contextMenuOptions = null;
		var m_archiveButtons = [];
		var m_archivePeriods = [];

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("PhotoGallery");
        };

        this.CreateDesktop = function (window_, form_) {

            m_form = form_;

            //Create the control.
            m_container = $('<div id="' + _base.ID() + '" style="padding-top: 10px;overflow-y: auto;"><ul id="gallery' + _base.ID() + '" class="photo-gallery" style="margin-top: 0; margin-bottom: 9px; list-style-position: inside;"></ul></div>');

            window_.AddControl(m_container);

			if(Application.HasOption(form_.Options,"hidenew") == false)
				window_.AddButton("New", "document_new", "New", function () {
					return _self.New();
				});

            Application.RunNext(function () {
                window_.ShowActions();
            });

            _self.Loaded(true);
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function (value_) {
            //Not used.            
        };

        this.New = function () {
			_base.Viewer().ShowLoad();
            Application.Camera.TakePhoto(function (img) {
                Application.RunNext(function () {
                    return $codeblock(

                        Application.BeginTransaction,

                        function () {
                            return m_record.New();
                        },

                        function (r) {
                            m_record = r;
                            m_record[m_form.Fields[0].Name] = img;
                            return m_record.Insert(true);
                        },

                        function () {
                            AddImage(m_record);
                            RefreshGallery();
							_base.Viewer().HideLoad();
                        },

                        Application.CommitTransaction

                    );
                });
            },Application.OptionValue(m_form.Options,"quality"),Application.OptionValue(m_form.Options,"maxwidth")); 
        };

        this.Update = function (rec_) {

            m_record = rec_;

            m_archivePeriods.forEach(function(el){
                $('#gallery' + _base.ID() + el).html("");
            });
            
            $('#gallery' + _base.ID()).html("");

			for(var i = 0; i < m_archiveButtons.length; i++){
				m_archiveButtons[i].remove();
			}
			m_archiveButtons = [];
			m_archivePeriods = [];
			
			if(Application.HasOption(m_form.Options,"autoarchive"))
				eval("m_archiveButtons.push(_base.Viewer().AddButton('This Year', 'calendar', 'This Year', function () {var id = '#gallery' + _base.ID(); $('.photo-gallery').hide(); $(id).show(); RefreshGallery(id);}));");
			
			var today = new Date();
			
            rec_.First();
            if (rec_.Count > 0)
                do {

					if(Application.HasOption(m_form.Options,"autoarchive")){
						
						var dte = rec_[m_form.Fields[1].Name];
						
						if(dte){	
							var year = dte.getFullYear();							
							if(year != today.getFullYear()){
								if(m_archivePeriods.indexOf(year) == -1){
									
									m_archivePeriods.push(year);
									
									var g = $('<ul id="gallery' + _base.ID() + year + '" class="photo-gallery" style="margin-top: 0; margin-bottom: 9px; list-style-position: inside; display: none;"></ul>');
									m_container.append(g);
									
									AddImage(rec_, '#gallery' + _base.ID() + year);
									
									eval("m_archiveButtons.push(_base.Viewer().AddButton('"+year+"', 'calendar', '"+year+"', function () {var id = '#gallery' + _base.ID() + '"+year+"'; $('.photo-gallery').hide(); $(id).show(); RefreshGallery(id);}));");
								}
							}else{
								AddImage(rec_);	
							}
						}else{
							AddImage(rec_);
						}
						
					}else{
			
						AddImage(rec_);
						
					}

                } while (rec_.Next());

            RefreshGallery();
            _self.Loaded(true);
        };

        this.Height = function (h) {
            m_container.height(h - 70);
        };

        this.Width = function (w) {
            m_container.width(w - 20);
        };
		
		this.ContextMenuOptions = function(val){
			if(typeof val == "undefined"){
				return m_contextMenuOptions;
			}else{
				m_contextMenuOptions = val;
			}
		};

        //#endregion

        //#region Private Methods

        function AddImage(rec_, parent_) {

            var id = $id();

            var photo = rec_[m_form.Fields[0].Name];
			var rec = new Record();
			rec.Copy(rec_);

            if (photo == null) {
                photo = m_baseImage;
            }

            var maxheight = Default(Application.OptionValue(m_form.Options, "maxheight"), "100px");

			parent_ = Default(parent_,'#gallery' + _base.ID());
			
            $(parent_).append('<li data-src="data:image/jpeg;base64,' + photo + '" style="padding-left: 0; list-style: none; display: inline-block; padding: -3px;"><img id="img'+id+'" src="data:image/jpeg;base64,' + photo + '" style="max-height: ' + maxheight + '; display: inline-block;" /><a id="clear' + id + '" rid="' + m_record.Position + '" style="color: #FFF; position: relative; right: 15px; bottom: -4px; cursor: pointer; font-weight: bold; text-shadow: 1px 1px 2px #000; font-size: 23pt;">x</a></li>');

            //Issue #72 - Allow image download
            if (Application.IsInMobile()) {
                $('#img' + id).taphold(function (ev) {
                    Application.FileDownload.DownloadBlob("photo.jpg", photo, "image.jpeg");
                    ev.preventDefault();
                    return false;
                })
            }else{
                $('#img' + id).mousedown(function (ev) {
                    if (ev.which == 3) {
						var opts = [];
						if(m_contextMenuOptions && m_contextMenuOptions.options){
							opts = m_contextMenuOptions.options;
						}else{
							opts = [{ Name: "Download", ID: 1 }];
						}
                        UI.ContextMenu(opts, function (cmd) {
							if(m_contextMenuOptions && m_contextMenuOptions.onselect){
								m_contextMenuOptions.onselect(cmd, rec);
							}else{
								if (cmd == 1) {
									Application.FileDownload.DownloadBlob("photo.jpg", photo, "image.jpeg");
								}
							}
                        });
                        ev.preventDefault();
                        return false;
                    }
                });
            }

            $('#clear' + id).click(function (e) {
                e.stopPropagation();
                Application.Confirm("Are you sure you wish to delete this image?", function (r) {
                    if (r) {
                        Application.RunNext(function () {
                            return $codeblock(

                                Application.BeginTransaction,

                                function () {
                                    m_record.First();
                                    do {
                                        if (m_record.Position.toString() == $('#clear' + id).attr("rid")) {
                                            return m_record.Delete(true);
                                        }
                                    } while (m_record.Next());
                                },

                                function (r) {
                                    m_record = r;
                                },

                                Application.CommitTransaction,

                                function () {
                                    return _self.Update(m_record);
                                }
                            );
                        });
                    }
                });
            });
            
        };

        function RefreshGallery(parent_) {
			
			parent_ = Default(parent_,'#gallery' + _base.ID());
			
            Application.RunSilent($(parent_).lightGallery().destroy);
            $(parent_).lightGallery({                
                showThumbByDefault: true,
                addClass: 'showThumbByDefault',
                cssEasing: 'cubic-bezier(1.000, 0.000, 0.000, 1.000)'
            });
        };

        //#endregion        

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        this.PageControl = function () {
            return true;
        };

        //Constructor
        this.Constructor();

    });  
/// <reference path="../Application.js" />

Define("QueueItem",

    function (field_, viewer_) {
        if (field_)
            field_.Enabled = false;
        return new Control("QueueItem", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_page = null;
        var m_view = null;
        var m_record = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("QueueItem");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<table id="' + _base.ID() + '" style="width: 120px; max-width: 210px; display: inline-block; margin: 10px; height: 120px;"><tbody>'+
            '<tr><td><div id="bg'+_base.ID()+'" data-ripple style="padding: 4px; text-align: center; width: 100px; height: 100px; border: 0px; border-radius: 50%; cursor: pointer; background-color: whitesmoke; line-height: 100px;">'+
            '<i id="img' + _base.ID() + '" class="mdi mdi-format-vanish" style="font-size: 50px"></i></div>'+
            '<div id="ctl' + _base.ID() + '" style="font-size: 20px; width: 40px; height: 40px; border-radius: 50%; color: white; background-color: transparent;text-align: center;line-height: 40px;margin-top: -38px;position: relative;"></div>'+
            '</td></tr>'+
            '<tr><td id="lbl' + _base.ID() + '" style="font-size: 14px; text-align: center; width: 120px;"></td></tr></tbody></table>')
			
            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

				_base.Viewer().Main().css("padding-bottom","0px").css("padding-top","20px").css("text-align","center");

                cont[0].disabled = false;
                container.width(120);

                _base.Label().removeClass("app-label");
                cont.removeClass("app-control");

                $("#bg"+_base.ID()).ripple({ color: "gray"});                

                container.on("click", function (e) {

                    //Open the page viewer.
                    if (m_page)
                        Application.App.LoadPage(m_page, Application.MergeView(m_view, m_record), { caption: _base.Field().Caption, mode: Application.OptionValue(_base.Field().Options, "mode") }, _base.Viewer().ParentWindow().ID());
                });

                if(!Application.IsInMobile()){
                    container.qtip({
                        position: {
                            at: 'center right'
                        },
                        content: 'View ' + _base.Field().Caption,
                        style: {
                            tip: {
                                corner: false
                            }
                        }
                    });
                }

            });
        };

        this.CreateMobile = function (window_) {
            return this.CreateDesktop(window_);
        };

        this.FormatValue = function (value_, rec_) {

            var img = Application.OptionValue(_base.Field().Options, "queueimage");
            
            if (img)
                $('#img' + _base.ID()).attr("class", "mdi " + UI.MapMDIcon(UI.MapIcon(img)));

            var color = Application.OptionValue(_base.Field().Options, "queueimagecolor");
            if(color)
                $('#img' + _base.ID()).css("color",color);

            m_page = Application.OptionValue(_base.Field().Options, "queuepage");
            m_view = Application.OptionValue(_base.Field().Options, "queueview");

            var g_limit = Default(Application.OptionValue(_base.Field().Options, "queue_g"), 1);
            var r_limit = Default(Application.OptionValue(_base.Field().Options, "queue_r"), 999999);
            var y_limit = Default(Application.OptionValue(_base.Field().Options, "queue_y"), 999999);
            var b_limit = Default(Application.OptionValue(_base.Field().Options, "queue_b"), 0);

            if (value_ >= parseInt(b_limit)) {
                _base.Control().css("background-color", "Gainsboro");
            }
            if (value_ >= parseInt(g_limit)) {
                _base.Control().css("background-color", "#00CC00");
            }
            if (value_ >= parseInt(y_limit)) {
                _base.Control().css("background-color", "#F1C40F");
            }
            if (value_ >= parseInt(r_limit)) {
                _base.Control().css("background-color", "#FF9999");
            }
			
			_base.Label().css("display","");
			_base.Label().css("text-align","center");

            if (value_ == -1) {
                _base.Control().hide();
            } else {
                _base.Control().show();
                _base.Control().text(value_);
            }
				
        };

        this.CreateList = function (value_) {
            Application.Error('QueueItems can only be used in a card page.');
        };

        this.Update = function (rec_) {

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined')
                return;

            m_record = rec_;
            _self.FormatValue(value, rec_);
            _self.Loaded(true);
        };

        this.SetSize = function (width, height) {

        };
		
		this.Show = function () {
			_base.Show();
            _base.Container().css("display", "inline-block");            
        };

        this.SetupTest = function () {
            _base.Field().Options = "queueimage:check";
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.IgnoreColumns = function () {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("QueueItemNew",

    function (field_, viewer_) {
        if (field_)
            field_.Enabled = false;
        return new Control("QueueItemNew", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_page = null;
        var m_view = null;
        var m_record = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("QueueItemNew");
        };

        this.CreateDesktop = function (window_) {

            //Create the control.
            var container = $('<table id="' + _base.ID() + '" style="width: 120px; max-width: 210px; display: inline-block; margin: 10px; height: 120px;"><tbody>'+
            '<tr><td><div id="bg'+_base.ID()+'" data-ripple style="padding: 4px; text-align: center; width: 100px; height: 100px; border: 0px; border-radius: 50%; cursor: pointer; background-color: whitesmoke; line-height: 100px;">'+
            '<i id="img' + _base.ID() + '" class="mdi mdi-format-vanish" style="font-size: 50px"></i></div>'+
            '<div id="ctl' + _base.ID() + '" style="font-size: 20px; width: 40px; height: 40px; border-radius: 50%; color: white; background-color: transparent;text-align: center;line-height: 40px;margin-top: -38px;position: relative;"></div>'+
            '</td></tr>'+
            '<tr><td id="lbl' + _base.ID() + '" style="font-size: 14px; text-align: center; width: 120px;"></td></tr></tbody></table>')
			
            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

				_base.Viewer().Main().css("padding-bottom","0px").css("padding-top","20px").css("text-align","center");

                cont[0].disabled = false;
                container.width(120);

                _base.Label().removeClass("app-label");
                cont.removeClass("app-control");

                $("#bg"+_base.ID()).ripple({ color: "gray"});                

                container.on("click", function (e) {

                    //Open the page viewer.
                    if (m_page)
                        Application.App.LoadPage(m_page, Application.MergeView(m_view, m_record), { caption: _base.Field().Caption, mode: Application.OptionValue(_base.Field().Options, "mode") }, _base.Viewer().ParentWindow().ID());
                });

                if(!Application.IsInMobile()){
                    container.qtip({
                        position: {
                            at: 'center right'
                        },
                        content: 'View ' + _base.Field().Caption,
                        style: {
                            tip: {
                                corner: false
                            }
                        }
                    });
                }

            });
        };

        this.CreateMobile = function (window_) {
            return this.CreateDesktop(window_);
        };

        this.FormatValue = function (value_, rec_) {

            var img = Application.OptionValue(_base.Field().Options, "queueimage");
            
            if (img)
                $('#img' + _base.ID()).attr("class", "mdi " + UI.MapMDIcon(UI.MapIcon(img)));

            var color = Application.OptionValue(_base.Field().Options, "queueimagecolor");
            if(color)
                $('#img' + _base.ID()).css("color",color);

            m_page = Application.OptionValue(_base.Field().Options, "queuepage");
            m_view = Application.OptionValue(_base.Field().Options, "queueview");

            var g_limit = Default(Application.OptionValue(_base.Field().Options, "queue_g"), 1);
            var r_limit = Default(Application.OptionValue(_base.Field().Options, "queue_r"), 999999);
            var y_limit = Default(Application.OptionValue(_base.Field().Options, "queue_y"), 999999);
            var b_limit = Default(Application.OptionValue(_base.Field().Options, "queue_b"), 0);

            if (value_ >= parseInt(b_limit)) {
                _base.Control().css("background-color", "Gainsboro");
            }
            if (value_ >= parseInt(g_limit)) {
                _base.Control().css("background-color", "#00CC00");
            }
            if (value_ >= parseInt(y_limit)) {
                _base.Control().css("background-color", "#F1C40F");
            }
            if (value_ >= parseInt(r_limit)) {
                _base.Control().css("background-color", "#FF9999");
            }
			
			_base.Label().css("display","");
			_base.Label().css("text-align","center");

            if (value_ == -1) {
                _base.Control().hide();
            } else {
                _base.Control().show();
                _base.Control().text(value_);
            }
				
        };

        this.CreateList = function (value_) {
            Application.Error('QueueItems can only be used in a card page.');
        };

        this.Update = function (rec_) {

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined')
                return;

            m_record = rec_;
            _self.FormatValue(value, rec_);
            _self.Loaded(true);
        };

        this.SetSize = function (width, height) {

        };
		
		this.Show = function () {
			_base.Show();
            _base.Container().css("display", "inline-block");            
        };

        this.SetupTest = function () {
            _base.Field().Options = "queueimage:check";
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.IgnoreColumns = function () {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Receipt",

    function (field_, viewer_) {
        return new Control("Receipt", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_loaded = false;
        var m_baseImage = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAQDAwMDAwQDAwQFBAMEBQcFBAQFBwgGBgcGBggKCAgICAgICggKCgsKCggNDQ4ODQ0SEhISEhQUFBQUFBQUFBT/2wBDAQUFBQgHCA8KCg8SDwwPEhYVFRUVFhYUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAD6APoDAREAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAUGAwQHAQII/8QARRAAAQMBAgcKCgkFAQEAAAAAAAECAwQFEQYSFCExUnIVMjM0QVORocHREyI1UVRicYGTskJEYXSCg5KxwhYjQ3PhJGP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fqqjUVy5kTSoGPKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIH2yRkmdjkddpuA+gMVTxeXYUCBA9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEnZfBv2uwDfAxVPF5dhQIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk7L4N+12Ab4GKp4vLsKBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJ2Xwb9rsA3wMVTxeXYUCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTsvg37XYBvgYqni8uwoEEAAAAADToA9xXeZQGK7zKB4AAZtK5k5VUCkWjhxUeHcyyo48natyTSpjK+7lRM1yAaf9b255qb4f/QPf64tvVpvh/8AQPP64tvVpvh/9A9/ri2tSm/QveA/ri2tSm/QveB6mHNs8sdKv4F7wLVYVvwW3E9Eb4Grizyw335l+k1eVAJcAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAApWGtp1cdTFZ0EjooPBeFkxFxVcrlVEvVORLgKl4efnpP1u7wHh6jnpP1u7wL/gdaNTXUEsdU9ZH00iNZI7O5WuS9EVeW64CxgROE1XkViVUiLc+VPAM9smZeq8Dl4AAAAAAAEjYVfuba1NVKt0WN4Ob/W/MvRpA6qAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAaQOe4ceWWfdmfu4CtgALxgFxau/2x/KoFuApWHlZe6js9q5m408nv8VvaBTgAAAAAAAPAOpYOV+6Nj08zlvmjTwM21Hmv96XASoAAAAXKAAAAAEnZfBv2uwDfAxVPF5dhQIIAAA1bRroLMopa6o4OJMzU0ucuhqe0Dm1o4QWrab1dLO6KFd7TxKrGInuzr7wI1VVc7lVV865wPAAHqOcmhVT2KAx36zulQPL1XTnAAAAAAAAAAPUc5NCqnsUD3Hfru6VAY79d3SoDHfru6VAY79d3SoH0yeeNcaOaRjk0K1yp+wFswbwqqXVDLPtR/hWSriw1Lt+1y6Ed50XzgXYAAAk7L4N+12Ab4GKp4vLsKBBAAAFQw9lclNRU6b18r3u/AlyfMBSAAAAAAAAAAD6jjkmdiQsdI7VYiuXqA32WBbciXts+e77W3fvcB8S2Na8CY0tDUNb58RV/a8DRXMuKuZyaUXSAAAAAAAAAAeXq3xk0tzp7gOx08izU8My6ZImPX2uaigZAAEnZfBv2uwDfAxVPF5dhQIIAAApmHv1D83+IFMAAAAAAAA+4YZqiVkFOx0s0i3Mjal6qoF1srAmCNEmth3hZdOTMW6NNp2l3uAtUEEFKxIqaJkMaaGxojf2Ay3LygM6Z+sDTrrLs+0mK2tp2S+vdc9PY5M4FKtrA+ooWuqbOV1TStzviXhWJ/JOsCsAegAAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAAH1HG+WRsUTVfK9UaxiaVVdCAdMwfsGGxae91z7QkT+/N5vUb9idYGzatr0VjwpLVu8d/BQt37/AGfZ9oFGtDC6161ypC/I4ORkW/u+1+noAhXzzyLjSSyPd53OVVAyQV1dSuxqapmid6r1/bQBZLKw2qYnNitZnh4fSI0ukb7W6HAXanqIamFlTTSJJC9L2SN0AVDCzB1qNfa9Ay67PWQt0Xc41Pm6QKYAAAAAADx29X2AdfoPJ9H93j+VANgABJ2Xwb9rsA3wMVTxeXYUCCAAAKZh79Q/N/iBTAAAAAAAXDAiy0c+S15kvxL4qW/W+m73aALXadoQWXRS1s+drEuYzle9d61PaByutrai0Kp9ZVuxppOhE5Gp5kQDAAAAAJnBy3H2NVYkiqtnTO/vs1V5xPtTlA6Z4rk5HMcntRUXvA5dhBZe5Npy07E/8z/7tPsO5PwrmAiwAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAPFzIB1qyKRKCzKSlTSyJFftu8Z3WoFQw4rllrobOav9unZ4R6f/STuaBVQAAAAAAdHwPrlrLIbE9b5aR3gV2NLOrMBqYdUqSUFPWonjwS4ir6kn/UAoYAAAAAeO3q+wDr9B5Po/u8fyoBsAAJOy+DftdgG+BiqeLy7CgQQAABTMPfqH5v8QKYAAAAAGSnbj1ELF0OlYi+9yAdjVPGu+24DlOEEiy25aD159W+5uYCOAAAAAABb8ApFyivi5FiY/wB6Ou7QJ/CpiPwfrb/ota9PwuQDmIAAAAAeO3q+wDr9B5Po/u8fyoBsAAJOy+DftdgG+BiqeLy7CgQQAABTMPfqH5v8QKYAAAAAH3C/wc0UmpIx3Q5AOyKt64yaFzgcrwjhWC3a9i8suOnsel4EYAAAAAAC4YBRL4Wvn+ijGR+9VVewCdwrkSPB+s9dGsT8TkA5kAAAAAHjt6vsA6/QeT6P7vH8qAbAACTsvg37XYBvgYqni8uwoEEAAAUzD36h+b/ECmAAAAAB4qXpcB1awqxK+yKWovvf4NI5NuPxVArOHVAqSwWoxPFengJl9ZN4vvTMBUAAAAAA80ZwOm4LWe6z7IiSRMWeoXw8icqY29T3NAi8O6tG01LQIvjSvWZ6eqzMnWoFHAAAAADx29X2AdfoPJ9H93j+VANgABJ2Xwb9rsA3wMVTxeXYUCCAAAKZh79Q/N/iBTAAAAAAAWnAu1kpqp9mTrdDVLjQqvJMnJ+JALtWUkFdSy0dS3GhmbiuTlTzKn2oBy61bKqbHqlpqlL2rnhm+jI3zp9vnQDRAAAAFkwWwedaEza+rZdZ8Tr2Iv8AlenInqpygdAkkZEx80zkbExFdI9dCNTSoHKbYtF1rWjNWrejHLiwtXkjbvU7QNEAAAAAPHb1fYB1+g8n0f3eP5UA2AAEnZfBv2uwDfAxVPF5dhQIIAAApmHv1D83+IFMAAAAAAAzpnRblTQqAdDwawkZabG0VY5G2k1LkVcyTInKnredAJusoqW0IFpq2JJYV5F0ovnavIoFNtDAeqjVX2ZMk8fJFL4kie/QoEJJg/bkS4r7Pn/C3GTpS8DLBgzb1QtzaJ8aa0t0adYFjsvAmCFzZrVkSocmdKdl6R3+sulwFsRGsbclzI2Jsta1OpEQCg4UYSJaF9nUDv8AwtX+9Kn+VU5E9VOsCsAAAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAAABnRUVMyot6KmlFAtdk4az06JBarFqYkzJUM4VNpNDgLZR21ZVeiZNVxucv0HLiP/AEuuAkEv5OoD5e5GJjSORqedy3fuBD12FFjUKKiz5RKn+KDx1/VvUApds4S19r3w8XouYYu+23cvs0AQwAAAAAAAHjt6vsA6/QeT6P7vH8qAbAACTsvg37XYBvgYqni8uwoEEAAAVLDyBzqSjqU3scrmP/Gmb5QKMAAAAAAAAAAeXIukD7bLMzMyWRqeZHuTtA8c57+Ec5+0qu/cDwAAAAAAAAAAYrnqjGpe5y4rU+1cwHYoI/AwRQ81G1n6UuAyAAJOy+DftdgG+BiqeLy7CgQQAABr1tHBaFJLRVKXwypc67SnmVPtRQOd2jgra9A9fBwrV0/0ZoUvzes3SigRuQV/olR8N3cAyCv9EqPhu7gGQV/olR8N3cAyCv8ARKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/AESo+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwH1HZdpzOxY6Koc7/W4C24OYKS0s7LQtS5JI88FMme52s9dGbkQC3gAAEnZfBv2uwDfAxVPF5dhQIIAAAAAPcZ3nUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBjOXSqgeAAAACTsvg37XYBvgYqni8uwoEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEnZfBv2uwDfAxVPF5dhQIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk7L4N+12Ab4GKp4vLsKBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJ2Xwb9rsA3wPmRiSMcxdDkuA09y4dd/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QGxT07adFa1VW9b84GYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//9k=";
        var m_cleared = false;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Receipt");
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<div id="' + _base.ID() + '" style="padding: 10px; text-align: center;"><img id="ctl' + _base.ID() + '" src="" style="max-width: ' +
                150 + 'px; max-height: ' + 300 +
                'px;" /><br/><div id="acc' + _base.ID() + '"></div><br/><input id="file' + _base.ID() + '" type="file" style="visibility: hidden;position: absolute;top: 0;left: -5000px;" /><br/><a id="clear' + _base.ID() + '" data-role="button" data-icon="delete" data-theme="c" data-inline="true">Delete</a></div>');

            if (Application.UnsupportedIE() || !window.FileReader) {
                container = _base.CreateUnsupported();
            }

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                if (Application.UnsupportedIE() || !window.FileReader) {
                    return;
                }

                if (_base.Field().Editable) {

                    $('#clear' + _base.ID()).buttonMarkup().click(function () {
                        Application.Confirm("Are you sure you wish to delete this image?", function (r) {
                            if (r) {

                                m_loaded = false;

                                _self.OnValueChange(_base.Field().Name, null);
                                m_cleared = true;
                                $('#file' + _base.ID()).val("");
                            }
                        });
                    });

                    if (window.FileReader) {

                        $('#ctl' + _base.ID()).click(function () {
                            $('#file' + _base.ID()).click();
                        });
                        $('#file' + _base.ID()).fileReaderJS({
                            on: {
                                load: function (url) {

                                    m_loaded = false;
                                    $('#file' + _base.ID()).val("");
                                    _base.Viewer().ShowLoad();

                                    _self.ResizeForProcessing(url);

                                }
                            }
                        });
                    }

                } else {
                    $('#clear' + _base.ID()).css("display", "none");
                }

                _base.Control().attr("src", m_baseImage);
            });
        };

        this.ResizeForProcessing = function (img) {
            UI.ImageManager.Resize(img, 1000, 0, 0, function (img) {
                _self.ResizeForSave(img);
            });
        };

        this.ResizeForSave = function (img) {

            UI.ImageManager.Resize(img, 200, 0, 0, function (imgsave) {

                _self.OnValueChange(_base.Field().Name, UI.ImageManager.Base64(imgsave));

                //Process after save.
                ProcessImage(UI.ImageManager.Base64(img));
            });
        };

        this.FormatValue = function (value_) {

            try {
                if (value_ == null || value_ == m_baseImage) {
                    _base.Control().attr("src", m_baseImage);
                } else {
                    _base.Control().attr("src", "data:image/png;base64," + value_);
                }
            } catch (e) {
                _base.Control().attr("src", m_baseImage);
            }

            m_loaded = true;
        };

        this.Update = function (rec_) {

            Application.LogInfo("Updating mobile control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            if (m_loaded) {
                _self.Loaded(true);
                return;
            }

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined' || value == "") {
                _self.FormatValue(m_baseImage);
                _self.Loaded(true);
                return;
            }

            if (value == null && !m_cleared) {
                _self.Loaded(true);
                return;
            }
            m_cleared = true;

            _self.FormatValue(value);
            _self.Loaded(true);
        };

        //#endregion

        function ProcessImage(img_) {

            var id = $id();
            Application.RunNext(function () {

                return Application.FileDownload.UploadFile("Receipt" + id, img_, function (file) {

                    _base.Viewer().ShowLoad();

                    Application.OCR.Process(file.Name, 2, "TOTAL", 3, "Decimal", function (match_) {

                        _base.Viewer().HideLoad();

                        Application.RunNext(function () {
                            //TODO: Replace this
                            alert("TODO: Replace this");
                            //return Application.Settings.ReceiptFinish(_base, match_);
                        });
                        Application.RunNext(_self.NextPage);

                    });

                });
            });

        };

        this.NextPage = function () {
            if (_base.Viewer().NextStep) {
                _base.Viewer().NextStep();
            }
            _base.Viewer().HideLoad();
        };

        //#region Overrideable Methods

        this.IgnoreColumns = function () {
            return true;
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

Define("Report",

    function (field_, viewer_) {
        return new Control("Report", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
        var m_data = null;
        var m_form = null;
        var m_design = null;
        var m_mergeFields = new Object();
        var m_record = null;
        var m_view = null;
		var m_baseView = null;
		var m_filterOptions = "";
		var m_reportOptions = null;
		var m_uid = null;
		var m_filterData = new Object();
		var m_groupFields = null;
		var m_groupFieldCaptions = null;
		var m_emailOptions = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Report");
        };

        this.CreateDesktop = function (window_, form_) {

            m_form = form_;
			
			m_uid = form_.Name + _base.Viewer().View();

            //Create the control.
            m_container = $('<div id="' + _base.ID() + '" style="width: 100%; height: auto;"></div>');
            //m_container.css("min-height", UI.Height() - 100);

            //Base design.
            m_design = "<div style='width: 100%; height: auto; font-family: Arial; font-size: 12px;'><table style='width: 100%;'>";
            m_design += "<tr><td style='vertical-align: top;'>%logo<h2>%title</h2></td><td style='width: 200px; text-align: right;'>Date: %date<br/>%userid</td></tr>";
            m_design += "<tr><td colspan='2'>%filters</td></tr>";
			m_design += "<tr><td colspan='2'><br/>%description</td></tr>";
            m_design += "<tr><td colspan='2'><table cellspacing='0' cellpadding='5'>";
            m_design += "<thead><tr style='background-color: "+$('.navbar-inner').css('background-color')+"; color: "+$('.navbar').css('color')+"; -webkit-print-color-adjust: exact;'>%columns</tr></thead>";
            m_design += "%rows";
            m_design += "</table></td></tr>";
            m_design += "</table></div>";

            //Base merge fields.
            m_mergeFields["%title"] = m_form.Caption;
            m_mergeFields["%date"] = $.format.date(new Date(), "dd/MM/yyyy");
            m_mergeFields["%userid"] = Application.auth.Username;
            m_mergeFields["%columns"] = "<th style='font-weight: bold; width: %columnwidthpx; text-align: %colalign; font-size: 12px;'>%columncaption</th>";
            m_mergeFields["%rows"] = "<tr>%cells</tr>";
            m_mergeFields["%cells"] = "<td style='text-align: %cellalign; font-size: 12px;'>%cellvalue</td>";
			m_mergeFields["%description"] = "";
			m_mergeFields["%filters"] = "";
			m_mergeFields["%logo"] = "";
			
            window_.AddControl("<br/>");
			
            window_.AddControl("<a id='btnPrint" + _base.ID() + "'>" + UI.IconImage("mdi-printer") + " Print</a>");
            $("#btnPrint" + _base.ID()).button().hide().click(function () {
				
				var landscape = Application.HasOption("landscape",m_form.Options);
				
				var printfunc = function(){
					var w = 800;
					var h = 800;
					var left = (screen.width/2)-(w/2);
					var top = (screen.height/2)-(h/2);					
					var wnd = window.open('', m_uid, 'left=0,top=0,width='+w+',height='+h+',toolbar=0,scrollbars=0,status=0, top='+top+', left='+left);
					_base.Viewer().ShowLoad();
					setTimeout(function(){
						wnd.document.write("<html><head><title>Print Preview</title><style>@media print {thead {display: table-header-group;}}</style></head><body>" + m_container.html() + "</body></html>");
						wnd.document.close();
						wnd.focus();
						wnd.print();
						wnd.close();
						_base.Viewer().HideLoad();
					},2000);
				};
				
				if(landscape){
					Application.Message("Before printing, please select 'Preferences' and change orientation to landscape.",function(){
						printfunc();
					});					
				}else{
					printfunc();
				}					
            });
			
			if(!Application.HasOption(m_form.Options,"skipfilters")){
				window_.AddControl("<a id='btnFilters" + _base.ID() + "'>" + UI.IconImage("mdi-filter") + " Filters</a>");
				$("#btnFilters" + _base.ID()).button().hide().click(function () {
					_self.ShowFilters();
				});				
			}
			
			window_.AddControl("<a id='btnExportCSV" + _base.ID() + "'>" + UI.IconImage("mdi-file-import") + " Export to CSV</a>");
            $("#btnExportCSV" + _base.ID()).button().hide().click(function () {
                _self.ExportCSV();
            });

			window_.AddControl("<a id='btnEmailPDF" + _base.ID() + "'>" + UI.IconImage("mdi-email") + " Email PDF</a>");
            $("#btnEmailPDF" + _base.ID()).button().hide().click(function () {
				var data = GenerateReportData(m_record);
                _self.EmailPDF(data);
            });
			
			if(!Application.HasOption(m_form.Options,"skipfilters")){
				window_.AddControl("<label id='filters"+_base.ID()+"' class='ui-state-hover' style='display: none; font-size: 11px; width: auto; float: right; margin-right: 10px; padding: 3px; max-width: 500px;'></label>");
				$("#filters"+_base.ID()).click(function(){
					_self.ShowFilters();
				});
			}
			
			if(Application.IsInMobile()){
				$("#btnFilters" + _base.ID()).parent().css("width","100px").css("display","inline-block");
				$("#btnPrint" + _base.ID()).parent().css("width","100px").css("display","inline-block");
				$("#btnExportCSV" + _base.ID()).parent().css("width","100px").css("display","inline-block");
				$("#btnEmailPDF" + _base.ID()).parent().css("width","100px").css("display","inline-block");
			}
			
            window_.AddControl(m_container);				

            var options = m_form.Options;
            m_groupFields = Application.OptionValue(options, "groupfields");
            m_groupFieldCaptions = Default(Application.OptionValue(options, "groupfieldcaptions"), m_groupFields);

            _self.Loaded(true);

			m_baseView = _base.Viewer().View();				
			
			if(!Application.HasOption(m_form.Options,"skipfilters"))
				_self.ShowFilters();
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

		this.ShowFilters = function(){
			
			//Show filters.
            Application.RunNext(function(){
				
				return $codeblock(
				
					function(){
						return _self.LoadReportOptions();
					},
				
					function(){	
						
						if(!m_reportOptions)
							m_reportOptions = new Object();										
						
						var opts = {
							page: m_form,
							view: Application.CombineViews(m_filterOptions, m_baseView),
							caption: _base.Viewer().Options()["caption"],
							filtercolumns: Application.OptionValue(m_form.Options, "filtercolumns"),
							optionvalues: m_reportOptions,
							addfilterdata: _self.AddFilterData
						};
						
						var options = null;
						
						if(typeof _self.OptionsPage != "undefined"){
							options = _self.OptionsPage(opts);							
						}else{
							options = new OptionsWindow(opts);
						}
						
						if(options.CloseFunction() == null){
							
							options.CloseFunction(function(okclicked){    
							
							  if(okclicked){
								  
								m_reportOptions = options.GetOptions();
								m_view = options.GetView();
								m_filterOptions = options.GetView();
								_self.SaveReportOptions();
								if (m_view == null)
									return _base.Viewer().Close();
								
								return _self.ApplyView();
								
							  }else{
								  
								if(m_view == null)
									return _base.Viewer().Close();
								
							  }
							  
							});							
						}
						
						if(options.AddField)
							options.AddField({
								Name: "PrintFilters",
								Caption: "Print Filters",
								Type: "Boolean",
								Mandatory: false							
							});
						
						return options.Open(_base.Viewer());
					}
				);
			});
			
		};
		
        this.Update = function (rec_) {
			
            m_record = rec_;

			if(Application.HasOption(m_form.Options,"skipfilters"))
				m_view = _base.Viewer().View();
			
            if (m_view == null)
                return;
			
			_self.SetFilters();

            //Show controls.
            $("#btnPrint" + _base.ID()).show();
			$("#btnFilters" + _base.ID()).show();
			$("#btnExportCSV" + _base.ID()).show();
			$("#btnEmailPDF" + _base.ID()).show();

            //Update title.
            m_mergeFields["%title"] = _base.Viewer().Options()["caption"];
			
			if(m_reportOptions && m_reportOptions.PrintFilters)
				m_mergeFields["%filters"] = GetFilters();
			
			var logo = _self.GetLogo();
			if(logo){
				m_mergeFields["%logo"] = "<img src='data:image/png;base64,"+logo+"' /><br/>";
			}

            m_data = GenerateReportData(rec_);

            _self.CreateReport(m_data);
        };        

        this.AddMergeField = function (key_, value_) {
            m_mergeFields[key_] = value_;
        };
		
		this.MergeFields = function(){
			return m_mergeFields;
		};

        this.CreateReport = function (data_) {

            //Clear container.
            m_container.html("");

			var html = "";
			html = _self.GenerateHTML(data_);
			
			for (var mf in m_mergeFields) {
                eval("html = html.replace(/" + mf + "/g, \"" + m_mergeFields[mf] + "\");");
            }

			//html = Application.ProcessCaption(html);
			
            m_container.html(html);
        };

        this.GenerateHTML = function (data_) {

            if(data_.length == 0)
                return "<h2>&nbsp;&nbsp;Oops, no report data found. Please check your filters and try again.</h2>";

            var html = m_design.toString();

            //Get columns.
            var cols = "";
            for (var i = 0; i < m_form.Fields.length; i++) {
                var align = "left";
                var f = m_form.Fields[i];                
                if ((f.Type == "Decimal" || f.Type == "Integer") && f.LookupDisplayField == "") align = "right";
				if(Application.HasOption(f.Options,"leftalign"))
					align = "left";
				if(Application.HasOption(f.Options,"rightalign"))
					align = "right";
                cols += m_mergeFields["%columns"]
                    .replace(/%columncaption/g, m_form.Fields[i].Caption)
                    .replace(/%columnwidth/g, m_form.Fields[i].Width)
                    .replace(/%colalign/g, align);
            }

            //Grouping.
            var lastgroup = [];
            var groups = [];
            var groupcaptions = [];
            if (m_groupFields) {
                groups = m_groupFields.split(",");
                groupcaptions = m_groupFieldCaptions.split(",");
                lastgroup = new Array(groups.length);
            }

            //Totals.
            var totals = [];
            var hasTotals = false;

            //Get rows.           
            var rows = "";
			var first = true;
            for (var i = 0; i < data_.length; i++) {

                for (var k = 0; k < groups.length; k++) {
                    if (lastgroup[k] != data_[i][groups[k]]) {                        
                        if (hasTotals)
                            rows += PrintTotals(totals);                        
                        lastgroup[k] = data_[i][groups[k]];
                        var f = _base.Viewer().Table().Column(groups[k]);
                        if (f) {
                            var val = Default(data_[i]["FF$"+groups[k]], data_[i][groups[k]]);
							var f2 = m_form.GetField(f.Name);
							if(!first && f2 && Application.HasOption(f2.Options,"pagebreak"))
								rows += "<tr><td colspan='" + m_form.Fields.length + "'>"+$PAGEBREAK+"</td></tr>";
							var grpcap = groupcaptions[k] + ": " + FormatData(val, f);
							if(Application.HasOption(m_form.Options,"hidegrpcaption"))
								grpcap = FormatData(val, f); 
                            rows += "<tr><td colspan='" + m_form.Fields.length + "' style='background-color: Gainsboro; -webkit-print-color-adjust: exact; font-weight: bold;'>" + grpcap + "</td></tr>";
							first = false;
                        }
                    }
                }

                var cells = "";                
                for (var j = 0; j < m_form.Fields.length; j++) {

                    if (totals.length != m_form.Fields.length)
                        totals.push(-1);

                    var align = "left";
                    var f = m_form.Fields[j];                    
                    if ((f.Type == "Decimal" || f.Type == "Integer") && typeof data_[i]["FF$" + f.Name] == "undefined") align = "right";
					
					if(Application.HasOption(f.Options,"leftalign"))
						align = "left";
					if(Application.HasOption(f.Options,"rightalign"))
						align = "right";
					
                    var val = Default(data_[i]["FF$"+f.Name],data_[i][f.Name]);  
					val = GetDisplayValue(f.Name,val);
					
					if(Application.HasOption(f.Options,"showvalue"))
						val = data_[i][f.Name];
										
                    cells += m_mergeFields["%cells"]
                        .replace(/%cellvalue/g, FormatData(val,f))
                        .replace(/%cellalign/g, align);
                    var tt = Application.OptionValue(f.Options,"totalstype");
                    if (tt) {
                        var reset = false;
                        var val2 = Default(data_[i]["FF$" + f.Name], data_[i][f.Name]);
                        if (totals[j] == -1) {
                            totals[j] = 0;
                            reset = true;
                        }
                        hasTotals = true;
                        if (tt == "Count") {
                            totals[j] += 1;
                        }
                        if (tt == "Sum") {
                            totals[j] += val2;
                        }
                        if (tt == "Avg") {
                            if (reset) {
                                totals[j] = [];
                                totals[j][0] = 0;
                                totals[j][1] = 0;
                            }
                            if (val2 != 0) {
                                totals[j][0] += val2;
                                totals[j][1] += 1;
                            }
                        }
                        if (tt == "Min") {
                            if (val2 < totals[j] || reset)
                                totals[j] = val2;
                        }
                        if (tt == "Max") {
                            if (val2 > totals[j] || reset)
                                totals[j] = val2;
                        }
                    } 
                }                
                rows += m_mergeFields["%rows"].replace(/%cells/g, cells);
            }

            if (hasTotals)
                rows += PrintTotals(totals);

            html = html.replace(/%columns/g, cols);
            html = html.replace(/%rows/g, rows);            

            return html;
        };					
		
		this.SetFilters = function () {

            var filtertxt = "";
			var filterbox = $("#filters"+_base.ID());

            //Hide the filter text.            
            filterbox.css("display", "none");

			if(Application.HasOption(m_form.Options,"hidefilters"))
				return;
			
            filtertxt = GetFilters();

            if (filtertxt != "")
                filterbox.css("display", "");

            filterbox.html(filtertxt);

            //Resize.
            //_base.Viewer().ResizeParent();
        };	
		
		this.ApplyView = function(){
			return $codeblock(
				function () {
					m_record.View = m_view;
				},
				function(){
					var maxrows = Default(Application.OptionValue(m_form.Options,"maxrows"),0);
					if(maxrows > 0){						
						COUNT(m_record.Table, m_record.View.replace(Application.GetSorting(m_record.View),""), function(c){
							if(c.Count > maxrows){
								var w = $wait();
								Application.Confirm("There are more than "+maxrows+" records. Do you wish to continue?",function(b){								
									w.resolve(!b);									
								});
								return w.promise();
							}
						});
					}
				},
				function(ret){
					if(ret)
						Application.Error("");
					return m_record.FindFirst();
				},
				function (r) {
					m_record = r;
					return _self.Update(m_record);
				}
			);
		};
		
		this.LoadReportOptions = function () {

            m_reportOptions = null;
			m_filterOptions = "";
			
			return $codeblock(

                function () {
                    return Application.GetUserLayout(Application.auth.Username, "REPORT" + m_form.Name);
                },

                function (layout) {

                    if (layout != "") {
                        var l = $.parseJSON(layout);
                        m_reportOptions = Default(l.options, null);
						m_filterOptions = Default(l.filters, null);
						m_filterData = Default(l.filterdata, new Object());
						m_emailOptions = Default(l.emailoptions, null);
                    }

                }
            );
        };

        this.SaveReportOptions = function () {

			Application.RunNext(function () {

				if(!_self) return;
				               
                var l = new Object();
                l.options = m_reportOptions;
				l.filters = m_filterOptions;
				l.filterdata = m_filterData;
				l.emailoptions = m_emailOptions;
				
                return Application.SaveUserLayout(Application.auth.Username, "REPORT" + m_form.Name, $.toJSON(l));                 

            },null,null,true);
        };
		
		this.EmailPDF = function(){					
			
			Application.RunNext(function(){
				return $codeblock(
					function(){
						FINDSET("Xpress Email Setup",null,function(setup){
							if(setup.Count == 0)
								Application.Error("Email is not setup. Please see your administrator");
						});
					},
					function(){
						
						var cap = _base.Viewer().Options()["caption"];
						var o = Default(m_emailOptions, {});
						o.Subject = Default(o.Subject,cap);
						o.Body = Default(o.Body,"Hi!<br/><br/>Please find the attached "+cap);
						o.FileName = Default(o.FileName,"Report.PDF");
						
						if(Application.Util && Application.Util.User)
							o.From = Application.Util.User().CompanyEmail;
						if(Application.Util && Application.Util.sendFrom)
							o.From = Application.Util.sendFrom;
				
						var options = new OptionsWindow({      
							caption: 'Email PDF',
							fields: [{
								Name: "To",
								Caption: "To",
								Type: "Text",
								Mandatory: true
							}, {
								Name: "From",
								Caption: "From",
								Type: "Text",
								Hidden: (Application.Util && Application.Util.sendFrom),
								Mandatory: true
							},{
								Name: "Subject",
								Caption: "Subject",
								Type: "Text",
								Mandatory: true
							},{
								Name: "Body",
								Caption: "Body",
								Type: "BigText",
								Size: 10000,
								CustomControl: "HTMLEditor",
								Mandatory: true
							},{
								Name: "FileName",
								Caption: "Attachment Name",
								Type: "Text",
								Mandatory: true
							}],
							optionvalues: o
						});

						options.CloseFunction(function(okclicked) {
							
							if (okclicked) {
								
								m_emailOptions = options.GetOptions();
								_self.SaveReportOptions();
								
								var html = m_container.html();

								//#235 - Temp Fix - TODO: Remove when new version of PDF software comes out
								html = html.replace(/thead/g,"tbody");

								return Application.WebServiceWait("EmailPDF", { 
									auth: Application.auth, 
									html_: html,
									name_: m_emailOptions.FileName,
									subject_: m_emailOptions.Subject,
									body_ : '<span style="font-family: '+$("body").css("font-family")+'">'+m_emailOptions.Body+'</span>',
									to_:m_emailOptions.To,
									from_:m_emailOptions.From,
									cc_:"",
									bcc_ :"",
									landscape_:Application.HasOption("landscape",m_form.Options),
									receipt_: false
								});
							 }
						});
					
						return options.Open(_base.Viewer());
					}
				);				
			});
		};
		
		this.ExportCSV = function(){
			
			var data = GenerateReportData(m_record);
			var csv_data = _self.GenerateCSVData(data);
			Application.FileDownload.DownloadText("Report.csv", csv_data, "text/csv;charset=utf-8;");
		};
		
		this.GenerateCSVData = function(data_){
			
			var csvFile = '';
			
			//Grouping.
            var lastgroup = [];
            var groups = [];
            var groupcaptions = [];
            if (m_groupFields) {
                groups = m_groupFields.split(",");
                groupcaptions = m_groupFieldCaptions.split(",");
                lastgroup = new Array(groups.length);
            }

            //Totals.
            var totals = [];
            var hasTotals = false;
			
			var hdrrow = [];
			for (var j = 0; j < m_form.Fields.length; j++){
				hdrrow.push(m_form.Fields[j].Caption);
			}
			csvFile += ProcessCSVRow(hdrrow, true);
				
			for (var i = 0; i < data_.length; i++) {
				
				for (var k = 0; k < groups.length; k++) {
                    if (lastgroup[k] != data_[i][groups[k]]) {                        
                        if (hasTotals)
							csvFile += ProcessCSVRow(PrintCSVTotals(totals));                            
                        lastgroup[k] = data_[i][groups[k]];
                        var f = _base.Viewer().Table().Column(groups[k]);
                        if (f) {
                            var val = Default(data_[i]["FF$"+groups[k]], data_[i][groups[k]]);
							var f2 = m_form.GetField(f.Name);							                
							var grpcap = groupcaptions[k] + ": " + FormatData(val, f);
							if(Application.HasOption(m_form.Options,"hidegrpcaption"))
								grpcap = FormatData(val, f); 							
							csvFile += ProcessCSVRow([grpcap]);							
                        }
                    }
                }
				
				var row = [];
				for (var j = 0; j < m_form.Fields.length; j++) {
					
					if (totals.length != m_form.Fields.length)
                        totals.push(-1);
					
				    var val = Default(data_[i]["FF$"+m_form.Fields[j].Name], data_[i][m_form.Fields[j].Name]);
					val = GetDisplayValue(m_form.Fields[j].Name,val);
					
					var f = m_form.Fields[j];          
					var tt = Application.OptionValue(f.Options,"totalstype");
                    if (tt) {
                        var reset = false;
                        var val2 = Default(data_[i]["FF$" + f.Name], data_[i][f.Name]);
                        if (totals[j] == -1) {
                            totals[j] = 0;
                            reset = true;
                        }
                        hasTotals = true;
                        if (tt == "Count") {
                            totals[j] += 1;
                        }
                        if (tt == "Sum") {
                            totals[j] += val2;
                        }
                        if (tt == "Avg") {
                            if (reset) {
                                totals[j] = [];
                                totals[j][0] = 0;
                                totals[j][1] = 0;
                            }
                            if (val2 != 0) {
                                totals[j][0] += val2;
                                totals[j][1] += 1;
                            }
                        }
                        if (tt == "Min") {
                            if (val2 < totals[j] || reset)
                                totals[j] = val2;
                        }
                        if (tt == "Max") {
                            if (val2 > totals[j] || reset)
                                totals[j] = val2;
                        }
                    } 
					
					row.push(FormatData(val,m_form.Fields[j],true));
				}
				csvFile += ProcessCSVRow(row);
			}
			
			 if (hasTotals)
                csvFile += ProcessCSVRow(PrintCSVTotals(totals));
			
			return csvFile;			
		};
		
        //#endregion

        //#region Public Properties

        this.ReportOptions = function (value_) {
            if (typeof value_ == "undefined") {
                return m_reportOptions;
            } else {
                m_reportOptions = value_;
                _self.SaveReportOptions();
            }
        };

        this.FilterOptions = function (value_) {
            if (typeof value_ == "undefined") {
                return m_filterOptions;
            } else {
                m_filterOptions = value_;
                _self.SaveReportOptions();
            }
        };
		
		this.EmailOptions = function (value_) {
            if (typeof value_ == "undefined") {
                return m_emailOptions;
            } else {
                m_emailOptions = value_;
                _self.SaveReportOptions();
            }
        };

        this.PageControl = function () {
            return true;
        };

        this.Design = function (value_) {
            if (typeof value_ != "undefined") {
                m_design = value_;
            } else {
                return m_design;
            }
        };
		
		this.GetLogo = function(){
			if(Application.Util && Application.Util.Company) //CIMS
				return Application.Util.Company().Logo;
			return null;
		};

        this.GetView = function () {
            return m_view;
        };

        this.GroupFields = function () {
            return m_groupFields;
        };

        this.GroupFieldCaptions = function () {
            return m_groupFieldCaptions;
        };

        this.SetView = function (value) {
            m_view = value;
        };
		
		this.AddFilterData = function(name,data){
			m_filterData[name] = data;
		};

        //#endregion

        //#region Private Methods

		function PrintTotals(totals) {            
		    var rows = "<tr>";			
		    for (var j = 0; j < m_form.Fields.length; j++) {
		        var f = m_form.Fields[j];
		        var tt = Application.OptionValue(f.Options, "totalstype");				
		        if (tt == "Avg") {
		            var avg = 0;
		            if (totals[j][1] != 0) {
		                avg = totals[j][0] / totals[j][1];
		                avg = avg.toFixed(2);
		            }
		            rows += "<td style='background-color: WhiteSmoke; -webkit-print-color-adjust: exact; text-align: right; border-top: 1px solid black; border-bottom: 1px solid black;'>" + (tt ? tt + ": " + (avg) : "") + "</td>";
				} else if(tt == "Count"){
		            rows += "<td style='background-color: WhiteSmoke; -webkit-print-color-adjust: exact; text-align: right; border-top: 1px solid black; border-bottom: 1px solid black;'>" + (tt ? tt + ": " + totals[j]: "") + "</td>";
		        } else {
		            rows += "<td style='background-color: WhiteSmoke; -webkit-print-color-adjust: exact; text-align: right; border-top: 1px solid black; border-bottom: 1px solid black;'>" + (tt ? tt + ": " + totals[j].toFixed(2) : "") + "</td>";
		        }		        
		        totals[j] = -1;
		    }			
		    rows += "</tr>";						
		    return rows;
		};
		
		function PrintCSVTotals(totals) {            
		    var rows = [];			
		    for (var j = 0; j < m_form.Fields.length; j++) {
		        var f = m_form.Fields[j];
		        var tt = Application.OptionValue(f.Options, "totalstype");				
		        if (tt == "Avg") {
		            var avg = 0;
		            if (totals[j][1] != 0) {
		                avg = totals[j][0] / totals[j][1];
		                avg = avg.toFixed(2);
		            }
		            rows.push((tt ? tt + ": " + (avg) : ""));
				} else if(tt == "Count"){
		            rows.push((tt ? tt + ": " + totals[j] : ""));
		        } else {
		            rows.push((tt ? tt + ": " + totals[j].toFixed(2) : ""));
		        }		        
		        totals[j] = -1;
		    }					    			
		    return rows;
		};

		function GetDisplayValue(column, value){
			
		    if (value == null)
		        return value;

			var filterdata = m_filterData[column];
			if(!filterdata)
				return value;
			
			for(var i = 0; i < filterdata.length; i++){												
				if(value.toString().toLowerCase() == filterdata[i].ValueCol.toString().toLowerCase()){
					return filterdata[i].DisplayCol;					
				}
			}	
			
			return value;
		};
		
		function GetFilters(){
			var ret = "";
			var v = Application.ViewSubstitute(m_view);
			var filters = Application.GetFilters(v,true);
			for (var i = 0; i < filters.length; i++) {    

				var col = filters[i][0];
				var filterdata = m_filterData[col];
				if(filterdata){
					
					var modifiedfilters = "";
					var filts = [filters[i][1]];
					if(filters[i][1].indexOf("|") != -1)
						filts = filters[i][1].split("|");
					if(filters[i][1].indexOf("&") != -1)
						filts = filters[i][1].split("&");
					
					for(var j = 0; j < filts.length; j++){
						
						var val = Application.StripFilters(filts[j]);
						var val2 = GetDisplayValue(col,val);
						
						if(modifiedfilters == ""){
							modifiedfilters = val2;
						}else{
							modifiedfilters += "," + val2;
						}							
					}
					
					if (ret == "") {
						ret = 'Filters: ' + col.replace("FF$", "") + " = FILTER(" + modifiedfilters + ")";
					} else {
						ret += ", " + col.replace("FF$", "") + " = FILTER(" + modifiedfilters + ")";
					}
					
				}else{
            
					var field = m_form.GetField(filters[i][0]);
					if(field){
						if(field.OptionCaption != ""){
							filters[i][1] =  Application.GetOptionFilter(filters[i][1], field.OptionCaption);
						}
					}
			
					if (ret == "") {
						ret = 'Filters: ' + filters[i][0].replace("FF$", "") + " = FILTER(" + filters[i][1] + ")";
					} else {
						ret += ", " + filters[i][0].replace("FF$", "") + " = FILTER(" + filters[i][1] + ")";
					}
					
				}
			}	
			return ret;
		};
		
        function GenerateReportData(rec_) {

            var recs = new Array();			
            if (rec_.Count > 0){
				rec_.First();
                do {
                    recs.push(ConvertRecordToReportData(rec_));
                }
                while (rec_.Next())
			}
            return recs;
        };

        function ConvertRecordToReportData(rec_) {
            var r = new Record();
			r.Copy(rec_);			
			return r;
        };

        function FormatData(value_, field_, export_) {

            if (value_ == null || typeof value_ == "undefined")
                return "";

            //Dates and times
            if (field_.Type == "Date") {
                return $.format.date(value_, "dd/MM/yyyy");
            } else if (field_.Type == "DateTime") {
                return $.format.date(value_, "dd/MM/yyyy hh:mm a");
            } else if (field_.Type == "Time") {
                return $.format.date(value_, "hh:mm a");
            }

			if (field_.Type == "Boolean" && !export_) {
				if(value_ == true){
					return UI.IconImage("check2");
				}else{
					return "";
				}
			}
			
			if(field_.OptionCaption != ""){
				var vals = field_.OptionString.split(",");
				var captions = field_.OptionCaption.split(",");
				for (var i = 0; i < vals.length; i++) {
					if (field_.Type == "Integer") {
						if (parseInt(vals[i]) == value_ || value_ == null)
							return captions[i];
					} else {
						if (vals[i] == value_)
							return captions[i];
					}
				}
			}
			
            return value_;
        };		
		
		function ProcessCSVRow(row,hdr) {
            var finalVal = '';
            for (var j = 0; j < row.length; j++) {
                var innerValue = row[j] === null ? '' : row[j].toString();
                if (row[j] instanceof Date) {
                    innerValue = row[j].toLocaleString();
                };
                var result = innerValue.replace(/"/g, '""');
				result = result.replace(/\<br\>/g,'\n');
				result = result.replace(/\<br\/\>/g,'\n');
				
				result = Application.SanitizeString(result);
				
                if (result.search(/("|,|\n)/g) >= 0)
                    result = '"' + result + '"';
				if(hdr && j == 0 && result == "ID")
					result = "\"ID\"";
                if (j > 0)
                    finalVal += ',';
                finalVal += result;
            }
            return finalVal + '\r\n';
        };
		
        //#endregion        

        //#region Overridden Methods

		this.Height = function (h) {
			_base.Viewer().SetHeight(h,true);              
        };

        this.Width = function (w) {
            m_container.width(w - 20);
        };
		
        //#endregion

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });  

//Global constants.	
$PAGEBREAK = "<div style='page-break-after: always'></div>";

/// <reference path="../Application.js" />

Define("Searchbox",

    function (field_, viewer_) {
        return new Control("Searchbox", field_, viewer_);
    },

    function (field_) {

        //#region Members

        var _self = this;
        var _base = null;
        var m_button = null;
        var m_values = null;
        var m_skipFocus = false;
        var m_loaded = false;
        var m_search = null;
        var m_view = "";
        var m_timer = 0;

        //#endregion

        //#region Public Methods

        this.Constructor = function (field_) {

            //Setup _base.            
            _base = Base("Searchbox");
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<fieldset data-role="controlgroup" data-type="horizontal"><label id="lbl' + _base.ID() + '" style="font-weight: bold;"></label><input type="search" id="search' + _base.ID() + '" placeholder="Search" /><select id="ctl' + _base.ID() + '" data-theme="a" data-clear-btn="false"></select></fieldset>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                cont.selectmenu({ mini: Application.MiniMode() });
                
                $('#search' + _base.ID()).textinput({ clearBtn: false, mini: Application.MiniMode() }).keyup(function (event) {

                    cont.selectmenu("disable");

                    clearTimeout(m_timer);
                    m_timer = setTimeout(function () {

                        m_search = $('#search' + _base.ID()).val();
                        if (m_search == "") 
                            return;
                        _base.Viewer().ShowLoad();
                        Application.RunNext(function () {
                            return $codeblock(
                                Application.BeginTransaction,
                                function () {
                                    return _self.GenerateData();
                                },
                                Application.CommitTransaction,
			                    function () {
			                        cont.selectmenu("enable");
			                        _base.Viewer().HideLoad(); 
                                }
                            );
			             });

                    }, 2000);
                }).focus(function () {
                    $(".placeholder").css("height", '800px');
                    $('html, body').animate({
                        scrollTop: cont.offset().top - 100
                    }, 1000);
                }).blur(function () {
                    $(".placeholder").css("height", '1px');
                    $.mobile.resetActivePageHeight();
                });

            });
        };

        //#endregion

        this.GenerateData = function (value) {

            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();

            //viewer.ShowLoad();

            //Get the lookup records.            

            if (m_search == null)
                m_search = "";

            //Save view.
            m_view = Application.MergeLookupView(field, viewer, m_search, value);

            return Application.LookupRecord(field, viewer, m_search, PopulateControl, value);
        };

        //#region Overloaded Methods

        this.Update = function (rec_) {

            Application.LogInfo("Updating mobile control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            var value = rec_[_base.Field().Name];

            m_search = $('#search' + _base.ID()).val();

            var view = Application.MergeLookupView(_base.Field(), _base.Viewer(), m_search, value);

            if (m_loaded) {
                if (typeof value == 'undefined') {
                    _self.Loaded(true);
                    return;
                }                
                _base.Control().val(value).attr('selected', true).siblings('option').removeAttr('selected');
                _base.Control().selectmenu("refresh", true);
                _self.Loaded(true);
            }
            if (!m_loaded || m_view != view) {
                return _self.GenerateData(value);
            }
        };

        //#endregion

        function PopulateControl(result, value, displcol) {

            var viewer = _base.Viewer();
            var view = viewer.View();
            var field = _base.Field();
            var cont = _base.Control();

            cont.html("");
            var lastcat = "";
            for (var i = 0; i < result.length; i++) {
                var sel = ""
                if (i == 0 && result[i][field.LookupField] != null)
                    cont.append('<option value="null"></option>');
                if (result[i][field.LookupField] == value) {
                    sel = " selected";
                }
                if (lastcat != result[i].BoldField && result[i].BoldField != "")
                    cont.append('<OPTGROUP LABEL="' + result[i].BoldField + '">');
                lastcat = result[i].BoldField;
                cont.append('<option value="' + result[i][field.LookupField] + '"' + sel + '>' + result[i][displcol] + '</option>');
            }

            cont.selectmenu();
            cont.selectmenu('refresh');

            if (typeof value != 'undefined')
                cont.val(value);

            m_loaded = true;
            _self.Loaded(true);

        };

        this.Enabled = function (value_, update_) {

            if (value_ !== undefined) { //SET

                _base.Enabled(value_, update_);

                if (value_ == true) {
                    if (_base.Field().Editable)
                        $('#search' + _base.ID()).parent().show();
                } else {
                    $('#search' + _base.ID()).parent().hide();
                }

            } else { //GET

                return _base.Enabled();

            }
        };

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor(field_);

    });
/// <reference path="../Application.js" />

Define("Signature",

    function (field_, viewer_) {
        return new Control("Signature", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_loaded = false;
        var m_leftButton = false;
        var m_context = null;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Signature");
        };

        this.CreateMobile = function (window_) {

            //Create the control.
            var container = $('<hr><label id="lbl' + _base.ID() + '" for="ctl' + _base.ID() + '" style="font-weight: bold;"></label><div id="' + _base.ID() + '" style=""><canvas id="ctl' + _base.ID() + '" style="width: 500; height: 300; border: 1px solid #000;"><b>' + UI.IconImage('warning') + ' This control is unsupported in your browser version. Please upgrade to the latest version.</b></canvas><br/><a id="clear' + _base.ID() + '" type="button" data-inline="true" data-mini="true" data-theme="a">Clear Signature</a></div>');

            //Call base method.
            _base.Create(window_, container, _self.OnValueChange, function (cont) {

                var canvas = $('#ctl' + _base.ID()).get(0);

                m_context = canvas.getContext('2d');

                setTimeout(_self.ClearPad, 1000);

                //$(window).resize(app_debouncer(function () {
                //    _self.ClearPad()
                //}));

                // Bind Mouse events
                $(canvas).on('mousedown', function (e) {
                    if (e.which === 1) {
                        m_leftButton = true;
                        m_context.fillStyle = "#000";
                        var x = e.pageX - $(e.target).offset().left;
                        var y = e.pageY - $(e.target).offset().top;
                        m_context.moveTo(x, y);
                    }
                    e.preventDefault();
                    return false;
                });

                $(canvas).on('mouseup', function (e) {
                    if (m_leftButton && e.which === 1) {
                        m_leftButton = false;
                        _self.SaveSignature();
                    }
                    e.preventDefault();
                    return false;
                });

                // draw a line from the last point to this one
                $(canvas).on('mousemove', function (e) {
                    if (m_leftButton == true) {
                        m_context.fillStyle = "#000";
                        var x = e.pageX - $(e.target).offset().left;
                        var y = e.pageY - $(e.target).offset().top;
                        m_context.lineTo(x, y);
                        m_context.stroke();
                    }
                    e.preventDefault();
                    return false;
                });

                //bind touch events
                $(canvas).on('touchstart', function (e) {
                    m_leftButton = true;
                    m_context.fillStyle = "#000";
                    var t = e.originalEvent.touches[0];
                    var x = t.pageX - $(e.target).offset().left;
                    var y = t.pageY - $(e.target).offset().top;
                    m_context.moveTo(x, y);

                    e.preventDefault();
                    return false;
                });

                $(canvas).on('touchmove', function (e) {
                    m_context.fillStyle = "#000";
                    var t = e.originalEvent.touches[0];
                    var x = t.pageX - $(e.target).offset().left;
                    var y = t.pageY - $(e.target).offset().top;
                    m_context.lineTo(x, y);
                    m_context.stroke();

                    e.preventDefault();
                    return false;
                });

                $(canvas).on('touchend', function (e) {
                    if (m_leftButton) {
                        m_leftButton = false;
                        _self.SaveSignature();
                    }

                });

                $('#clear' + _base.ID()).bind("click", function () {

                    _self.ClearPad();
                    _self.SaveSignature();

                }).buttonMarkup({ icon: "delete", mini: Application.MiniMode() });
            });
        };

        this.SaveSignature = function () {
            try {
                var canvas = $('#ctl' + _base.ID()).get(0);
                var imgData = canvas.toDataURL();
                _self.OnValueChange(_base.Field().Name, imgData.split(';')[1].substr(7), null, false);
            } catch (e) {
                Application.Message('Failed to save signature. Error: ' + e);
            }
        };

        this.ClearPad = function () {

            m_leftButton = false;

            var canvas = $('#ctl' + _base.ID()).get(0);
            var w = $(window).width() - 40;
            if(w > 500)
                w = 500;
            canvas.width = w;

            if (m_context) {

                m_context.canvas.width = canvas.width;
                m_context.canvas.height = canvas.height;

                m_context.fillStyle = "#fff";
                m_context.fillRect(0, 0, canvas.width, canvas.height);

                //m_context.moveTo(50, 150);
                //m_context.lineTo(canvas.width - 50, 150);
                //m_context.stroke();

                //m_context.fillStyle = "#000";
                //m_context.font = "20px Arial";
                //m_context.fillText("x", 40, 155);
            }
        };

        this.Update = function (rec_) {

            Application.LogInfo("Updating mobile control: " + _base.ID() + ", Caption: " + _base.Field().Caption);

            if (m_loaded) {
                _self.Loaded(true);
                return;
            }

            var value = rec_[_base.Field().Name];
            if (typeof value == 'undefined') {
                _self.Loaded(true);
                return;
            }

            if (m_context) {
                var image = new Image();
                image.src = "data:image/png;base64," + btoa(value);
                image.onload = function () {
                    m_context.drawImage(image, 0, 0);
                };
            }

            _self.Loaded(true);
        };

        //#endregion

        //#region Overrideable Methods

        this.OnValueChange = function (name, value) {
            return true;
        };

        this.IgnoreColumns = function () {
            return true;
        };

        //#endregion

        //Constructor
        this.Constructor();

    });
/// <reference path="../Application.js" />

DefineModule("ControlApp",

    {
        singleInstance: true,
        requiresVersion: '3.0',
        created: new Date(2013, 09, 03),
        version: '1.0',
        author: 'Paul Fisher',
        copyright: 'Copyright 2011-2015, Liveapp Solutions',

        changelog: [
            '03/09/13   PF  Created class.'
        ]

    },

    function () {

        //#region Members

        var _self = this;
        var m_username = "";
        var m_passcode = "";

        //#endregion

        //#region Public Methods        

        this.OnLoad = function () {

            //Assign module.
            ControlApp = this;

            Application.On("Load", _self.LoadEvent);
            Application.On("ShowLogin", _self.LoginEvent);
        };

        this.LoginEvent = function () {
            
            if (Application.App.Params()["instance"].toLowerCase().indexOf("app") != 0)
                return;

            //Get device token.
            var token = Application.CookieManager.Get("https://go.scrubit.com.au/".replace(/\W/g, '_')+"DEVICETOKEN");
            if (token && token == "")
                token = null;

            if (!token) {

                $("#hdrLogin").css("text-align", "center").html('<img src="https://go.scrubit.com.au/Assets/LoginLogo.png" style="width: 200px;">');
                $("#imgHeader").attr("src", "https://go.scrubit.com.au/Assets/LoginLogo.png").css({
                    "max-width": "300px",
                    width: UI.MagicWidth()
                });

            } else {

                $("#divLogin").css({
                    "width": UI.MagicWidth() + 10,
                    "max-width": "400px"
                });

                $("#hdrLogin").css("text-align", "center").html('<img src="https://go.scrubit.com.au/Assets/LoginLogo.png" style="width: 200px;">');
                $("#imgHeader").attr("src", "https://go.scrubit.com.au/Assets/LoginLogo.png").css({
                    "max-width": "200px",
                    width: UI.MagicWidth()
                });
            }

            $(".login-header").removeClass("login-header");
            $("#imgHeader").css("max-height", "").css("margin-bottom","20px");
            $("#divLogin").css("padding-top", "10px");

            $("#btnLogin").css({                
                "background-color": "Black",
                "color": "white",
                "text-shadow": "none"
            });

            $("#trFooter").css("background-color", "white");

            $("#divTop").hide();
        };

        this.LoadEvent = function () {

            Application.App.ProfileImageOnClick = function () {

                Application.App.LoadPage("User Card", "WHERE(Username=CONST(" + Application.auth.Username + "))", { dialog: true });

            };

            if (Application.App.Params()["instance"].toLowerCase().indexOf("app") != 0)
                return;

            //Get device token.
            var token = Application.CookieManager.Get("https://go.scrubit.com.au/".replace(/\W/g, '_')+"DEVICETOKEN");
            if (token && token == "")
                token = null;

            var url = "https://go.scrubit.com.au/" + Application.App.Params()["instance"] + "?";
            if (Application.IsInMobile())
                url += "mobile=true&";

            if (!token) {
                if (_self.SelfService())
                    $("#divLogin").append('<br/> &nbsp;<center><table class="buttonwrapper" style="background-color: #3399FF; width: 180px;" border="0" cellspacing="0" cellpadding="0">' +
                                                          '<tr>' +
                                                            '<td class="button" height="45">' +
                                                             ' <a href="' + url + 'pageid=New User Account&auth=ZmB5dTHckmP7ZcYl7gSz/Q==" style="color: #ffffff;" target="_parent">+ Create Account</a>' +
                                                            '</td>' +
                                                          '</tr>' +
                                                        '</table><table class="buttonwrapper" style="background-color: Gray; width: 180px;" border="0" cellspacing="0" cellpadding="0">' +
                                                          '<tr>' +
                                                            '<td class="button" height="45">' +
                                                             ' <a href="' + url + 'pageid=Lost Password&auth=liHrJzuhVpsRId+vuh6FKA==" style="color: #ffffff;" target="_parent">Forgot Password?</a>' +
                                                            '</td>' +
                                                          '</tr>' +
                                                        '</table></center>');
            } else {

                var tiles = $('<br/><a href="' + url + 'pageid=New User Account&auth=ZmB5dTHckmP7ZcYl7gSz/Q==" style="color: #ffffff;" target="_parent"><div style="display: inline-block; line-height: 80%; font-size: 100px; margin: 5px; cursor: pointer; border-radius: 50%; height: 100px; width: 100px; color: white; background-color: #00ACCD;">' +
                        '<span style="display: flex; justify-content: center; line-items: center;">+</span>' +
                    '</div></a>' +
                    '<a href="' + url + 'pageid=Lost Passcode&auth=liHrJzuhVpsRId+vuh6FKA==" style="color: #ffffff;" target="_parent"><div style="display: inline-block; line-height: 119%; font-size: 80px; margin: 5px; cursor: pointer; border-radius: 50%; height: 100px; width: 100px; color: white; background-color: #47BFAF;">' +
                        '<span style="display: flex; justify-content: center; line-items: center;">?</span>' +
                    '<div>');

                if (!_self.SelfService())
                    tiles = "";

                if (Application.IsInMobile()) {
                    $("#divLogin").append("<div id='divTiles'></div>");
                    $("#divTiles").append(tiles);
                } else {
                    $("#hdrLogin").after(tiles);
                }                
            }

            if (Application.IsMobileDisplay())
                $(".buttonwrapper").css("font-size", "7pt");

            if (_self.SelfService())
                $("#txtUsername").attr("placeholder", "E-Mail");

            Application.On("Authorized", _self.AuthorizedEvent);

            if(token)
                return _self.SetupTiles(token);
        };

        this.AuthorizedEvent = function () {

            $("body,#mainPage").css({
                "background": "white",
                "background-size": "cover"
            });
            $("#divTop").show();
        };

        this.SelfService = function () {
            //Hardcode app values.
            return "https://go.scrubit.com.au/".indexOf("QS") != -1;
        };

        this.SetupTiles = function (token) {

            var compid = null;

            //Resave token.
            Application.CookieManager.Save("https://go.scrubit.com.au/".replace(/\W/g, '_') + "DEVICETOKEN", token, 999);

            var deviceusers = Application.CookieManager.Get("Liveapp FrameworkDEVICEUSERS");
            if (deviceusers && deviceusers != "") {
                deviceusers = $.parseJSON(deviceusers);
            } else {
                deviceusers = [];
            }

            PressPasscode = function (v) {
                var ctrlid = "#passcode" + v;
                var clr = "#00ACCD";
                if (v === 99)
                    ctrlid = '#passcodeok';
                if (v === -1)
                    ctrlid = '#passcodedel';
                if (v === -1 || v === 99)
                    clr = "#47BFAF";
                $(ctrlid)[0].style.backgroundColor = "darkgray";
                $(ctrlid)[0].style.backgroundColor = "darkgray";
                setTimeout(function () {
                    $(ctrlid)[0].style.backgroundColor = clr;
                }, 200);
                if (v > -1 && v < 10) {
                    m_passcode = "" + m_passcode + v;
                    $("#displaypasscode").text(Array(m_passcode.length + 1).join("*"));
                }
                if (v === -1 && m_passcode !== "") {
                    m_passcode = m_passcode.substr(0, m_passcode.length - 1);
                    $("#displaypasscode").text(Array(m_passcode.length + 1).join("*"));
                }
                if (v === 99 && m_passcode !== "") {
                    Application.RunNext(function () {
                        return $codeblock(

							function () {
							    return Application.App.Authorize({
							        type: "Tile",
							        username: m_username,
							        passcode: m_passcode
							    });
							},
							function () {
							    Application.ExecuteWebService("GenerateURL", { auth: Application.auth, id_: compid }, function (url) {
                                    window.location = url + "&returnurl=https://" + window.location.hostname + window.location.pathname + "&user=" + Application.auth.Username + (Application.IsInMobile() ? "&mobile=true" : "&mobile=false");
							    })
							}
						);
                    });
                }
            }

            return $codeblock(
				function () {
				    return Application.App.ShowLogin(null, true);
				},
				function () {
				    $("#txtUsername, #txtPassword, #spanRemember, #btnLogin, #fieldsLogin").hide();
				    $("#divLogin").css({
				        "text-align": "center",
				        "padding-bottom": "30px"
				    });
				    var w = $wait();
				    Application.ExecuteEndpoint(Application.url + "q/?e=ControlApp&m=GetUsersFromToken&p={token_:\"" + token + "\"}", function (r) {
				        w.resolve(r);
				    });
				    return w.promise();
				},
				function (ret) {

				    if (!ret) {
				        Application.Message("Unable to load company", null, function () {
				            //Clear cookie.
				        });
				        return;
				    }

				    var retusers = ret[2];
				    var users = [];
				    compid = ret[0];

				    for (var j = 0; j < retusers.length; j++) {
				        if (deviceusers.indexOf(retusers[j].Fields[1].Value) == -1) {
				            users.push(retusers[j]);
				        }
				    }
				    for (var i = 0; i < deviceusers.length; i++) {
				        for (var j = 0; j < retusers.length; j++) {
				            if (retusers[j].Fields[1].Value == deviceusers[i]) {
				                users.push(retusers[j]);
				                break;
				            }
				        }
				    }

				    for (var i = 0; i < users.length; i++) {
				        var photo = users[i].Fields[2].Value;
				        if (photo)
				            photo = photo.replace(/ /g, "+");
				        var clr = "#00ACCD";
				        if (Math.round(Math.random()) === 1)
				            clr = "#47BFAF";
				        var initial = Default(users[i].Fields[3].Value, "");
				        if (initial.length > 0)
				            initial = initial.substr(0, 1).toUpperCase();
				        if (photo)
				            initial = "";
				        var tile = $('<table id="usertiles" data-username="' + users[i].Fields[1].Value + '" style="width: 110px; max-width: 110px; display: inline-block; margin: 5px;"><tr><td><div style="cursor: pointer; font-size: 40px; line-height: 100px; border-radius: 50%; height: 100px; width: 100px; color: white; background-color: ' + clr + '; background-size: cover;background-position: center center; background-image: url(\'data:image/jpeg;base64,' + photo + '\')">' + initial + '</div></td></tr><tr><td style="font-size: 14px; color: black; height: 50px;"><div style="width: 100px;overflow: hidden;">' + users[i].Fields[3].Value + ' ' + users[i].Fields[4].Value + '</div></td></tr></table>');
				        tile.on("click", function () {

				            m_username = $(this).attr("data-username");

				            $("#enterpasscode").show();

				            var j = deviceusers.indexOf(m_username);
				            if (j >= 0)
				                deviceusers.splice(j, 1);

				            deviceusers.push(m_username);
				            Application.CookieManager.Save("Liveapp FrameworkDEVICEUSERS", $.toJSON(deviceusers), 999);
				        });
				        if (Application.IsInMobile()) {
				            $("#divTiles").prepend(tile);
				        } else {
				            $("#hdrLogin").after(tile);
				        }
				    }

				    if (Application.IsInMobile()) {
				        $("#divTiles").prepend("<h2 style='color: black; font-weight: normal;'>" + ret[1] + "</h2>");
				    } else {
				        $("#hdrLogin").after("<h3 style='color: black'>" + ret[1] + "</h3>");
				    }

				    m_passcode = "";
				    var enterpasscode = '<div id="enterpasscode" style="display: none; position: fixed;z-index:28000;background: white;left: 0px;top: 0px;width: 100vw;height:100vh;box-sizing:border-box;padding:20px;"><div style="display: inline; padding-left: 10px;"><span style="font-size: 20px; color: gray;">Enter Passcode</font></div><div id="passcodeclose" style="float: right;font-size: 20px;color: grey;font-weight: bold;"><i class="mdi mdi-close"></i></div><table style="margin: auto; padding-bottom: 10px;"><tr><td id="displaypasscode" colspan="3" style="height: 62px; font-size:40px; text-align: center; color: gray; padding: 10px; line-height: 40px;"></td></tr><tr><td>%1%</td><td>%2%</td><td>%3%</td></tr><tr><td>%4%</td><td>%5%</td><td>%6%</td></tr><tr><td>%7%</td><td>%8%</td><td>%9%</td></tr><tr><td>%ok%</td><td>%0%</td><td>%del%</td></tr></table></div>';
				    var number = '<div id="passcode%id%" onclick="PressPasscode(%no%)" style="cursor: pointer; font-size: 40px; text-align: center; line-height: 80px; border-radius: 50%; height: 80px; width: 80px; color: white; background-color: %colour%;">%no%</div>';
				    for (i = 0; i < 10; i++) {
				        enterpasscode = enterpasscode.replace("%" + i + "%", number.replace("%id%", i).replace("%colour%", "#00ACCD").replace("%no%", i).replace("%no%", i));
				    }
				    enterpasscode = enterpasscode.replace("%ok%", number.replace("%id%", "ok").replace("%colour%", "#47BFAF").replace("%no%", "99").replace("%no%", "OK"));
				    enterpasscode = enterpasscode.replace("%del%", number.replace("%id%", "del").replace("%colour%", "#47BFAF").replace("%no%", "-1").replace("%no%", "&#9003;").replace("font-size: 40px; line-height: 80px;", "font-size: 50px; line-height: 70px;"));

				    $("body").append(enterpasscode);
				    $("#passcodeclose").bind("click", function () {
				        $("#enterpasscode").hide();
				        m_passcode = "";
				        $("#displaypasscode").text("");
				    });
				}
			);

        };

        //#endregion

    });

    Application.ModuleManager.LoadModule(new ControlApp());
/// <reference path="../Application.js" />

//27/01/15      Issue #7        PF      Added new control.

Define("Explorer",

    function (field_, viewer_) {
        return new Control("Explorer", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_container = null;
        var m_form = null;
        var m_baseImage = "/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAQDAwMDAwQDAwQFBAMEBQcFBAQFBwgGBgcGBggKCAgICAgICggKCgsKCggNDQ4ODQ0SEhISEhQUFBQUFBQUFBT/2wBDAQUFBQgHCA8KCg8SDwwPEhYVFRUVFhYUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAD6APoDAREAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAUGAwQHAQII/8QARRAAAQMBAgcKCgkFAQEAAAAAAAECAwQFEQYSFCExUnIVMjM0QVORocHREyI1UVRicYGTskJEYXSCg5KxwhYjQ3PhJGP/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fqqjUVy5kTSoGPKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIDKafnWdIH2yRkmdjkddpuA+gMVTxeXYUCBA9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEnZfBv2uwDfAxVPF5dhQIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk7L4N+12Ab4GKp4vLsKBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJ2Xwb9rsA3wMVTxeXYUCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTsvg37XYBvgYqni8uwoEEAAAAADToA9xXeZQGK7zKB4AAZtK5k5VUCkWjhxUeHcyyo48natyTSpjK+7lRM1yAaf9b255qb4f/QPf64tvVpvh/8AQPP64tvVpvh/9A9/ri2tSm/QveA/ri2tSm/QveB6mHNs8sdKv4F7wLVYVvwW3E9Eb4Grizyw335l+k1eVAJcAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAApWGtp1cdTFZ0EjooPBeFkxFxVcrlVEvVORLgKl4efnpP1u7wHh6jnpP1u7wL/gdaNTXUEsdU9ZH00iNZI7O5WuS9EVeW64CxgROE1XkViVUiLc+VPAM9smZeq8Dl4AAAAAAAEjYVfuba1NVKt0WN4Ob/W/MvRpA6qAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAaQOe4ceWWfdmfu4CtgALxgFxau/2x/KoFuApWHlZe6js9q5m408nv8VvaBTgAAAAAAAPAOpYOV+6Nj08zlvmjTwM21Hmv96XASoAAAAXKAAAAAEnZfBv2uwDfAxVPF5dhQIIAAA1bRroLMopa6o4OJMzU0ucuhqe0Dm1o4QWrab1dLO6KFd7TxKrGInuzr7wI1VVc7lVV865wPAAHqOcmhVT2KAx36zulQPL1XTnAAAAAAAAAAPUc5NCqnsUD3Hfru6VAY79d3SoDHfru6VAY79d3SoH0yeeNcaOaRjk0K1yp+wFswbwqqXVDLPtR/hWSriw1Lt+1y6Ed50XzgXYAAAk7L4N+12Ab4GKp4vLsKBBAAAFQw9lclNRU6b18r3u/AlyfMBSAAAAAAAAAAD6jjkmdiQsdI7VYiuXqA32WBbciXts+e77W3fvcB8S2Na8CY0tDUNb58RV/a8DRXMuKuZyaUXSAAAAAAAAAAeXq3xk0tzp7gOx08izU8My6ZImPX2uaigZAAEnZfBv2uwDfAxVPF5dhQIIAAApmHv1D83+IFMAAAAAAAA+4YZqiVkFOx0s0i3Mjal6qoF1srAmCNEmth3hZdOTMW6NNp2l3uAtUEEFKxIqaJkMaaGxojf2Ay3LygM6Z+sDTrrLs+0mK2tp2S+vdc9PY5M4FKtrA+ooWuqbOV1TStzviXhWJ/JOsCsAegAAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAAH1HG+WRsUTVfK9UaxiaVVdCAdMwfsGGxae91z7QkT+/N5vUb9idYGzatr0VjwpLVu8d/BQt37/AGfZ9oFGtDC6161ypC/I4ORkW/u+1+noAhXzzyLjSSyPd53OVVAyQV1dSuxqapmid6r1/bQBZLKw2qYnNitZnh4fSI0ukb7W6HAXanqIamFlTTSJJC9L2SN0AVDCzB1qNfa9Ay67PWQt0Xc41Pm6QKYAAAAAADx29X2AdfoPJ9H93j+VANgABJ2Xwb9rsA3wMVTxeXYUCCAAAKZh79Q/N/iBTAAAAAAAXDAiy0c+S15kvxL4qW/W+m73aALXadoQWXRS1s+drEuYzle9d61PaByutrai0Kp9ZVuxppOhE5Gp5kQDAAAAAJnBy3H2NVYkiqtnTO/vs1V5xPtTlA6Z4rk5HMcntRUXvA5dhBZe5Npy07E/8z/7tPsO5PwrmAiwAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAPFzIB1qyKRKCzKSlTSyJFftu8Z3WoFQw4rllrobOav9unZ4R6f/STuaBVQAAAAAAdHwPrlrLIbE9b5aR3gV2NLOrMBqYdUqSUFPWonjwS4ir6kn/UAoYAAAAAeO3q+wDr9B5Po/u8fyoBsAAJOy+DftdgG+BiqeLy7CgQQAABTMPfqH5v8QKYAAAAAGSnbj1ELF0OlYi+9yAdjVPGu+24DlOEEiy25aD159W+5uYCOAAAAAABb8ApFyivi5FiY/wB6Ou7QJ/CpiPwfrb/ota9PwuQDmIAAAAAeO3q+wDr9B5Po/u8fyoBsAAJOy+DftdgG+BiqeLy7CgQQAABTMPfqH5v8QKYAAAAAH3C/wc0UmpIx3Q5AOyKt64yaFzgcrwjhWC3a9i8suOnsel4EYAAAAAAC4YBRL4Wvn+ijGR+9VVewCdwrkSPB+s9dGsT8TkA5kAAAAAHjt6vsA6/QeT6P7vH8qAbAACTsvg37XYBvgYqni8uwoEEAAAUzD36h+b/ECmAAAAAB4qXpcB1awqxK+yKWovvf4NI5NuPxVArOHVAqSwWoxPFengJl9ZN4vvTMBUAAAAAA80ZwOm4LWe6z7IiSRMWeoXw8icqY29T3NAi8O6tG01LQIvjSvWZ6eqzMnWoFHAAAAADx29X2AdfoPJ9H93j+VANgABJ2Xwb9rsA3wMVTxeXYUCCAAAKZh79Q/N/iBTAAAAAAAWnAu1kpqp9mTrdDVLjQqvJMnJ+JALtWUkFdSy0dS3GhmbiuTlTzKn2oBy61bKqbHqlpqlL2rnhm+jI3zp9vnQDRAAAAFkwWwedaEza+rZdZ8Tr2Iv8AlenInqpygdAkkZEx80zkbExFdI9dCNTSoHKbYtF1rWjNWrejHLiwtXkjbvU7QNEAAAAAPHb1fYB1+g8n0f3eP5UA2AAEnZfBv2uwDfAxVPF5dhQIIAAApmHv1D83+IFMAAAAAAAzpnRblTQqAdDwawkZabG0VY5G2k1LkVcyTInKnredAJusoqW0IFpq2JJYV5F0ovnavIoFNtDAeqjVX2ZMk8fJFL4kie/QoEJJg/bkS4r7Pn/C3GTpS8DLBgzb1QtzaJ8aa0t0adYFjsvAmCFzZrVkSocmdKdl6R3+sulwFsRGsbclzI2Jsta1OpEQCg4UYSJaF9nUDv8AwtX+9Kn+VU5E9VOsCsAAAAAAA8dvV9gHX6DyfR/d4/lQDYAASdl8G/a7AN8DFU8Xl2FAggAACmYe/UPzf4gUwAAAAAAABnRUVMyot6KmlFAtdk4az06JBarFqYkzJUM4VNpNDgLZR21ZVeiZNVxucv0HLiP/AEuuAkEv5OoD5e5GJjSORqedy3fuBD12FFjUKKiz5RKn+KDx1/VvUApds4S19r3w8XouYYu+23cvs0AQwAAAAAAAHjt6vsA6/QeT6P7vH8qAbAACTsvg37XYBvgYqni8uwoEEAAAVLDyBzqSjqU3scrmP/Gmb5QKMAAAAAAAAAAeXIukD7bLMzMyWRqeZHuTtA8c57+Ec5+0qu/cDwAAAAAAAAAAYrnqjGpe5y4rU+1cwHYoI/AwRQ81G1n6UuAyAAJOy+DftdgG+BiqeLy7CgQQAABr1tHBaFJLRVKXwypc67SnmVPtRQOd2jgra9A9fBwrV0/0ZoUvzes3SigRuQV/olR8N3cAyCv9EqPhu7gGQV/olR8N3cAyCv8ARKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/RKj4bu4BkFf6JUfDd3AMgr/AESo+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwDIK/0So+G7uAZBX+iVHw3dwH1HZdpzOxY6Koc7/W4C24OYKS0s7LQtS5JI88FMme52s9dGbkQC3gAAEnZfBv2uwDfAxVPF5dhQIIAAAAAPcZ3nUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBju1lAY7tZQGO7WUBjOXSqgeAAAACTsvg37XYBvgYqni8uwoEEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEnZfBv2uwDfAxVPF5dhQIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJOy+DftdgG+BiqeLy7CgQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASdl8G/a7AN8DFU8Xl2FAggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAk7L4N+12Ab4GKp4vLsKBBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABJ2Xwb9rsA3wPmRiSMcxdDkuA09y4dd/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QDcyHWf1ANzIdZ/UA3Mh1n9QGxT07adFa1VW9b84GYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//9k=";
        var m_pencilImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIYAAACGCAMAAAAvpwKjAAAAA3NCSVQICAjb4U/gAAAAUVBMVEX////////////////39/fv7+/m5ubf39/X19fMzMzFxcW9vb21tbWtra2lpaWZmZmMjIyCgoJ6enpycnJmZmZZWVlRUVFJSUlDQ0M7OzszMzNEfw7eAAAAG3RSTlMAZt3///////////////////////////////+uggLgAAAACXBIWXMAAArwAAAK8AFCrDSYAAAAJXRFWHRTb2Z0d2FyZQBNYWNyb21lZGlhIEZpcmV3b3JrcyBNWCAyMDA0h3aszwAAAxNJREFUeJzt3NuWqjAMAFDk4ogygIpY8/8femjachMorjlJfUge5yXbtDSF1U4UMcYhTkYRHzhzryACQd4ROrgdB5v3Uj8UgGrqc4iCGEVWdwQXqkq5C2IUvyMEQi68DqO4wVvUOC6cirR5VwDc+MqxobD14HBsKgAuPMPiUYBKOcrhUwBUHOWIfQpQGkrN8CoAzjyM5L7NqBkYsd/RMDDMArrpUKQM3dm7/rnDQck4uA2F30HIcPuLHQ7CQTGr1nmXg26KurWz2OMge2CHFXyPg2r5GvcRv4NqMZ92M6+DqLXNe6rHoTKSRv/e2bcdBUkxlvYXWw6azejyLmfdodeM/1+Mtb3WmqNJKYqxvuNbdnArlh38iiVHCMW7I4xi7gilmDmCKWaOYIq5I5RicMQEn5v2K3oHQXyioOqonyoA8oRis/WpAteL71CwdfZNRcAnVRSiEIUoRCEKUYhCFKIQhShEIQpRiEIUohCFKEQhClGI4s/hP9/JoTh8hQKL8Qiu0MX4Ca7AYtTBFTgzXqEVWIzf4Ao8f9xNUOVHUCr0mORditz/xBIqcEzueCSsuD+aZyCFLsYRzOWELjYYlAosRgXwNIpkfYaQKiKbu7KM1QlCq9BjUnRZ8PzmxpNLq8AxaczJyThaLwexQhfg1KU5YRJtypYcxApMfAV4YDHcDbBGtS2rQufNwJwAOkSjU/MNpwKLUY5PWztHy6mIbMY66U/e2LuS5Gddx6F/+7nLdJzkcc8wl8K1k3syOoZky9HwKdzmL+8TDddXc8WlcJu/1k3QAXFp2GphntZu81faRcMhssq0WVUfE3qF3fypF/7iYTTszdFHYe7Pkl8J1Dn020mZ9JEW9nXlltu/kF8ndu0E4GpTHu1t4meVcSHMmNgBQEfujqNfEj5E304wyqw0y/fr+sOJ6NuJDfO21JYpqyEyE3TY/+pJcc95C6HDtZPeYRcJ5qv28aSNNgX7aGBMviVcT/yjYWL4ltCWjIvEPPSKGWpaThkFqCrItJwy6iJoITBG/50jHGLYgYc0oCP+AsQ/D4a0IKvi07YAAAAASUVORK5CYII=";
        var m_record = null;
		var m_editMode = false;
		var m_accMode = false;
		var m_level = 0;

        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Explorer");
        };

        this.CreateDesktop = function (window_, form_) {

            var viewer = _base.Viewer();
            if (Application.IsInMobile())
                viewer = _base.Viewer().ParentWindow();

            m_form = form_;

            //Create the control.
            m_container = $('<div id="' + _base.ID() + '" style="padding-top: 0px;"></div>');

			window_.Main().append("<h1 id='msg" + _base.ID() + "' style='font-size: 30px;'>"+Application.ProcessCaption("Please select a company")+"</h1>")
            window_.AddControl(m_container);

            window_.Main().css("text-align", "center");
            viewer.ShowActions();
            Application.App.ToggleMainMenu(false);
			
			var divTop = $("#tdTop");
			
			viewer.AddButton("Edit", "mdi-lead-pencil", "Edit", function () {
			    if (m_record && m_record.Count == 0)
			        Application.Error("You do not have any companies to edit");
			    ToggleEditMode();
			});
			
			if (ControlApp.SelfService()) {
			    viewer.AddButton("Manage", "mdi-credit-card", "Manage", function () {
			        if (m_record && m_record.Count == 0)
			            Application.Error("You do not have any companies to manage");
			        ToggleAccMode();
			    });
			}
			
			//m_toggleModeButton.on('click',function(){
			//	Application.SwitchMode(!Application.IsInMobile(),Application.auth.Instance);			
			//});				
			
			if (Application.IsInMobile()) {

			    Application.App.RefreshProfileImages = function () {
			        $(".circle-img-small,.square-img-large").css("background-image", 'url(' + Application.App.ProfileImageURL() + ')').css({
			            width: "30px",
			            height: "30px"
			        });
			    };
			    Application.App.RefreshProfileImages();
            }

			var cust = Application.App.Params()["custom"];
			if(cust){				
				Application.RunNext(function(){				
					Application.ExecuteWebService("ProcessCustom",{auth: Application.auth, custom_: cust},function(ret){
						if(ret)
							eval(ret);
					});				
				});
			}			
											
            _self.Loaded(true);
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function (value_) {
            //Not used.            
        };

        this.Update = function (rec_) {

			Application.RunNext(function(){
				
			    var needsupdate = false;

			    return $codeblock(

                    function () {

                        var w = $wait();

                        Application.ExecuteWebService("GetUserRequest", { auth: Application.auth }, function (pending) {
                            if (pending && pending != "") {
                                Application.Confirm("Would you like to join " + pending + "?", function (r) {
                                    w.resolve(r);
                                }, Application.ProcessCaption("Join Company?"), "Join", "No Thanks");
                            } else {
                                w.resolve(null);
                            }
                        });

                        return w.promise();
                    },

					function (r) {
					    if (r === null)
					        return null;
						if (r) {
							m_editMode = false;
							$("#msg" + _base.ID()).text(Application.ProcessCaption("Please select a company"));
							needsupdate = true;
							return Application.WebServiceWait("AcceptUserRequest", { auth: Application.auth });
						} else {
							return Application.WebServiceWait("RejectUserRequest", { auth: Application.auth });
						}
					},

					function () {
					    if (needsupdate)
						    return ThisViewer().Update();
					}
                );
			});				
			
            m_record = rec_;

            $('#'+_base.ID()).html("");

            rec_.First();
            if (rec_.Count > 0){
                do {

                    AddPart(rec_);

                    var lvl = 0;
                    if (rec_.Level == "Admin")
                        lvl = 1;
                    if (rec_.Level == "Super")
                        lvl = 2;
                    if (lvl > m_level)
                        m_level = lvl;

                } while (rec_.Next());	
            } else {
                if(ControlApp.SelfService())
				    m_editMode = true;
            }

            if (!ControlApp.SelfService() && m_level == 0 && rec_.Count == 1){
                Application.CodeEngine.Restart();
                _base.Viewer().Hide();
                EditClick(rec_['Company ID'], false);                
            }
			
			if(m_editMode)
				ToggleEditMode(m_editMode);
			
			if(m_accMode)
				ToggleAccMode(m_accMode);

            _self.Loaded(true);
        };

        this.Height = function (h) {
            m_container.height(h - 70);
        };

        this.Width = function (w) {
            m_container.width(w - 20);
        };	

        //#endregion

        //#region Private Methods

        function AddPart(rec_) {

            var id = $id();

            var photo = rec_[m_form.Fields[0].Name];

            if (photo == null) {
                photo = m_baseImage;
			}
			
			var name = rec_["FF$"+m_form.Fields[1].Name];
			if(name == null){
				name = rec_[m_form.Fields[1].Name];
				if(name == null){
					name = "";
				}
			}

            var maxheight = Default(Application.OptionValue(m_form.Options, "maxheight"), "100px");

			var super_user = false;
			if(rec_.Level)
				super_user = (rec_.Level == "Super" || rec_.Level == "Admin");
			
			var id = $id();
			var w = 200;
			if (Application.IsMobileDisplay())
			    w = 100;
			$('#' + _base.ID()).append('<table class="' + (!super_user ? "noedit" : "") + '" style="width: ' + (w + 10) + 'px; max-width: ' + (w + 10) + 'px; display: inline-block; margin: 5px;"><tr><td><div id="' + id + '" class="' + (super_user ? "explorerpart" : "") + '" style="background-image: url(data:image/jpeg;base64,' + photo + '); padding: 4px; text-align: center; width: ' + w + 'px; height: ' + w + 'px; border: 1px Solid Gainsboro; background-size: cover;background-position: center center;border-radius: 50%;cursor: pointer;"></div></td></tr><tr><td style="font-size: 14px;">' + name + '</td></tr></table>');
            eval("$('#' + id).on('click',function(){EditClick('"+rec_['Company ID']+"',"+super_user+");});");
        };
		
		function ToggleEditMode(mode){
			
			if(m_accMode)
					ToggleAccMode();
				
			var w = 200;
			if (Application.IsMobileDisplay())
			    w = 100;

			if(m_editMode == false || mode == true){				
				if(mode == null)
					m_editMode = true;
				$(".explorerpart").css("opacity", "0.7").append('<div class="exploreredit" style="background-image: url(' + m_pencilImage + ');width: 100px;height: 100px;padding: 4px;position: relative;top: 20%;left: 20%;background-repeat: no-repeat;background-size: cover;"></div>');

				if (m_level == 2 || ControlApp.SelfService()) {
				    var id = $id();
				    $('#' + _base.ID()).append('<table class="exploreredit explorernew" style="width: ' + (w + 10) + 'px; max-width: ' + (w + 10) + 'px; display: inline-block; margin: 5px;"><tr><td><div id="' + id + '" style="background-image: url(http://www.iconsdb.com/icons/preview/gray/plus-4-xxl.png); padding: 4px; text-align: center; width: ' + w + 'px; height: ' + w + 'px; border: 1px Solid Gainsboro; background-size: cover;background-position: center center;border-radius: 50%;cursor: pointer;"></div></td></tr><tr><td style="font-size: 14px;">'+Application.ProcessCaption("Add new company")+'</td></tr></table>');
				    $('#' + id).on('click', function () {
				        NewClick();
				    });
				}
				$(".noedit").css("opacity", "0.7");
                if(Application.IsMobileDisplay())
				    $(".exploreredit").css("background-size", "60px 60px");
                $("#msg" + _base.ID()).text((m_record.Count == 0 ? Application.ProcessCaption("Add a new company") : Application.ProcessCaption("Select a company to edit")));
			}else{
				if(mode == null)
					m_editMode = false;
				$(".exploreredit").remove();
				$(".noedit").css("opacity","");
				$(".explorerpart").css("opacity","");
				$("#msg" + _base.ID()).text(Application.ProcessCaption("Please select a company"));
			}
		};
		
		function ToggleAccMode(mode){
			
			if(m_editMode)
					ToggleEditMode();
				
			if(m_accMode == false || mode == true){				
				if(mode == null)
					m_accMode = true;
				$(".explorerpart").css("opacity","0.7").append('<div class="explorermanage" style="background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAP8AAAD/CAQAAACUAchBAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wsCDA4yrSt4qgAAAAJiS0dEAP+Hj8y/AAA4lUlEQVR42u29R3cjS5Zmu83hDq0BgpqhrsqsWl2rB2/4/v+kR12VeW/cENQECK2FK+uBG0BIkiBAEhTGVZlZEUEI/8zsbDt2BLyP9/E+3sf7eB/v4328j/fxPl7/EOP/j5z3h69wvJXveffQ504H+b4u3sbQ3h/Bu/zv4932j9lGDT9B/PhevCkQgMTBwsbGwcEVUwzwlglAn/unfnY5YIcIGg7OCxbfB9i0qVKhToeuMN/X/F3yBzng/+M/2ULHYvCCTZuBoE+RY35wTglXWkJO7Q3v8s+s/h3+k/+fI3QG9HFf7Lfzo9HhghQ6IHCw6M2cAN/lnxg+ImxxhB8IEXrh3zGATo8ONj4EQlboijmnXPEu/9i2qS/8u5c34uwxwE+UMAH81GRHDHgfCyV2sBi8+HV/MzL4iJMkgh8/AYrSFs47A8yXX+IwoP+K5A8TJkkEDReBhsOA1jsD3LbBu6/g+8kxox5mhy49XMDGlI7ojtv8t8gA+pua7BG2sTHwIwCfrNB5236A1y6/mALaFDoRQmhINAxKsvaWGUB/Y9M9QIAoOjYWvDPA25FfjnaCIDnadHEAG+stM4D+ZsSfPAds47wzwNuRX0x96xTGBAMUZf0tMoDO2xxBglMMYL5FBngq+eWYSX1eozrOAFtvnQGeSn6BiwtozxxfJGf8AA4GAcUAVdpviwGeSn4HExuBjnjWCTDNAGnFAEIxgHhbDPAU8luY9BlgIfATIICBsXF+APMtMsC65Ze4ODg42NhYWJiYDBgwwAYMAgTwqx8dHzoaOj58T2xkZxnAfXsMsP7Vb9KlQ4sGLTr06DFggImNC/gwlPRBQkSIEiNKlCiRZ2cA/xgDvJF4AH2NqwjApkONMgWuKFKjSYceJvYorFbDh58AYaKkyLFDji28mJxFr/pUDBBUDOCfiQeQ7/Lf/SAlLaoUuOKUE84pUadFDxOJpkDKe7wBwsTZ4oA6HUw0/KQWyvN0DGApBrDfxl3AujZ/iUOfJiUKXHHFKadcUaYu+gt+wSBOFwsbkwE2Jj3iBPA98clgmgF6uEgsTGmL3mtngHXJ36ZOhRJ5LslToEiJKo1F4oOwZAuBZECTKmWu2SVHjgzhZ2cAAxcLR9boCYdXPPQ1rBpwqHPGKRecc0GBGm16DLBufQWbDjZtyhS4YId9PvAr/ieVf5YB/EQxsBng4KMqWxN5AfJd/tkH16XCKX9xwimXlGkJVwoEUgohFy47SZ8eDQxKFLimRBs/adLP6BUIECCCpEsbC3Cx6b5eBljH5j+gQp4zTjjhgqLoAIgbL//MUxPe/0n1lyam7NHHwiBDjhhb6gj2tEZgnAEOaOKgAa6Ur5cBVpPfxaJLnXNOOOGESyqe+EtvJX1ZRyNEijiCNhlizxhnHGUXhxBhLzfo9TLAavI7tCiT54SfnHBJkc5DX0r0ZYNrIvixaPGRwyeVf3Ip+8kRJEEYgYOLRlW2XyMDrCa/RZPCjfiivdKrdahxiYaFiZ8k6We7HBKECBHHx4AuFgIX+zXmBq4mv0mDvDrjV2izwDqKO05dw4w72aaMBvjZ4uBZsozGGSBEjkNaOPgAKSuvjwFWlb/GBT84IU9LTK6fB6wQYckmEkmEA+p0nz3LKMYeDiEiGAiErNN9XQywmvw9qlxwzCn1sa1xhe1RDKSFJEGRGi3CBJ94cU2+m6EYIIKGjYsGr4sBVpF/QJca11xSEPbanr8rq5SpUKNBBDCe/Cp4EQPYr48BHia/RGDTpkGdOvVp8cWSS22KAaRs06BKhTCCiKow9JwMsE2DFu7rY4CHye+d96vUaNLFZN0PwqRFmQIBfOhP7gJazADh18YAD5W/R4MyZZqPUvlH0qFMXoWEPMcWO98P8OoY4GHyO/RpUKVGC3P5Tf8e8veoUSJGmq2NeE5DBui/LgZ4qO036dCgQQfzpg7A2jZ/hwFt6jTpjuKEnmdMM0Cd9ogByt519ktmgIdu/iYdmrToYT2CPC4mXdp0VIDopowo+7ijuwBk/aXfBTx89fdo06b3KKtTYtGnRx/zmYtKTi7lADlCJAkjFANUZVvwchngoavfZkCP3vjWv1b5vdJSg2fe+uczQAyNPh0VD+C8ZAZ4qNvHxcbCxhmXX6xlieFlC9iqCu9mVBiadxfg4kMgZeXlMsAqwV4Sdyx1c70PW+Kqn01cUzH2cQkTwQDEy2WAVYK9BNoj5usKnj8beLEfYJsQSSIIbOTLZYCHyq/hQ0d/JH+8QEPDh+9RJ9gqn8/zA2jKD/BiGUB/4Nf3jZI1xybAQ63ezO8JNAwCGOgbJv6sH6CFi/5SGeCh8hsEiRAi8CgXMgKDAEGCGM9y4bM8A+gvkwEeJr+GQYgoUYKPkiKuYRAmSuSRptc6GSBM6uUywEPl9xMhTpwI/keIyPMRJEqcGOGN2/5nGSCGUAXjXxwDPFT+ADFSqkK2eITVHyJBljRR/Bv53KYZ4Ig2UjFA9eXEA+gPlieJRY04/keY44IwWXbYJrkBt/33ZYDIy2OAh8uvI6kRJ/gI1tlHlC322CH55NF+qzBA+KUxwEPlBx9JUiSJEh6GeK9NpxBxsmyTJbYxVYBeJQPoK4kUJUmWLdmnLdxbzvH3Pe97fxoiSYoUyWdN9HoIA+ReGgPoK67SFPt8BEqysY5qOFIjRJZttkgSfXHdRGLsI4kQfSkMsJr8ftIc0sKHD3si6u9B1k4KomTYY58tEi9C/Ol4gG3CJAnDkAFor/pUNln+JPv0AZO2bI4FfMsH7yZ7HHHINjECvLQxhwGkIzaYAVaT3yDODjYuHZp0ZMWbAGKBjZ9eMlM230+SXT7wmQ/kiM39bFJZ2007DczGA7Rh8xlAX/G3Y0h8CPp0GKDJuug98Pn5SbLNB37nVw7ZJbLg+czruyw3bDrEOICX4AdYTX6NCAFC+Bio8myaLD2kKLLUibPFPl/4g9/JLdj6JTY2Et+Mr/G5J8A0A+xMM8Bm+gH0Fb+0wE8aSYcWfU8gWRRLfjlpkCTHPkd85BMfSC74hzY9elj4CBMe8whsmikQBAm+BD/Aeip7eQUaTXR0DEKygYnrVfcVcr46UuBTQR2ef3+HAz5zSG6h+C5dSpRo4yNOmjhB/BgPFF/i4GKrCsReYJkcmRYxFnLiU6EtqzLABsYDrOe61iDJITpxkmxxRYk6Tdp06d36W2GixEmSZYc99tjjkMTCf29T5wdfKeBji0N2yZAmMfYdljEBEpseXbr06DPAxMLBRSIQ+NBHlYdDhNVJ/qEMEEZHgqzT3ywGWE9hN4jiI0qWHHvkyXPFFUWEKpQ+X/yIqum7yw777JEjTfyWqn4WdX7yf/iBYJ9f+cIhciri4P4TwKJDkzo1VXy6q7IKXAQ+FW7iXWonSCHw3+tuY5YBIiQJASYugvpm+QHWFazhx0+cJCkyZMkQw+/FAsqm6M7ZIcPESZHjgCMO2GOfXdJ3FHR06VLmlK+41LFxsPETG6sFfl/pHbq0aFKj7FUfpUGbrqo77oWyhQirb5RWhV4TS18+C9UzCLq0sQEp7bFKp/Llrv7Z9SaIKuvvSR8hTY2WHOYBCmVbNQJEiJEkyx777LHNNlmCdz5ML8LQT48mV/hw8RPER/JOYeSox4DJgA4tmjSoUaVKfVR8flh5XMcgSIiYmgA1amRJElG9CAwMfLfuBvPuAkBHg01igHWHagWIAToBEuzTpDW2qQ6xSsdPkDAx4qTJkCJJ/E7xQSfKDr9gUqJHiS5tHMBhhzSxW6OOBJbqMlCjToM6DZq0aNGho+y/t/a9Dt+62v7DRIgSJ06ShLrjTKg4p/tfdHsMECXqnVZkY1P8AOst6A4CPzH8xNimTx8TEwsLS7Vz8FjaUHHCQfUTuJeD10+Sj/QIccIxecqq8qZDDxf/2B2BnPlcFh1qFLngkgJlqjRo08NSXUdsxf835D8kfoMAfgKESLClzNQ2EuPWCTv57kF2iZAijMTCRcBmMID+CK+oE0LCKFPHwVZczSg7wPtPbVjf9V47n0aUPVyC+OlwTQuLIBF8uBiEx+SffjWTBhWKXPCTYy4oUqWpsvS0Oxs2ebkGBjF2qNHHRiNyywllsR8AusoPsCEMsH75F4npKPl9K5mWBDaSPmXKmNj0yKPjYsxlAC9RtEuDKiWuueSMM/JUqI98k3fnELpqCnWkJECYEHG27pl4Pp8BjE1hgKfr4ulbQ1CYThSBhkUHmwjVCQaw2SFDbOz5DahQUj9FSpRUzbDWA7v1talRIkqazoMSzz0GiA29CM/PAC+riauPEAY6EkmANKccczXGAH3kBEe0uFJFJwuqUmBPOXgeesrpqyZVg3vKP8sAUVKERgwgJ6ogPzkDvLQevgKDFAINP1H8tCiMMYDET4Rt9W/rFDnjb75xQYEKTWEpd/McNrzXPq4rUnjoHj30A8gxBnCekwE2S36vC+CN791LJBVzNlHPOdunRAUThz7XGEj8+HEIYtOkwjnf+MkZecqiMdJgqs/AougEMfusQiTZYpvs0k7geXkB4vkZYLPkdzEZjHzvGgZBtDnM4COKRGDSwSFKjT5V+nRxcajjo0uFMtecc06B2sMLzU+4qRMc8U++8IGdlULRhgwQeW4G2Cz5vYpeXeUl8HJ95id5+kngw8UlQJozTilQpomLQwlJjSIl6tSo06a3eoUgqRElxxf+F7+Tu5eb6gUwwKat/j4tmvTU6TqKg7EgjUwnqRzIUfy0KVCnh4FGDYsyBap06GNhi5UKxEjPWxEmyx6f+JVfia1MMEMG6IzuAp6FATZt9feoUaahgkcS9NExiC4whHEkGj76XHNJDYcW13QZeK8yHXo+DXziHgtVrdYkWxzwmQNyK4k/6wfooikGqNITT8wAmyW/RYsS5xQp0cAlS1fZ/9Bcj75GEj8GJlVq2DQR1GnRp017Xt7Bw3BdRjjgF77wK4crr/zJ6XuIRnTIADTkEzPApq3+LlXynHNGCYsckjhxNFgwAQQRdHqUqTCgQJOOahZvr0d8kBoJPvJf/MEB20va/A1ngE07+DlY9GhS5oouXRJsk1RXxdEFvxUgRpIMadq06NH0VtDk5rn8SX90kx1jiyN+4w+2CK31iQ0ZwH0uBtgs+X2ESZClQYkKPfqUOCFAjx42LAj+7tNWl7Y9+jdHKLFg2SmU827sBdroL11VTdDBFg4IpCBAnB0+csQeWwujEF8sA2yW/H4yfMJPEJD4sajzlRbFURHF6XRyiw5lzjjjXLl/rYWr+GZH1YkSJUQAHR0NDS/2b6Bi/9rqoOhjiw985A8+3BmL9CIZYLPkD5IjRpYkBhoBSrQ44ZoSNkHCaCQIjzGAQ50Cl3znb35wRpXBdJD57P4pdSKkyJAgTBC/cuU6WLRpUKOBqyIUQ+zxT37nM4fE17ztT37vPWLPwQCbtvn7CJIkoEJEffSpUmZAlCxx9RhuGKBNkTOO+c4xF1xPrxg5C3E6AcKkyJEjTUztAD4EDgNaVIgQxidt0QYyHPIr/2CfrYlpt+4hVO/gJ2eAzZF/PGYwzZ7agPt0qNOjyDF+euqmLYyGQ5trLvjJD04o0LgRf2hYx5eY9OEnSpwUKdIqRDyiVr8nv0mbDFlqZEnJGhof+MJH9tla2sv3QhhgM2/8AuRwCBBCILnAosZXmpToItCxgR41LvnGn/zgitKtGQVIQVBB3Ed2SamahAElvmf7vdCQNi2qFGkg2eY3jsgSe6ICcx4DxJ6OATZHfjHlzgmQIKp6epZockyBChAlSA+bJmXO+Ju/OKZKd9yrL+Z9zyBJDvhP/ovPJPAhlbEZlo2VivwtBrSo0sQhxg67JB6lftFtDBBcwACv3PbfDAODGDoD+kjFABUcMuwSIYJJnSLnHHPGxWQjudlMDznM2Imzwyd+VwzvTrgEbhLHHXo0aassghihJ4u/GjKAQ3suA7wB+ScZYJ82DoI+XWr0KXOGRgCLBlXy5KneiC8F8ib1XwoVU2yg4eLSp0t3rD2MNrECxRiARgkSw8JH8ImKTEzHA3yg9xQMsNnRPkG2sBUDCC6RtPlJDQ2Lnoq8602a+LGlJGWAFEnCDKjRpMwlJ+wQYp/0Hdu5Tgj/3FiDxxJ/kgGOnoYBNk/+ySu51BgDBKhhcsrJKGOnT2/czTOV8m8QY5c9ojRxqNFCJ04ElxYf2Lvju2v3DkBfx3eetFjDu4AgLqbXN3AiL+DV2/6bzxcnrhjAReeKMg16QkoxShqbsRpSwzvmbXPEB2JUaFOkTYs8P9Cw0PCzc4f861jVw2I02hKTfpIBvJhidyIv4A3IP74eUuzRxMSlTdFLGRVj0s/Y/JBKH9vnMwdEiNOljY6LSQGBi44fQXJNlt1LYzFH/YfsUcUAdyS/b9QCQ1eZioY6ck4bgXE/gMcAOgJHVr3w9HUywMuI9A2yhYkPQZP8/GP9xNqJcsRnjthnnywGKXWYrNLmmqZyKVnskCE+eRv0oKdp0qROa3T15F05Wzhjpah8Km00QpQkGZLE7nQlJTjCp84eFo5sMhBvZPVPMkCMfXz0uSQmfdMYNPVI/KT5xP/md/bIEEaSwk+INCd854JrWsixvIBV/XmO6jhcUvnCXmJrT6WMMpI/QFTtSnscYuMVghO3fO8Qe8RIoqvaSay7Z/LLWP0SnRAxYoQJ4JsM3JTj275Xa2iHT/zBf7BNBJCEvaIzQJUrOqoDhw9JgOiY/MuH/juYtChxwQV5ipSoUFfVAvpjXQgFPkLESLHFNh1sFdsQv6NGkZ8MIQbUqWMiEOupnnqX/N5mtSnD6xheokKTwfQxaSS+jxARkuzyG5/YZ0sVfhDEVEu4LmWqqszSFZpiAEgu2ZXAwWRAnx49OjQoUSBPkYoSv0VnJrzUwZRd+qo5pUmHKjmypIjPNK2ZZIAw23ykg04QAyFr62MAfYH4urp1n/dxnn6YlDjlmG9c0Fp4/2WQ4ICPfOQTv5CdyPiNkAVMekgSVNVJwGMAk90lGcCiToXq6KdGXW36nvXvz48tFpZs49Unq3JJjj0O2Cenrp9uY4CP6CSJYeDiyNa6GGDx6tce8YJz2dHjkv/h35xwQWNhTq5Bko/8F7+zzzaJic9vEEfDRRIkwzE/uKREWzHAAJZigC4lzrjkkksKVGjTx8JStQxu6zxq08GiwSUh0hzwRSWaazP3CuP6RjgkSYYgzsjTMXg8+SUmXVqk1uhfXGW0KPCDP7mgTnfh6tcIk+WIL+wQndnOb/ICImjUySsGiCoGiNyTAbxg8guOOeGMUy6pij7IiaCM2e1SDuW3PRcuyII6zDoIAoSJL3x/LyYwgkVjjAHMx5Lfps4pf/GJ1AYUVvacuwWuqdDFGT7JmasdRyFihMiCuOCYOod3KVND4tDjEnDuZACvJtCAHh1qFDjjlAsuyVPyEkfF3KAMOXLpzb6s6MsiAQwkGgGC+AjPTTgcZ4BPdDAIYSBkfXUG0BfY2jz/jcs1nzkaC3B8agZwselT4ZoiVeq0hHtL6MtgrDrf/HGTG9hDklTewBYd3LkMMP5EGtSojOoElChRpUJDWCt8vw7XSAa4GPiBlLppWDSSfEInRRwDF3d1BtAXPMgrXGoU6BJcY3zrssOiQ508eUrUhzQtJub6BFgN6NCkQXTuSvIOUl5uoCRElp/84IIiHSQaNoMFfgCXNkXynHHMKXnqdOgr984qrg1HVunTA4IEEdhk0CYqlEx+B48BsoSwVezzigywaPOv0qNBlwi77I4yW56aAWxaXHPJJSWa9Gcs6eQ+6cOlS5VrDFiYF3DDAGEEdfJ0KRMhig+m/ABD8auqMMwP/uY7+eFdvJhvhJaZAC5taRIgThRd5TT7b3GF3TBAA3t1BpgvvyMcOcAmwE92CHP0TB21LOrkOeGcIu3xoA4xFFxX1XZtJEF8tDhHp0efPVhYFH6aAVy6XMFoE/ba07nqfN6gTJ5LLjjljIKoTWsib3FXLtivxI2jWpiywgVhhMpziLAIIsYZwEt/W5EB9EX+VoHsUeUnAbp85jNHo3PA0zGARY0zvnNMke5cWx4mShAfEhcffmr8SZH8KC9gPgL6iMIEA3iVwrq4CExyJAgCLa65okBxZPGLjxJ81eYKMNFJ3XEPOc4ASWLoODjyobWKbnX6OnQ4Y0CZPD1CY/I/1RhQ5ZwfnFOlP/ekHyNDnABCcXydAieUcAgRVhNgPgMM/QAhshzznctRIKlJm12SCEr8zZ+cUKI68uTba/lmkxtGnyJ9TGIc0VX3+7dda0Q4IkmWIDY9LKRsP2wC6LfducgeFi1qz8YAPWoUuKRAF1eKmT4BBlG22CKMgcuAMk3q9LBJkCOGwMW9BwNAjTwdIEYMGGDSRSPPD/7ND8o06Q997XLND0AiJH36EnYp06S7MJvxRpoAW4QxqVPHQqDJ5kMmgD5vSo6skoPDQNoEFQMckiLwZN7ALi0a1KmL1vinG0MtnTjbHKituk+MHnVMelzzHY0O3TsZQCDoU6OJBpgUkbRpkMVHke+ckac+Hmoxa2OXmwwLbXSLOhUqVIHgAq/r+NyLjBgghB/tIQyg32sNVvhJgA6f+TLRa+OxGEAiMalTo0n7lgh+gwR7fCFLFI0eaVwG6FhU+JM616qpokZwAQPE8aHjYqOzRZ0+dZoUOCeJjwZ5rmmv95L1lnNOlyoF4kgShO9RPzzFF/yklR/gAQxwH/ldOpzRp0SBPuEn8AN4NX4qVGneRPPN4WeDBLt8YpcEOj2SOJjoFGlwTJ4KkjBhfLCAAXQSGEggSIYzzriijkuQMD5MunSeSHwQDKiTJ4KGhn+u/PMYIEMQmy4WLDsB9Pt8qhED9Iiyy86jM4BNj4aSv38LbPmJqTLLMUBi0KWDg6BLlQqSpCrGspgBIEyCLbr0aXJJR5Rm6Uw+wpcV81C3TpGY6iRwn5e4YYChH2ApBtDvY5VGDBDiJ9uEOSS5YDtd1+rvUqNMhSZ9xnL3xu2s1AgRIU5STUdBij1auAgG9GiMGKBN7xYGMOmr5C6vqv8CeeTUOV/MM8zGWKlqL6BjVFhKLHBZiZtd1ksyTZCezFq6kwF2+EQX//IMsEy0T58qP/DT4TOf+TjFAGKtq79NhWtKNMabwUy9RUhd79zk3QfI4RJSuYFXigFqXNNZyAADahQ45TvHnFPFXGU9S4MIARW84dCnQ5f71hWTWLSpUaVBn2WqkT2YAfSl1mRbMUCePpGp7WmdnfQcOlQpUqa1SA4pCBIiSGDMRmqkCJJQEyJAkQY/yVNdyAA9qlxzzFf+5JgiNVa4wpF+Yqrnh6EmsY4ru/cuLGfRoaGKUzlLWI4bP4C1HAPo9z+ajDFAnxh7j8gAQ9tfU5VvZ6UHg8AoR3fSnxdF0KOPi6BLhSqSFNvEZxigRYVrrjjmJ8ec0WAwu+rkzFMRU/+NAHwESag+RkEMBBZNQvhpyh4W1rQRWPC9WzTpYC6V0z9kgAG1WQa4zQgsFeqpGMBRDBBUdwHrZwAXkw4t2gu8bAKBjoEx8vlPb4b7dJFoYwzwQzHALjZ+HHq0qVMkzxVnnFOiRe8+61SMu+39qhuJ1/YlSZokUbX6vQ4iVepeBLDsCvuOzd/BpEeXPtY9N/9pBvhMb5oB1rX5j2+Yj8sALiY9OnQXFk7XVKsV39zJF2RbsQFIrnCo8ZU6JTo4WGjqZFDmmjzXqgDsYOnqn4IoaVJkyJAmSYIYkVHgpo1JV5WW/s4JtnSEvNVGeu0nvN5HD6noMcMAmGLt8g8ZoEieAdFHYACvzFKPvmoBM28BCpWZL+e6c9KEFANIgpRoKgZw8WMjqaqrnDzXo1i95ZMoQ6TYZ48DDtkjS4zgqE3NsJVNjxJ/IejQwZYWt5VqcVW+kH1v+WcZIDXOAHe5rPTl3ZNjDDAgzi7ba2cAOQquskbtlaa3PKm6BDnYc76FxwDQo4cEOpQpYhEniYNDiXOuKHJNSTRvt/WzB0Bl8yNssccRH/jIJw7ZIoJvzjMoAVUKtJCqXPViX6ejEsUeVoXYyw0MTTCAvI0BHpTmMcYAP8gR5JDUWhlAqkh6c8GDuJkeJuZc+b2Ro4uFgU6fJj0a5PlJB4cKBS9ca1r8Oz+awC89f0OKbdWH8IA9cmOhmpMjwzaHXGNhUKJ5ixtLqtZX7mTy6oMZIIgBsr6YOVbJ8vHiAfy0+cyXtTKAtwoWboJCAgPZVrk01sIQ7QBHBEkRxqaLjaTMN66xaY9aNy47NMIqc3iPLGlSqqJo6JbfiHNACx8BUMFdt993rFrJK8UXAqSJomFiyi7OVB7kGuR3aHNKjyIFzLUygFRbuzN36x+ODm1atGkvrPgNIT4QB2pc06BBnR4+HNVZ8CH23keQHH/wX3wmTVix/20dfiVhdnHwA02KD/MHL/UbUT6QIo1OT2UF9ufvo/oyrz3DAF3MEQPsrZUB5OhnoVUWtuxQp0wRHzH0mbYvwwkYJU6MKEEatKnfVf1PLHg/tXw0Vdv/iC9kCIx191k8gmTREDQ4uSN1zkuvWf35+ckSVEltFho1Fc28yrl/5rO6mJjSIcxPcgQ4JLkgvGr52Tz8uW10KfKDAA3SxAirNTjcOWxAw6HJKSVamJjLpUeOpr1OgAA6Fj3cUYyvhbxnV+8APgQ9koRvfeJCyf/QKTB5GRFll1/oEyCImN+/bB0Zvj0q/MBYIwMIVQrBd8dj6HFJgDZ77LFNmgh+tDH3iZeCWeWCH1zRerBD10+KJAHalKjTpMQl58QQbN+r0q/XwzBB9NZgmZvWsQ9d/9PH4Ay/ESRNkAHVedGS65Dfpc0p3TUywLCJsoF+q2Q98vQpssdHPrJDQhVct1SkUJUyRcpUvOaND7vOkRoxttkhRBWThhjIMudk8GEjOBh7hrdN9wAhgl6trlsg0ae+9cMnwPiI8YUsKSzyHK9M/gsYQMquqm8xIMEeOyOvunjw1u+VZPNP2nMxe0VSpU2NpmromlS1sLyrkxpFrrii7Ll1Jou+zr6emD3iaapf4C5HHBAkSoeGbGBR5Rw/PoKEyd0T2bybQHGr/F7fcP/c9nUPGToZNC7IzN+l1lLeQTGAS5gf5AhwQGolBripyOdthHLh+0JPWgj8CLoqU95b/W3Vtrk4Gal3zxWvY4yazCfZ5YgdDBLYuJSQmOSRuOgYuCTuFQHpW+CivvnWXsHpiJfDtxI4j0/GGHFixGRYdKc343VW9/DuAgyafOaXlRhAjBqn63c/VmHLDkVsqqMDmKNCODqq4erydtNPjBQ5dtkjxzZbJBBk8RPiigoN8tRo4yAZsEt2oqP3Q5lHJ0RUQewqAC2mQpV0IiRISImJHD8ArlN+lxandLnmGovYCgwg0NVtvv9utpZgUqNLcSzOxlXu0/v26xVTaz9Cll0+8iu/sEeGKAY2acLEyPKDvynSpwP4sDHRCN0ZmmnfmvnvNagNE78TEZf9PiZeQesk9nTkor7Kay9kAIsE+2w/mAF8BIgQJ0ZjXP75J3QBFtZ9sm/mJ2OJqb+SGnHlzf/CH/ymIgk9J5KBnyAmRS5VjY4oGoIgkTsZwFS1vhYTiEGEpKr55VvjshQEiBCloz7Do6z+aQYwOHwgA/iIkGaLFnUVh/skQ2oYhIiT45AjjvjI0Zgza5gbKGlToYmOQ5cLXBx8dzKASZ/BHZc5BlHVZ2S9URT6KC7B9wjoN5cBdMUAn8as4n1tope906ZDGUM8XV9rgzQ5djjgEx/ZV82ax8k8igRMBvjIUKZJnobyqM0ywI0H06FLx0vIuvX9Y2TZIqUC09a0KtFG56ipk8djyD9kgKJigMQDZmucHANaXD5pdZEAKQ74wGd+4TM7xGYQzCCBhosgTJbv/M0FJXqIWxnAVs1pOwvDV4bewTiZtct/41Ca8Sas5vS9mwGSD2IAnTBpTGqkiUr/ohvrZW29mP1b4X1idc4PElYNX7bIsbXAMHm5gX5C2JQp0KDKJbE5DDB8I1OFfTXGm0mL2VcOEidNeu0NJOQo+EQ+/uZ/wwARfrCFwQGppVoh+QgBFllV/LTyKJ/SyxQI4ZcuFhY6IRyaVEjTvNVDGFXlWttUVK3gLufYCxhAYNGgxDUVVaB5kWs5rOSPrdX2CxU85/UykI8u/9hdwHd8NPiyJANoBDFwyZIlS1qac8okrmNoJNgiptJCbCRdzmnjEiVFmNQCEXRiCMSIAUqKAbpzGUAwoEaeC65v7TMYUNk9SWJrjZ3WVH+SORHEjym/xwAdihSxiS/BAF7g9HAT3sZCkx1hr/0ThsnygSwaA9q0qasiDraqpm8TXxDG4R8xQGSGAawZBuhT5Yrz+fKrSeAnQow4iQXFpVbZ+k3aNGjQwZw8eazH6Xs7AzQUA+SWZACDOFn2qOKiIWRrfnvWxTf2Yj4PCBBSCsJsc8BHchgMaFLHoIlJmwLn7BDCJkdqQW7gDQMEsSmTVyLH0PDSz4YMYKlicHlKqirQ1MeVPvSR1Y+uPXC+OwqM6eE8PvkvYgB9aQaIkOMzNkH8CGzZXnVZSB9+ggRkkAgJ9vjEB7IYSqKQyguwuOYbDk2Va7foM08ygB+HjmIAHR2HtArv6lDlWtX/dOaeOBLkOGRnbR0GJk1wlQYdr7uxfLLN/2brGzLAZ35digG8nL0wcRVqYa2cbK0TI0WaHDlybLPDFjEMvFy/GC42V1iUsSlRHDVTmO+8ms8AdbqAoM8uaQJ0aFHlmmuq05uvegpe0eZPHJBcayFtr2JAniL1obtX8NTyO7Q4ocM1RZylGMAgS4QkYSyaNLFWLmUaIcMOh3ziE3tkiBMmgIGOTZMwNhYGBWpUuKIxaqbALXUCJxngnBIDFV3cpUecHnUqlKmI3hzgA03F5n7hgMRaD3xdSlxxRp4avXnus/U6fW9jgBYNbFJLMYBGgABhXGqUaSEwZIueB4FSDNPrxKIT/ygoUUiQBglVRfsTv/GFfRIqDMsbcVxatHFxaCm3bpYcYSTuwjqB4wxgUSZPkzpXxHAxGZDC4poKddGb96yUry/HIR/YIb5G+fvUKXDGGQXqN6WxVo7zX4EBvpPFx+FSDOAnzSFNBCmKVKhLVUF7cXMz4U0PXTk7/dIgQIQUW+ywwyFH7JKd8c+lOKCPhmDAgBY98vyNvQQDVGkTAAbkMWlSI4XDKdc3nbjkbKJ6gi322GOL6NoUsWhQ4IRvnHBBff6J4ym7eQwZoM6XJRkgwh6Q4ogr8lxT9ir83hmm7SeqDlNJUqp5s5eTlyU+x8qG2EFTtb0FeSzK/IsSJfr3ZgCdc+r0KVMlzwVxUOeCRTAaIcEWO2yTukc9n/uNYY+Rb/ybM65pzE8ueUr5bxighENiKQbIEWOXEpecccEVl/hwpXOrLyBEjDQZtthmj122SBEnQpiQysGdfRoZIiQIqmo/BWrUyNPER/TeDLDFCSdc0kAQIYJGfzzOcMxEavhUYyfPwbUu7POqhOQ54TtfuaQ17e17XKfvYgYY0KKBQ4p9tu7NAD5ChEiTJEKQIEF0fBiEZYeBusG+6eunoeMnpB5sjm32OOSAHAkidwRSaIQJ49Khh8SlTZUmBlm2l2KAEpZoAHWp40PODfTQlEHaYZvsGpnfpEmZPGecccalqMxX56lXP8LFxZIuUcUAB6SILOEHSGBhoxEiqq5bu6NMQKmMqqYsfki5UNNkyLHLtkp6Wnw7JG5lgK9YdzJAHIEPQYPzYeKZsG+23amaQJIQOQ75xIdR36F1iF+nwDknHPOTa1rMXYzPIP9cBvg8lhp5FwN4W6ufJDuqyGofE1MlRbtjIaIBAgQJESZClBgJEksEnjyUATQS+BFU+UlalkVr1t94swkLKaMc8k9+5cvaNv4BLcqc8idfOeWK8u3Bbs8hv0OTE9oUFAPEl/hdPwnCZLHUj9c90yuJYKPhVwVf/PhV7Q+fyhgw7oiyXcQAUjFAlTxN9DsYAEKkyZAhRVxaDCZSK+UU9CU45B/8zh7ptSjhiX/FT/7Fv7ikcVeRmMd1+t7OAE1c0hwswQDMlHLxrmoH9Bgo+UOqQepq32ycAVAM0MJg604/ADi4qheaodJUp56G+l9JchzwkQ+k13K/P7T5pxxzzIm4xzX5s7RxVAwgifKdDNrSDDDtGIooAvBW/yoPchkGEDM7gEmPBgVOKdJWJVrmtB2RBgF143CgLpXEGsT3bP4xJ/ygQGPBpvP88o9dRnxDUOczvy3FALPbjF8du/QVV5GYwwDRMQYoYikG8GHMlItvcsEpp/zgByU6k5G9Y1M2To4DjvhDBcOuLv6kzb+kfL/r8eeUf8gA15SQSzLArGxeGuW6OxxniJAkMGKAKjXytDCIE0ZDjMUDDCjxjf+r+gRX6Cxo8ySIss9vfOYzOyotbV02/9/8Dxd3xCo9tfy3MkBTMcD+UgwwT/7HGB4D2IoBHFrUaBEgN/IDJJUJ6FPikh985TtFmvSH4s+UgBUElJ8vS3wNa//mnD/X5q+rqOtjMQCKAQQHpB/IAOsek+YnzQF9fCpLvkWfAt+wadFllxhSlWL/xnfOuabOQCwO6fRK1mijNNbxdxUPEH/c5udp3sfmb4T8UwxQ48uKDPBY44YBBBrX2FT4kzIlupgkGVDknCvOOeWa1rj4cya9lH1VfcDEndq1lp0ANzb/r/uc8zdR/hsGKCNJrsQA67ZXNwwQVQwAIYrUqXFJHRBkaHLCdy6oUKNJf1z8uXradKhTo0EPa4Vrnjk2f7nZoz/HM13IAJIM+2OZNY+98uXIWSxGgQNiAQOE2MemreqC1qlhI0kQoUmdH/zNFS36NwXc5ejlpEoy8P5GBjBU6HeSDMmxfILlvq9n868442RZm79Jq/+GAS75RvoJGWBAgyYDfISIEFzQQeNmbNPFQkfSpi76ss4lQRI0OacwHVEjxiePF3XgXVQF8GNRwAF0fFgPSuswaZDnjBNO+L6szd8o+UcMUH5iBuhywRkN/GTYIUPsjrIKQQ7xEQZa1OSAAQVcgvSo0WQgFvcWD3klFogRQqNNhQuKtLBw6bHH1lR9AHHnxG1RerjN30T5PQZoUXgiBpDUOeO/KRLkABMHVzV4XDyi7KPR5IJz6nSo0kXDxpz2rk8oGCBOjgxbbBHD5Zw6ZQZ0AU3VJQ0vcekzbfMby9r853X63s4ALSDDwSMzgEOda874wRVB+mi4DBiQIoqBmMiH897f+xNn5M/XcUR/tq6AnEIIFWN4wLbqg2TicoFP5QVEEcr43JcBJm3+qSgvb/M3cfWPM8B30sD+rXf0Dx8eeV/znRMuKGBg49BQZdm9evzaWCc9Lz3SxsXFpMoPCsqle8ehQWoj7/5n9tgmS5g+JkUaBHBpc4bpFV9mQJzgneVsbmz+Md/J38+3/yLkV6NPmb+BKl/4nS9j5RVWYYDx3dikyAmnfOcn15QR9GhyQYwYUSJERoVlNMDFUdfKJgN6NClySZnBvOc9/jbSa8mc4xN/8DsHZIjho4tNF0GGEnUuqdLBxqHDDlnVkvKRbf4my+/Q5JgWBSoIUmPyrw/58nzlK6ecUaGJTZOy6soRIqTKwIZUjICrrpS7dPHKSHfp0Z93lz71BwES7HDAF/7gHxwQx8Cho24QMvzNX5QoM0BDw8TCR/gW+Sdt/vny5/zNcvrOZwBXxQO0gCz7ZNbCAGJsetW44oQfXFCiIfp4XXQYJYFFSZAgPOrIZdGjp5q9tafv0sZ9+hMbv6HKxHzkEx84JKOeeAIXr+BKj2vydGhSJEWQCJlbyr2P2/yT1Wz+Jq/+ST9ACsnBGhlgQJUrLrngiiKtyQBs4dCTPQYM6I5qcHqrf0CPnujex0kovVINSfZUeZtP7E6cY6LK3dSiSpcSGi41imRoL9zM12rzN1r+EQNU+Bu5RgawVa7tCecq820g5kgpBwhshX9eZQyv/Ls5z9bP+Sg6EVJs84V/8gcf2CY1cawzVF5AnwEGeVrY9Kku6lw2Y/MvKa2nkfwmy+/Q4JgW12tjgAFVLjnjmHOK1BfW95YMFI17Pls5cg/fR3yvQFuKbQ75hX9wNMeX4OUF2ECYHfIU6YyaOC22+cc3Nn899c42w+m7iAE69GnRQqyFASRtylxwzBkFasOcu1mbKbxj3i0vNPz3Ys5EUOXf/apaR3phXkACBxddVfGroBOYW8v3xuYfr8vmv4TVj5DYtMYYwJsCD2WALnWu+Mm3yZy7dU5h6fn0DWza1GjQpn/Lr0TIAAH8hKihsT8nzWto849X8e2/SPkn/ACSCr88kAG8Wnwtypzzja/kqT9GW3bpI0yYAC59BjgkOeSQ2MIaQQZRBCFi5OggSLIzVUxm3OafcEVptXP+S5TfY4AmBaoI0g9gAEdV77jmnGN+Un2EOkFIjQgpEhh06NPEJMEpu4SwFgR1aQTRiZLGwkZgEJw49Q9z9dZu8zfT6Xs7A7TR2FKHwOXMnUWbKnmuuCJP6X51Qhc3bJ843YtR2FaIJFkS6FTo08GkQYEzgljk5jKAwLjlosekSYk8p+s757/E1T/OAH+TxF2aAXpcc8pPvnJKeVz8VVuOSg0/YaIkSJIgTZYYkjwakg4Wef6iS12VfLt/TQOJSXNk87+t2+a/KPlnGOALfyzFAB0u+Bd/8pPTcXfJGq4SfURJsasyiDOkCDLgHAPBNQMKdMhTwVT5SaF7hXVIBrSVzf+T0/Xb/Jco/zgD+JZgAEmPEid844KqcNb3gSRESbPLZ/7gV/bJEEOnQxKJjU6eCkXydAkQJ6hyA+/eAUzalMlzzJ/8N+c07igF/brkvxcD7C/BABIXGwfwywgmttr1Jbf0ihPzPo9QdQRc1SIhyzYHfOIXfmNfNbBII2nTwcWiQZcuYc7YIoCLA3cElEzb/DNRWr/Nf4mrf8gAgku+kcThgDSxe6ymIFk+YpKkQZsOXfoMMJfdCcSoLiABQsRIkWWbHT5wOBGuleKAAToCE5s2XS4I0qHGZ2xcVa9bLPBMNsfO+Vfr8e2/CvlHIFfmKw5lfuEPfhlbTfMZQBDjIzq7XFOiRJkKVepqLS77vGIkSJEhQ4YsGbKkyZKZSNMMsYtOlACgUWBAgS55SgzQ8CFVfZL57t0SZ/z7cW3+S5Z/yADX1PCNuYIXjxh+tvhCkUvOueTKi6y9aW5+T1uvE1O1Qg44YJstVYY1NJVQrpMlSgIDFwhyRYkSBQbEyJEkgA9tjvyebz/PT/7kvzmj+Vg2/0XIfysDNGnjY4v9saq7i8yhofqDJIkQUC2XA4RoyA4Ddc0iZvbX8dLAEo0gcVUraJ8PHLFD5pYavEF2MWnTRaqilI5q6LCgL/lT2vyXvPo9BmhLbcQAHnNrdxznBQlMHAzF6zWatOnRx1JlGJxRywMx6qTrtVX1ikXFSJIiwzY7SvzIrbPXYwADDYmBS4o4UUL457RzvLH5x3zn6nHO+a9C/hEDlBYwwKIJoBNDEmaLNm06tOnQoYcX4GGqtu6uaiLrQ1dlooKERz/DWkExInemZ3kMkCBCkCQWBwoRwzOlZsZt/gl5SphP8QhfsvwODX7SoHBvBoAgOnEcHNXqsUOHDl06Kn7PKxMnVC9dQxkJL/Yvoqr/6qOqQXe5cPxkiJImTIAUfXJ8IEdixv8/tPnHT2XzX5bT93Y/QAedHAf3YIBZH3tPSd8e7QKmiuQ3VPq1d8RLECfyALPrUzWCLAx6pMiN3D/zbP7xU9n817D6xxngbxLYcxjgrqcWUlt7ZMwAeAXi9FFFMK/BU3BZh+DYOyfYQTAgSnqmS8/Q5v98jPv8Vy2/Gn3FACV+nWGA+6zPwKgvl42jqFxDU4ez2SIMy2xY3giQxsDGT3TqlSZt/qOf81+j/PaIAeoqE3+5daphoKv6PVJF9A0Tvr2fVWOMva4AEm2qMN2szTefrmfpy3P63sUABrl7+QEmX1Q8eiq5V37utnP+6dPa/Ne0+m8Y4IK/SWCxT/YefoDnHZ7NPx359p/U5r8q+UcMUFYM8Av/4NcJl8ymTYChzf/zeWz+a5Tfpo6jGMDrArSpY9rmN57qnP8q5L+FAXqKAbbZJ/lkNYKWG5M2//w5bP5rXP0IiaP8AF+JY7FPhviGMcC4zf/22Pf5b0r+CT+ATZFfN44BvG3/jD/5t/LtW8/5cV6j/B4D1LmmsWEMYI5y9f7ifzh9Ot/+q5T/DgboYrDNwcYwgElDtVU84YTzx4jbf1/9kwzwN3EG7JN9dga4sfnHz3fOfxPyjzHAX1gbwQCzNt/chEf0muUfMkCBBv419sp6uM0/2RSb/6rkv5MBAuywT3yUGCKeWPyhzT/mdDNs/ltY/TcMcMFXos/EAEOb793nX26GzX8T8s8wwG/8g98IPyEDbKjNf0vy29SxqVOgiZ+tCfmf1uY3FvXSfZf/sRmg/eQMsME2/y2t/iED+LjkK1H6HMwwwPpVmLT5V5tl89+U/Gr0KPIX5lwGeEybf0ye8mbZ/Lcov8cANa5pEiD3iPLP2nxL8C7/czNAmx5tegTYZY/YIzGASX1Ue/eUi020+W9x9SMYMcBfROizz9baGWBAk8KYzX/W+/x3+ef5AYr8ick1v/HPNTPAQFUP3HCb/5blH/oBrmkRXCsDmKMYvr/4H05obqrNfxPyL2AAZ8QAQXbZXxsDTNv8B/TVe5f/KRnggr+I0OVgDQxwY/OP+bGp5/x3+eczwH/w21Q13Vdt89/lH78LaBNkawX5b2z+15dh89+U/LcyQIseIXZWYIChzT99OTb/ffUPGaAjqyMG2GeL5NLiN8Zs/uXLsPnv8k8zwIACv/MfBJcyAl6njXP+5F8cU3gpNv9d/kkGsKhxTYcQuSXkt1S9/RO+8i9OaDxGn4B3+R+fAbq0GRBmlz0iqumae0fef48GZVWM7ZTLl2Tz31f/5LRw6cgKF/xFmDY7pIjcWnvbpEONIhecccbPTfftv8t/Pwb4Nz0u+chnPrB9S6eNNkXynPKDn5xzTeVl2fx3+ecxQA2LGleUGGAQwLeAA9qUOeeM73zlO1e0sHHf5X+RDDAq3Tv0A3SAMFEEHdXMXcfrCaCh4dKhzAWn6px/Kaovz+a/r/7FfgBBiBCSEhlihAmoVs4SFweTDlWuyVPgihKtl2jz3+VfPAaUkdT4Tlw1cg+osszWqI93gzpNGjRwXviEf7tDznkEklExxwARYsQJEySAjlQtZdv0VfVfCxv3pjOYfHGPVrwv9ttstYyo7f9G/iZdrMlOgPLFPtJ3+e9ANRkkiIEfHxKTLh3hLnqFl/dI323/XcNCYtJHQ+JgCvc1fbn31X/75g/aRKd2FznbAvZ9838zxuBlnu8XDe1d7rc83uV/l/99vI/38T7ex9sa/w8QIQoSbWe3qwAAAABJRU5ErkJggg==);width: 100px;height: 100px;padding: 4px;position: relative;top: 20%;left: 20%;background-repeat: no-repeat;background-size: cover;"></div>');				
				$(".noedit").css("opacity", "0.7");
				if (Application.IsMobileDisplay())
				    $(".explorermanage").css("background-size", "60px 60px");
				$("#msg" + _base.ID()).text(Application.ProcessCaption("Select a company to manage"));
			}else{
				if(mode == null)
					m_accMode = false;
				$(".explorermanage").remove();
				$(".noedit").css("opacity","");
				$(".explorerpart").css("opacity","");
				$("#msg" + _base.ID()).text(Application.ProcessCaption("Please select a company"));
			}
		};
		
		function NewClick(){
		    Application.App.LoadPage("New Company Dialog", null, { mode: "New", dialog: true }, ThisViewer().ID());
		    ToggleEditMode();
		};

		function EditClick(id, superUser){
			if(m_accMode){
				AccClick(id, superUser);
				return;
			}
			if (m_editMode && superUser) {
			    Application.App.LoadPage("Company Card", "WHERE(ID=CONST(" + id + "))", { dialog: true }, ThisViewer().ID());
			    ToggleEditMode();
			    return;
			}
			if(!m_editMode)
				Application.RunNext(function(){
					return $codeblock(
						function(){
							FINDSET("Company",{ID:id},function(comp){
								if(comp.Count == 0){
									Application.Message("Sorry, this company has been deleted.",null,"Application Error");									
									return _base.Viewer().Update();
								}
							    if(comp.Status == "Inactive"){									
							        if(superUser){										
							            Application.Confirm("This company is not currently active. Please activate the company before continuing.<br/><br/>Would you like to activate the company now?",function(ret){
							                if (ret) {
							                    if (ControlApp.SelfService()) {
							                        Application.Util.ActivateCompany(id);
							                    } else {
							                        Application.Util.Activate(comp);
							                    }
							                }
							            });
							        }else{
							            Application.Error("This company is not currently active. Please see the company administrator.");
							        }
							    } else if (comp.Status == "Activating") {
							        Application.Message("Your company is being activated and will be ready shortly.");
							    } else {
							        Application.App.ShowLoad();
							        Application.ExecuteWebService("GenerateURL", { auth: Application.auth, id_: id }, function (url) {
							            window.location = url + "&returnurl=https://" + window.location.hostname + window.location.pathname + "&user=" + Application.auth.Username + (Application.IsInMobile() ? "&mobile=true" : "&mobile=false");
							        });
								}
							});
						}
					);
				});
		};
		
		function AccClick(id, superUser){
		    if (m_accMode && superUser) {
		        Application.App.LoadPage("Account Management", "WHERE(ID=CONST(" + id + "))", { dialog: true }, ThisViewer().ID());
		        ToggleAccMode();
		    }
		};
		
        //#endregion        

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        this.PageControl = function () {
            return true;
        };

        //Constructor
        this.Constructor();

    });  
/// <reference path="../Application.js" />

//27/01/15      Issue #7        PF      Added new control.

Define("Purchase",

    function (field_, viewer_) {
        return new Control("Purchase", field_, viewer_);
    },

    function () {

        //#region Members

        var _self = this;
        var _base = null;
        var m_page1 = null;
		//var m_page2 = null;
		var m_page3 = null;
		var m_page4 = null;
		var m_page5 = null;
        var m_form = null;
        var m_record = null;	
		var m_promoqty = 0;
		var m_promominqty = 0;
		var m_promocode = "";
		var m_prices = new Object();
		var m_bundles = [];
		//var m_creditCardDetails = [];
		var m_totalPrice = 0;
		var m_totalBundles = 0;
		var m_unitCaption = "";
		var m_gstLabel = "";
		var m_currencyCode = "";
		var m_gstPerc = 0;
		//var m_skipToEnd = false;
		var m_transactionNo = 0;
        //#endregion

        //#region Public Methods

        this.Constructor = function () {

            //Setup _base.            
            _base = Base("Purchase");
        };

        this.CreateDesktop = function (window_, form_) {			
		
            m_form = form_;
			_base.Viewer().CloseAction(null);

            //Create the control.            
			$("#"+window_.ID()).css("margin-top","-15px");
			
			//First page.
			m_page1 = $('<div id="' + _base.ID() + 'page1"></div>');
			m_page1.append("<div id='paymentBundles' style='text-align: center; color: Black;  font-size: 20px; background-color: white;'><h2 id='paymentTitle' style='font-size: 20px;margin-bottom: 0px;font-weight: normal;'></h2></div>");
			m_page1.append('<div id="paymentCoupon" style="background-color: whitesmoke;padding: 5px;"><label style="display: inline-block;font-size: 20px;margin-right: 5px;margin-left:20px">Coupon Code: </label><input type="text" id="paymentPromo" class="ui-widget ui-widget-content" style="font-size: 20px;display: block; width: 200px; margin: 5px; display: inline-block;"><div id="paymentPromoBtn" style="display: inline-block;cursor: pointer;padding: 5px;">&#65088;</div></div>');
			m_page1.append("<div id='paymentCart' style='text-align: center; color: rgb(220, 220, 220);  font-size: 26px;'></div>");		
			m_page1.append('<div id="paymentBestValue" style="font-size: 18px; color: rgb(230, 0, 0); cursor: pointer;margin-top: 30px;"></div>');
            m_page1.append('<div id="paymentTotal" style="height: 50px; width: 100%; border: 1px solid rgb(220, 220, 220); text-align: left; display: block; margin-top: 30px; color: white; background-color: gray;"><div id="paymentTotalUnits" style="display: inline-block;font-size: 22px;margin-top: -2px;margin-left: 10px;"></div><div id="paymentTotalAmount" style="display: inline-block;float: right;font-size: 22px;margin-top: 5px;margin-right: 56px;line-height: 18px;text-align: right;"></div></div>');
			window_.AddControl(m_page1);					
			
			//2nd page.
			// m_page2 = $('<div id="' + _base.ID() + 'page2" style="display: none; padding: 20px;"></div>');
			// m_page2.append('<div class="card-wrapper"></div><div class="form-container active" style="width: 400px;margin-left: 145px; margin-top: 20px;"><form action="">'+
			// '<div style=" margin-bottom: 19px; ">'+
			// '<div style=" display: inline-block; "><input placeholder="Card number" type="text" name="number" id="paymentCCNumber" style=" font-size: 14px; padding: 8px; border: 1px solid #cccccc; width: 175px; " value="4564710000000004"></div>'+
			// '<div style=" display: inline-block; "><input placeholder="Full name" type="text" name="name" id="paymentCCName" style=" padding: 8px; font-size: 14px; border: 1px solid #cccccc; border-left: 0px none; width: 160px; " value="P Fisher"></div>'+
			// '</div><div>'+
			// '<div style=" display: inline-block; "><input placeholder="MM/YY" type="text" name="expiry" id="paymentCCExpiry" style=" font-size: 14px; padding: 8px; border: 1px solid #cccccc; width: 87.5px;"value="02 / 19"></div>'+
			// '<div style=" display: inline-block; "><input placeholder="CVC" type="text" name="cvc" id="paymentCCCVC" style=" font-size: 14px; padding: 8px; border: 1px solid #cccccc;border-left: 0px none; width: 87.5px;" value="847"></div>'+
			// '</div></form></div></div>');	
			
			// window_.AddControl(m_page2);	
			
			//3rd page.
			m_page3 = $('<div id="' + _base.ID() + 'page3" style="display: none; padding: 10px; font-size: 20px"></div>');
			m_page3.append('<h2 style=" text-align: center; ">Payment Confirmation</h2> <div style=" padding: 5px; ">'+
			'<div id="paymentConfirmBundles" style=" display: inline-block; "></div><div id="paymentConfirmPrice" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="paymentConfirmGSTLabel" style=" display: inline-block; "></div><div id="paymentConfirmGSTAmount" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" background-color: gray; color: white; padding: 5px; "><div style=" display: inline-block; ">Total</div><div id="paymentConfirmTotal" style=" display: inline-block; float: right; "></div>'+
			'<div id="paymentConfirmCurrency" style=" display: inline-block; float: right; font-size: 14px; margin-top: 6px; margin-right: 5px; "></div></div>'+
			'<div id="paymentConfirmCCLabel" style="visibility: hidden"><div style="display: inline-block; background-color: gray; color: white; padding: 5px; border-top: white;border-top-style: solid; border-width: 10px;width:98.5%">Credit Card Details<a id="addCCButton" style="display: inline-block;float: right;font-size: 14px;">Add/Edit</a></div>'+
			'<div style=" padding: 5px; "><div id="paymentConfirmCCTypeLabel" style=" display: inline-block; ">Card Type</div><div id="paymentConfirmCCType" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="paymentConfirmCCNoLabel" style=" display: inline-block; ">Card No.</div><div id="paymentConfirmCCNo" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="paymentConfirmCCNameLabel" style=" display: inline-block; ">Name on Card</div><div id="paymentConfirmCCName" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="paymentConfirmCCExpiryLabel" style=" display: inline-block; ">Expiry Date</div><div id="paymentConfirmCCExpiry" style=" display: inline-block; float: right; "></div></div></div></div>');

			//'<div style=" padding: 5px; "><div id="paymentConfirmCCNo" style=" display: inline-block; "></div><div id="paymentConfirmCCName" style=" display: inline-block; float: right;width: 40%;white-space: nowrap;overflow: hidden;" ></div>'+
			//'<div id="paymentConfirmCCExpiry" style=" display: inline-block; "></div><div id="paymentConfirmCCCVC" style=" display: inline-block; float: right; width: 40% "></div></div></div>');
			window_.AddControl(m_page3);	
			
			//4th page.
			m_page4 = $('<div id="' + _base.ID() + 'page4" style="display: none; padding: 10px; font-size: 20px"></div>');
			m_page4.append('<h2 style=" text-align: center; color: red;">Processing Error</h2> <div style=" padding: 5px; ">'+
			'<div style=" display: inline-block; ">Transaction Date:</div><div id="errorDate" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="errorAmountLabel" style=" display: inline-block; "></div><div id="errorAmount" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="errorNoofUnitsLabel" style=" display: inline-block; "></div><div id="errorUnits" style=" display: inline-block; float: right; "></div></div>'+			
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Transaction No.:</div><div id="errorTransactionNo" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Receipt No.:</div><div id="errorReceiptNo" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Response Code:</div><div id="errorResponseCode" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Description:</div><div id="errorDescription" style=" display: inline-block; float: right; "></div></div></div>');
			window_.AddControl(m_page4);	
			
			//5th page.
			m_page5 = $('<div id="' + _base.ID() + 'page5" style="display: none; padding: 10px; font-size: 20px"></div>');
			m_page5.append('<h2 style=" text-align: center; color: green;">Payment Successful</h2> <div style=" padding: 5px; ">'+
			'<div style=" display: inline-block; ">Transaction Date:</div><div id="successDate" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="successAmountLabel" style=" display: inline-block; "></div><div id="successAmount" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div id="successNoofUnitsLabel" style=" display: inline-block; "></div><div id="successUnits" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Transaction No.:</div><div id="successTransactionNo" style=" display: inline-block; float: right; "></div></div>'+
			'<div style=" padding: 5px; "><div style=" display: inline-block; ">Receipt No.:</div><div id="successReceiptNo" style=" display: inline-block; float: right; "></div></div></div>');
			window_.AddControl(m_page5);	
			
			UpdateAmounts();
			
			$("#paymentPromo").on("change",ApplyPromo);
			$("#paymentPromoBtn").on("click",ApplyPromo);		
			// $("#paymentCCNumber").on("change",ValidateCardNumber);
			// $("#paymentCCExpiry").on("blur",ValidateCCExpiry);
			// $("#paymentCCName").on("change",ValidateCCName);
			// $("#paymentCCCVC").on("change",ValidateCCCVC);
			
			// $('.active form').card({
				// container: '.card-wrapper'
			// });

			$(".boxy-bottom").hide();
			
			var CCbtn = $('#addCCButton').button();
			CCbtn.on("click",function(){	
				Application.Loading.ShowOverlay(_base.ID()+"page3","For security purposes a new page has opened for you to enter your credit card details.<br/>This message will clear once you have closed that page. <br/>If you encounter a problem then you will need to refresh your browser to restart the purchase process.");
				var win = window.open("./Custom/PayWay?r="+$id());
				var timer = setInterval(function(){
					if (win.closed==true){
						clearInterval(timer);
						Application.Loading.HideOverlay(_base.ID()+"page3");
					} else {					
						if(win && win.location && win.location.toString().indexOf("singleUseTokenId") != -1){
							clearInterval(timer);
							var token = win.location.toString().split("=");
							win.close();
							if (window.focus){
								window.focus();
							};
							Application.RunNext(function(){
								return $codeblock(
									function(){
										Application.Loading.ShowOverlay(_base.ID()+"page3","Getting Credit Card details.");
									},
									function(){
										return Application.WebServiceWait("CreateCustomer",{auth: Application.auth, token_: token[1]});
									},
									function(ret){
										var paymentDetails = $.parseJSON(ret);
										//add credit card details
										$("#paymentConfirmCCLabel").css("visibility","visible");				
										if (paymentDetails.data==null){
											$("#paymentConfirmCCType").text(paymentDetails.paymentSetup.creditCard.cardScheme);
											$("#paymentConfirmCCNo").text(paymentDetails.paymentSetup.creditCard.cardNumber);
											$("#paymentConfirmCCName").text(paymentDetails.paymentSetup.creditCard.cardholderName);
											$("#paymentConfirmCCExpiry").text(paymentDetails.paymentSetup.creditCard.expiryDateMonth+"/"+paymentDetails.paymentSetup.creditCard.expiryDateYear);										
										} else {
											$("#paymentConfirmCCType").text("");
											$("#paymentConfirmCCNo").text("");
											$("#paymentConfirmCCName").text("");
											$("#paymentConfirmCCExpiry").text("");																			
										}
									},
									function(){
										Application.Loading.HideOverlay(_base.ID()+"page3");
									}
								);
							});
						};
					};
				},1000)
			});
		
			var nextbtn = $("<a style='float: right;margin-top: 20px;font-size: 14px;'>Continue</a>");
			if (Application.IsInMobile()) {
			    nextbtn.buttonMarkup();
			} else {
			    nextbtn.button();
			}
			m_page1.append(nextbtn);
			nextbtn.on("click",function(){
				if(m_totalBundles + m_promoqty == 0)
					Application.Error("You must add one or more bundles to continue.");				
				m_page1.hide();
				//m_skipToEnd = false;
				if(m_totalPrice > 0){
					//get credit details from payway
					Application.RunNext(function(){
						return $codeblock(
							function(){
								Application.Loading.ShowOverlay(_base.ID()+"page3","Getting Credit Card details.");
							},
							function(){
								return Application.WebServiceWait("GetCustomer",{auth: Application.auth});
							},
							function(ret){
								var paymentDetails = $.parseJSON(ret);
								//add credit card details
								$("#paymentConfirmCCLabel").css("visibility","visible");				
								if (paymentDetails.data==null){
									$("#paymentConfirmCCType").text(paymentDetails.creditCard.cardScheme);
									$("#paymentConfirmCCNo").text(paymentDetails.creditCard.cardNumber);
									$("#paymentConfirmCCName").text(paymentDetails.creditCard.cardholderName);
									$("#paymentConfirmCCExpiry").text(paymentDetails.creditCard.expiryDateMonth+"/"+paymentDetails.creditCard.expiryDateYear);										
								} else {
									$("#paymentConfirmCCType").text("");
									$("#paymentConfirmCCNo").text("");
									$("#paymentConfirmCCName").text("");
									$("#paymentConfirmCCExpiry").text("");																			
								}							
							},
							function(){
								Application.Loading.HideOverlay(_base.ID()+"page3");
							}
						);
					});					
				} else {	
					$("#paymentConfirmCCLabel").css("visibility","hidden");
				};
				m_page3.show();
	
			});
			
			var nextbtn3 = $("<a style='float: right;margin-top: 20px;font-size: 14px;'>Submit</a>");
			if (Application.IsInMobile()) {
			    nextbtn3.buttonMarkup();
			} else {
			    nextbtn3.button();
			}
			m_page3.append(nextbtn3);
			nextbtn3.on("click",function(){				
				
				if ($("#paymentConfirmCCType").text()=="" && m_totalPrice>0){
					Application.Error("Please Add Credit Card Details.");
				}

				if (_base.Viewer().Options()["activateCompany"] && m_totalPrice == 0) {
				    Application.Error("You must make a purchase to activate a company.");
				}
				
				_base.Viewer().ShowLoad();
				m_record.Bundles = m_bundles.list(",");
				m_record["Promo Code"] = m_promocode;					
				m_record["Promo Units"] = m_promoqty;
				m_record["Total Excl GST"] = m_totalPrice;
				m_record["GST Percentage"] = m_gstPerc;
							
				Application.RunNext(function(){
					return $codeblock(
					
						Application.BeginTransaction,
						
						function(){
							m_record.Temp = false;
							return m_record.Insert(true);
						},
						
						Application.CommitTransaction,
						
						function(){
							m_record.Temp = true;						
							FINDSET("Transaction",{"Receipt No.":m_record["Receipt No."]},function(t){
								m_transactionNo = t["Transaction No"];
								var tme = "";
								var ampm = "AM"
								if (t["Date"].getHours()>12) {
									tme = t["Date"].getHours()-12;
									ampm ="PM";
								} else {
									tme = t["Date"].getHours();
								};
								tme += ":";
								if (t["Date"].getMinutes()<10) {
									tme+="0";
								};
								tme+=t["Date"].getMinutes() + " " + ampm;
								if (t["Response Status"]!="approved") {
									$("#errorDate").text(tme + ", " + t["Date"].getDate() + "-" + (t["Date"].getMonth()+1) + "-" + t["Date"].getFullYear());								
									$("#errorAmount").text("$"+t["Amount"].toFixed(2).toString());								
									$("#errorUnits").text(m_record["Units"].toString());								
									$("#errorTransactionNo").text(t["Transaction No"].toString());								
									$("#errorReceiptNo").text(m_record["Receipt No."]);								
									$("#errorResponseCode").text(m_record["Response Code"]);								
									$("#errorDescription").text(t["Response Status"]);	
									$("#errorAmountLabel").text("Amount (Inc "+m_gstLabel+"):");								
									$("#errorNoofUnitsLabel").text("No. of " + m_unitCaption + ":");
									m_page3.hide();
									m_page4.show();
									_base.Viewer().HideLoad();
								} else {
									BundleUsed;
									$("#successDate").text(tme + ", " + t["Date"].getDate() + "-" + (t["Date"].getMonth()+1) + "-" + t["Date"].getFullYear());								
									$("#successAmount").text("$"+t["Amount"].toFixed(2).toString());								
									$("#successUnits").text(m_record["Units"].toString());								
									$("#successTransactionNo").text(t["Transaction No"].toString());								
									$("#successReceiptNo").text(m_record["Receipt No."]);								
									$("#successAmountLabel").text("Amount (Inc "+m_gstLabel+"):");	
									$("#successNoofUnitsLabel").text("No. of " + m_unitCaption + ":");
									m_page3.hide();
									m_page5.show();
									_base.Viewer().HideLoad();	
									if (_base.Viewer().Options()["activateCompany"] && m_totalPrice > 0) {
										ActivateCompany();
									}
								};
							});
						}
					);
				});
			});
			
			var prevbtn3 = $("<a style='float: right;margin-top: 20px;font-size: 14px;margin-right:10px;'>Back</a>");
			if (Application.IsInMobile()) {
			    prevbtn3.buttonMarkup();
			} else {
			    prevbtn3.button();
			}
			m_page3.append(prevbtn3);
			prevbtn3.on("click",function(){
				// if(m_skipToEnd){
					// m_page1.show();
				// }else{
					// m_page2.show();
				// }		
				m_page1.show();				
				m_page3.hide();
			});
			
			var nextbtn4 = $("<a style='float: right;margin-top: 20px;font-size: 14px;'>Close</a>");
			if (Application.IsInMobile()) {
			    nextbtn4.buttonMarkup();
			} else {
			    nextbtn4.button();
			}
			m_page4.append(nextbtn4);
			nextbtn4.on("click",function(){		
				Application.RunNext(_base.Viewer().Close);
			});
			
			var prevbtn4 = $("<a style='float: right;margin-top: 20px;font-size: 14px;margin-right:10px;'>Back</a>");
			if (Application.IsInMobile()) {
			    prevbtn4.buttonMarkup();
			} else {
			    prevbtn4.button();
			}
			m_page4.append(prevbtn4);
			prevbtn4.on("click",function(){
				// if(m_skipToEnd){
					// m_page1.show();
				// }else{
					// m_page2.show();
				// }				
				m_page1.show();
				m_page4.hide();
			});
			
			var nextbtn5 = $("<a style='float: right;margin-top: 20px;font-size: 14px;'>Close</a>");
			if (Application.IsInMobile()) {
			    nextbtn5.buttonMarkup();
			} else {
			    nextbtn5.button();
			}
			m_page5.append(nextbtn5);
			nextbtn5.on("click",function(){		
				Application.RunNext(_base.Viewer().Close);
			});
			
			var invbtn1 = $("<a style='float: right;margin-top: 20px;font-size: 14px;margin-right:10px;'>View Invoice</a>");
			if (Application.IsInMobile()) {
			    invbtn1.buttonMarkup();
			} else {
			    invbtn1.button();
			}
			m_page5.append(invbtn1);
			invbtn1.on("click",function(){				
				Application.RunNext(_base.Viewer().CloseSilent);
				OPENPAGE("Invoice Report",{"Transaction No":m_transactionNo},{dialog: true},null,true);
			});			
			
			Application.RunNext(function(){
				return $codeblock(
					function(){
						FINDSET("Application Settings",null,function(settings){
							return settings;
						});
					},
					function(settings){
						
						m_unitCaption = settings["Unit Caption"];
						m_gstLabel = settings["GST Label"];
						m_gstPerc = settings["GST Percentage"];
						m_currencyCode = settings["Currency Code"];
						
						$("#paymentTitle").text(settings["Payment Header Caption"]);
						$("#paymentBundles,#paymentCoupon").css("background-color",settings["Payment Header Background"]);
						$("#paymentBundles").css("color",settings["Payment Header Foreground"]);
						
						FINDSET("Bundle",null,function(pm){
							if(pm.Count > 0){			
																
								do{																		                 
									
									var btn = $('<div style="width: 23%;height: 120px;background-color: '+pm["Background"]+';display: inline-block; margin-right: 2px;cursor: pointer;"><h2 style=" margin-bottom: 3px;line-height: 24px;margin-top: 13px;font-weight: normal;font-size:1em;color: '+pm["Foreground"]+';">'+pm["Quantity"]+" "+settings["Unit Caption"]+'</h2><small style="color: '+pm["Foreground"]+';">($'+(pm["Unit Price"]*pm["Quantity"])+')<br/>&#65088;</small></div>');
									$("#paymentBundles").append(btn);																	
									eval("btn.on('click',function(){AddBundle("+pm["Quantity"]+")});");     
									
									m_prices[pm["Quantity"]] = pm["Unit Price"];
												
								}while(pm.Next());
							}
						});
					}
				);
			});
			
            _self.Loaded(true);
        };

        this.CreateMobile = function (window_, form_) {
            return _self.CreateDesktop(window_, form_);
        };

        this.CreateList = function (value_) {
            //Not used.            
        };

        this.Update = function (rec_) {

            m_record = rec_;						
            _self.Loaded(true);
        };

        this.Height = function (h) {
            m_page1.height(h - 70);
        };

        this.Width = function (w) {
            m_page1.width(w - 20);
        };	

        //#endregion

        //#region Private Methods

        function ActivateCompany() {

			var callbacks = new Object();
			callbacks.onerror = function (err) {

			    UI.HideServerProgress();

			    setTimeout(function () {
			        Application.Error(err);
			    }, 500);
			};
			callbacks.onsuccess = function () {

			    UI.HideServerProgress();

			    setTimeout(function () {
				    Application.RunNext(function(){
					    FINDSET("Company",{ID: m_record["Company ID"]},function(comp){
						    Application.Message('Your company '+comp.Name+' is ready.', function () {
							    if (ThisViewer()) Application.RunNext(ThisViewer().Update);
						    });	
					    });						
				    });
			    }, 500);
			};
			callbacks.onsend = function () { };

			setTimeout(function () {
			    Application.ExecuteWebService("ActivateCompany", { auth: Application.auth, id_: m_record["Company ID"] }, null, true, null, true, callbacks);
			},1000);
			
			UI.ShowServerProgress("Awesome work!<br/>We are activating your company", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAcFElEQVR4Xu1dB3SUVfb/vTeTnhASSEIIPRXSkKqACIJCEtFdV9EV17K2Y3fXsra/ZV0VFP0ruu7+LevaFbtiEsRGFRAJySQsKRAgoYWQAOmZmff+5w4MmzLl+2a+KUDuOTkn58x799533/2+771bGU5BSPvuPwOMZlMqlzKVgadKKRKFYP05RzjMMgJcRjDGI8wCEQAkg2hiDM0QrAk61gSJJsbYYQDbJUS5BMqDmK68bG56w6kmLnayL2jUik2R3Bg8nTMxExCTzZKlcsYHeGJdAqhnEOWQfD1n8gfWGbi6/KK0Jk/Q8hbOk04BRvxYHaxva57OOTtXmOVMxsUEgHNvCawHHTOAX6TED5zLH4UIWV2Vm9zhI15cIntyKICULKVw61TBzFcxM5sPjkiXVuvhSQxolAwfSinfqZqbuR6MSQ+TdBu9XytAUr4hkTP8wQz8gQOj3F6tNxGYzVXQ87c5k++Wz8mu9iZpNbT8UgGSCkrOkoI9xDny1CzGb8dK+RXj/MmKuRkb/Y1H/1EAy2u+5FwAD0nwmf4mKE34kVghIZ+syslc5S+fB79QgJT8khwTx6M6ySZrImg/RyIh1jLOH6+ck7nC16z6VAHSCopGmKFfAmCerwXhC/pCiM+g53dtn5NZ4wv6RNMnCpCUXxnEefvdUuJhACG+Wrw/0DULtOg4Hu8X0/HCrxMmGL3Nk9cVIKWgeJaA7hUGmeLtxfo3PblVStxSlZu10pt8ek0B0peWBXb2My+CZHd5c4EnHS0pn+kX2/mwt94GXlGA1OXFI4VgHwFs4km3IT5gmMG8zsx1l3vjbOBxBUgpMPxWCrzpr9Y7H+yvIpJSiAam51dXzslcpmiCi4M8pwBLl+qS+6Ut7nvlu7gz1mlSPlO5MfMBPMaEm5hsTveIApDDJqC9+X0Av/UE06cbTsnERxChV3vC0aS5ApB7VmcK+hLAOafbRnlyvULgO70p4GKt3c+aKsDowq3xRnNnAeO6bE8K43TFzYBfzVzkbp+TXaeVDDRTgJRlJaNMjH2n4xipFXPexDMgUI/YYD1CdRwhOo5AztApJFpMAo2dJhzoMKHN7JHPsLplms1VJhY4uzpvzC51E22P1kQB6MnvMJvXngybTwseFR6E7MhQZEWGIDUiGENCAhCscx5TQopQ1dyBsqPtKD7Sis2NrWj1hVJIVAqdmKbFm8BtBbCEZHXqV/rza1/HGMZHhWJmTATOiYlATJBei4cHJilRdLgVP9Y1YcWBozhspAAh7wB9DlhnwEx3zwRuKcDx036hvx74aKN/M7g/Lkroj7igAI/uDCnDqoPN+Li2EZsaWzxKy4qcDobBLTyvbH56p6sEXVcAuudHjP7YH696CSGBuG7kAOQOigQ9/d6GbU3teKO6Hj8d9Eq86IeVGzIWuGoncFk6yYUl/+tvRp7oQD1uTozBvHjfbHxPRSs72obnKg7AcKTNozrIwBZW5GQ84AoRlxTAYt4FPnOFoCfmcAZcnBCFWxJjEKHXeYKEWzi/3ncYL1bW4YgHzwgMMq8iJytfLaOqFcDi2JF8MyT6qyXmifHxwQF4IiMB2ZH+HVbQ0GnCX7fuw9pDzZ4QA4QUhxgwtio3u1YNAVUKYHHpRpjX+ItXb1ZsBB4eHY9wP3zq7W3Cu7sP4eWqgzBLj0SMr0kIrp/508yZJqVKoEoBUgpKnpdgf1KK3FPjiOlbEmNxzQiPJAB5iu0TeDc1tuJ+Q61HPgkSeLoqJ/NBpYtQrAAUySPBv1OK2FPjyEL31/TBmBXbz1MkvIJ3d2snbivajX3t2keBMfCzK3LS1yhZiCIFoBg+KduLOUeqEqSeGkOb/0L2UEyMDvMUCa/iPdBhxM2bd6Om1eVrvG1+JUr7xXaMUxJVpEgBUgoND0qJJ70qnR7EaPOfyx6KM0+Rzbcur67DhBt/3Yk9bdq+CRjk3RU5Wc872zOnCnA8dHurL6N3icmFmUNwbixlc596QG+Aq3/ZiSaTdqZkYRbNOinTKuaN3eNIYk4VIDm/5EswdqEvxX7jqBjcMHKgL1nwOO1fGlpw+5YaTW8HFEhSNTf7cpcVILGwbC6XosDjq3dAYHpMBJ7LGuJLFrxG++1dh/BSlWaufgvfEphZlZP5k71F2H8DSMlGLTf87Mt0rf4BOiw9cxSiArXx3nltJ90gdGvRbmxs0NCZJOVPlblZdnMt7SqAP1z7Fp3C3317OnKg3YhL1+/QNPiESzatPDdjrS2ajhTgB19m6dJp/6UzhrnxLPl+qtHcCT0PAFPpkfygpgHPVxzQbAGSsYKquRm5ihWA8vMZ2DrNOFCJiLTy3UkjkRIRrHKm4+FNnUew62gV9jbX4GDLXhzpaESz8Sg6zUZIaYaO6xGsC0VEYD9Eh8QiLjQeQyOTMCR8mOU3NdBhasc7W/+OS1KvQf8gdRZLii24bP0OkLFIK5BMjK+am725Jz6bb4DEbwzLfFmcYU5cP/wtI0GTtR/taMTmAz9ja/0W7G9R5Sc5QZ+e4uSodGTGjEfqgCwEcMfBJW2mVrxd+hL2NO3C1Rl3IDEqTfVavj1wFA+VOrzBqcJJmcjb87J/51QBqCwLY6hShV3jwW9NHIEx/dzz7tU0VWNVTSEqGkohNXS8hAaEY2L82ZgcPwPhgb3tEi3GJrxlWIL9Lcc274KkyzEpfrpqCZGr6OJ121HbptFbQAhpDtSP2HFe+u6uzPR6A6QUGB6TwKOqOdZoAgVp0uvfVTjUVoeCHR+joqHMVRSK5gXqgjE1YRamDTkPAbpAy5ymzsP4d8kSHGzbfwLHWQmzkDOq14OniMaHNQ2WgBKtgAEPVuRkPm1fAejql1+63ZfRvfelDsKlQ6JUr1lIgZW7C7C6djlMQrE3VDWdnhOiggfityl/QP/gaMvmN7Qf7DYkdUAmFoy52SU6R41m5KyptISnawFSYFtVbsaYruVpur0BUgrKpkmI1VoQcxXHV1OTQEEeaoCevKXb/oVdR3zz5WJgCA4IRZux9/09JmQQbp/wiJrldBt7d0ktVmkYW8gFJpbnZW6yEummAEmFJa8yyW5wmVs3J44IDcTHZyWqwnKgZQ/eLn0ZdML3R6DbwyNTXlR9FbSuhcLJKJJIQ3ipMifzjl4KYAnxbm3e78s07t8lROH+tEGK10pP/Htb/4F2k/qgy+jgWAwKG4z+IQMRqguFnustn45mUzMa2w5aror0ZtEC/jzpCdVXQStdchlfsEa7NxuVuw1u4gnWUPITb4CkfMP5jGG5Fgt2Fcc9KXG4bGi0oum1TTvxb8OL6DQrq8xKr+mR/VOQFTsRKVGZNk/wPQnT97z8kAFFB9a7fIUknK5eBa385K2pBLmNNQMhz6nMy1pF+E4oQEph6UIp5V80I+IAEcXq6xmg5wx0vrHm3L1yxjBFwR6N7fV4dcuzoCuXM6CNz4gZjxnDchATGu9suN3f6W3z4+5vsONwuWocrl4FrYS0Pgcw4PGKnMzHuilA0jeGDYxjkurVOZlA2Tnj+ofijKhQJIYFYXBIoCU1q+vho90sUN9pQmxQgCUp0xEYhRGvFz+Lfc3OjTqxofG4MHkBhvXTrsos3TS+3/W1KjG5cxUkQkuq6vDOrkOqaDoaLARbvT0vw2KcsEj7WE5/QINWVbfD9Rxz4iKRGx9pScDUEgqrP8W62u+dojwj7izMS7rcYovXCsiS+G/DErQa1YV2p0ZnYkG6a1dB4v2jmgYs1tAeIASMbaKj/955E1otCpCUXzqPMfmVu4KKDNBhwbBozB8ajTAF2bZq6ZFp9dXiZ5xa9mYOy8PM4dqWGd7TvBtvG5aAzLxqwd2roNZmYQv/HOdTpVKLArgb7k1IKDPntqRY0NPvKXh1yzOgw58jmD38QkwfNldTFmqOVuOdspddum0QI3TD+B83roIrDzbhnhLnnzw1i7amkx1XgC1rJXRT1CCwjo0N0uMpyszpH+rKdMVztjWU4P2yfzocP37QNFyUfIVinEoG0uHvnbK/K75t2MPpzlWQkkzv1VwBxI8VOdnnWhQgMb+43pU2KxOiwvBUZgKiAjyfj/falmdBDh57EBc2GDeNvd/ytGkFRnMHvt7+EfY316KhvR6d5naXUbtzFaTaAw9q6BmkRQgp927PzUpg1GDJbDTVq13ZbHLZpg/2Svo1nfj/UfSUXRbpqnfj2PuQEDFc7TJUjW/ubLLY+hvbD1oU4lBrHRra63Covd6mGbgrcneugp/uacTCbf91MKli2sFgKYMjWeJywxQuYDNcyN5cyrt/dMxgOLmxacUn8nd8gvV7frCLb2zsZFycerVm9FxB1G5qtShCQ1sdGtqOK0h7HRrb6i1manevgo1GMyhymApQbDms/iBqa03kF2DJhSXXQrJ/KV30pOgwLBk71CtPvpWnxRsewtHORpss0tNPzpaBIXFKl+D1cfQpaTe3IyJQm1ZHdCZYtG2/xXbiDkgpr2RqLIBDQwNBwRrezMGva92Hl399wu46R/VPxTWZd7ojh5NyLhWsur90j6VQlcsg2RMsuaDkY4Bd4gwJmW/fmDAc6W5G6jij0/P3jftWYVnVh3an0amfTv+nI1CcAIWNuVqKRgj5AUv8xrCCc8x2JsCrhg/A7UmxzoZp/vuXle/h1/32jyj3TH4S/QLVB5BozqiPEBqlxJ+La7D+kEu5BPksucDwM4AzHfFPRRS/nJqEIG+d+row83rJc9h9ZLtN9voFReGeST7NWfXRtncn22IWuOaXndjZoswzap1NPgGWvKykFDqW7mglroZpaSGdxRsfAkX22oKkqDG4KuM2LchoiqO4bgMig6IRHzYUQXptQ9vtMVrd0oErN1arCh8zM7GFJecX7wLjdjMwqPLWsmlJCFCZ3KCVRJ9YdxcowcIWjB80FRclL9CKlGZ4rEYruqFEh8QgPnwoBocNRXz4MAwOH4qQAM/UN1CfUCK2s5QCQ4ME7H5Erx0xwFKOxVfw6OpbISnF0QZMGTIbc0de7CvW7NIlv0FlA2XU94YBIbG4c4LFFa85UGzFgo07LOVsFYFAHR0CjZzDrv30iylJSAjRzqWqiLEugx5ZfYvdKVOHnIc5I/2vJcF7Za+gvKHUJt8UinbXRM8oABHc0NBiKT2jENpYckGx2V4cQGJ4ED6crF0whUKmug0rrtuIvc27LX9kEu5qj6cEjXlJv3cFrUfnvGl4AdWHK2zSoCCV28b/j0fpX7tpJ0oVFacUHSz5m+I2cG7zpHLlsAG4M9l3r/+eUqJPASV+HFOIGgTxIM39/lrszEu/PoGDrbYjeYdHJuG6rD9rQcYuju/rjuJ+g/O0MgHRRIagIwCzWXLruewhmD7w1CzL4qkdoAQVOria7SSnZMVMwCVpf/QUeQteSi7NW1MFKk7pCChCmKUUFO+T4DZjsX39/feolDyEfF9zDf5R1C37qhslilSiiCVPA3kPyYvoEKTYbdcOQEaf1TPTfNNb1tPS8SD+NbUr8G3153YpXDHmJqQN8HxHnZ8PteCOLc4Og7KIjSo0rNRJ9EpfpfQsStPqA3USeHXLItQ22e/mct/khQgP9HyRS4q0nrGywnHRKYkVLDnf8AkYeqWvJoUH4QMf3wDUid73oykl/JXN9k3TcWEJuHXcQ15jlCyD5U0Oopgke58lFZQ+xyB7HUszIkPw5oQRXmPWGaGPt/0LRzsPIzo4BgOCYxAdGmP5n/6C9dqGnjvjxd7vn2x7EyUHf7E7fcawXJw7/AJX0aue90jZXhTst58zSXWF6Q1wOxiW9MTubp6+am6dTPii8l1s3m+7ag0VbYgOHgiyspHplVK2BwTT/wMRFuCdWwwd/v5ZtNCu1ZKWR4ErFCLuLfi/HQfxerX9aD8m2Y0sebnhAgj0SnWh4I/PVGbqenJhq2u+xYqdX6gmQc4YUg7L2yIkFgNDYjE29kyXs3VtMUBXPwpZJ/uEPaC8xGszvds4fWltI54ttx9LyJg8jx3r7M139GSc+uetnOHT2tDdWNp6qAgfbn1NtQJ0ncAZxyVp1yJj4Hi38PScTKd+Ov07givTb0VKtEOnq6Y8EbJl+47g8a177eLluoAEhsckT5xQcoTreHjPkYVnJ4NiAfwBqA7A3x0csJzxqGM6zB99HUYPGOtsqKrfiw78jM8r3nE4Z2i/kbgh+15VeLUYnL//CB4ts60A1GFke05WjCUvIDnfsA4MZ/UkqjRbVwtmneEglzBZ2FwByhW4LO0GULkWLYH8FJ9XvE3tWuyiJZfw9WPvwdAI1+seucrzJ7WNWGTvE3C8guixxJBvDC9yjhNVI6wE/a1I87MbHlRdtIFKuv1+zE2g4BGtgHwSq2uW4/udXzs89BG9SfHn4IKky7QirQoPHQDpIGgTqC19btZfjiWHFhrmM4mPeg4c2z8Ur433bLKFmhW9UfK86jpAvx9zo6avfaoaQnGKSqqQUaj6zWc8cKKKmJq1ajHW0TVQgl9UlZP+1bHcwK+3JEi9rlf2IUUC509LAkUF+QM4ugra44+qfs4afiGy4yaDzgGuAn2C1u/9CStrChWliFEZuZvG3utWUQpXebXOW7ChGhXNtg1BzBQYUzEvtf6/JWIKSssZZEpPon9KjsMVw5SVbXGXYWfz6bW7YueXzobZ/J3KtY4fNAXZcZNU1esht25R3QYU7f9ZUUUSIk63jSvG3Oz1U3/XhVOJudmrKuzEUqGkMifT4pA4oQDJ+YYXwNArw4Iqdy09K9EvnEJaXAVp0RSUQX75QWFDLMGbYQHhllrARtGJVmOLJf+PDDsUjdyz7p8z7bNcNVOvtZSl8SU4SihljC2qmJtxfzcFSCooncMgqRF0L3gmcwhm+kG7Fme2dl8KnGgH6IJwWdr1Pn3yrTK4u7gGq+ptVzKRUs6oys1a2V0B8iuDGGursxUcQo6h9yaN8loyqL2NpBy7J9b5vG2hTfbI/HzZ6OsxONz3Je4Pdpgwb22VTU8g3f/7xxrjrR3FehSKNLzFJK6ytcK7U+JwucISbp58Ep/d8ECvopAUZk1PHt3LyTDjbUgfOM4Snu4vTinqNUAh4raBvVqZk3GT9bduCpBcaMiDxDJbE8P03OIeVlvGVevN6HkVJN86FV+gAhEEFI69vPpTUFKpp4EOlnmJ8zU3MLnDNzWivPTn7eiwU1+YQcyuyMk+UWWrmwKM37Qp4GhdUA0YbOZaU2Lo6xOGQ++jJBESzBcV72LzgWNeQcoJvCbrjl6p4WSZozfB2trvUN+mXbVt68YQ3enDzse4uKmaViRxZ+NPfPsd1xaurWz6zwjMn3+iP13vcvFOCkZSMagHVJRz1WJRXXFYr4L0zb02606HVzqy2NEbgZShorHUboaREh7JhkCNH8YNmoLU6Cy3bApK6LkyxpnzhzH214q5Gd1aAfRSgMTC0iQuZaUjBnxpIi6rL8L3O7+ybH5EoPIO9nSA3HGkwmJJ3N20A/Wt+y1XPntAJ/pBoYMxOGKYpcRsYuRor+X5ubL525s7cM2mnaBQMJsghDQhYGR13phu8Wo2y3ImFxi+AWCzyZAV+U2jYnC9D5o5UqUQSmSy1a1DreCovHuLqdlS+08KAcY5AnkQ+gVGeix/Ty2PSsbvbzfij5t2gk7/DuDzypzMXnl0NhUgNb/sXMGE03KcVN37ntQ4n54JlAjoVB5T09aJ24tqsMdJaxnBMXX7nMxeIVW2C/NKyZILSjeBYZwz4VHs4MKMBMSpbPLgDG/f784lUHy4FfcZ9jhNAGEwr6vIGTvVFka7lZmTCksuYpIpisGi6qA3J8bikoQonxuLnIvt5B9hlhJv7TqEV3fUK+o1LCXmVOVmfqtKASAlSyos3ciACUpFRn3+bhw5EOfEeCcQUylfp9K4TY2tWFyxH3ToUwhrKudmTO/aJ6jrPIe12V1tIkFZxXRdPD+uH6j/bx+4JwHK9Vtb34z3djegSG2NwC7NIdS9AY6PVnIjsLc8MhiNiwrFhKhQjIsKw6iwQK+WmHNP7L6dTT2Ei4+0WYpDUhWww8YTthvljEl8Wpmb6bACnOPuDABSC4pTTYKXOioioZwjICpQZwk0pahj+lPbV1cNrZNpLDW3bDULNJsE9rYb7d/nFS9KdHCO0eVzsu0XWO4aD+AIb3J+ySIwdp9i2n0DfS6Brm1hHDHj9A1Akwd/vSk0TB9QAnB1Pd18LobTkwHBxH+YCD2jKjfZ6UlRkQKQGJUah05PkfvRqoWQnOnOLs/NUFQAXLEC0BLthY350fJPe1a6hnspEYYqBbA0l2xr/oU6sSlB3jfGuxJgwK8BTXyKtSmkEuqqFIAQJhWWpTMpNgLwbI8YJdz3jekiAXlUJ8TEbXljbZcnsyMr1QpAeFLyDZdJBvslvPs2xusSkEz+pmpuluqYeZcUwPImyDcsZgx3e32lfQR7S4Dhycq5mQ+7IhqXFQBLl+qSw9M+A2MXukK4b442EmBgH1dsSL8cjzH7GaoOSLmuAACylheHtQr+kxqHkTbL7sNCEiA3b2tT6+za+VPUt08/LkK3FIBwJC4vjmUmvpJxpPVtixclIFGqC9TP2DZ7tFtNhd1WAMuh8OstCSauW63j8H4SvBdl7jekJCqNkk/fmZfudi85TRSABJNWUDSiU+h/6FMCD6uJ2VxlDgqYteO8dGdVIBUxopkCWN8Eguu+6/scKJK9+kESpUbJz9PiybcS11QBrGcCLtgygE1Uv8K+GfYkQAc+HhB0obvf/J74NVcAIkDew3B98PsS8qK+LXVfAnTV6wwOu2rnzJGuNy+2w4ZHFMBCa+lSXWLY6Kc5h/fLY7kvc//BQEae9RmPuHrPd7YQzynAccpJBSWXCsHe1HF4plOSsxWetL/Lo5LhKlfMu2qW7HEFIGaS8svGMCY+INuRGuZO17Hk1ePCfIVax44r8vKKAhxTgsogsI6nbBWmdoXxU3KOEJJx3aKAJvaoGpeuO7LwmgJYmUzKLzmHgb0GhmR3GD/V5lIYl17oblAayaPV+r2uAMT4kKXrQoLDIx6WEvdyDt/1pNNKim7hER0MfKGQwU8rieFzi5SNyT5RACsfo77dmqwzmRafvh5F+Qnn8j5nodtab3pXfD5VACsjKQXFsyT435w1sfakILyMew2EfKgyL2uVl+n2IucXCmDhSkqWUmjIEYI9yjgm+VownqBP1jwhdY9X5WSssJer5wm6jnD6jwJYuSRFWF4yTQp2zynxaRBCgvMvBMdiW/n53t7wnvT8TwG6cGhpZiH5dcIs/8g5i/e1sFTSr2XAG0ahe7NnWRaVeDw63K8VwLryGT/+qK9tG3guZ2I+wC921O3co9JygpyKMHKm+5TBvLSiqfynrtW4fMnXyfUJcCKp9KVlgaZwTBPMlAMzy4GOebcPS2/+ShhjBUKIgsjYznXWCpz+uuEn1SdAiRBHfmeICzBiipCYKjgm6iUyPfWGkEI0MMZKAGyUTLeWm/TrqOS6Ej79dcxJ8QlQJTyqbFJQkgDwMZzJEQAfaRZiOMBiOJcDIORAwXkIIIIABHGAGr50AryDS9EKxg5BsnqAHZRM7uKSVYOLasYDt5afl7rPX07vqmTiYPD/AxHoLAMy31vHAAAAAElFTkSuQmCC", true);

		};
		
		function BundleUsed(){
			if (m_record["Promo Code"]!="") {
				CODEMODULE("Control App Functions",function(c){
					return c.UsedCoupon(m_record["Company ID"],m_record["Promo Code"]);
				});
			};
		};
		
		// function ValidateCCName(){
			// var ccname = $("#paymentCCName");
			// ccname.css("background-color","");
		// };

		// function ValidateCCCVC(){
			// var cccvc = $("#paymentCCCVC");
			// cccvc.css("background-color","");
		// };
		
		// function ValidateCCExpiry(){
			// var ccexp = $("#paymentCCExpiry");
			// ccexp.css("background-color","");
			// if(ccexp.val() == ""){
				// return false;
			// } else {
				// var b_OK=true;
				// var m_mthyr = [];
				// m_mthyr = ccexp.val().split(" / ");
				// for(var i=0; i<m_mthyr.length;i++) m_mthyr[i] = +m_mthyr[i];
				
				// if (m_mthyr.length!=2){
					// b_OK=false;
				// } else if (m_mthyr[0]>12) {
					// b_OK=false;
				// } else {
					// var m_today = new Date();
					// var m_expdate = new Date(m_mthyr[1]+2000,m_mthyr[0],1);
					// if (m_today>=m_expdate) {
						// b_OK=false;
					// };
				// };
				// if (b_OK==false) {
					// ccexp.css("background-color","#FFE6E6")
				// };
				// return b_OK;
			// }
		// };
		
		// function ValidateCardNumber(b_continue){
			// var ccno = $("#paymentCCNumber");
			// if(ccno.val() == ""){
				// if (b_continue==true){
					// ccno.css("background-color","#FFE6E6");
				// } else {
					// ccno.css("background-color","");
				// };
			// } else {
				// Application.RunNext(function(){
					// return $codeblock(
						// function(){
							// CODEMODULE("Control App Functions",function(c){
								// return c.checkCC(ccno.val());
							// });
						// },
						// function(b){	
							// if (b==true){
								// ccno.css("background-color","#CCFF66")
							// } else {
								// if (b_continue==true){
									// ccno.css("background-color","");
								// } else {
									// ccno.css("background-color","#FFE6E6");
								// };							
							// }
						// }
					// );
				// });				
			// }
		// };
		
		function ApplyPromo(){
			
			var promo = $("#paymentPromo");				
			//m_promoqty = 0;
			//UpdateAmounts();

			if(promo.val() == ""){
				promo.css("background-color","");
			}else{				
				Application.RunNext(function(){
					return $codeblock(
						function(){
							CODEMODULE("Control App Functions",function(c){
								return c.ValidateCoupon(m_record["Company ID"],promo.val(),m_totalBundles,function(){
									promo.css("background-color","#FFE6E6");
								});
							});
						},
						function(cp){								
							promo.css("background-color","#CCFF66");
							m_promoqty = cp.PROMOQTY;
							m_promominqty = cp.MINQTY;
							m_promocode = promo.val().toUpperCase();
							promo.val(m_promocode);
							UpdateAmounts();
						}
					);
				});
			}
			
		};
	
		function AddBundle(qty){
			m_bundles.push(qty);
			UpdateAmounts();
		};
		
		function AddBundles(bundles){
			m_bundles = bundles.split(",");
			for(var i = 0; i < m_bundles.length; i++){
				m_bundles[i] = +(m_bundles[i]);
			}
			UpdateAmounts();
		};
		
		function RemoveBundle(qty){
			for(var i = 0; i < m_bundles.length; i++){
				if(m_bundles[i] == qty){
					m_bundles.splice(i,1);
					break;
				}
			}
			UpdateAmounts();
		};
		
		function RemovePromo(){
			m_promocode="";
			m_promoqty=0;
			m_promominqty=0;
			UpdateAmounts();
		};
		
		function UpdateAmounts(){
			
			var cart = $("#paymentCart");
			cart.html("");			
			$("#paymentBestValue").hide().unbind('click');
			$("#paymentTotal").hide();
			m_totalPrice = 0;
			m_totalBundles = 0;
			
			if(m_bundles.length == 0 && m_promoqty==0){
				
				cart.html("<br/><br/>You have no bundles yet");							
				
			}else{
				
				m_bundles.sort(function(a,b){
					if (a == b)
                        return 0;
                    if (a > b) {
                        return 1;
                    } else {
                        return -1;
                    }
				});
				
				var rolledbundles = [];
				var lastbundle = null;
				for(var i = 0; i < m_bundles.length; i++){					
					if(m_bundles[i]!=lastbundle){
						lastbundle = m_bundles[i];
						rolledbundles.push({bundle:m_bundles[i],qty:1});
					}else{
						rolledbundles[rolledbundles.length-1].qty += 1;
					}
				}
				
				cart.css('padding-top','');
				for(var i = 0; i < rolledbundles.length; i++){
					var lineprice = +(rolledbundles[i].bundle*rolledbundles[i].qty*m_prices[rolledbundles[i].bundle]);		
					m_totalPrice += lineprice;
					m_totalBundles += (rolledbundles[i].bundle*rolledbundles[i].qty);
					var id = $id();
					cart.append("<div style='height: 50px; width: 100%; background-color: WhiteSmoke;border: 1px solid gainsboro; text-align: left; margin-top: 5px;'>"+												
						"<div style='color: Gray;display: inline-block;font-size: 20px;margin-top: 10px;margin-left: 10px;'>"+rolledbundles[i].bundle+" "+m_unitCaption+" x "+rolledbundles[i].qty+"</div>"+
						'<div id="'+id+'" style="display: inline-block;font-family: Arial;font-size: 15px;color: #CCC;margin-left: 10px;border: 3px solid #CCC;border-radius: 50%;width: 20px;height: 20px;text-align: center;font-weight: bold;float: right;margin-top: 13px;margin-right: 10px;cursor: pointer;">&#9644;</div>'+
						"<div style='color: Gray;display: inline-block;float: right;font-size: 20px;margin-top: 10px;margin-right: 10px;'>$"+lineprice.toFixed(2).toString()+"</div>"+						
						"</div>");
					eval("$('#"+id+"').on('click',function(){RemoveBundle("+rolledbundles[i].bundle+")});");     
				}

				if (m_totalBundles<m_promominqty){
					RemovePromo();
				};
				
				if (m_promoqty!=0){
					var id = $id();
					cart.append("<div style='height: 50px; width: 100%; background-color: #CCFF66;border: 1px solid gainsboro; text-align: left; margin-top: 5px;'>"+												
						"<div style='color: Gray;display: inline-block;font-size: 20px;margin-top: 10px;margin-left: 10px;'>"+m_promoqty+" "+m_unitCaption+" x 1 [Promo Code "+m_promocode+"]</div>"+
						'<div id="'+id+'" style="display: inline-block;font-family: Arial;font-size: 15px;color: #CCC;margin-left: 10px;border: 3px solid #CCC;border-radius: 50%;width: 20px;height: 20px;text-align: center;font-weight: bold;float: right;margin-top: 13px;margin-right: 10px;cursor: pointer;">&#9644;</div>'+
						"<div style='color: Gray;display: inline-block;float: right;font-size: 20px;margin-top: 10px;margin-right: 10px;'>$0.00</div>"+						
						"</div>");
					eval("$('#"+id+"').on('click',function(){RemovePromo()});");     					
				};
				
				var displayqty = +m_totalBundles+m_promoqty;
				$("#paymentTotalUnits").text("Total: "+displayqty+" "+m_unitCaption);
				var gstamt = (m_gstPerc/100)*m_totalPrice;
				$("#paymentTotalAmount").html('$'+m_totalPrice.toFixed(2).toString()+'<br><small style="font-size: 12px;">(+'+gstamt.toFixed(2).toString()+' '+m_gstLabel+')</small>');
				$("#paymentTotal").show();
				var totalincgst = m_totalPrice+gstamt;
				
				//Update payment confirm page
				$("#paymentConfirmBundles").text("Total: "+displayqty+" "+m_unitCaption);
				$("#paymentConfirmPrice").text("$"+m_totalPrice.toFixed(2).toString());
				$("#paymentConfirmGSTLabel").text(m_gstLabel);
				$("#paymentConfirmGSTAmount").text("$"+gstamt.toFixed(2).toString());
				$("#paymentConfirmTotal").text("$"+totalincgst.toFixed(2).toString());
				$("#paymentConfirmCurrency").text(m_currencyCode);
				
				Application.RunNext(function(){
					return $codeblock(
						function(){
							CODEMODULE("Control App Functions",function(c){
								return c.CalculateBestPrice(m_totalPrice);
							});
						},
						function(bp){			
						
							var bundles = bp.BUNDLES.split(",");
							var totalbundles = 0;
							for(var i = 0; i < bundles.length; i++){
								totalbundles += +(bundles[i]);
							}
							
							if(totalbundles == m_totalBundles && bp.SAVING == 0)
								return;
							
							if(totalbundles >= m_totalBundles){								
								var newprice = m_totalPrice - bp.SAVING;
								displayqty = +totalbundles+m_promoqty;
								$("#paymentBestValue").show().html("You can do better! Do you want to get "+displayqty+" " + m_unitCaption + " for $"+newprice.toFixed(2).toString()+"? Click Here").on("click",function(){
									AddBundles(bp.BUNDLES);
								});
							}
						}
					);
				});
			
				_base.Viewer().CenterDialog();
			}					
		};
		
        //#endregion        

        //#region Overrideable Methods

        this.Enabled = function (value_) {
        };

        this.OnValueChange = function (name, value) {
            return true;
        };

        //#endregion

        this.PageControl = function () {
            return true;
        };

        //Constructor
        this.Constructor();

    });  

//# sourceURL=Liveapp.js